X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/b17f53abc28496125965f36147b76ea5f6a2b4fb..29cdc13ed61e5a64ba30df1030029898a26b7947:/src/indent.c
diff --git a/src/indent.c b/src/indent.c
index 2d48dc746d..970904cba7 100644
--- a/src/indent.c
+++ b/src/indent.c
@@ -1,13 +1,14 @@
/* Indentation functions.
Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1998, 2000, 2001,
- 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ Free Software Foundation, Inc.
This file is part of GNU Emacs.
-GNU Emacs is free software; you can redistribute it and/or modify
+GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3, or (at your option)
-any later version.
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -15,17 +16,17 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
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., 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA. */
+along with GNU Emacs. If not, see . */
#include
#include
+#include
#include "lisp.h"
#include "buffer.h"
-#include "charset.h"
+#include "character.h"
#include "category.h"
+#include "composite.h"
#include "indent.h"
#include "keyboard.h"
#include "frame.h"
@@ -34,6 +35,7 @@ Boston, MA 02110-1301, USA. */
#include "termopts.h"
#include "disptab.h"
#include "intervals.h"
+#include "dispextern.h"
#include "region-cache.h"
/* Indentation can insert tabs if this is non-zero;
@@ -59,8 +61,8 @@ EMACS_INT last_known_column_point;
static int last_known_column_modified;
-static double current_column_1 P_ ((void));
-static double position_indentation P_ ((int));
+static double current_column_1 (void);
+static double position_indentation (int);
/* Cache of beginning of line found by the last call of
current_column. */
@@ -70,7 +72,7 @@ static EMACS_INT current_column_bol_cache;
/* Get the display table to use for the current buffer. */
struct Lisp_Char_Table *
-buffer_display_table ()
+buffer_display_table (void)
{
Lisp_Object thisbuf;
@@ -87,9 +89,7 @@ buffer_display_table ()
/* Return the width of character C under display table DP. */
static int
-character_width (c, dp)
- int c;
- struct Lisp_Char_Table *dp;
+character_width (int c, struct Lisp_Char_Table *dp)
{
Lisp_Object elt;
@@ -123,9 +123,7 @@ character_width (c, dp)
invalidate the buffer's width_run_cache. */
int
-disptab_matches_widthtab (disptab, widthtab)
- struct Lisp_Char_Table *disptab;
- struct Lisp_Vector *widthtab;
+disptab_matches_widthtab (struct Lisp_Char_Table *disptab, struct Lisp_Vector *widthtab)
{
int i;
@@ -143,9 +141,7 @@ disptab_matches_widthtab (disptab, widthtab)
/* Recompute BUF's width table, using the display table DISPTAB. */
void
-recompute_width_table (buf, disptab)
- struct buffer *buf;
- struct Lisp_Char_Table *disptab;
+recompute_width_table (struct buffer *buf, struct Lisp_Char_Table *disptab)
{
int i;
struct Lisp_Vector *widthtab;
@@ -164,7 +160,7 @@ recompute_width_table (buf, disptab)
state of current_buffer's cache_long_line_scans variable. */
static void
-width_run_cache_on_off ()
+width_run_cache_on_off (void)
{
if (NILP (current_buffer->cache_long_line_scans)
/* And, for the moment, this feature doesn't work on multibyte
@@ -215,11 +211,7 @@ width_run_cache_on_off ()
will equal the return value. */
EMACS_INT
-skip_invisible (pos, next_boundary_p, to, window)
- EMACS_INT pos;
- EMACS_INT *next_boundary_p;
- EMACS_INT to;
- Lisp_Object window;
+skip_invisible (EMACS_INT pos, EMACS_INT *next_boundary_p, EMACS_INT to, Lisp_Object window)
{
Lisp_Object prop, position, overlay_limit, proplimit;
Lisp_Object buffer, tmp;
@@ -251,7 +243,7 @@ skip_invisible (pos, next_boundary_p, to, window)
{
/* Don't scan terribly far. */
XSETFASTINT (proplimit, min (pos + 100, to));
- /* No matter what. don't go past next overlay change. */
+ /* No matter what, don't go past next overlay change. */
if (XFASTINT (overlay_limit) < XFASTINT (proplimit))
proplimit = overlay_limit;
tmp = Fnext_single_property_change (position, Qinvisible,
@@ -281,32 +273,6 @@ skip_invisible (pos, next_boundary_p, to, window)
return pos;
}
-/* If a composition starts at POS/POS_BYTE and it doesn't stride over
- POINT, set *LEN / *LEN_BYTE to the character and byte lengths, *WIDTH
- to the width, and return 1. Otherwise, return 0. */
-
-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;
-}
-
/* Set variables WIDTH and BYTES for a multibyte sequence starting at P.
DP is a display table or NULL.
@@ -319,7 +285,7 @@ check_composition (pos, pos_byte, point, len, len_byte, width)
int c; \
\
wide_column = 0; \
- c = STRING_CHAR_AND_LENGTH (p, MAX_MULTIBYTE_LENGTH, bytes); \
+ c = STRING_CHAR_AND_LENGTH (p, bytes); \
if (BYTES_BY_CHAR_HEAD (*p) != bytes) \
width = bytes * 4; \
else \
@@ -327,7 +293,7 @@ check_composition (pos, pos_byte, point, len, len_byte, width)
if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c))) \
width = XVECTOR (DISP_CHAR_VECTOR (dp, c))->size; \
else \
- width = WIDTH_BY_CHAR_HEAD (*p); \
+ width = CHAR_WIDTH (c); \
if (width > 1) \
wide_column = width; \
} \
@@ -346,7 +312,7 @@ 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. */)
- ()
+ (void)
{
Lisp_Object temp;
XSETFASTINT (temp, (int) current_column ()); /* iftc */
@@ -356,13 +322,13 @@ Text that has an invisible property is considered as having width 0, unless
/* Cancel any recorded value of the horizontal position. */
void
-invalidate_current_column ()
+invalidate_current_column (void)
{
last_known_column_point = 0;
}
double
-current_column ()
+current_column (void)
{
register int col;
register unsigned char *ptr, *stop;
@@ -446,9 +412,9 @@ current_column ()
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));
+ if (GLYPH_CODE_P (entry)
+ && GLYPH_CODE_CHAR_VALID_P (entry))
+ c = GLYPH_CODE_CHAR (entry);
else
c = ' ';
}
@@ -503,77 +469,162 @@ current_column ()
return col;
}
-/* Return the column number of position POS
- by scanning forward from the beginning of the line.
- This function handles characters that are invisible
- due to text properties or overlays. */
-static double
-current_column_1 ()
+/* Check the presence of a display property and compute its width.
+ If a property was found and its width was found as well, return
+ its width (>= 0) and set the position of the end of the property
+ in ENDPOS.
+ Otherwise just return -1. */
+static int
+check_display_width (EMACS_INT pos, EMACS_INT col, EMACS_INT *endpos)
+{
+ Lisp_Object val, overlay;
+
+ if (CONSP (val = get_char_property_and_overlay
+ (make_number (pos), Qdisplay, Qnil, &overlay))
+ && EQ (Qspace, XCAR (val)))
+ { /* FIXME: Use calc_pixel_width_or_height, as in term.c. */
+ Lisp_Object plist = XCDR (val), prop;
+ int width = -1;
+
+ if ((prop = Fplist_get (plist, QCwidth), NATNUMP (prop)))
+ width = XINT (prop);
+ else if (FLOATP (prop))
+ width = (int)(XFLOAT_DATA (prop) + 0.5);
+ else if ((prop = Fplist_get (plist, QCalign_to), NATNUMP (prop)))
+ width = XINT (prop) - col;
+ else if (FLOATP (prop))
+ width = (int)(XFLOAT_DATA (prop) + 0.5) - col;
+
+ if (width >= 0)
+ {
+ EMACS_INT start;
+ if (OVERLAYP (overlay))
+ *endpos = OVERLAY_POSITION (OVERLAY_END (overlay));
+ else
+ get_property_and_range (pos, Qdisplay, &val, &start, endpos, Qnil);
+ return width;
+ }
+ }
+ return -1;
+}
+
+/* Scanning from the beginning of the current line, stop at the buffer
+ position ENDPOS or at the column GOALCOL or at the end of line, whichever
+ comes first.
+ Return the resulting buffer position and column in ENDPOS and GOALCOL.
+ PREVCOL gets set to the column of the previous position (it's always
+ strictly smaller than the goal column). */
+static void
+scan_for_column (EMACS_INT *endpos, EMACS_INT *goalcol, EMACS_INT *prevcol)
{
register EMACS_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);
+ struct composition_it cmp_it;
+ Lisp_Object window;
+ struct window *w;
/* Start the scan at the beginning of this line with column number 0. */
- register EMACS_INT col = 0;
+ register EMACS_INT col = 0, prev_col = 0;
+ EMACS_INT goal = goalcol ? *goalcol : MOST_POSITIVE_FIXNUM;
+ EMACS_INT end = endpos ? *endpos : PT;
EMACS_INT scan, scan_byte;
EMACS_INT next_boundary;
+ {
EMACS_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;
+ }
+
+ window = Fget_buffer_window (Fcurrent_buffer (), Qnil);
+ w = ! NILP (window) ? XWINDOW (window) : NULL;
if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
+ memset (&cmp_it, 0, sizeof cmp_it);
+ cmp_it.id = -1;
+ composition_compute_stop_pos (&cmp_it, scan, scan_byte, end, Qnil);
/* Scan forward to the target position. */
- while (scan < opoint)
+ while (scan < end)
{
int c;
/* Occasionally we may need to skip invisible text. */
while (scan == next_boundary)
{
- int old_scan = scan;
+ EMACS_INT old_scan = scan;
/* This updates NEXT_BOUNDARY to the next place
where we might need to skip more invisible text. */
- scan = skip_invisible (scan, &next_boundary, opoint, Qnil);
- if (scan >= opoint)
- goto endloop;
+ scan = skip_invisible (scan, &next_boundary, end, Qnil);
if (scan != old_scan)
scan_byte = CHAR_TO_BYTE (scan);
+ if (scan >= end)
+ goto endloop;
}
- /* Check composition sequence. */
- {
- int len, len_byte, width;
+ /* Test reaching the goal column. We do this after skipping
+ invisible characters, so that we put point before the
+ character on which the cursor will appear. */
+ if (col >= goal)
+ break;
+ prev_col = col;
- if (check_composition (scan, scan_byte, opoint,
- &len, &len_byte, &width))
+ { /* Check display property. */
+ EMACS_INT end;
+ int width = check_display_width (scan, col, &end);
+ if (width >= 0)
{
- scan += len;
- scan_byte += len_byte;
- if (scan <= opoint)
- col += width;
- continue;
+ col += width;
+ if (end > scan) /* Avoid infinite loops with 0-width overlays. */
+ {
+ scan = end; scan_byte = charpos_to_bytepos (scan);
+ continue;
+ }
}
}
+ /* Check composition sequence. */
+ if (cmp_it.id >= 0
+ || (scan == cmp_it.stop_pos
+ && composition_reseat_it (&cmp_it, scan, scan_byte, end,
+ w, NULL, Qnil)))
+ composition_update_it (&cmp_it, scan, scan_byte, Qnil);
+ if (cmp_it.id >= 0)
+ {
+ scan += cmp_it.nchars;
+ scan_byte += cmp_it.nbytes;
+ if (scan <= end)
+ col += cmp_it.width;
+ if (cmp_it.to == cmp_it.nglyphs)
+ {
+ cmp_it.id = -1;
+ composition_compute_stop_pos (&cmp_it, scan, scan_byte, end,
+ Qnil);
+ }
+ else
+ cmp_it.from = cmp_it.to;
+ continue;
+ }
+
c = FETCH_BYTE (scan_byte);
+ /* See if there is a display table and it relates
+ to this character. */
+
if (dp != 0
- && ! (multibyte && BASE_LEADING_CODE_P (c))
+ && ! (multibyte && 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. */
+ Update the column/position based on those glyphs. */
charvec = DISP_CHAR_VECTOR (dp, c);
n = ASIZE (charvec);
@@ -582,12 +633,11 @@ current_column_1 ()
{
/* This should be handled the same as
next_element_from_display_vector does it. */
- Lisp_Object entry;
- entry = AREF (charvec, i);
+ Lisp_Object entry = AREF (charvec, i);
- if (INTEGERP (entry)
- && GLYPH_CHAR_VALID_P (XFASTINT (entry)))
- c = FAST_GLYPH_CHAR (XFASTINT (entry));
+ if (GLYPH_CODE_P (entry)
+ && GLYPH_CODE_CHAR_VALID_P (entry))
+ c = GLYPH_CODE_CHAR (entry);
else
c = ' ';
@@ -606,8 +656,8 @@ current_column_1 ()
}
else
{
- /* The display table says nothing for this character.
- Display it as itself. */
+ /* The display table doesn't affect this character;
+ it displays as itself. */
if (c == '\n')
goto endloop;
@@ -618,17 +668,17 @@ current_column_1 ()
col += tab_width;
col = col / tab_width * tab_width;
}
- else if (multibyte && BASE_LEADING_CODE_P (c))
+ else if (multibyte && LEADING_CODE_P (c))
{
+ /* Start of multi-byte form. */
unsigned char *ptr;
int bytes, width, wide_column;
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--;
+ scan_byte += bytes - 1;
col += width;
}
else if (ctl_arrow && (c < 040 || c == 0177))
@@ -648,6 +698,26 @@ current_column_1 ()
last_known_column_point = PT;
last_known_column_modified = MODIFF;
+ if (goalcol)
+ *goalcol = col;
+ if (endpos)
+ *endpos = scan;
+ if (prevcol)
+ *prevcol = prev_col;
+}
+
+/* Return the column number of position POS
+ by scanning forward from the beginning of the line.
+ This function handles characters that are invisible
+ due to text properties or overlays. */
+
+static double
+current_column_1 (void)
+{
+ EMACS_INT col = MOST_POSITIVE_FIXNUM;
+ EMACS_INT opoint = PT;
+
+ scan_for_column (&opoint, &col, NULL);
return col;
}
@@ -741,8 +811,7 @@ Optional second argument MINIMUM says always do at least MINIMUM spaces
even if that goes past COLUMN; by default, MINIMUM is zero.
The return value is COLUMN. */)
- (column, minimum)
- Lisp_Object column, minimum;
+ (Lisp_Object column, Lisp_Object minimum)
{
int mincol;
register int fromcol;
@@ -786,14 +855,14 @@ The return value is COLUMN. */)
}
-static double position_indentation P_ ((int));
+static double position_indentation (int);
DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
0, 0, 0,
doc: /* Return the indentation of the current line.
This is the horizontal position of the character
following any initial whitespace. */)
- ()
+ (void)
{
Lisp_Object val;
int opoint = PT, opoint_byte = PT_BYTE;
@@ -806,8 +875,7 @@ following any initial whitespace. */)
}
static double
-position_indentation (pos_byte)
- register int pos_byte;
+position_indentation (register int pos_byte)
{
register EMACS_INT column = 0;
register EMACS_INT tab_width = XINT (current_buffer->tab_width);
@@ -896,9 +964,7 @@ position_indentation (pos_byte)
preceding line. */
int
-indented_beyond_p (pos, pos_byte, column)
- int pos, pos_byte;
- double column;
+indented_beyond_p (int pos, int pos_byte, double column)
{
double val;
int opoint = PT, opoint_byte = PT_BYTE;
@@ -930,184 +996,50 @@ In addition, if FORCE is t, and the line is too short to reach
COLUMN, add spaces/tabs to get there.
The return value is the current column. */)
- (column, force)
- Lisp_Object column, force;
+ (Lisp_Object column, Lisp_Object force)
{
- register EMACS_INT pos;
- register EMACS_INT col = current_column ();
- register EMACS_INT goal;
- register EMACS_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);
+ EMACS_INT pos;
+ EMACS_INT col, prev_col;
+ EMACS_INT goal;
- Lisp_Object val;
- EMACS_INT prev_col = 0;
- int c = 0;
- EMACS_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;
+ col = goal;
+ pos = ZV;
+ scan_for_column (&pos, &col, &prev_col);
- /* If we're starting past the desired column,
- back up to beginning of line and scan from there. */
- if (col > goal)
- {
- end = pos;
- pos = current_column_bol_cache;
- pos_byte = CHAR_TO_BYTE (pos);
- col = 0;
- }
+ SET_PT (pos);
- next_boundary = pos;
-
- while (pos < end)
+ /* If a tab char made us overshoot, change it to spaces
+ and scan through it again. */
+ if (!NILP (force) && col > goal)
{
- while (pos == next_boundary)
- {
- EMACS_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;
- }
-
- /* Test reaching the goal column. We do this after skipping
- invisible characters, so that we put point before the
- character on which the cursor will appear. */
- if (col >= goal)
- break;
-
- /* Check composition sequence. */
- {
- 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);
-
- /* 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);
-
- for (i = 0; i < n; i++)
- {
- /* This should be handled the same as
- next_element_from_display_vector does it. */
-
- Lisp_Object entry;
- entry = AREF (charvec, i);
-
- if (INTEGERP (entry)
- && GLYPH_CHAR_VALID_P (XFASTINT (entry)))
- c = FAST_GLYPH_CHAR (XFASTINT (entry));
- else
- c = ' ';
+ int c;
+ EMACS_INT pos_byte = PT_BYTE;
- 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
+ DEC_POS (pos_byte);
+ c = FETCH_CHAR (pos_byte);
+ if (c == '\t' && prev_col < goal)
{
- /* 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;
- 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))
- {
- /* Start of multi-byte form. */
- 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;
+ EMACS_INT goal_pt, goal_pt_byte;
+
+ /* Insert spaces in front of the tab to reach GOAL. Do this
+ first so that a marker at the end of the tab gets
+ adjusted. */
+ SET_PT_BOTH (PT - 1, PT_BYTE - 1);
+ Finsert_char (make_number (' '), make_number (goal - prev_col), Qt);
+
+ /* Now delete the tab, and indent to COL. */
+ 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);
+
+ /* Set the last_known... vars consistently. */
+ col = goal;
}
-
- pos++;
- pos_byte++;
- }
- endloop:
-
- SET_PT_BOTH (pos, pos_byte);
-
- /* If a tab char made us overshoot, change it to spaces
- and scan through it again. */
- if (!NILP (force) && col > goal && c == '\t' && prev_col < goal)
- {
- EMACS_INT goal_pt, goal_pt_byte;
-
- /* Insert spaces in front of the tab to reach GOAL. Do this
- first so that a marker at the end of the tab gets
- adjusted. */
- SET_PT_BOTH (PT - 1, PT_BYTE - 1);
- Finsert_char (make_number (' '), make_number (goal - prev_col), Qt);
-
- /* Now delete the tab, and indent to COL. */
- 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);
-
- /* Set the last_known... vars consistently. */
- col = goal;
}
/* If line ends prematurely, add space to the end. */
@@ -1118,8 +1050,7 @@ The return value is the current column. */)
last_known_column_point = PT;
last_known_column_modified = MODIFF;
- XSETFASTINT (val, col);
- return val;
+ return make_number (col);
}
/* compute_motion: compute buffer posn given screen posn and vice versa */
@@ -1190,12 +1121,7 @@ struct position val_compute_motion;
the scroll bars if they are turned on. */
struct position *
-compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, hscroll, tab_offset, win)
- EMACS_INT from, fromvpos, fromhpos, to, tovpos, tohpos;
- int did_motion;
- EMACS_INT width;
- EMACS_INT hscroll, tab_offset;
- struct window *win;
+compute_motion (EMACS_INT from, EMACS_INT fromvpos, EMACS_INT fromhpos, int did_motion, EMACS_INT to, EMACS_INT tovpos, EMACS_INT tohpos, EMACS_INT width, EMACS_INT hscroll, EMACS_INT tab_offset, struct window *win)
{
register EMACS_INT hpos = fromhpos;
register EMACS_INT vpos = fromvpos;
@@ -1243,6 +1169,8 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
EMACS_INT prev_tab_offset; /* Previous tab offset. */
EMACS_INT continuation_glyph_width;
+ struct composition_it cmp_it;
+
XSETBUFFER (buffer, current_buffer);
XSETWINDOW (window, win);
@@ -1283,6 +1211,10 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
pos_byte = prev_pos_byte = CHAR_TO_BYTE (from);
contin_hpos = 0;
prev_tab_offset = tab_offset;
+ memset (&cmp_it, 0, sizeof cmp_it);
+ cmp_it.id = -1;
+ composition_compute_stop_pos (&cmp_it, pos, pos_byte, to, Qnil);
+
while (1)
{
while (pos == next_boundary)
@@ -1397,10 +1329,20 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
if (hpos > width)
{
- if (hscroll
- || (truncate_partial_width_windows
- && ((width + continuation_glyph_width)
- < FRAME_COLS (XFRAME (WINDOW_FRAME (win)))))
+ int total_width = width + continuation_glyph_width;
+ int truncate = 0;
+
+ if (!NILP (Vtruncate_partial_width_windows)
+ && (total_width < FRAME_COLS (XFRAME (WINDOW_FRAME (win)))))
+ {
+ if (INTEGERP (Vtruncate_partial_width_windows))
+ truncate
+ = total_width < XFASTINT (Vtruncate_partial_width_windows);
+ else
+ truncate = 1;
+ }
+
+ if (hscroll || truncate
|| !NILP (current_buffer->truncate_lines))
{
/* Truncating: skip to newline, unless we are already past
@@ -1560,21 +1502,29 @@ 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. */
- {
- 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;
- }
- }
+ if (cmp_it.id >= 0
+ || (pos == cmp_it.stop_pos
+ && composition_reseat_it (&cmp_it, pos, pos_byte, to, win,
+ NULL, Qnil)))
+ composition_update_it (&cmp_it, pos, pos_byte, Qnil);
+ if (cmp_it.id >= 0)
+ {
+ pos += cmp_it.nchars;
+ pos_byte += cmp_it.nbytes;
+ hpos += cmp_it.width;
+ if (cmp_it.to == cmp_it.nglyphs)
+ {
+ cmp_it.id = -1;
+ composition_compute_stop_pos (&cmp_it, pos, pos_byte, to,
+ Qnil);
+ }
+ else
+ cmp_it.from = cmp_it.to;
+ continue;
+ }
+ c = FETCH_BYTE (pos_byte);
pos++, pos_byte++;
/* Perhaps add some info to the width_run_cache. */
@@ -1606,7 +1556,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
}
if (dp != 0
- && ! (multibyte && BASE_LEADING_CODE_P (c))
+ && ! (multibyte && LEADING_CODE_P (c))
&& VECTORP (DISP_CHAR_VECTOR (dp, c)))
{
charvec = DISP_CHAR_VECTOR (dp, c);
@@ -1626,9 +1576,9 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
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));
+ if (GLYPH_CODE_P (entry)
+ && GLYPH_CODE_CHAR_VALID_P (entry))
+ c = GLYPH_CODE_CHAR (entry);
else
c = ' ';
}
@@ -1712,7 +1662,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width,
hpos = width;
}
}
- else if (multibyte && BASE_LEADING_CODE_P (c))
+ else if (multibyte && LEADING_CODE_P (c))
{
/* Start of multi-byte form. */
unsigned char *ptr;
@@ -1804,9 +1754,7 @@ 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;
+ (Lisp_Object from, Lisp_Object frompos, Lisp_Object to, Lisp_Object topos, Lisp_Object width, Lisp_Object offsets, Lisp_Object window)
{
struct window *w;
Lisp_Object bufpos, hpos, vpos, prevhpos;
@@ -1885,9 +1833,7 @@ visible section of the buffer, and pass LINE and COL as TOPOS. */)
struct position val_vmotion;
struct position *
-vmotion (from, vtarget, w)
- register EMACS_INT from, vtarget;
- struct window *w;
+vmotion (register EMACS_INT from, register EMACS_INT vtarget, struct window *w)
{
EMACS_INT hscroll = XINT (w->hscroll);
struct position pos;
@@ -2041,19 +1987,32 @@ 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.
+LINES can optionally take the form (COLS . LINES), in which case
+the motion will not stop at the start of a screen line but on
+its column COLS (if such exists on that line, that is).
+
`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;
+ (Lisp_Object lines, Lisp_Object window)
{
struct it it;
struct text_pos pt;
struct window *w;
Lisp_Object old_buffer;
struct gcpro gcpro1;
+ Lisp_Object lcols = Qnil;
+ double cols;
+
+ /* Allow LINES to be of the form (HPOS . VPOS) aka (COLUMNS . LINES). */
+ if (CONSP (lines) && (NUMBERP (XCAR (lines))))
+ {
+ lcols = XCAR (lines);
+ cols = INTEGERP (lcols) ? (double) XINT (lcols) : XFLOAT_DATA (lcols);
+ lines = XCDR (lines);
+ }
CHECK_NUMBER (lines);
if (! NILP (window))
@@ -2079,68 +2038,110 @@ whether or not it is currently displayed in some window. */)
}
else
{
- int it_start;
- int oselective;
- int it_overshoot_expected;
+ int it_start, first_x, it_overshoot_expected;
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. */
+ first_x = it.first_visible_x;
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,
- composition, 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)
+ /* See comments below for why we calculate this. */
+ if (XINT (lines) > 0)
{
- const char *s = SDATA (it.string);
- const char *e = s + SBYTES (it.string);
-
- while (s < e && *s != '\n')
- ++s;
-
- /* If there is no newline in the string, we need to check
- whether there is a newline immediately after the string
- in move_it_to below. This may happen if there is an
- overlay with an after-string just before the newline. */
- it_overshoot_expected = (s == e) ? -1 : 0;
+ if (it.cmp_it.id >= 0)
+ it_overshoot_expected = 1;
+ else 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);
}
- else
- it_overshoot_expected = (it.method == GET_FROM_IMAGE
- || it.method == GET_FROM_STRETCH
- || it.method == GET_FROM_COMPOSITION);
+ /* 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. */
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
- || (it_overshoot_expected < 0
- && it.method == GET_FROM_BUFFER
- && it.c == '\n')))
- 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);
+ if (IT_CHARPOS (it) != PT)
+ /* We used to temporarily disable selective display here; the
+ comment said this is "so we don't move too far" (2005-01-19
+ checkin by kfs). But this does nothing useful that I can
+ tell, and it causes Bug#2694 . -- cyd */
+ move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
+
+ if (XINT (lines) <= 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);
+ }
+ else
+ {
+ if (IT_CHARPOS (it) > it_start)
+ {
+ /* IT may move too far if truncate-lines is on and PT
+ lies beyond the right margin. In that case,
+ backtrack unless the starting point is on an image,
+ stretch glyph, composition, or Lisp string. */
+ if (!it_overshoot_expected
+ /* Also, backtrack if the Lisp string contains no
+ newline, but there is a newline right after it.
+ In this case, IT overshoots if there is an
+ after-string just before the newline. */
+ || (it_overshoot_expected < 0
+ && it.method == GET_FROM_BUFFER
+ && it.c == '\n'))
+ move_it_by_lines (&it, -1, 0);
+ it.vpos = 0;
+ move_it_by_lines (&it, XINT (lines), 0);
+ }
+ else
+ {
+ /* Otherwise, we are at the first row occupied by PT,
+ which might span multiple screen lines (e.g., if it's
+ on a multi-line display string). We want to start
+ from the last line that it occupies. */
+ if (it_start < ZV)
+ {
+ while (IT_CHARPOS (it) <= it_start)
+ {
+ it.vpos = 0;
+ move_it_by_lines (&it, 1, 0);
+ }
+ if (XINT (lines) > 1)
+ move_it_by_lines (&it, XINT (lines) - 1, 0);
+ }
+ else
+ {
+ it.vpos = 0;
+ move_it_by_lines (&it, XINT (lines), 0);
+ }
+ }
+ }
+
+ /* Move to the goal column, if one was specified. */
+ if (!NILP (lcols))
+ {
+ /* If the window was originally hscrolled, move forward by
+ the hscrolled amount first. */
+ if (first_x > 0)
+ {
+ move_it_in_display_line (&it, ZV, first_x, MOVE_TO_X);
+ it.current_x = 0;
+ }
+ move_it_in_display_line
+ (&it, ZV,
+ (int)(cols * FRAME_COLUMN_WIDTH (XFRAME (w->frame)) + 0.5),
+ MOVE_TO_X);
+ }
SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
}
@@ -2156,7 +2157,7 @@ whether or not it is currently displayed in some window. */)
/* File's initialization. */
void
-syms_of_indent ()
+syms_of_indent (void)
{
DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode,
doc: /* *Indentation can insert tabs if this is non-nil. */);