#include <config.h>
#include "lisp.h"
#include "buffer.h"
#include "charset.h"
#include "category.h"
#include "indent.h"
#include "keyboard.h"
#include "frame.h"
#include "window.h"
#include "termchar.h"
#include "termopts.h"
#include "disptab.h"
#include "intervals.h"
#include "region-cache.h"
int indent_tabs_mode;
#define CR 015
double last_known_column;
int last_known_column_point;
int last_known_column_modified;
static double current_column_1 P_ ((void));
static double position_indentation P_ ((int));
int current_column_bol_cache;
struct Lisp_Char_Table *
buffer_display_table ()
{
Lisp_Object thisbuf;
thisbuf = current_buffer->display_table;
if (DISP_TABLE_P (thisbuf))
return XCHAR_TABLE (thisbuf);
if (DISP_TABLE_P (Vstandard_display_table))
return XCHAR_TABLE (Vstandard_display_table);
return 0;
}
static int
character_width (c, dp)
int c;
struct Lisp_Char_Table *dp;
{
Lisp_Object elt;
if (dp && (elt = DISP_CHAR_VECTOR (dp, c), VECTORP (elt)))
return XVECTOR (elt)->size;
if (c == '\n' || c == '\t' || c == '\015')
return 0;
else if (c >= 040 && c < 0177)
return 1;
else
return 0;
}
int
disptab_matches_widthtab (disptab, widthtab)
struct Lisp_Char_Table *disptab;
struct Lisp_Vector *widthtab;
{
int i;
if (widthtab->size != 256)
abort ();
for (i = 0; i < 256; i++)
if (character_width (i, disptab)
!= XFASTINT (widthtab->contents[i]))
return 0;
return 1;
}
void
recompute_width_table (buf, disptab)
struct buffer *buf;
struct Lisp_Char_Table *disptab;
{
int i;
struct Lisp_Vector *widthtab;
if (!VECTORP (buf->width_table))
buf->width_table = Fmake_vector (make_number (256), make_number (0));
widthtab = XVECTOR (buf->width_table);
if (widthtab->size != 256)
abort ();
for (i = 0; i < 256; i++)
XSETFASTINT (widthtab->contents[i], character_width (i, disptab));
}
static void
width_run_cache_on_off ()
{
if (NILP (current_buffer->cache_long_line_scans)
|| !NILP (current_buffer->enable_multibyte_characters))
{
if (current_buffer->width_run_cache)
{
free_region_cache (current_buffer->width_run_cache);
current_buffer->width_run_cache = 0;
current_buffer->width_table = Qnil;
}
}
else
{
if (current_buffer->width_run_cache == 0)
{
current_buffer->width_run_cache = new_region_cache ();
recompute_width_table (current_buffer, buffer_display_table ());
}
}
}
int
skip_invisible (pos, next_boundary_p, to, window)
int pos;
int *next_boundary_p;
int to;
Lisp_Object window;
{
Lisp_Object prop, position, overlay_limit, proplimit;
Lisp_Object buffer, tmp;
int end, inv_p;
XSETFASTINT (position, pos);
XSETBUFFER (buffer, current_buffer);
recenter_overlay_lists (current_buffer, pos);
overlay_limit = Fnext_overlay_change (position);
proplimit = Fnext_property_change (position, buffer, Qt);
if (XFASTINT (overlay_limit) < XFASTINT (proplimit))
proplimit = overlay_limit;
if (XFASTINT (proplimit) > pos + 100 || XFASTINT (proplimit) >= to)
*next_boundary_p = XFASTINT (proplimit);
else
{
XSETFASTINT (proplimit, min (pos + 100, to));
if (XFASTINT (overlay_limit) < XFASTINT (proplimit))
proplimit = overlay_limit;
tmp = Fnext_single_property_change (position, Qinvisible,
buffer, proplimit);
end = XFASTINT (tmp);
#if 0
if (end == pos + 100
&& !NILP (current_buffer->enable_multibyte_characters)
&& end < ZV)
while (pos < end && !CHAR_HEAD_P (POS_ADDR (end)))
end--;
#endif
*next_boundary_p = end;
}
prop = Fget_char_property (position, Qinvisible,
(!NILP (window)
&& EQ (XWINDOW (window)->buffer, buffer))
? window : buffer);
inv_p = TEXT_PROP_MEANS_INVISIBLE (prop);
if (NILP (window) ? inv_p == 1 : inv_p)
return *next_boundary_p;
return pos;
}
static int
check_composition (pos, pos_byte, point, len, len_byte, width)
int pos, pos_byte, point;
int *len, *len_byte, *width;
{
Lisp_Object prop;
int start, end;
int id;
if (! find_composition (pos, -1, &start, &end, &prop, Qnil)
|| pos != start || point < end
|| !COMPOSITION_VALID_P (start, end, prop))
return 0;
if ((id = get_composition_id (pos, pos_byte, end - pos, prop, Qnil)) < 0)
return 0;
*len = COMPOSITION_LENGTH (prop);
*len_byte = CHAR_TO_BYTE (end) - pos_byte;
*width = composition_table[id]->width;
return 1;
}
#define MULTIBYTE_BYTES_WIDTH(p, dp) \
do { \
int c; \
\
wide_column = 0; \
c = STRING_CHAR_AND_LENGTH (p, MAX_MULTIBYTE_LENGTH, bytes); \
if (BYTES_BY_CHAR_HEAD (*p) != bytes) \
width = bytes * 4; \
else \
{ \
if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c))) \
width = XVECTOR (DISP_CHAR_VECTOR (dp, c))->size; \
else \
width = WIDTH_BY_CHAR_HEAD (*p); \
if (width > 1) \
wide_column = width; \
} \
} while (0)
DEFUN ("current-column", Fcurrent_column, Scurrent_column, 0, 0, 0,
doc: )
()
{
Lisp_Object temp;
XSETFASTINT (temp, (int) current_column ());
return temp;
}
void
invalidate_current_column ()
{
last_known_column_point = 0;
}
double
current_column ()
{
register int col;
register unsigned char *ptr, *stop;
register int tab_seen;
int post_tab;
register int c;
register int tab_width = XINT (current_buffer->tab_width);
int ctl_arrow = !NILP (current_buffer->ctl_arrow);
register struct Lisp_Char_Table *dp = buffer_display_table ();
if (PT == last_known_column_point
&& MODIFF == last_known_column_modified)
return last_known_column;
if (BUF_INTERVALS (current_buffer)
|| current_buffer->overlays_before
|| current_buffer->overlays_after
|| Z != Z_BYTE)
return current_column_1 ();
ptr = BYTE_POS_ADDR (PT_BYTE - 1) + 1;
if (PT == BEGV)
stop = ptr;
else if (PT <= GPT || BEGV > GPT)
stop = BEGV_ADDR;
else
stop = GAP_END_ADDR;
if (tab_width <= 0 || tab_width > 1000)
tab_width = 8;
col = 0, tab_seen = 0, post_tab = 0;
while (1)
{
EMACS_INT i, n;
Lisp_Object charvec;
if (ptr == stop)
{
if (ptr == BEGV_ADDR)
break;
stop = BEGV_ADDR;
ptr = GPT_ADDR;
if (BEGV >= GPT)
break;
}
c = *--ptr;
if (dp && VECTORP (DISP_CHAR_VECTOR (dp, c)))
{
charvec = DISP_CHAR_VECTOR (dp, c);
n = ASIZE (charvec);
}
else
{
charvec = Qnil;
n = 1;
}
for (i = n - 1; i >= 0; --i)
{
if (VECTORP (charvec))
{
Lisp_Object entry = AREF (charvec, i);
if (INTEGERP (entry)
&& GLYPH_CHAR_VALID_P (XFASTINT (entry)))
c = FAST_GLYPH_CHAR (XFASTINT (entry));
else
c = ' ';
}
if (c >= 040 && c < 0177)
col++;
else if (c == '\n'
|| (c == '\r'
&& EQ (current_buffer->selective_display, Qt)))
{
ptr++;
goto start_of_line_found;
}
else if (c == '\t')
{
if (tab_seen)
col = ((col + tab_width) / tab_width) * tab_width;
post_tab += col;
col = 0;
tab_seen = 1;
}
else if (VECTORP (charvec))
++col;
else
col += (ctl_arrow && c < 0200) ? 2 : 4;
}
}
start_of_line_found:
if (tab_seen)
{
col = ((col + tab_width) / tab_width) * tab_width;
col += post_tab;
}
if (ptr == BEGV_ADDR)
current_column_bol_cache = BEGV;
else
current_column_bol_cache = BYTE_TO_CHAR (PTR_BYTE_POS (ptr));
last_known_column = col;
last_known_column_point = PT;
last_known_column_modified = MODIFF;
return col;
}
static double
current_column_1 ()
{
register int tab_width = XINT (current_buffer->tab_width);
register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
register struct Lisp_Char_Table *dp = buffer_display_table ();
int multibyte = !NILP (current_buffer->enable_multibyte_characters);
register int col = 0;
int scan, scan_byte;
int next_boundary;
int opoint = PT, opoint_byte = PT_BYTE;
scan_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, 1);
current_column_bol_cache = PT;
scan = PT, scan_byte = PT_BYTE;
SET_PT_BOTH (opoint, opoint_byte);
next_boundary = scan;
if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
while (scan < opoint)
{
int c;
while (scan == next_boundary)
{
int old_scan = scan;
scan = skip_invisible (scan, &next_boundary, opoint, Qnil);
if (scan >= opoint)
goto endloop;
if (scan != old_scan)
scan_byte = CHAR_TO_BYTE (scan);
}
{
int len, len_byte, width;
if (check_composition (scan, scan_byte, opoint,
&len, &len_byte, &width))
{
scan += len;
scan_byte += len_byte;
if (scan <= opoint)
col += width;
continue;
}
}
c = FETCH_BYTE (scan_byte);
if (dp != 0
&& ! (multibyte && BASE_LEADING_CODE_P (c))
&& VECTORP (DISP_CHAR_VECTOR (dp, c)))
{
Lisp_Object charvec;
EMACS_INT i, n;
charvec = DISP_CHAR_VECTOR (dp, c);
n = ASIZE (charvec);
for (i = 0; i < n; i++)
{
Lisp_Object entry;
entry = AREF (charvec, i);
if (INTEGERP (entry)
&& GLYPH_CHAR_VALID_P (XFASTINT (entry)))
c = FAST_GLYPH_CHAR (XFASTINT (entry));
else
c = ' ';
if (c == '\n')
goto endloop;
if (c == '\r' && EQ (current_buffer->selective_display, Qt))
goto endloop;
if (c == '\t')
{
col += tab_width;
col = col / tab_width * tab_width;
}
else
++col;
}
}
else
{
if (c == '\n')
goto endloop;
if (c == '\r' && EQ (current_buffer->selective_display, Qt))
goto endloop;
if (c == '\t')
{
col += tab_width;
col = col / tab_width * tab_width;
}
else if (multibyte && BASE_LEADING_CODE_P (c))
{
unsigned char *ptr;
int bytes, width, wide_column;
ptr = BYTE_POS_ADDR (scan_byte);
MULTIBYTE_BYTES_WIDTH (ptr, dp);
scan_byte += bytes;
scan_byte--;
col += width;
}
else if (ctl_arrow && (c < 040 || c == 0177))
col += 2;
else if (c < 040 || c >= 0177)
col += 4;
else
col++;
}
scan++;
scan_byte++;
}
endloop:
last_known_column = col;
last_known_column_point = PT;
last_known_column_modified = MODIFF;
return col;
}
#if 0
static double
string_display_width (string, beg, end)
Lisp_Object string, beg, end;
{
register int col;
register unsigned char *ptr, *stop;
register int tab_seen;
int post_tab;
register int c;
register int tab_width = XINT (current_buffer->tab_width);
int ctl_arrow = !NILP (current_buffer->ctl_arrow);
register struct Lisp_Char_Table *dp = buffer_display_table ();
int b, e;
if (NILP (end))
e = SCHARS (string);
else
{
CHECK_NUMBER (end);
e = XINT (end);
}
if (NILP (beg))
b = 0;
else
{
CHECK_NUMBER (beg);
b = XINT (beg);
}
ptr = SDATA (string) + e;
stop = SDATA (string) + b;
if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
col = 0, tab_seen = 0, post_tab = 0;
while (1)
{
if (ptr == stop)
break;
c = *--ptr;
if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c)))
col += XVECTOR (DISP_CHAR_VECTOR (dp, c))->size;
else if (c >= 040 && c < 0177)
col++;
else if (c == '\n')
break;
else if (c == '\t')
{
if (tab_seen)
col = ((col + tab_width) / tab_width) * tab_width;
post_tab += col;
col = 0;
tab_seen = 1;
}
else
col += (ctl_arrow && c < 0200) ? 2 : 4;
}
if (tab_seen)
{
col = ((col + tab_width) / tab_width) * tab_width;
col += post_tab;
}
return col;
}
#endif
DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "NIndent to column: ",
doc: )
(column, minimum)
Lisp_Object column, minimum;
{
int mincol;
register int fromcol;
register int tab_width = XINT (current_buffer->tab_width);
CHECK_NUMBER (column);
if (NILP (minimum))
XSETFASTINT (minimum, 0);
CHECK_NUMBER (minimum);
fromcol = current_column ();
mincol = fromcol + XINT (minimum);
if (mincol < XINT (column)) mincol = XINT (column);
if (fromcol == mincol)
return make_number (mincol);
if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
if (indent_tabs_mode)
{
Lisp_Object n;
XSETFASTINT (n, mincol / tab_width - fromcol / tab_width);
if (XFASTINT (n) != 0)
{
Finsert_char (make_number ('\t'), n, Qt);
fromcol = (mincol / tab_width) * tab_width;
}
}
XSETFASTINT (column, mincol - fromcol);
Finsert_char (make_number (' '), column, Qt);
last_known_column = mincol;
last_known_column_point = PT;
last_known_column_modified = MODIFF;
XSETINT (column, mincol);
return column;
}
static double position_indentation P_ ((int));
DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
0, 0, 0,
doc: )
()
{
Lisp_Object val;
int opoint = PT, opoint_byte = PT_BYTE;
scan_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, 1);
XSETFASTINT (val, (int) position_indentation (PT_BYTE));
SET_PT_BOTH (opoint, opoint_byte);
return val;
}
static double
position_indentation (pos_byte)
register int pos_byte;
{
register int column = 0;
register int tab_width = XINT (current_buffer->tab_width);
register unsigned char *p;
register unsigned char *stop;
unsigned char *start;
int next_boundary_byte = pos_byte;
int ceiling = next_boundary_byte;
if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
p = BYTE_POS_ADDR (pos_byte);
stop = p;
start = p;
while (1)
{
while (p == stop)
{
int stop_pos_byte;
if (p != start)
pos_byte = PTR_BYTE_POS (p);
if (pos_byte == ZV_BYTE)
return column;
if (pos_byte == next_boundary_byte)
{
int next_boundary;
int pos = BYTE_TO_CHAR (pos_byte);
pos = skip_invisible (pos, &next_boundary, ZV, Qnil);
pos_byte = CHAR_TO_BYTE (pos);
next_boundary_byte = CHAR_TO_BYTE (next_boundary);
}
if (pos_byte >= ceiling)
ceiling = BUFFER_CEILING_OF (pos_byte) + 1;
stop_pos_byte = min (ceiling, next_boundary_byte);
stop = BYTE_POS_ADDR (stop_pos_byte - 1) + 1;
p = BYTE_POS_ADDR (pos_byte);
}
switch (*p++)
{
case 0240:
if (! NILP (current_buffer->enable_multibyte_characters))
return column;
case ' ':
column++;
break;
case '\t':
column += tab_width - column % tab_width;
break;
default:
if (ASCII_BYTE_P (p[-1])
|| NILP (current_buffer->enable_multibyte_characters))
return column;
{
int c;
pos_byte = PTR_BYTE_POS (p - 1);
c = FETCH_MULTIBYTE_CHAR (pos_byte);
if (CHAR_HAS_CATEGORY (c, ' '))
{
column++;
INC_POS (pos_byte);
p = BYTE_POS_ADDR (pos_byte);
}
else
return column;
}
}
}
}
int
indented_beyond_p (pos, pos_byte, column)
int pos, pos_byte;
double column;
{
double val;
int opoint = PT, opoint_byte = PT_BYTE;
SET_PT_BOTH (pos, pos_byte);
while (PT > BEGV && FETCH_BYTE (PT_BYTE) == '\n')
scan_newline (PT - 1, PT_BYTE - 1, BEGV, BEGV_BYTE, -1, 0);
val = position_indentation (PT_BYTE);
SET_PT_BOTH (opoint, opoint_byte);
return val >= column;
}
DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 2, "p",
doc: )
(column, force)
Lisp_Object column, force;
{
register int pos;
register int col = current_column ();
register int goal;
register int end;
register int tab_width = XINT (current_buffer->tab_width);
register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
register struct Lisp_Char_Table *dp = buffer_display_table ();
register int multibyte = !NILP (current_buffer->enable_multibyte_characters);
Lisp_Object val;
int prev_col = 0;
int c = 0;
int next_boundary, pos_byte;
if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
CHECK_NATNUM (column);
goal = XINT (column);
pos = PT;
pos_byte = PT_BYTE;
end = ZV;
if (col > goal)
{
end = pos;
pos = current_column_bol_cache;
pos_byte = CHAR_TO_BYTE (pos);
col = 0;
}
next_boundary = pos;
while (pos < end)
{
while (pos == next_boundary)
{
int prev = pos;
pos = skip_invisible (pos, &next_boundary, end, Qnil);
if (pos != prev)
pos_byte = CHAR_TO_BYTE (pos);
if (pos >= end)
goto endloop;
}
if (col >= goal)
break;
{
int len, len_byte, width;
if (check_composition (pos, pos_byte, Z, &len, &len_byte, &width))
{
pos += len;
pos_byte += len_byte;
col += width;
continue;
}
}
c = FETCH_BYTE (pos_byte);
if (dp != 0
&& ! (multibyte && BASE_LEADING_CODE_P (c))
&& VECTORP (DISP_CHAR_VECTOR (dp, c)))
{
Lisp_Object charvec;
EMACS_INT i, n;
charvec = DISP_CHAR_VECTOR (dp, c);
n = ASIZE (charvec);
for (i = 0; i < n; i++)
{
Lisp_Object entry;
entry = AREF (charvec, i);
if (INTEGERP (entry)
&& GLYPH_CHAR_VALID_P (XFASTINT (entry)))
c = FAST_GLYPH_CHAR (XFASTINT (entry));
else
c = ' ';
if (c == '\n')
goto endloop;
if (c == '\r' && EQ (current_buffer->selective_display, Qt))
goto endloop;
if (c == '\t')
{
prev_col = col;
col += tab_width;
col = col / tab_width * tab_width;
}
else
++col;
}
}
else
{
if (c == '\n')
goto endloop;
if (c == '\r' && EQ (current_buffer->selective_display, Qt))
goto endloop;
if (c == '\t')
{
prev_col = col;
col += tab_width;
col = col / tab_width * tab_width;
}
else if (ctl_arrow && (c < 040 || c == 0177))
col += 2;
else if (c < 040 || c == 0177)
col += 4;
else if (c < 0177)
col++;
else if (multibyte && BASE_LEADING_CODE_P (c))
{
unsigned char *ptr;
int bytes, width, wide_column;
ptr = BYTE_POS_ADDR (pos_byte);
MULTIBYTE_BYTES_WIDTH (ptr, dp);
pos_byte += bytes - 1;
col += width;
}
else
col += 4;
}
pos++;
pos_byte++;
}
endloop:
SET_PT_BOTH (pos, pos_byte);
if (!NILP (force) && col > goal && c == '\t' && prev_col < goal)
{
int goal_pt, goal_pt_byte;
SET_PT_BOTH (PT - 1, PT_BYTE - 1);
Finsert_char (make_number (' '), make_number (goal - prev_col), Qt);
del_range (PT, PT + 1);
goal_pt = PT;
goal_pt_byte = PT_BYTE;
Findent_to (make_number (col), Qnil);
SET_PT_BOTH (goal_pt, goal_pt_byte);
col = goal;
}
if (col < goal && EQ (force, Qt))
Findent_to (make_number (col = goal), Qnil);
last_known_column = col;
last_known_column_point = PT;
last_known_column_modified = MODIFF;
XSETFASTINT (val, col);
return val;
}
struct position val_compute_motion;
struct position *
compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, hscroll, tab_offset, win)
int from, fromvpos, fromhpos, to, tovpos, tohpos;
int did_motion;
register int width;
int hscroll, tab_offset;
struct window *win;
{
register int hpos = fromhpos;
register int vpos = fromvpos;
register int pos;
int pos_byte;
register int c = 0;
register int tab_width = XFASTINT (current_buffer->tab_width);
register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
register struct Lisp_Char_Table *dp = window_display_table (win);
int selective
= (INTEGERP (current_buffer->selective_display)
? XINT (current_buffer->selective_display)
: !NILP (current_buffer->selective_display) ? -1 : 0);
int selective_rlen
= (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp))
? XVECTOR (DISP_INVIS_VECTOR (dp))->size : 0);
int next_boundary = from;
int width_run_start = from;
int width_run_end = from;
int width_run_width = 0;
Lisp_Object *width_table;
Lisp_Object buffer;
int next_width_run = from;
Lisp_Object window;
int multibyte = !NILP (current_buffer->enable_multibyte_characters);
int wide_column_end_hpos = 0;
int prev_pos;
int prev_pos_byte;
int prev_hpos = 0;
int prev_vpos = 0;
int contin_hpos;
int prev_tab_offset;
int continuation_glyph_width;
XSETBUFFER (buffer, current_buffer);
XSETWINDOW (window, win);
width_run_cache_on_off ();
if (dp == buffer_display_table ())
width_table = (VECTORP (current_buffer->width_table)
? XVECTOR (current_buffer->width_table)->contents
: 0);
else
width_table = 0;
if (tab_width <= 0 || tab_width > 1000)
tab_width = 8;
if (width < 0)
{
width = window_box_text_cols (win);
#ifdef HAVE_WINDOW_SYSTEM
if (!FRAME_WINDOW_P (XFRAME (win->frame)))
#endif
width -= 1;
}
continuation_glyph_width = 1;
#ifdef HAVE_WINDOW_SYSTEM
if (FRAME_WINDOW_P (XFRAME (win->frame)))
continuation_glyph_width = 0;
#endif
immediate_quit = 1;
QUIT;
pos = prev_pos = from;
pos_byte = prev_pos_byte = CHAR_TO_BYTE (from);
contin_hpos = 0;
prev_tab_offset = tab_offset;
while (1)
{
while (pos == next_boundary)
{
int pos_here = pos;
int newpos;
if (vpos > tovpos || (vpos == tovpos && hpos >= tohpos))
{
if (contin_hpos && prev_hpos == 0
&& hpos > tohpos
&& (contin_hpos == width || wide_column_end_hpos > width))
{
pos = prev_pos;
pos_byte = prev_pos_byte;
hpos = prev_hpos;
vpos = prev_vpos;
tab_offset = prev_tab_offset;
}
break;
}
if (!did_motion)
{
unsigned char *ovstr;
int ovlen = overlay_strings (pos, win, &ovstr);
hpos += ((multibyte && ovlen > 0)
? strwidth (ovstr, ovlen) : ovlen);
}
did_motion = 0;
if (pos >= to)
break;
newpos = skip_invisible (pos, &next_boundary, to, window);
if (newpos >= to)
{
pos = min (to, newpos);
pos_byte = CHAR_TO_BYTE (pos);
goto after_loop;
}
if (newpos != pos_here)
{
pos = newpos;
pos_byte = CHAR_TO_BYTE (pos);
}
}
if (hpos > width)
{
if (hscroll
|| (truncate_partial_width_windows
&& ((width + continuation_glyph_width)
< FRAME_COLS (XFRAME (WINDOW_FRAME (win)))))
|| !NILP (current_buffer->truncate_lines))
{
if (pos <= to)
{
pos = find_before_next_newline (pos, to, 1);
pos_byte = CHAR_TO_BYTE (pos);
hpos = width;
if (pos >= next_boundary)
next_boundary = pos + 1;
prev_hpos = width;
prev_vpos = vpos;
prev_tab_offset = tab_offset;
}
}
else
{
prev_tab_offset = tab_offset;
if (wide_column_end_hpos > width)
{
hpos -= prev_hpos;
tab_offset += prev_hpos;
}
else
{
tab_offset += width;
hpos -= width;
}
vpos++;
contin_hpos = prev_hpos;
prev_hpos = 0;
prev_vpos = vpos;
}
}
if (pos > to)
{
pos = prev_pos;
pos_byte = prev_pos_byte;
hpos = prev_hpos;
vpos = prev_vpos;
tab_offset = prev_tab_offset;
if (contin_hpos && prev_hpos == 0
&& contin_hpos < width && !wide_column_end_hpos)
{
hpos = contin_hpos;
vpos = vpos - 1;
}
break;
}
if (vpos > tovpos || (vpos == tovpos && hpos >= tohpos))
{
if (contin_hpos && prev_hpos == 0
&& hpos > tohpos
&& (contin_hpos == width || wide_column_end_hpos > width))
{
pos = prev_pos;
pos_byte = prev_pos_byte;
hpos = prev_hpos;
vpos = prev_vpos;
tab_offset = prev_tab_offset;
}
break;
}
if (pos == ZV)
break;
prev_hpos = hpos;
prev_vpos = vpos;
prev_pos = pos;
prev_pos_byte = pos_byte;
wide_column_end_hpos = 0;
if (current_buffer->width_run_cache && pos >= next_width_run)
{
int run_end;
int common_width
= region_cache_forward (current_buffer,
current_buffer->width_run_cache,
pos, &run_end);
if (common_width != 0)
{
int run_end_hpos;
if (run_end > to)
run_end = to;
run_end_hpos = hpos + (run_end - pos) * common_width;
if (vpos == tovpos && run_end_hpos > tohpos)
{
run_end = pos + (tohpos - hpos) / common_width;
run_end_hpos = hpos + (run_end - pos) * common_width;
}
if (run_end_hpos >= width)
{
run_end = pos + (width - hpos) / common_width;
run_end_hpos = hpos + (run_end - pos) * common_width;
}
hpos = run_end_hpos;
if (run_end > pos)
prev_hpos = hpos - common_width;
if (pos != run_end)
{
pos = run_end;
pos_byte = CHAR_TO_BYTE (pos);
}
}
next_width_run = run_end + 1;
}
else
{
EMACS_INT i, n;
Lisp_Object charvec;
c = FETCH_BYTE (pos_byte);
{
int len, len_byte, width;
if (check_composition (pos, pos_byte, to, &len, &len_byte, &width))
{
pos += len;
pos_byte += len_byte;
hpos += width;
continue;
}
}
pos++, pos_byte++;
if (current_buffer->width_run_cache)
{
if (pos - 1 == width_run_end
&& XFASTINT (width_table[c]) == width_run_width)
width_run_end = pos;
else
{
if (width_run_start < width_run_end
&& width_run_width == 1)
know_region_cache (current_buffer,
current_buffer->width_run_cache,
width_run_start, width_run_end);
width_run_width = XFASTINT (width_table[c]);
width_run_start = pos - 1;
width_run_end = pos;
}
}
if (dp != 0
&& ! (multibyte && BASE_LEADING_CODE_P (c))
&& VECTORP (DISP_CHAR_VECTOR (dp, c)))
{
charvec = DISP_CHAR_VECTOR (dp, c);
n = ASIZE (charvec);
}
else
{
charvec = Qnil;
n = 1;
}
for (i = n - 1; i >= 0; --i)
{
if (VECTORP (charvec))
{
Lisp_Object entry = AREF (charvec, i);
if (INTEGERP (entry)
&& GLYPH_CHAR_VALID_P (XFASTINT (entry)))
c = FAST_GLYPH_CHAR (XFASTINT (entry));
else
c = ' ';
}
if (c >= 040 && c < 0177)
hpos++;
else if (c == '\t')
{
int tem = ((hpos + tab_offset + hscroll - (hscroll > 0))
% tab_width);
if (tem < 0)
tem += tab_width;
hpos += tab_width - tem;
}
else if (c == '\n')
{
if (selective > 0
&& indented_beyond_p (pos, pos_byte,
(double) selective))
{
if (pos < to)
{
do
{
pos = find_before_next_newline (pos, to, 1);
if (pos < to)
pos++;
pos_byte = CHAR_TO_BYTE (pos);
}
while (pos < to
&& indented_beyond_p (pos, pos_byte,
(double) selective));
if (selective_rlen)
{
hpos += selective_rlen;
if (hpos >= width)
hpos = width;
}
DEC_BOTH (pos, pos_byte);
}
}
else
{
vpos++;
hpos = 0;
hpos -= hscroll;
if (hscroll > 0)
hpos += continuation_glyph_width;
tab_offset = 0;
}
contin_hpos = 0;
}
else if (c == CR && selective < 0)
{
if (pos < to)
{
pos = find_before_next_newline (pos, to, 1);
pos_byte = CHAR_TO_BYTE (pos);
}
if (pos > next_boundary)
next_boundary = pos;
if (selective_rlen)
{
hpos += selective_rlen;
if (hpos >= width)
hpos = width;
}
}
else if (multibyte && BASE_LEADING_CODE_P (c))
{
unsigned char *ptr;
int bytes, width, wide_column;
pos_byte--;
ptr = BYTE_POS_ADDR (pos_byte);
MULTIBYTE_BYTES_WIDTH (ptr, dp);
pos_byte += bytes;
if (wide_column)
wide_column_end_hpos = hpos + wide_column;
hpos += width;
}
else if (VECTORP (charvec))
++hpos;
else
hpos += (ctl_arrow && c < 0200) ? 2 : 4;
}
}
}
after_loop:
if (current_buffer->width_run_cache
&& width_run_width == 1
&& width_run_start < width_run_end)
know_region_cache (current_buffer, current_buffer->width_run_cache,
width_run_start, width_run_end);
val_compute_motion.bufpos = pos;
val_compute_motion.bytepos = pos_byte;
val_compute_motion.hpos = hpos;
val_compute_motion.vpos = vpos;
if (contin_hpos && prev_hpos == 0)
val_compute_motion.prevhpos = contin_hpos;
else
val_compute_motion.prevhpos = prev_hpos;
val_compute_motion.ovstring_chars_done = 0;
val_compute_motion.contin = (contin_hpos && prev_hpos == 0);
immediate_quit = 0;
return &val_compute_motion;
}
DEFUN ("compute-motion", Fcompute_motion, Scompute_motion, 7, 7, 0,
doc: )
(from, frompos, to, topos, width, offsets, window)
Lisp_Object from, frompos, to, topos;
Lisp_Object width, offsets, window;
{
struct window *w;
Lisp_Object bufpos, hpos, vpos, prevhpos;
struct position *pos;
int hscroll, tab_offset;
CHECK_NUMBER_COERCE_MARKER (from);
CHECK_CONS (frompos);
CHECK_NUMBER_CAR (frompos);
CHECK_NUMBER_CDR (frompos);
CHECK_NUMBER_COERCE_MARKER (to);
if (!NILP (topos))
{
CHECK_CONS (topos);
CHECK_NUMBER_CAR (topos);
CHECK_NUMBER_CDR (topos);
}
if (!NILP (width))
CHECK_NUMBER (width);
if (!NILP (offsets))
{
CHECK_CONS (offsets);
CHECK_NUMBER_CAR (offsets);
CHECK_NUMBER_CDR (offsets);
hscroll = XINT (XCAR (offsets));
tab_offset = XINT (XCDR (offsets));
}
else
hscroll = tab_offset = 0;
if (NILP (window))
window = Fselected_window ();
else
CHECK_LIVE_WINDOW (window);
w = XWINDOW (window);
if (XINT (from) < BEGV || XINT (from) > ZV)
args_out_of_range_3 (from, make_number (BEGV), make_number (ZV));
if (XINT (to) < BEGV || XINT (to) > ZV)
args_out_of_range_3 (to, make_number (BEGV), make_number (ZV));
pos = compute_motion (XINT (from), XINT (XCDR (frompos)),
XINT (XCAR (frompos)), 0,
XINT (to),
(NILP (topos)
? window_internal_height (w)
: XINT (XCDR (topos))),
(NILP (topos)
? (window_box_text_cols (w)
- (
#ifdef HAVE_WINDOW_SYSTEM
FRAME_WINDOW_P (XFRAME (w->frame)) ? 0 :
#endif
1))
: XINT (XCAR (topos))),
(NILP (width) ? -1 : XINT (width)),
hscroll, tab_offset,
XWINDOW (window));
XSETFASTINT (bufpos, pos->bufpos);
XSETINT (hpos, pos->hpos);
XSETINT (vpos, pos->vpos);
XSETINT (prevhpos, pos->prevhpos);
return Fcons (bufpos,
Fcons (hpos,
Fcons (vpos,
Fcons (prevhpos,
Fcons (pos->contin ? Qt : Qnil, Qnil)))));
}
struct position val_vmotion;
struct position *
vmotion (from, vtarget, w)
register int from, vtarget;
struct window *w;
{
int hscroll = XINT (w->hscroll);
struct position pos;
register int vpos = 0;
int prevline;
register int first;
int from_byte;
int lmargin = hscroll > 0 ? 1 - hscroll : 0;
int selective
= (INTEGERP (current_buffer->selective_display)
? XINT (current_buffer->selective_display)
: !NILP (current_buffer->selective_display) ? -1 : 0);
Lisp_Object window;
int start_hpos = 0;
int did_motion;
Lisp_Object text_prop_object;
XSETWINDOW (window, w);
if (EQ (w->buffer, Fcurrent_buffer ()))
text_prop_object = window;
else
text_prop_object = Fcurrent_buffer ();
if (vpos >= vtarget)
{
first = 1;
while ((vpos > vtarget || first) && from > BEGV)
{
Lisp_Object propval;
prevline = find_next_newline_no_quit (from - 1, -1);
while (prevline > BEGV
&& ((selective > 0
&& indented_beyond_p (prevline,
CHAR_TO_BYTE (prevline),
(double) selective))
|| (propval = Fget_char_property (make_number (prevline - 1),
Qinvisible,
text_prop_object),
TEXT_PROP_MEANS_INVISIBLE (propval))))
prevline = find_next_newline_no_quit (prevline - 1, -1);
pos = *compute_motion (prevline, 0,
lmargin + (prevline == BEG ? start_hpos : 0),
0,
from,
1 << (BITS_PER_SHORT - 1),
1 << (BITS_PER_SHORT - 1),
-1, hscroll,
(prevline == BEG ? -start_hpos : 0),
w);
vpos -= pos.vpos;
first = 0;
from = prevline;
}
if (vpos >= vtarget)
{
val_vmotion.bufpos = from;
val_vmotion.bytepos = CHAR_TO_BYTE (from);
val_vmotion.vpos = vpos;
val_vmotion.hpos = lmargin;
val_vmotion.contin = 0;
val_vmotion.prevhpos = 0;
val_vmotion.ovstring_chars_done = 0;
val_vmotion.tab_offset = 0;
return &val_vmotion;
}
}
from_byte = CHAR_TO_BYTE (from);
if (from > BEGV && FETCH_BYTE (from_byte - 1) != '\n')
{
Lisp_Object propval;
prevline = find_next_newline_no_quit (from, -1);
while (prevline > BEGV
&& ((selective > 0
&& indented_beyond_p (prevline,
CHAR_TO_BYTE (prevline),
(double) selective))
|| (propval = Fget_char_property (make_number (prevline),
Qinvisible,
text_prop_object),
TEXT_PROP_MEANS_INVISIBLE (propval))))
prevline = find_next_newline_no_quit (prevline - 1, -1);
pos = *compute_motion (prevline, 0,
lmargin + (prevline == BEG
? start_hpos : 0),
0,
from,
1 << (BITS_PER_SHORT - 1),
1 << (BITS_PER_SHORT - 1),
-1, hscroll,
(prevline == BEG ? -start_hpos : 0),
w);
did_motion = 1;
}
else
{
pos.hpos = lmargin + (from == BEG ? start_hpos : 0);
pos.vpos = 0;
pos.tab_offset = 0;
did_motion = 0;
}
return compute_motion (from, vpos, pos.hpos, did_motion,
ZV, vtarget, - (1 << (BITS_PER_SHORT - 1)),
-1, hscroll,
pos.tab_offset - (from == BEG ? start_hpos : 0),
w);
}
DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 2, 0,
doc: )
(lines, window)
Lisp_Object lines, window;
{
struct it it;
struct text_pos pt;
struct window *w;
Lisp_Object old_buffer;
struct gcpro gcpro1;
CHECK_NUMBER (lines);
if (! NILP (window))
CHECK_WINDOW (window);
else
window = selected_window;
w = XWINDOW (window);
old_buffer = Qnil;
GCPRO1 (old_buffer);
if (XBUFFER (w->buffer) != current_buffer)
{
old_buffer = w->buffer;
XSETBUFFER (w->buffer, current_buffer);
}
if (noninteractive)
{
struct position pos;
pos = *vmotion (PT, XINT (lines), w);
SET_PT_BOTH (pos.bufpos, pos.bytepos);
}
else
{
int it_start;
int oselective;
int it_overshoot_expected;
SET_TEXT_POS (pt, PT, PT_BYTE);
start_display (&it, w, pt);
it_start = IT_CHARPOS (it);
if (it.method == GET_FROM_STRING)
{
const char *s = SDATA (it.string);
const char *e = s + SBYTES (it.string);
while (s < e && *s != '\n')
++s;
it_overshoot_expected = (s == e) ? -1 : 0;
}
else
it_overshoot_expected = (it.method == GET_FROM_IMAGE
|| it.method == GET_FROM_STRETCH
|| it.method == GET_FROM_COMPOSITION);
reseat_at_previous_visible_line_start (&it);
it.current_x = it.hpos = 0;
oselective = it.selective;
it.selective = 0;
move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
it.selective = oselective;
if (IT_CHARPOS (it) > it_start && XINT (lines) > 0
&& (!it_overshoot_expected
|| (it_overshoot_expected < 0
&& it.method == GET_FROM_BUFFER
&& it.c == '\n')))
move_it_by_lines (&it, -1, 0);
it.vpos = 0;
if (XINT (lines) >= 0 || IT_CHARPOS (it) > 0)
move_it_by_lines (&it, XINT (lines), 0);
SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
}
if (BUFFERP (old_buffer))
w->buffer = old_buffer;
RETURN_UNGCPRO (make_number (it.vpos));
}
void
syms_of_indent ()
{
DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode,
doc: );
indent_tabs_mode = 1;
defsubr (&Scurrent_indentation);
defsubr (&Sindent_to);
defsubr (&Scurrent_column);
defsubr (&Smove_to_column);
defsubr (&Svertical_motion);
defsubr (&Scompute_motion);
}