summaryrefslogtreecommitdiff
path: root/src/indent.c
diff options
context:
space:
mode:
authorStefan Monnier <monnier@iro.umontreal.ca>2022-09-25 16:15:16 -0400
committerStefan Monnier <monnier@iro.umontreal.ca>2022-09-25 16:15:16 -0400
commit650c20f1ca4e07591a727e1cfcc74b3363d15985 (patch)
tree85d11f6437cde22f410c25e0e5f71a3131ebd07d /src/indent.c
parent8869332684c2302b5ba1ead4568bbc7ba1c0183e (diff)
parent4b85ae6a24380fb67a3315eaec9233f17a872473 (diff)
downloademacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.tar.gz
emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.tar.bz2
emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.zip
Merge 'master' into noverlay
Diffstat (limited to 'src/indent.c')
-rw-r--r--src/indent.c445
1 files changed, 280 insertions, 165 deletions
diff --git a/src/indent.c b/src/indent.c
index 8ac7c6ef109..f14593932c0 100644
--- a/src/indent.c
+++ b/src/indent.c
@@ -1,5 +1,5 @@
/* Indentation functions.
- Copyright (C) 1985-1988, 1993-1995, 1998, 2000-2017 Free Software
+ Copyright (C) 1985-1988, 1993-1995, 1998, 2000-2022 Free Software
Foundation, Inc.
This file is part of GNU Emacs.
@@ -18,7 +18,6 @@ You should have received a copy of the GNU General Public License
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <config.h>
-#include <stdio.h>
#include "lisp.h"
#include "character.h"
@@ -49,7 +48,7 @@ ptrdiff_t last_known_column_point;
/* Value of MODIFF when current_column was called. */
-static EMACS_INT last_known_column_modified;
+static modiff_count last_known_column_modified;
static ptrdiff_t current_column_1 (void);
static ptrdiff_t position_indentation (ptrdiff_t);
@@ -116,7 +115,7 @@ disptab_matches_widthtab (struct Lisp_Char_Table *disptab, struct Lisp_Vector *w
for (i = 0; i < 256; i++)
if (character_width (i, disptab)
- != XFASTINT (widthtab->contents[i]))
+ != XFIXNAT (widthtab->contents[i]))
return 0;
return 1;
@@ -232,24 +231,24 @@ skip_invisible (ptrdiff_t pos, ptrdiff_t *next_boundary_p, ptrdiff_t to, Lisp_Ob
/* As for text properties, this gives a lower bound
for where the invisible text property could change. */
proplimit = Fnext_property_change (position, buffer, Qt);
- if (XFASTINT (overlay_limit) < XFASTINT (proplimit))
+ if (XFIXNAT (overlay_limit) < XFIXNAT (proplimit))
proplimit = overlay_limit;
/* PROPLIMIT is now a lower bound for the next change
in invisible status. If that is plenty far away,
use that lower bound. */
- if (XFASTINT (proplimit) > pos + 100 || XFASTINT (proplimit) >= to)
- *next_boundary_p = XFASTINT (proplimit);
+ if (XFIXNAT (proplimit) > pos + 100 || XFIXNAT (proplimit) >= to)
+ *next_boundary_p = XFIXNAT (proplimit);
/* Otherwise, scan for the next `invisible' property change. */
else
{
/* Don't scan terribly far. */
XSETFASTINT (proplimit, min (pos + 100, to));
/* No matter what, don't go past next overlay change. */
- if (XFASTINT (overlay_limit) < XFASTINT (proplimit))
+ if (XFIXNAT (overlay_limit) < XFIXNAT (proplimit))
proplimit = overlay_limit;
tmp = Fnext_single_property_change (position, Qinvisible,
buffer, proplimit);
- end = XFASTINT (tmp);
+ end = XFIXNAT (tmp);
#if 0
/* Don't put the boundary in the middle of multibyte form if
there is no actual property change. */
@@ -283,9 +282,7 @@ skip_invisible (ptrdiff_t pos, ptrdiff_t *next_boundary_p, ptrdiff_t to, Lisp_Ob
#define MULTIBYTE_BYTES_WIDTH(p, dp, bytes, width) \
do { \
- int ch; \
- \
- ch = STRING_CHAR_AND_LENGTH (p, bytes); \
+ int ch = string_char_and_length (p, &(bytes)); \
if (BYTES_BY_CHAR_HEAD (*p) != bytes) \
width = bytes * 4; \
else \
@@ -306,6 +303,8 @@ and point (e.g., 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).
+In a buffer with very long lines, the value will be an approximation,
+because calculating the exact number is very expensive.
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
@@ -313,6 +312,7 @@ Text that has an invisible property is considered as having width 0, unless
(void)
{
Lisp_Object temp;
+
XSETFASTINT (temp, current_column ());
return temp;
}
@@ -341,6 +341,14 @@ current_column (void)
&& MODIFF == last_known_column_modified)
return last_known_column;
+ ptrdiff_t line_beg = find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1,
+ NULL, NULL, 1);
+
+ /* Avoid becoming abysmally slow for very long lines. */
+ if (current_buffer->long_line_optimizations_p
+ && !NILP (Vlong_line_threshold)
+ && PT - line_beg > XFIXNUM (Vlong_line_threshold))
+ return PT - line_beg; /* this is an approximation! */
/* If the buffer has overlays, text properties,
or multibyte characters, use a more general algorithm. */
if (buffer_intervals (current_buffer)
@@ -468,31 +476,40 @@ check_display_width (ptrdiff_t pos, ptrdiff_t col, ptrdiff_t *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. */
- Lisp_Object plist = XCDR (val), prop;
+ if (!NILP (val = get_char_property_and_overlay (make_fixnum (pos), Qdisplay,
+ Qnil, &overlay)))
+ {
int width = -1;
- EMACS_INT align_to_max =
- (col < MOST_POSITIVE_FIXNUM - INT_MAX
- ? (EMACS_INT) INT_MAX + col
- : MOST_POSITIVE_FIXNUM);
-
- if ((prop = Fplist_get (plist, QCwidth),
- RANGED_INTEGERP (0, prop, INT_MAX))
- || (prop = Fplist_get (plist, QCrelative_width),
- RANGED_INTEGERP (0, prop, INT_MAX)))
- width = XINT (prop);
- else if (FLOATP (prop) && 0 <= XFLOAT_DATA (prop)
- && XFLOAT_DATA (prop) <= INT_MAX)
- width = (int)(XFLOAT_DATA (prop) + 0.5);
- else if ((prop = Fplist_get (plist, QCalign_to),
- RANGED_INTEGERP (col, prop, align_to_max)))
- width = XINT (prop) - col;
- else if (FLOATP (prop) && col <= XFLOAT_DATA (prop)
- && (XFLOAT_DATA (prop) <= align_to_max))
- width = (int)(XFLOAT_DATA (prop) + 0.5) - col;
+ Lisp_Object plist = Qnil;
+
+ /* Handle '(space ...)' display specs. */
+ if (CONSP (val) && EQ (Qspace, XCAR (val)))
+ { /* FIXME: Use calc_pixel_width_or_height. */
+ Lisp_Object prop;
+ EMACS_INT align_to_max =
+ (col < MOST_POSITIVE_FIXNUM - INT_MAX
+ ? (EMACS_INT) INT_MAX + col
+ : MOST_POSITIVE_FIXNUM);
+
+ plist = XCDR (val);
+ if ((prop = plist_get (plist, QCwidth),
+ RANGED_FIXNUMP (0, prop, INT_MAX))
+ || (prop = plist_get (plist, QCrelative_width),
+ RANGED_FIXNUMP (0, prop, INT_MAX)))
+ width = XFIXNUM (prop);
+ else if (FLOATP (prop) && 0 <= XFLOAT_DATA (prop)
+ && XFLOAT_DATA (prop) <= INT_MAX)
+ width = (int)(XFLOAT_DATA (prop) + 0.5);
+ else if ((prop = plist_get (plist, QCalign_to),
+ RANGED_FIXNUMP (col, prop, align_to_max)))
+ width = XFIXNUM (prop) - col;
+ else if (FLOATP (prop) && col <= XFLOAT_DATA (prop)
+ && (XFLOAT_DATA (prop) <= align_to_max))
+ width = (int)(XFLOAT_DATA (prop) + 0.5) - col;
+ }
+ /* Handle 'display' strings. */
+ else if (STRINGP (val))
+ width = XFIXNUM (Fstring_width (val, Qnil, Qnil));
if (width >= 0)
{
@@ -504,7 +521,8 @@ check_display_width (ptrdiff_t pos, ptrdiff_t col, ptrdiff_t *endpos)
/* For :relative-width, we need to multiply by the column
width of the character at POS, if it is greater than 1. */
- if (!NILP (Fplist_get (plist, QCrelative_width))
+ if (!NILP (plist)
+ && !NILP (plist_get (plist, QCrelative_width))
&& !NILP (BVAR (current_buffer, enable_multibyte_characters)))
{
int b, wd;
@@ -516,6 +534,7 @@ check_display_width (ptrdiff_t pos, ptrdiff_t col, ptrdiff_t *endpos)
return width;
}
}
+
return -1;
}
@@ -524,9 +543,11 @@ check_display_width (ptrdiff_t pos, ptrdiff_t col, ptrdiff_t *endpos)
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). */
+ strictly smaller than the goal column), and PREVPOS and PREVBPOS get set
+ to the corresponding buffer character and byte positions. */
static void
-scan_for_column (ptrdiff_t *endpos, EMACS_INT *goalcol, ptrdiff_t *prevcol)
+scan_for_column (ptrdiff_t *endpos, EMACS_INT *goalcol,
+ ptrdiff_t *prevpos, ptrdiff_t *prevbpos, ptrdiff_t *prevcol)
{
int tab_width = SANE_TAB_WIDTH (current_buffer);
bool ctl_arrow = !NILP (BVAR (current_buffer, ctl_arrow));
@@ -540,14 +561,59 @@ scan_for_column (ptrdiff_t *endpos, EMACS_INT *goalcol, ptrdiff_t *prevcol)
register ptrdiff_t col = 0, prev_col = 0;
EMACS_INT goal = goalcol ? *goalcol : MOST_POSITIVE_FIXNUM;
ptrdiff_t end = endpos ? *endpos : PT;
- ptrdiff_t scan, scan_byte, next_boundary;
+ ptrdiff_t scan, scan_byte, next_boundary, prev_pos, prev_bpos;
scan = find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, NULL, &scan_byte, 1);
- next_boundary = scan;
window = Fget_buffer_window (Fcurrent_buffer (), Qnil);
w = ! NILP (window) ? XWINDOW (window) : NULL;
+ if (current_buffer->long_line_optimizations_p)
+ {
+ bool lines_truncated = false;
+
+ if (!NILP (BVAR (current_buffer, truncate_lines)))
+ lines_truncated = true;
+ else if (!NILP (Vtruncate_partial_width_windows) && w
+ && w->total_cols < FRAME_COLS (XFRAME (WINDOW_FRAME (w))))
+ {
+ if (FIXNUMP (Vtruncate_partial_width_windows))
+ lines_truncated =
+ w->total_cols < XFIXNAT (Vtruncate_partial_width_windows);
+ else
+ lines_truncated = true;
+ }
+ /* Special optimization for buffers with long and truncated
+ lines: assumes that each character is a single column. */
+ if (lines_truncated)
+ {
+ ptrdiff_t bolpos = scan;
+ /* The newline which ends this line or ZV. */
+ ptrdiff_t eolpos =
+ find_newline (PT, PT_BYTE, ZV, ZV_BYTE, 1, NULL, NULL, 1);
+
+ scan = bolpos + goal;
+ if (scan > end)
+ scan = end;
+ if (scan > eolpos)
+ scan = (eolpos == ZV ? ZV : eolpos - 1);
+ col = scan - bolpos;
+ if (col > large_hscroll_threshold)
+ {
+ prev_col = col - 1;
+ prev_pos = scan - 1;
+ prev_bpos = CHAR_TO_BYTE (scan);
+ goto endloop;
+ }
+ /* Restore the values we've overwritten above. */
+ scan = bolpos;
+ col = 0;
+ }
+ }
+ next_boundary = scan;
+ prev_pos = scan;
+ prev_bpos = scan_byte;
+
memset (&cmp_it, 0, sizeof cmp_it);
cmp_it.id = -1;
composition_compute_stop_pos (&cmp_it, scan, scan_byte, end, Qnil);
@@ -576,6 +642,8 @@ scan_for_column (ptrdiff_t *endpos, EMACS_INT *goalcol, ptrdiff_t *prevcol)
if (col >= goal)
break;
prev_col = col;
+ prev_pos = scan;
+ prev_bpos = scan_byte;
{ /* Check display property. */
ptrdiff_t endp;
@@ -596,7 +664,7 @@ scan_for_column (ptrdiff_t *endpos, EMACS_INT *goalcol, ptrdiff_t *prevcol)
if (cmp_it.id >= 0
|| (scan == cmp_it.stop_pos
&& composition_reseat_it (&cmp_it, scan, scan_byte, end,
- w, NULL, Qnil)))
+ w, -1, NULL, Qnil)))
composition_update_it (&cmp_it, scan, scan_byte, Qnil);
if (cmp_it.id >= 0)
{
@@ -705,6 +773,10 @@ scan_for_column (ptrdiff_t *endpos, EMACS_INT *goalcol, ptrdiff_t *prevcol)
*goalcol = col;
if (endpos)
*endpos = scan;
+ if (prevpos)
+ *prevpos = prev_pos;
+ if (prevbpos)
+ *prevbpos = prev_bpos;
if (prevcol)
*prevcol = prev_col;
}
@@ -720,7 +792,7 @@ current_column_1 (void)
EMACS_INT col = MOST_POSITIVE_FIXNUM;
ptrdiff_t opoint = PT;
- scan_for_column (&opoint, &col, NULL);
+ scan_for_column (&opoint, &col, NULL, NULL, NULL);
return col;
}
@@ -748,16 +820,16 @@ string_display_width (Lisp_Object string, Lisp_Object beg, Lisp_Object end)
e = SCHARS (string);
else
{
- CHECK_NUMBER (end);
- e = XINT (end);
+ CHECK_FIXNUM (end);
+ e = XFIXNUM (end);
}
if (NILP (beg))
b = 0;
else
{
- CHECK_NUMBER (beg);
- b = XINT (beg);
+ CHECK_FIXNUM (beg);
+ b = XFIXNUM (beg);
}
/* Make a pointer for decrementing through the chars before point. */
@@ -810,39 +882,39 @@ DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "NIndent to column: ",
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. */)
+The return value is the column where the insertion ends. */)
(Lisp_Object column, Lisp_Object minimum)
{
EMACS_INT mincol;
register ptrdiff_t fromcol;
int tab_width = SANE_TAB_WIDTH (current_buffer);
- CHECK_NUMBER (column);
+ CHECK_FIXNUM (column);
if (NILP (minimum))
XSETFASTINT (minimum, 0);
- CHECK_NUMBER (minimum);
+ CHECK_FIXNUM (minimum);
fromcol = current_column ();
- mincol = fromcol + XINT (minimum);
- if (mincol < XINT (column)) mincol = XINT (column);
+ mincol = fromcol + XFIXNUM (minimum);
+ if (mincol < XFIXNUM (column)) mincol = XFIXNUM (column);
if (fromcol == mincol)
- return make_number (mincol);
+ return make_fixnum (mincol);
if (indent_tabs_mode)
{
Lisp_Object n;
XSETFASTINT (n, mincol / tab_width - fromcol / tab_width);
- if (XFASTINT (n) != 0)
+ if (XFIXNAT (n) != 0)
{
- Finsert_char (make_number ('\t'), n, Qt);
+ Finsert_char (make_fixnum ('\t'), n, Qt);
fromcol = (mincol / tab_width) * tab_width;
}
}
XSETFASTINT (column, mincol - fromcol);
- Finsert_char (make_number (' '), column, Qt);
+ Finsert_char (make_fixnum (' '), column, Qt);
last_known_column = mincol;
last_known_column_point = PT;
@@ -856,14 +928,16 @@ The return value is COLUMN. */)
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. */)
+This is the horizontal position of the character following any initial
+whitespace.
+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)
{
ptrdiff_t posbyte;
find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, NULL, &posbyte, 1);
- return make_number (position_indentation (posbyte));
+ return make_fixnum (position_indentation (posbyte));
}
static ptrdiff_t
@@ -940,7 +1014,7 @@ position_indentation (ptrdiff_t pos_byte)
if (CHAR_HAS_CATEGORY (c, ' '))
{
column++;
- INC_POS (pos_byte);
+ pos_byte += next_char_len (pos_byte);
p = BYTE_POS_ADDR (pos_byte);
}
else
@@ -959,7 +1033,7 @@ indented_beyond_p (ptrdiff_t pos, ptrdiff_t pos_byte, EMACS_INT column)
{
while (pos > BEGV && FETCH_BYTE (pos_byte) == '\n')
{
- DEC_BOTH (pos, pos_byte);
+ dec_both (&pos, &pos_byte);
pos = find_newline (pos, pos_byte, BEGV, BEGV_BYTE,
-1, NULL, &pos_byte, 0);
}
@@ -975,28 +1049,32 @@ 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.
+Text that has an invisible property is considered as having width 0,
+unless `buffer-invisibility-spec' specifies that it is replaced by
+an ellipsis.
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.
Optional second argument FORCE non-nil 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, add spaces/tabs to get there.
+middle of a tab character, either change it to spaces (when
+`indent-tabs-mode' is nil), or insert enough spaces before it to reach
+COLUMN (otherwise). 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. */)
(Lisp_Object column, Lisp_Object force)
{
- ptrdiff_t pos, prev_col;
+ ptrdiff_t pos, prev_pos, prev_bpos, prev_col;
EMACS_INT col;
EMACS_INT goal;
- CHECK_NATNUM (column);
- goal = XINT (column);
+ CHECK_FIXNAT (column);
+ goal = XFIXNUM (column);
col = goal;
pos = ZV;
- scan_for_column (&pos, &col, &prev_col);
+ scan_for_column (&pos, &col, &prev_pos, &prev_bpos, &prev_col);
SET_PT (pos);
@@ -1005,25 +1083,23 @@ The return value is the current column. */)
if (!NILP (force) && col > goal)
{
int c;
- ptrdiff_t pos_byte = PT_BYTE;
- DEC_POS (pos_byte);
- c = FETCH_CHAR (pos_byte);
- if (c == '\t' && prev_col < goal)
+ c = FETCH_CHAR (prev_bpos);
+ if (c == '\t' && prev_col < goal && prev_bpos < PT_BYTE)
{
ptrdiff_t 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);
+ SET_PT_BOTH (prev_pos, prev_bpos);
+ Finsert_char (make_fixnum (' '), make_fixnum (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);
+ Findent_to (make_fixnum (col), Qnil);
SET_PT_BOTH (goal_pt, goal_pt_byte);
/* Set the last_known... vars consistently. */
@@ -1033,13 +1109,13 @@ The return value is the current column. */)
/* If line ends prematurely, add space to the end. */
if (col < goal && EQ (force, Qt))
- Findent_to (make_number (col = goal), Qnil);
+ Findent_to (make_fixnum (col = goal), Qnil);
last_known_column = col;
last_known_column_point = PT;
last_known_column_modified = MODIFF;
- return make_number (col);
+ return make_fixnum (col);
}
/* compute_motion: compute buffer posn given screen posn and vice versa */
@@ -1125,8 +1201,8 @@ compute_motion (ptrdiff_t from, ptrdiff_t frombyte, EMACS_INT fromvpos,
bool ctl_arrow = !NILP (BVAR (current_buffer, ctl_arrow));
struct Lisp_Char_Table *dp = window_display_table (win);
EMACS_INT selective
- = (INTEGERP (BVAR (current_buffer, selective_display))
- ? XINT (BVAR (current_buffer, selective_display))
+ = (FIXNUMP (BVAR (current_buffer, selective_display))
+ ? XFIXNUM (BVAR (current_buffer, selective_display))
: !NILP (BVAR (current_buffer, selective_display)) ? -1 : 0);
ptrdiff_t selective_rlen
= (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp))
@@ -1184,7 +1260,7 @@ compute_motion (ptrdiff_t from, ptrdiff_t frombyte, EMACS_INT fromvpos,
/* Negative width means use all available text columns. */
if (width < 0)
{
- width = window_body_width (win, 0);
+ width = window_body_width (win, WINDOW_BODY_IN_CANONICAL_CHARS);
/* We must make room for continuation marks if we don't have fringes. */
#ifdef HAVE_WINDOW_SYSTEM
if (!FRAME_WINDOW_P (XFRAME (win->frame)))
@@ -1306,7 +1382,7 @@ compute_motion (ptrdiff_t from, ptrdiff_t frombyte, EMACS_INT fromvpos,
j ^---- next after the point
^--- next char. after the point.
----------
- In case of sigle-column character
+ In case of single-column character
----------
abcdefgh\\
@@ -1335,9 +1411,9 @@ compute_motion (ptrdiff_t from, ptrdiff_t frombyte, EMACS_INT fromvpos,
if (!NILP (Vtruncate_partial_width_windows)
&& (total_width < FRAME_COLS (XFRAME (WINDOW_FRAME (win)))))
{
- if (INTEGERP (Vtruncate_partial_width_windows))
+ if (FIXNUMP (Vtruncate_partial_width_windows))
truncate
- = total_width < XFASTINT (Vtruncate_partial_width_windows);
+ = total_width < XFIXNAT (Vtruncate_partial_width_windows);
else
truncate = 1;
}
@@ -1503,7 +1579,7 @@ compute_motion (ptrdiff_t from, ptrdiff_t frombyte, EMACS_INT fromvpos,
if (cmp_it.id >= 0
|| (pos == cmp_it.stop_pos
&& composition_reseat_it (&cmp_it, pos, pos_byte, to, win,
- NULL, Qnil)))
+ -1, NULL, Qnil)))
composition_update_it (&cmp_it, pos, pos_byte, Qnil);
if (cmp_it.id >= 0)
{
@@ -1530,7 +1606,7 @@ compute_motion (ptrdiff_t from, ptrdiff_t frombyte, EMACS_INT fromvpos,
/* Is this character part of the current run? If so, extend
the run. */
if (pos - 1 == width_run_end
- && XFASTINT (width_table[c]) == width_run_width)
+ && XFIXNAT (width_table[c]) == width_run_width)
width_run_end = pos;
/* The previous run is over, since this is a character at a
@@ -1545,7 +1621,7 @@ compute_motion (ptrdiff_t from, ptrdiff_t frombyte, EMACS_INT fromvpos,
width_run_start, width_run_end);
/* Start recording a new width run. */
- width_run_width = XFASTINT (width_table[c]);
+ width_run_width = XFIXNAT (width_table[c]);
width_run_start = pos - 1;
width_run_end = pos;
}
@@ -1602,7 +1678,7 @@ compute_motion (ptrdiff_t from, ptrdiff_t frombyte, EMACS_INT fromvpos,
{
pos = find_before_next_newline (pos, to, 1, &pos_byte);
if (pos < to)
- INC_BOTH (pos, pos_byte);
+ inc_both (&pos, &pos_byte);
rarely_quit (++quit_count);
}
while (pos < to
@@ -1615,7 +1691,7 @@ compute_motion (ptrdiff_t from, ptrdiff_t frombyte, EMACS_INT fromvpos,
if (hpos >= width)
hpos = width;
}
- DEC_BOTH (pos, pos_byte);
+ dec_both (&pos, &pos_byte);
/* We have skipped the invis text, but not the
newline after. */
}
@@ -1751,57 +1827,57 @@ visible section of the buffer, and pass LINE and COL as TOPOS. */)
ptrdiff_t hscroll;
int tab_offset;
- CHECK_NUMBER_COERCE_MARKER (from);
+ CHECK_FIXNUM_COERCE_MARKER (from);
CHECK_CONS (frompos);
- CHECK_NUMBER_CAR (frompos);
- CHECK_NUMBER_CDR (frompos);
- CHECK_NUMBER_COERCE_MARKER (to);
+ CHECK_FIXNUM (XCAR (frompos));
+ CHECK_FIXNUM (XCDR (frompos));
+ CHECK_FIXNUM_COERCE_MARKER (to);
if (!NILP (topos))
{
CHECK_CONS (topos);
- CHECK_NUMBER_CAR (topos);
- CHECK_NUMBER_CDR (topos);
+ CHECK_FIXNUM (XCAR (topos));
+ CHECK_FIXNUM (XCDR (topos));
}
if (!NILP (width))
- CHECK_NUMBER (width);
+ CHECK_FIXNUM (width);
if (!NILP (offsets))
{
CHECK_CONS (offsets);
- CHECK_NUMBER_CAR (offsets);
- CHECK_NUMBER_CDR (offsets);
- if (! (0 <= XINT (XCAR (offsets)) && XINT (XCAR (offsets)) <= PTRDIFF_MAX
- && 0 <= XINT (XCDR (offsets)) && XINT (XCDR (offsets)) <= INT_MAX))
+ CHECK_FIXNUM (XCAR (offsets));
+ CHECK_FIXNUM (XCDR (offsets));
+ if (! (0 <= XFIXNUM (XCAR (offsets)) && XFIXNUM (XCAR (offsets)) <= PTRDIFF_MAX
+ && 0 <= XFIXNUM (XCDR (offsets)) && XFIXNUM (XCDR (offsets)) <= INT_MAX))
args_out_of_range (XCAR (offsets), XCDR (offsets));
- hscroll = XINT (XCAR (offsets));
- tab_offset = XINT (XCDR (offsets));
+ hscroll = XFIXNUM (XCAR (offsets));
+ tab_offset = XFIXNUM (XCDR (offsets));
}
else
hscroll = tab_offset = 0;
w = decode_live_window (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));
+ if (XFIXNUM (from) < BEGV || XFIXNUM (from) > ZV)
+ args_out_of_range_3 (from, make_fixnum (BEGV), make_fixnum (ZV));
+ if (XFIXNUM (to) < BEGV || XFIXNUM (to) > ZV)
+ args_out_of_range_3 (to, make_fixnum (BEGV), make_fixnum (ZV));
- pos = compute_motion (XINT (from), CHAR_TO_BYTE (XINT (from)),
- XINT (XCDR (frompos)),
- XINT (XCAR (frompos)), 0,
- XINT (to),
+ pos = compute_motion (XFIXNUM (from), CHAR_TO_BYTE (XFIXNUM (from)),
+ XFIXNUM (XCDR (frompos)),
+ XFIXNUM (XCAR (frompos)), 0,
+ XFIXNUM (to),
(NILP (topos)
? window_internal_height (w)
- : XINT (XCDR (topos))),
+ : XFIXNUM (XCDR (topos))),
(NILP (topos)
- ? (window_body_width (w, 0)
+ ? (window_body_width (w, WINDOW_BODY_IN_CANONICAL_CHARS)
- (
#ifdef HAVE_WINDOW_SYSTEM
FRAME_WINDOW_P (XFRAME (w->frame)) ? 0 :
#endif
1))
- : XINT (XCAR (topos))),
- (NILP (width) ? -1 : XINT (width)),
+ : XFIXNUM (XCAR (topos))),
+ (NILP (width) ? -1 : XFIXNUM (width)),
hscroll, tab_offset, w);
XSETFASTINT (bufpos, pos->bufpos);
@@ -1817,8 +1893,8 @@ visible section of the buffer, and pass LINE and COL as TOPOS. */)
static struct position val_vmotion;
struct position *
-vmotion (register ptrdiff_t from, register ptrdiff_t from_byte,
- register EMACS_INT vtarget, struct window *w)
+vmotion (ptrdiff_t from, ptrdiff_t from_byte,
+ EMACS_INT vtarget, struct window *w)
{
ptrdiff_t hscroll = w->hscroll;
struct position pos;
@@ -1828,8 +1904,8 @@ vmotion (register ptrdiff_t from, register ptrdiff_t from_byte,
register ptrdiff_t first;
ptrdiff_t lmargin = hscroll > 0 ? 1 - hscroll : 0;
ptrdiff_t selective
- = (INTEGERP (BVAR (current_buffer, selective_display))
- ? clip_to_bounds (-1, XINT (BVAR (current_buffer, selective_display)),
+ = (FIXNUMP (BVAR (current_buffer, selective_display))
+ ? clip_to_bounds (-1, XFIXNUM (BVAR (current_buffer, selective_display)),
PTRDIFF_MAX)
: !NILP (BVAR (current_buffer, selective_display)) ? -1 : 0);
Lisp_Object window;
@@ -1841,7 +1917,7 @@ vmotion (register ptrdiff_t from, register ptrdiff_t from_byte,
/* If the window contains this buffer, use it for getting text properties.
Otherwise use the current buffer as arg for doing that. */
- if (EQ (w->contents, Fcurrent_buffer ()))
+ if (BASE_EQ (w->contents, Fcurrent_buffer ()))
text_prop_object = window;
else
text_prop_object = Fcurrent_buffer ();
@@ -1859,7 +1935,7 @@ vmotion (register ptrdiff_t from, register ptrdiff_t from_byte,
Lisp_Object propval;
prevline = from;
- DEC_BOTH (prevline, bytepos);
+ dec_both (&prevline, &bytepos);
prevline = find_newline_no_quit (prevline, bytepos, -1, &bytepos);
while (prevline > BEGV
@@ -1867,12 +1943,12 @@ vmotion (register ptrdiff_t from, register ptrdiff_t from_byte,
&& indented_beyond_p (prevline, bytepos, selective))
/* Watch out for newlines with `invisible' property.
When moving upward, check the newline before. */
- || (propval = Fget_char_property (make_number (prevline - 1),
+ || (propval = Fget_char_property (make_fixnum (prevline - 1),
Qinvisible,
text_prop_object),
TEXT_PROP_MEANS_INVISIBLE (propval))))
{
- DEC_BOTH (prevline, bytepos);
+ dec_both (&prevline, &bytepos);
prevline = find_newline_no_quit (prevline, bytepos, -1, &bytepos);
}
pos = *compute_motion (prevline, bytepos, 0, lmargin, 0, from,
@@ -1917,12 +1993,12 @@ vmotion (register ptrdiff_t from, register ptrdiff_t from_byte,
&& indented_beyond_p (prevline, bytepos, selective))
/* Watch out for newlines with `invisible' property.
When moving downward, check the newline after. */
- || (propval = Fget_char_property (make_number (prevline),
+ || (propval = Fget_char_property (make_fixnum (prevline),
Qinvisible,
text_prop_object),
TEXT_PROP_MEANS_INVISIBLE (propval))))
{
- DEC_BOTH (prevline, bytepos);
+ dec_both (&prevline, &bytepos);
prevline = find_newline_no_quit (prevline, bytepos, -1, &bytepos);
}
pos = *compute_motion (prevline, bytepos, 0, lmargin, 0, from,
@@ -1956,26 +2032,44 @@ line_number_display_width (struct window *w, int *width, int *pixel_width)
else
{
struct it it;
- struct text_pos wstart;
+ struct text_pos startpos;
bool saved_restriction = false;
- ptrdiff_t count = SPECPDL_INDEX ();
- SET_TEXT_POS_FROM_MARKER (wstart, w->start);
+ struct buffer *old_buf = current_buffer;
+ specpdl_ref count = SPECPDL_INDEX ();
+ SET_TEXT_POS_FROM_MARKER (startpos, w->start);
void *itdata = bidi_shelve_cache ();
- /* We must start from window's start point, but it could be
- outside the accessible region. */
- if (wstart.charpos < BEGV || wstart.charpos > ZV)
+
+ /* Make sure W's buffer is the current one. */
+ set_buffer_internal_1 (XBUFFER (w->contents));
+ /* We want to start from window's start point, but it could be
+ outside the accessible region, in which case we widen the
+ buffer temporarily. It could even be beyond the buffer's end
+ (Org mode's display of source code snippets is known to cause
+ that) or belong to the wrong buffer, in which cases we just
+ punt and start from point instead. */
+ if (startpos.charpos > Z
+ || !(BUFFERP (w->contents)
+ && XBUFFER (w->contents) == XMARKER (w->start)->buffer))
+ SET_TEXT_POS (startpos, PT, PT_BYTE);
+ if (startpos.charpos < BEGV || startpos.charpos > ZV)
{
record_unwind_protect (save_restriction_restore,
save_restriction_save ());
Fwiden ();
saved_restriction = true;
}
- start_display (&it, w, wstart);
+ start_display (&it, w, startpos);
+ /* The call to move_it_by_lines below will not generate a line
+ number if the first line shown in the window is hscrolled
+ such that all of its display elements are out of view. So we
+ pretend the hscroll doesn't exist. */
+ it.first_visible_x = 0;
move_it_by_lines (&it, 1);
*width = it.lnum_width;
*pixel_width = it.lnum_pixel_width;
if (saved_restriction)
unbind_to (count, Qnil);
+ set_buffer_internal_1 (old_buf);
bidi_unshelve_cache (itdata, 0);
}
}
@@ -1983,16 +2077,28 @@ line_number_display_width (struct window *w, int *width, int *pixel_width)
DEFUN ("line-number-display-width", Fline_number_display_width,
Sline_number_display_width, 0, 1, 0,
doc: /* Return the width used for displaying line numbers in the selected window.
-If optional argument PIXELWISE is non-nil, return the width in pixels,
-otherwise return the width in columns of the face used to display
-line numbers, `line-number'. */)
+If optional argument PIXELWISE is the symbol `columns', return the width
+in units of the frame's canonical character width. In this case, the
+value is a float.
+If optional argument PIXELWISE is t or any other non-nil value, return
+the width as an integer number of pixels.
+Otherwise return the value as an integer number of columns of the face
+used to display line numbers, `line-number'. Note that in the latter
+case, the value doesn't include the 2 columns used for padding the
+numbers on display. */)
(Lisp_Object pixelwise)
{
int width, pixel_width;
+ struct window *w = XWINDOW (selected_window);
line_number_display_width (XWINDOW (selected_window), &width, &pixel_width);
- if (!NILP (pixelwise))
- return make_number (pixel_width);
- return make_number (width);
+ if (EQ (pixelwise, Qcolumns))
+ {
+ struct frame *f = XFRAME (w->frame);
+ return make_float ((double) pixel_width / FRAME_COLUMN_WIDTH (f));
+ }
+ else if (!NILP (pixelwise))
+ return make_fixnum (pixel_width);
+ return make_fixnum (width);
}
/* In window W (derived from WINDOW), return x coordinate for column
@@ -2012,6 +2118,7 @@ window_column_x (struct window *w, Lisp_Object window,
/* Restore window's buffer and point. */
+/* FIXME: Merge with `with_echo_area_buffer_unwind_data`? */
static void
restore_window_buffer (Lisp_Object list)
{
@@ -2020,8 +2127,8 @@ restore_window_buffer (Lisp_Object list)
wset_buffer (w, XCAR (list));
list = XCDR (list);
set_marker_both (w->pointm, w->contents,
- XFASTINT (XCAR (list)),
- XFASTINT (XCAR (XCDR (list))));
+ XFIXNAT (XCAR (list)),
+ XFIXNAT (XCAR (XCDR (list))));
}
DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 3, 0,
@@ -2063,27 +2170,27 @@ whether or not it is currently displayed in some window. */)
struct it it;
struct text_pos pt;
struct window *w;
- Lisp_Object lcols;
+ Lisp_Object lcols = Qnil;
void *itdata = NULL;
- ptrdiff_t count = SPECPDL_INDEX ();
+ specpdl_ref count = SPECPDL_INDEX ();
/* Allow LINES to be of the form (HPOS . VPOS) aka (COLUMNS . LINES). */
- bool lcols_given = CONSP (lines);
- if (lcols_given)
+ if (CONSP (lines))
{
lcols = XCAR (lines);
+ CHECK_NUMBER (lcols);
lines = XCDR (lines);
}
- CHECK_NUMBER (lines);
+ CHECK_FIXNUM (lines);
w = decode_live_window (window);
if (XBUFFER (w->contents) != current_buffer)
{
/* Set the window's buffer temporarily to the current buffer. */
Lisp_Object old = list4 (window, w->contents,
- make_number (marker_position (w->pointm)),
- make_number (marker_byte_position (w->pointm)));
+ make_fixnum (marker_position (w->pointm)),
+ make_fixnum (marker_byte_position (w->pointm)));
record_unwind_protect (restore_window_buffer, old);
wset_buffer (w, Fcurrent_buffer ());
set_marker_both (w->pointm, w->contents,
@@ -2093,7 +2200,7 @@ whether or not it is currently displayed in some window. */)
if (noninteractive)
{
struct position pos;
- pos = *vmotion (PT, PT_BYTE, XINT (lines), w);
+ pos = *vmotion (PT, PT_BYTE, XFIXNUM (lines), w);
SET_PT_BOTH (pos.bufpos, pos.bytepos);
it.vpos = pos.vpos;
}
@@ -2103,7 +2210,7 @@ whether or not it is currently displayed in some window. */)
int first_x;
bool overshoot_handled = 0;
bool disp_string_at_start_p = 0;
- ptrdiff_t nlines = XINT (lines);
+ ptrdiff_t nlines = XFIXNUM (lines);
int vpos_init = 0;
double start_col UNINIT;
int start_x UNINIT;
@@ -2122,11 +2229,12 @@ whether or not it is currently displayed in some window. */)
will sometimes err by one column. */
int lnum_width = 0;
int lnum_pixel_width = 0;
- if (!NILP (Vdisplay_line_numbers)
- && !EQ (Vdisplay_line_numbers, Qvisual))
+ if (!NILP (Vdisplay_line_numbers))
line_number_display_width (w, &lnum_width, &lnum_pixel_width);
SET_TEXT_POS (pt, PT, PT_BYTE);
itdata = bidi_shelve_cache ();
+ record_unwind_protect_void (unwind_display_working_on_window);
+ display_working_on_window_p = true;
start_display (&it, w, pt);
it.lnum_width = lnum_width;
first_x = it.first_visible_x;
@@ -2159,7 +2267,10 @@ whether or not it is currently displayed in some window. */)
}
else
it_overshoot_count =
- !(it.method == GET_FROM_IMAGE || it.method == GET_FROM_STRETCH);
+ /* If image_id is negative, it's a fringe bitmap, which by
+ definition doesn't affect display in the text area. */
+ !((it.method == GET_FROM_IMAGE && it.image_id >= 0)
+ || it.method == GET_FROM_STRETCH);
if (start_x_given)
{
@@ -2252,15 +2363,17 @@ whether or not it is currently displayed in some window. */)
overshoot_handled = 1;
}
- if (lcols_given)
- to_x = window_column_x (w, window, extract_float (lcols), lcols);
+ if (!NILP (lcols))
+ to_x =
+ window_column_x (w, window, XFLOATINT (lcols), lcols)
+ + lnum_pixel_width;
if (nlines <= 0)
{
it.vpos = vpos_init;
it.current_y = 0;
/* Do this even if LINES is 0, so that we move back to the
beginning of the current line as we ought. */
- if ((nlines < 0 && IT_CHARPOS (it) > 0)
+ if ((nlines < 0 && IT_CHARPOS (it) > BEGV)
|| (nlines == 0 && !(start_x_given && start_x <= to_x)))
move_it_by_lines (&it, max (PTRDIFF_MIN, nlines));
}
@@ -2278,7 +2391,15 @@ whether or not it is currently displayed in some window. */)
last line that it occupies. */
if (it_start < ZV)
{
- while (IT_CHARPOS (it) <= it_start)
+ if ((it.bidi_it.scan_dir > 0)
+ ? IT_CHARPOS (it) < it_start
+ : IT_CHARPOS (it) > it_start)
+ {
+ it.vpos = 0;
+ it.current_y = 0;
+ move_it_by_lines (&it, 1);
+ }
+ while (IT_CHARPOS (it) == it_start)
{
it.vpos = 0;
it.current_y = 0;
@@ -2303,14 +2424,8 @@ whether or not it is currently displayed in some window. */)
/* Move to the goal column, if one was specified. If the window
was originally hscrolled, the goal column is interpreted as
an addition to the hscroll amount. */
- if (lcols_given)
+ if (!NILP (lcols))
{
- /* If we are displaying line numbers, we could cross the
- line where the width of the line-number display changes,
- in which case we need to fix up the pixel coordinate
- accordingly. */
- if (lnum_pixel_width > 0)
- to_x += it.lnum_pixel_width - lnum_pixel_width;
move_it_in_display_line (&it, ZV, first_x + to_x, MOVE_TO_X);
/* If we find ourselves in the middle of an overlay string
which includes a newline after current string position,
@@ -2318,7 +2433,7 @@ whether or not it is currently displayed in some window. */)
and then reposition point at the requested X coordinate;
if we don't, the cursor will be placed just after the
string, which might not be the requested column. */
- if (nlines > 0 && it.area == TEXT_AREA)
+ if (nlines >= 0 && it.area == TEXT_AREA)
{
while (it.method == GET_FROM_STRING
&& !it.string_from_display_prop_p
@@ -2336,9 +2451,7 @@ whether or not it is currently displayed in some window. */)
bidi_unshelve_cache (itdata, 0);
}
- unbind_to (count, Qnil);
-
- return make_number (it.vpos);
+ return unbind_to (count, make_fixnum (it.vpos));
}
@@ -2352,6 +2465,8 @@ syms_of_indent (void)
doc: /* Indentation can insert tabs if this is non-nil. */);
indent_tabs_mode = 1;
+ DEFSYM (Qcolumns, "columns");
+
defsubr (&Scurrent_indentation);
defsubr (&Sindent_to);
defsubr (&Scurrent_column);