X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/79c2a4fc6894ce20dcaf10457fa264fbc668e15f..14b6e3bb481f4cb48f397c50ae8116b6fc39c937:/src/indent.c diff --git a/src/indent.c b/src/indent.c index c843ba2753..3cbb105e80 100644 --- a/src/indent.c +++ b/src/indent.c @@ -1,6 +1,6 @@ /* Indentation functions. - Copyright (C) 1985,86,87,88,93,94,95,98, 2000, 2001 - Free Software Foundation, Inc. + Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1998, 2000, 2001, + 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -16,8 +16,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ #include #include "lisp.h" @@ -47,7 +47,7 @@ int indent_tabs_mode; Some things in set last_known_column_point to -1 to mark the memorized value as invalid. */ -int last_known_column; +double last_known_column; /* Value of point when current_column was called. */ @@ -57,8 +57,8 @@ int last_known_column_point; int last_known_column_modified; -static int current_column_1 P_ ((void)); -static int position_indentation P_ ((int)); +static double current_column_1 P_ ((void)); +static double position_indentation P_ ((int)); /* Cache of beginning of line found by the last call of current_column. */ @@ -220,8 +220,8 @@ skip_invisible (pos, next_boundary_p, to, window) Lisp_Object window; { Lisp_Object prop, position, overlay_limit, proplimit; - Lisp_Object buffer; - int end; + Lisp_Object buffer, tmp; + int end, inv_p; XSETFASTINT (position, pos); XSETBUFFER (buffer, current_buffer); @@ -251,8 +251,9 @@ skip_invisible (pos, next_boundary_p, to, window) /* No matter what. don't go past next overlay change. */ if (XFASTINT (overlay_limit) < XFASTINT (proplimit)) proplimit = overlay_limit; - end = XFASTINT (Fnext_single_property_change (position, Qinvisible, - buffer, proplimit)); + tmp = Fnext_single_property_change (position, Qinvisible, + buffer, proplimit); + end = XFASTINT (tmp); #if 0 /* Don't put the boundary in the middle of multibyte form if there is no actual property change. */ @@ -266,13 +267,13 @@ skip_invisible (pos, next_boundary_p, to, window) } /* if the `invisible' property is set, we can skip to the next property change */ - if (!NILP (window) && EQ (XWINDOW (window)->buffer, buffer)) - prop = Fget_char_property (position, Qinvisible, window); - else - prop = Fget_char_property (position, Qinvisible, buffer); - if (NILP (window) - ? TEXT_PROP_MEANS_INVISIBLE_NOELLIPSIS (prop) - : TEXT_PROP_MEANS_INVISIBLE (prop)) + prop = Fget_char_property (position, Qinvisible, + (!NILP (window) + && EQ (XWINDOW (window)->buffer, buffer)) + ? window : buffer); + inv_p = TEXT_PROP_MEANS_INVISIBLE (prop); + /* When counting columns (window == nil), don't skip over ellipsis text. */ + if (NILP (window) ? inv_p == 1 : inv_p) return *next_boundary_p; return pos; } @@ -329,20 +330,23 @@ check_composition (pos, pos_byte, point, len, len_byte, width) } \ } while (0) + DEFUN ("current-column", Fcurrent_column, Scurrent_column, 0, 0, 0, - "Return the horizontal position of point. Beginning of line is column 0.\n\ -This is calculated by adding together the widths of all the displayed\n\ -representations of the character between the start of the previous line\n\ -and point. (eg control characters will have a width of 2 or 4, tabs\n\ -will have a variable width)\n\ -Ignores finite width of frame, which means that this function may return\n\ -values greater than (frame-width).\n\ -Whether the line is visible (if `selective-display' is t) has no effect;\n\ -however, ^M is treated as end of line when `selective-display' is t.") - () + doc: /* Return the horizontal position of point. Beginning of line is column 0. +This is calculated by adding together the widths of all the displayed +representations of the character between the start of the previous line +and point (eg. control characters will have a width of 2 or 4, tabs +will have a variable width). +Ignores finite width of frame, which means that this function may return +values greater than (frame-width). +Whether the line is visible (if `selective-display' is t) has no effect; +however, ^M is treated as end of line when `selective-display' is t. +Text that has an invisible property is considered as having width 0, unless +`buffer-invisibility-spec' specifies that it is replaced by an ellipsis. */) + () { Lisp_Object temp; - XSETFASTINT (temp, current_column ()); + XSETFASTINT (temp, (int) current_column ()); /* iftc */ return temp; } @@ -354,7 +358,7 @@ invalidate_current_column () last_known_column_point = 0; } -int +double current_column () { register int col; @@ -373,8 +377,8 @@ current_column () /* If the buffer has overlays, text properties, or multibyte characters, use a more general algorithm. */ if (BUF_INTERVALS (current_buffer) - || !NILP (current_buffer->overlays_before) - || !NILP (current_buffer->overlays_after) + || current_buffer->overlays_before + || current_buffer->overlays_after || Z != Z_BYTE) return current_column_1 (); @@ -401,25 +405,25 @@ current_column () { EMACS_INT i, n; Lisp_Object charvec; - + if (ptr == stop) { /* We stopped either for the beginning of the buffer or for the gap. */ if (ptr == BEGV_ADDR) break; - + /* It was the gap. Jump back over it. */ stop = BEGV_ADDR; ptr = GPT_ADDR; - + /* Check whether that brings us to beginning of buffer. */ if (BEGV >= GPT) break; } c = *--ptr; - + if (dp && VECTORP (DISP_CHAR_VECTOR (dp, c))) { charvec = DISP_CHAR_VECTOR (dp, c); @@ -430,7 +434,7 @@ current_column () charvec = Qnil; n = 1; } - + for (i = n - 1; i >= 0; --i) { if (VECTORP (charvec)) @@ -438,14 +442,14 @@ current_column () /* This should be handled the same as next_element_from_display_vector does it. */ 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' @@ -459,7 +463,7 @@ current_column () { if (tab_seen) col = ((col + tab_width) / tab_width) * tab_width; - + post_tab += col; col = 0; tab_seen = 1; @@ -501,7 +505,7 @@ current_column () This function handles characters that are invisible due to text properties or overlays. */ -static int +static double current_column_1 () { register int tab_width = XINT (current_buffer->tab_width); @@ -512,7 +516,7 @@ current_column_1 () /* Start the scan at the beginning of this line with column number 0. */ register int col = 0; int scan, scan_byte; - int next_boundary, next_boundary_byte; + int next_boundary; int opoint = PT, opoint_byte = PT_BYTE; scan_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, 1); @@ -520,7 +524,6 @@ current_column_1 () scan = PT, scan_byte = PT_BYTE; SET_PT_BOTH (opoint, opoint_byte); next_boundary = scan; - next_boundary_byte = scan_byte; if (tab_width <= 0 || tab_width > 1000) tab_width = 8; @@ -528,8 +531,6 @@ current_column_1 () while (scan < opoint) { int c; - EMACS_INT i, n; - Lisp_Object charvec; /* Occasionally we may need to skip invisible text. */ while (scan == next_boundary) @@ -542,7 +543,6 @@ current_column_1 () goto endloop; if (scan != old_scan) scan_byte = CHAR_TO_BYTE (scan); - next_boundary_byte = CHAR_TO_BYTE (next_boundary); } /* Check composition sequence. */ @@ -566,39 +566,52 @@ current_column_1 () && ! (multibyte && BASE_LEADING_CODE_P (c)) && VECTORP (DISP_CHAR_VECTOR (dp, c))) { + Lisp_Object charvec; + EMACS_INT i, n; + + /* This character is displayed using a vector of glyphs. + Update the column based on those glyphs. */ + charvec = DISP_CHAR_VECTOR (dp, c); n = ASIZE (charvec); - } - else - { - charvec = Qnil; - n = 1; - } - for (i = n - 1; i >= 0; --i) - { - if (VECTORP (charvec)) + for (i = 0; i < n; i++) { /* This should be handled the same as next_element_from_display_vector does it. */ - Lisp_Object entry = AREF (charvec, 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 + { + /* The display table says nothing for this character. + Display it as itself. */ + if (c == '\n') goto endloop; if (c == '\r' && EQ (current_buffer->selective_display, Qt)) goto endloop; - scan++; - scan_byte++; if (c == '\t') { - int prev_col = col; col += tab_width; col = col / tab_width * tab_width; } @@ -606,15 +619,15 @@ current_column_1 () { unsigned char *ptr; int bytes, width, wide_column; - - scan_byte--; + ptr = BYTE_POS_ADDR (scan_byte); MULTIBYTE_BYTES_WIDTH (ptr, dp); scan_byte += bytes; + /* Subtract one to compensate for the increment + that is going to happen below. */ + scan_byte--; col += width; } - else if (VECTORP (charvec)) - ++col; else if (ctl_arrow && (c < 040 || c == 0177)) col += 2; else if (c < 040 || c >= 0177) @@ -622,6 +635,9 @@ current_column_1 () else col++; } + scan++; + scan_byte++; + } endloop: @@ -639,7 +655,7 @@ current_column_1 () If BEG is nil, that stands for the beginning of STRING. If END is nil, that stands for the end of STRING. */ -static int +static double string_display_width (string, beg, end) Lisp_Object string, beg, end; { @@ -654,10 +670,10 @@ string_display_width (string, beg, end) int b, e; if (NILP (end)) - e = XSTRING (string)->size; + e = SCHARS (string); else { - CHECK_NUMBER (end, 0); + CHECK_NUMBER (end); e = XINT (end); } @@ -665,15 +681,15 @@ string_display_width (string, beg, end) b = 0; else { - CHECK_NUMBER (beg, 0); + CHECK_NUMBER (beg); b = XINT (beg); } /* Make a pointer for decrementing through the chars before point. */ - ptr = XSTRING (string)->data + e; + ptr = SDATA (string) + e; /* Make a pointer to where consecutive chars leave off, going backwards from point. */ - stop = XSTRING (string)->data + b; + stop = SDATA (string) + b; if (tab_width <= 0 || tab_width > 1000) tab_width = 8; @@ -717,20 +733,20 @@ string_display_width (string, beg, end) DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "NIndent to column: ", - "Indent from point with tabs and spaces until COLUMN is reached.\n\ -Optional second argument MININUM says always do at least MININUM spaces\n\ -even if that goes past COLUMN; by default, MININUM is zero.") - (column, minimum) + doc: /* Indent from point with tabs and spaces until COLUMN is reached. +Optional second argument MINIMUM says always do at least MINIMUM spaces +even if that goes past COLUMN; by default, MINIMUM is zero. */) + (column, minimum) Lisp_Object column, minimum; { int mincol; register int fromcol; register int tab_width = XINT (current_buffer->tab_width); - CHECK_NUMBER (column, 0); + CHECK_NUMBER (column); if (NILP (minimum)) XSETFASTINT (minimum, 0); - CHECK_NUMBER (minimum, 1); + CHECK_NUMBER (minimum); fromcol = current_column (); mincol = fromcol + XINT (minimum); @@ -765,26 +781,26 @@ even if that goes past COLUMN; by default, MININUM is zero.") } -static int position_indentation P_ ((int)); +static double position_indentation P_ ((int)); DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation, - 0, 0, 0, - "Return the indentation of the current line.\n\ -This is the horizontal position of the character\n\ -following any initial whitespace.") - () + 0, 0, 0, + doc: /* Return the indentation of the current line. +This is the horizontal position of the character +following any initial whitespace. */) + () { Lisp_Object val; int opoint = PT, opoint_byte = PT_BYTE; scan_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, 1); - XSETFASTINT (val, position_indentation (PT_BYTE)); + XSETFASTINT (val, (int) position_indentation (PT_BYTE)); /* iftc */ SET_PT_BOTH (opoint, opoint_byte); return val; } -static int +static double position_indentation (pos_byte) register int pos_byte; { @@ -834,7 +850,7 @@ position_indentation (pos_byte) /* The -1 and +1 arrange to point at the first byte of gap (if STOP_POS_BYTE is the position of the gap) rather than at the data after the gap. */ - + stop = BYTE_POS_ADDR (stop_pos_byte - 1) + 1; p = BYTE_POS_ADDR (pos_byte); } @@ -876,9 +892,10 @@ position_indentation (pos_byte) int indented_beyond_p (pos, pos_byte, column) - int pos, pos_byte, column; + int pos, pos_byte; + double column; { - int val; + double val; int opoint = PT, opoint_byte = PT_BYTE; SET_PT_BOTH (pos, pos_byte); @@ -887,26 +904,27 @@ indented_beyond_p (pos, pos_byte, column) val = position_indentation (PT_BYTE); SET_PT_BOTH (opoint, opoint_byte); - return val >= column; + return val >= column; /* hmm, float comparison */ } DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 2, "p", - "Move point to column COLUMN in the current line.\n\ -The column of a character is calculated by adding together the widths\n\ -as displayed of the previous characters in the line.\n\ -This function ignores line-continuation;\n\ -there is no upper limit on the column number a character can have\n\ -and horizontal scrolling has no effect.\n\ -\n\ -If specified column is within a character, point goes after that character.\n\ -If it's past end of line, point goes to end of line.\n\n\ -A non-nil second (optional) argument FORCE means,\n\ -if COLUMN is in the middle of a tab character, change it to spaces.\n\ -In addition, if FORCE is t, and the line is too short\n\ -to reach column COLUMN, add spaces/tabs to get there.\n\ -\n\ -The return value is the current column.") - (column, force) + doc: /* Move point to column COLUMN in the current line. +The column of a character is calculated by adding together the widths +as displayed of the previous characters in the line. +This function ignores line-continuation; +there is no upper limit on the column number a character can have +and horizontal scrolling has no effect. + +If specified column is within a character, point goes after that character. +If it's past end of line, point goes to end of line. + +A non-nil second (optional) argument FORCE means, +if COLUMN is in the middle of a tab character, change it to spaces. +In addition, if FORCE is t, and the line is too short +to reach column COLUMN, add spaces/tabs to get there. + +The return value is the current column. */) + (column, force) Lisp_Object column, force; { register int pos; @@ -921,20 +939,16 @@ The return value is the current column.") Lisp_Object val; int prev_col = 0; int c = 0; - int next_boundary; - - int pos_byte, end_byte, next_boundary_byte; + int next_boundary, pos_byte; if (tab_width <= 0 || tab_width > 1000) tab_width = 8; - CHECK_NATNUM (column, 0); + CHECK_NATNUM (column); goal = XINT (column); pos = PT; pos_byte = PT_BYTE; end = ZV; - end_byte = ZV_BYTE; next_boundary = pos; - next_boundary_byte = PT_BYTE; /* If we're starting past the desired column, back up to beginning of line and scan from there. */ @@ -948,16 +962,12 @@ The return value is the current column.") while (pos < end) { - Lisp_Object charvec; - EMACS_INT i, n; - while (pos == next_boundary) { int prev = pos; pos = skip_invisible (pos, &next_boundary, end, Qnil); if (pos != prev) pos_byte = CHAR_TO_BYTE (pos); - next_boundary_byte = CHAR_TO_BYTE (next_boundary); if (pos >= end) goto endloop; } @@ -983,49 +993,65 @@ The return value is the current column.") c = FETCH_BYTE (pos_byte); + /* See if there is a display table and it relates + to this character. */ + if (dp != 0 && ! (multibyte && BASE_LEADING_CODE_P (c)) && VECTORP (DISP_CHAR_VECTOR (dp, c))) { + Lisp_Object charvec; + EMACS_INT i, n; + + /* This character is displayed using a vector of glyphs. + Update the position based on those glyphs. */ + charvec = DISP_CHAR_VECTOR (dp, c); n = ASIZE (charvec); - } - else - { - charvec = Qnil; - n = 1; - } - for (i = n - 1; i >= 0; --i) - { - if (VECTORP (charvec)) + for (i = 0; i < n; i++) { /* This should be handled the same as next_element_from_display_vector does it. */ - Lisp_Object entry = AREF (charvec, 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 + { + /* The display table doesn't affect this character; + it displays as itself. */ - if (c == '\n') goto endloop; if (c == '\r' && EQ (current_buffer->selective_display, Qt)) goto endloop; - pos++; - pos_byte++; if (c == '\t') { prev_col = col; col += tab_width; col = col / tab_width * tab_width; } - else if (VECTORP (charvec)) - ++col; else if (ctl_arrow && (c < 040 || c == 0177)) col += 2; else if (c < 040 || c == 0177) @@ -1038,15 +1064,17 @@ The return value is the current column.") unsigned char *ptr; int bytes, width, wide_column; - pos_byte--; ptr = BYTE_POS_ADDR (pos_byte); MULTIBYTE_BYTES_WIDTH (ptr, dp); - pos_byte += bytes; + pos_byte += bytes - 1; col += width; } else col += 4; } + + pos++; + pos_byte++; } endloop: @@ -1070,7 +1098,7 @@ The return value is the current column.") goal_pt_byte = PT_BYTE; Findent_to (make_number (col), Qnil); SET_PT_BOTH (goal_pt, goal_pt_byte); - + /* Set the last_known... vars consistently. */ col = goal; } @@ -1106,6 +1134,9 @@ struct position val_compute_motion; WIDTH is the number of columns available to display text; compute_motion uses this to handle continuation lines and such. + If WIDTH is -1, use width of window's text area adjusted for + continuation glyph when needed. + HSCROLL is the number of columns not being displayed at the left margin; this is usually taken from a window's hscroll member. TAB_OFFSET is the number of columns of the first tab that aren't @@ -1134,18 +1165,18 @@ struct position val_compute_motion; window_width - 1 - (has_vertical_scroll_bars - ? FRAME_SCROLL_BAR_COLS (XFRAME (window->frame)) - : (window_width + window_left != frame_width)) + ? WINDOW_CONFIG_SCROLL_BAR_COLS (window) + : (window_width + window_left != frame_cols)) where - window_width is XFASTINT (w->width), - window_left is XFASTINT (w->left), + window_width is XFASTINT (w->total_cols), + window_left is XFASTINT (w->left_col), has_vertical_scroll_bars is - FRAME_HAS_VERTICAL_SCROLL_BARS (XFRAME (WINDOW_FRAME (window))) - and frame_width = FRAME_WIDTH (XFRAME (window->frame)) + WINDOW_HAS_VERTICAL_SCROLL_BAR (window) + and frame_cols = FRAME_COLS (XFRAME (window->frame)) - Or you can let window_internal_width do this all for you, and write: - window_internal_width (w) - 1 + Or you can let window_box_text_cols do this all for you, and write: + window_box_text_cols (w) - 1 The `-1' accounts for the continuation-line backslashes; the rest accounts for window borders if the window is split horizontally, and @@ -1172,7 +1203,6 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, = (INTEGERP (current_buffer->selective_display) ? XINT (current_buffer->selective_display) : !NILP (current_buffer->selective_display) ? -1 : 0); - int prev_hpos = 0; int selective_rlen = (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp)) ? XVECTOR (DISP_INVIS_VECTOR (dp))->size : 0); @@ -1200,8 +1230,11 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, int wide_column_end_hpos = 0; int prev_pos; /* Previous buffer position. */ int prev_pos_byte; /* Previous buffer position. */ + int prev_hpos = 0; + int prev_vpos = 0; int contin_hpos; /* HPOS of last column of continued line. */ int prev_tab_offset; /* Previous tab offset. */ + int continuation_glyph_width; XSETBUFFER (buffer, current_buffer); XSETWINDOW (window, win); @@ -1219,6 +1252,23 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, if (tab_width <= 0 || tab_width > 1000) tab_width = 8; + /* Negative width means use all available text columns. */ + if (width < 0) + { + width = window_box_text_cols (win); + /* We must make room for continuation marks if we don't have fringes. */ +#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; /* In the fringe. */ +#endif + immediate_quit = 1; QUIT; @@ -1234,7 +1284,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, int newpos; /* Don't skip invisible if we are already at the margin. */ - if (vpos > tovpos || vpos == tovpos && hpos >= tohpos) + if (vpos > tovpos || (vpos == tovpos && hpos >= tohpos)) { if (contin_hpos && prev_hpos == 0 && hpos > tohpos @@ -1248,6 +1298,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, pos = prev_pos; pos_byte = prev_pos_byte; hpos = prev_hpos; + vpos = prev_vpos; tab_offset = prev_tab_offset; } break; @@ -1329,7 +1380,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, W_ ^---- next after the point ^---- next char. after the point. ---------- - In case of wide-column character + In case of wide-column character The problem here is continuation at a wide-column character. In this case, the line may shorter less than WIDTH. @@ -1341,7 +1392,8 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, { if (hscroll || (truncate_partial_width_windows - && width + 1 < FRAME_WIDTH (XFRAME (WINDOW_FRAME (win)))) + && ((width + continuation_glyph_width) + < FRAME_COLS (XFRAME (WINDOW_FRAME (win))))) || !NILP (current_buffer->truncate_lines)) { /* Truncating: skip to newline, unless we are already past @@ -1357,6 +1409,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, if (pos >= next_boundary) next_boundary = pos + 1; prev_hpos = width; + prev_vpos = vpos; prev_tab_offset = tab_offset; } } @@ -1379,6 +1432,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, vpos++; contin_hpos = prev_hpos; prev_hpos = 0; + prev_vpos = vpos; } } @@ -1389,6 +1443,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, pos = prev_pos; pos_byte = prev_pos_byte; hpos = prev_hpos; + vpos = prev_vpos; tab_offset = prev_tab_offset; /* NOTE on contin_hpos, hpos, and prev_hpos. @@ -1409,14 +1464,10 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, hpos = contin_hpos; vpos = vpos - 1; } - else if (c == '\n') - /* If previous character is NEWLINE, - set VPOS back to previous line */ - vpos = vpos - 1; break; } - if (vpos > tovpos || vpos == tovpos && hpos >= tohpos) + if (vpos > tovpos || (vpos == tovpos && hpos >= tohpos)) { if (contin_hpos && prev_hpos == 0 && hpos > tohpos @@ -1430,6 +1481,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, pos = prev_pos; pos_byte = prev_pos_byte; hpos = prev_hpos; + vpos = prev_vpos; tab_offset = prev_tab_offset; } break; @@ -1438,6 +1490,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, break; prev_hpos = hpos; + prev_vpos = vpos; prev_pos = pos; prev_pos_byte = pos_byte; wide_column_end_hpos = 0; @@ -1499,7 +1552,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, { EMACS_INT i, n; Lisp_Object charvec; - + c = FETCH_BYTE (pos_byte); /* Check composition sequence. */ @@ -1565,14 +1618,14 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, /* This should be handled the same as next_element_from_display_vector does it. */ 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') @@ -1586,7 +1639,8 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, else if (c == '\n') { if (selective > 0 - && indented_beyond_p (pos, pos_byte, selective)) + && indented_beyond_p (pos, pos_byte, + (double) selective)) /* iftc */ { /* If (pos == to), we don't have to take care of selective display. */ @@ -1601,7 +1655,8 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, pos_byte = CHAR_TO_BYTE (pos); } while (pos < to - && indented_beyond_p (pos, pos_byte, selective)); + && indented_beyond_p (pos, pos_byte, + (double) selective)); /* iftc */ /* Allow for the " ..." that is displayed for them. */ if (selective_rlen) { @@ -1622,7 +1677,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, hpos -= hscroll; /* Count the truncation glyph on column 0 */ if (hscroll > 0) - hpos++; + hpos += continuation_glyph_width; tab_offset = 0; } contin_hpos = 0; @@ -1700,75 +1755,76 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, } -#if 0 /* The doc string is too long for some compilers, - but make-docfile can find it in this comment. */ -DEFUN ("compute-motion", Ffoo, Sfoo, 7, 7, 0, - "Scan through the current buffer, calculating screen position.\n\ -Scan the current buffer forward from offset FROM,\n\ -assuming it is at position FROMPOS--a cons of the form (HPOS . VPOS)--\n\ -to position TO or position TOPOS--another cons of the form (HPOS . VPOS)--\n\ -and return the ending buffer position and screen location.\n\ -\n\ -There are three additional arguments:\n\ -\n\ -WIDTH is the number of columns available to display text;\n\ -this affects handling of continuation lines.\n\ -This is usually the value returned by `window-width', less one (to allow\n\ -for the continuation glyph).\n\ -\n\ -OFFSETS is either nil or a cons cell (HSCROLL . TAB-OFFSET).\n\ -HSCROLL is the number of columns not being displayed at the left\n\ -margin; this is usually taken from a window's hscroll member.\n\ -TAB-OFFSET is the number of columns of the first tab that aren't\n\ -being displayed, perhaps because the line was continued within it.\n\ -If OFFSETS is nil, HSCROLL and TAB-OFFSET are assumed to be zero.\n\ -\n\ -WINDOW is the window to operate on. It is used to choose the display table;\n\ -if it is showing the current buffer, it is used also for\n\ -deciding which overlay properties apply.\n\ -Note that `compute-motion' always operates on the current buffer.\n\ -\n\ -The value is a list of five elements:\n\ - (POS HPOS VPOS PREVHPOS CONTIN)\n\ -POS is the buffer position where the scan stopped.\n\ -VPOS is the vertical position where the scan stopped.\n\ -HPOS is the horizontal position where the scan stopped.\n\ -\n\ -PREVHPOS is the horizontal position one character back from POS.\n\ -CONTIN is t if a line was continued after (or within) the previous character.\n\ -\n\ -For example, to find the buffer position of column COL of line LINE\n\ -of a certain window, pass the window's starting location as FROM\n\ -and the window's upper-left coordinates as FROMPOS.\n\ -Pass the buffer's (point-max) as TO, to limit the scan to the end of the\n\ -visible section of the buffer, and pass LINE and COL as TOPOS.") - (from, frompos, to, topos, width, offsets, window) -#endif - DEFUN ("compute-motion", Fcompute_motion, Scompute_motion, 7, 7, 0, - 0) - (from, frompos, to, topos, width, offsets, window) + doc: /* Scan through the current buffer, calculating screen position. +Scan the current buffer forward from offset FROM, +assuming it is at position FROMPOS--a cons of the form (HPOS . VPOS)-- +to position TO or position TOPOS--another cons of the form (HPOS . VPOS)-- +and return the ending buffer position and screen location. + +If TOPOS is nil, the actual width and height of the window's +text area are used. + +There are three additional arguments: + +WIDTH is the number of columns available to display text; +this affects handling of continuation lines. A value of nil +corresponds to the actual number of available text columns. + +OFFSETS is either nil or a cons cell (HSCROLL . TAB-OFFSET). +HSCROLL is the number of columns not being displayed at the left +margin; this is usually taken from a window's hscroll member. +TAB-OFFSET is the number of columns of the first tab that aren't +being displayed, perhaps because the line was continued within it. +If OFFSETS is nil, HSCROLL and TAB-OFFSET are assumed to be zero. + +WINDOW is the window to operate on. It is used to choose the display table; +if it is showing the current buffer, it is used also for +deciding which overlay properties apply. +Note that `compute-motion' always operates on the current buffer. + +The value is a list of five elements: + (POS HPOS VPOS PREVHPOS CONTIN) +POS is the buffer position where the scan stopped. +VPOS is the vertical position where the scan stopped. +HPOS is the horizontal position where the scan stopped. + +PREVHPOS is the horizontal position one character back from POS. +CONTIN is t if a line was continued after (or within) the previous character. + +For example, to find the buffer position of column COL of line LINE +of a certain window, pass the window's starting location as FROM +and the window's upper-left coordinates as FROMPOS. +Pass the buffer's (point-max) as TO, to limit the scan to the end of the +visible section of the buffer, and pass LINE and COL as TOPOS. */) + (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, 0); - CHECK_CONS (frompos, 0); - CHECK_NUMBER (XCAR (frompos), 0); - CHECK_NUMBER (XCDR (frompos), 0); - CHECK_NUMBER_COERCE_MARKER (to, 0); - CHECK_CONS (topos, 0); - CHECK_NUMBER (XCAR (topos), 0); - CHECK_NUMBER (XCDR (topos), 0); - CHECK_NUMBER (width, 0); + 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, 0); - CHECK_NUMBER (XCAR (offsets), 0); - CHECK_NUMBER (XCDR (offsets), 0); + CHECK_CONS (offsets); + CHECK_NUMBER_CAR (offsets); + CHECK_NUMBER_CDR (offsets); hscroll = XINT (XCAR (offsets)); tab_offset = XINT (XCDR (offsets)); } @@ -1778,7 +1834,8 @@ DEFUN ("compute-motion", Fcompute_motion, Scompute_motion, 7, 7, 0, if (NILP (window)) window = Fselected_window (); else - CHECK_LIVE_WINDOW (window, 0); + 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)); @@ -1787,9 +1844,20 @@ DEFUN ("compute-motion", Fcompute_motion, Scompute_motion, 7, 7, 0, pos = compute_motion (XINT (from), XINT (XCDR (frompos)), XINT (XCAR (frompos)), 0, - XINT (to), XINT (XCDR (topos)), - XINT (XCAR (topos)), - XINT (width), hscroll, tab_offset, + 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); @@ -1814,12 +1882,11 @@ vmotion (from, vtarget, w) register int from, vtarget; struct window *w; { - int width = window_internal_width (w) - 1; int hscroll = XINT (w->hscroll); struct position pos; /* vpos is cumulative vertical position, changed as from is changed */ register int vpos = 0; - Lisp_Object prevline; + int prevline; register int first; int from_byte; int lmargin = hscroll > 0 ? 1 - hscroll : 0; @@ -1853,39 +1920,36 @@ vmotion (from, vtarget, w) { Lisp_Object propval; - XSETFASTINT (prevline, find_next_newline_no_quit (from - 1, -1)); - while (XFASTINT (prevline) > BEGV + prevline = find_next_newline_no_quit (from - 1, -1); + while (prevline > BEGV && ((selective > 0 - && indented_beyond_p (XFASTINT (prevline), - CHAR_TO_BYTE (XFASTINT (prevline)), - selective)) - /* watch out for newlines with `invisible' property */ - || (propval = Fget_char_property (prevline, + && indented_beyond_p (prevline, + CHAR_TO_BYTE (prevline), + (double) selective)) /* iftc */ + /* Watch out for newlines with `invisible' property. + When moving upward, check the newline before. */ + || (propval = Fget_char_property (make_number (prevline - 1), Qinvisible, text_prop_object), TEXT_PROP_MEANS_INVISIBLE (propval)))) - XSETFASTINT (prevline, - find_next_newline_no_quit (XFASTINT (prevline) - 1, - -1)); - pos = *compute_motion (XFASTINT (prevline), 0, - lmargin + (XFASTINT (prevline) == BEG - ? start_hpos : 0), + prevline = find_next_newline_no_quit (prevline - 1, -1); + pos = *compute_motion (prevline, 0, + lmargin + (prevline == BEG ? start_hpos : 0), 0, - from, + from, /* Don't care for VPOS... */ 1 << (BITS_PER_SHORT - 1), /* ... nor HPOS. */ 1 << (BITS_PER_SHORT - 1), - width, hscroll, + -1, hscroll, /* This compensates for start_hpos so that a tab as first character still occupies 8 columns. */ - (XFASTINT (prevline) == BEG - ? -start_hpos : 0), + (prevline == BEG ? -start_hpos : 0), w); vpos -= pos.vpos; first = 0; - from = XFASTINT (prevline); + from = prevline; } /* If we made exactly the desired vertical distance, @@ -1913,30 +1977,30 @@ vmotion (from, vtarget, w) { Lisp_Object propval; - XSETFASTINT (prevline, find_next_newline_no_quit (from, -1)); - while (XFASTINT (prevline) > BEGV + prevline = find_next_newline_no_quit (from, -1); + while (prevline > BEGV && ((selective > 0 - && indented_beyond_p (XFASTINT (prevline), - CHAR_TO_BYTE (XFASTINT (prevline)), - selective)) - /* watch out for newlines with `invisible' property */ - || (propval = Fget_char_property (prevline, Qinvisible, + && indented_beyond_p (prevline, + CHAR_TO_BYTE (prevline), + (double) selective)) /* iftc */ + /* Watch out for newlines with `invisible' property. + When moving downward, check the newline after. */ + || (propval = Fget_char_property (make_number (prevline), + Qinvisible, text_prop_object), TEXT_PROP_MEANS_INVISIBLE (propval)))) - XSETFASTINT (prevline, - find_next_newline_no_quit (XFASTINT (prevline) - 1, - -1)); - pos = *compute_motion (XFASTINT (prevline), 0, - lmargin + (XFASTINT (prevline) == BEG + prevline = find_next_newline_no_quit (prevline - 1, -1); + pos = *compute_motion (prevline, 0, + lmargin + (prevline == BEG ? start_hpos : 0), 0, - from, + from, /* Don't care for VPOS... */ 1 << (BITS_PER_SHORT - 1), /* ... nor HPOS. */ 1 << (BITS_PER_SHORT - 1), - width, hscroll, - (XFASTINT (prevline) == BEG ? -start_hpos : 0), + -1, hscroll, + (prevline == BEG ? -start_hpos : 0), w); did_motion = 1; } @@ -1949,33 +2013,33 @@ vmotion (from, vtarget, w) } return compute_motion (from, vpos, pos.hpos, did_motion, ZV, vtarget, - (1 << (BITS_PER_SHORT - 1)), - width, hscroll, + -1, hscroll, pos.tab_offset - (from == BEG ? start_hpos : 0), w); } DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 2, 0, - "Move point to start of the screen line LINES lines down.\n\ -If LINES is negative, this means moving up.\n\ -\n\ -This function is an ordinary cursor motion function\n\ -which calculates the new position based on how text would be displayed.\n\ -The new position may be the start of a line,\n\ -or just the start of a continuation line.\n\ -The function returns number of screen lines moved over;\n\ -that usually equals LINES, but may be closer to zero\n\ -if beginning or end of buffer was reached.\n\ -\n\ -The optional second argument WINDOW specifies the window to use for\n\ -parameters such as width, horizontal scrolling, and so on.\n\ -The default is to use the selected window's parameters.\n\ -\n\ -`vertical-motion' always uses the current buffer,\n\ -regardless of which buffer is displayed in WINDOW.\n\ -This is consistent with other cursor motion functions\n\ -and makes it possible to use `vertical-motion' in any buffer,\n\ -whether or not it is currently displayed in some window.") - (lines, window) + doc: /* Move point to start of the screen line LINES lines down. +If LINES is negative, this means moving up. + +This function is an ordinary cursor motion function +which calculates the new position based on how text would be displayed. +The new position may be the start of a line, +or just the start of a continuation line. +The function returns number of screen lines moved over; +that usually equals LINES, but may be closer to zero +if beginning or end of buffer was reached. + +The optional second argument WINDOW specifies the window to use for +parameters such as width, horizontal scrolling, and so on. +The default is to use the selected window's parameters. + +`vertical-motion' always uses the current buffer, +regardless of which buffer is displayed in WINDOW. +This is consistent with other cursor motion functions +and makes it possible to use `vertical-motion' in any buffer, +whether or not it is currently displayed in some window. */) + (lines, window) Lisp_Object lines, window; { struct it it; @@ -1984,9 +2048,9 @@ whether or not it is currently displayed in some window.") Lisp_Object old_buffer; struct gcpro gcpro1; - CHECK_NUMBER (lines, 0); + CHECK_NUMBER (lines); if (! NILP (window)) - CHECK_WINDOW (window, 0); + CHECK_WINDOW (window); else window = selected_window; w = XWINDOW (window); @@ -1999,15 +2063,76 @@ whether or not it is currently displayed in some window.") old_buffer = w->buffer; XSETBUFFER (w->buffer, current_buffer); } - - SET_TEXT_POS (pt, PT, PT_BYTE); - start_display (&it, w, pt); - move_it_by_lines (&it, XINT (lines), 0); - SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it)); + + 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_p; + + SET_TEXT_POS (pt, PT, PT_BYTE); + start_display (&it, w, pt); + + /* Scan from the start of the line containing PT. If we don't + do this, we start moving with IT->current_x == 0, while PT is + really at some x > 0. The effect is, in continuation lines, that + we end up with the iterator placed at where it thinks X is 0, + while the end position is really at some X > 0, the same X that + PT had. */ + it_start = IT_CHARPOS (it); + + /* We expect the call to move_it_to, further down, to overshoot + if the starting point is on an image, stretch glyph, or Lisp + string. We won't need to backtrack in this situation, except + for one corner case: when the Lisp string contains a + newline. */ + 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_p = (s == e); + } + else + it_overshoot_expected_p = (it.method == GET_FROM_IMAGE + || it.method == GET_FROM_STRETCH); + + reseat_at_previous_visible_line_start (&it); + it.current_x = it.hpos = 0; + /* Temporarily disable selective display so we don't move too far */ + oselective = it.selective; + it.selective = 0; + move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS); + it.selective = oselective; + + /* Move back if we got too far. This may happen if + truncate-lines is on and PT is beyond right margin. + Don't go back if the overshoot is expected (see above). */ + if (IT_CHARPOS (it) > it_start && XINT (lines) > 0 + && !it_overshoot_expected_p) + move_it_by_lines (&it, -1, 0); + + it.vpos = 0; + /* Do this even if LINES is 0, so that we move back + to the beginning of the current line as we ought. */ + 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)); } @@ -2019,8 +2144,8 @@ void syms_of_indent () { DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode, - "*Indentation can insert tabs if this is non-nil.\n\ -Setting this variable automatically makes it local to the current buffer."); + doc: /* *Indentation can insert tabs if this is non-nil. +Setting this variable automatically makes it local to the current buffer. */); indent_tabs_mode = 1; defsubr (&Scurrent_indentation); @@ -2030,3 +2155,6 @@ Setting this variable automatically makes it local to the current buffer."); defsubr (&Svertical_motion); defsubr (&Scompute_motion); } + +/* arch-tag: 9adfea44-71f7-4988-8ee3-96da15c502cc + (do not change this comment) */