summaryrefslogtreecommitdiff
path: root/src/xdisp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xdisp.c')
-rw-r--r--src/xdisp.c111
1 files changed, 52 insertions, 59 deletions
diff --git a/src/xdisp.c b/src/xdisp.c
index 84c75bd91d9..fa4b3c4f9ab 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -899,7 +899,7 @@ static void init_to_row_start (struct it *, struct window *,
static int init_to_row_end (struct it *, struct window *,
struct glyph_row *);
static void back_to_previous_line_start (struct it *);
-static int forward_to_next_line_start (struct it *, int *);
+static int forward_to_next_line_start (struct it *, int *, struct bidi_it *);
static struct text_pos string_pos_nchars_ahead (struct text_pos,
Lisp_Object, EMACS_INT);
static struct text_pos string_pos (EMACS_INT, Lisp_Object);
@@ -3134,13 +3134,10 @@ next_overlay_change (EMACS_INT pos)
return endpos;
}
-/* Record one cached display string position found recently by
- compute_display_string_pos. */
-static EMACS_INT cached_disp_pos;
-static EMACS_INT cached_prev_pos = -1;
-static struct buffer *cached_disp_buffer;
-static int cached_disp_modiff;
-static int cached_disp_overlay_modiff;
+/* How many characters forward to search for a display property or
+ display string. Enough for a screenful of 100 lines x 50
+ characters in a line. */
+#define MAX_DISP_SCAN 5000
/* Return the character position of a display string at or after
position specified by POSITION. If no display string exists at or
@@ -3152,57 +3149,33 @@ static int cached_disp_overlay_modiff;
on a GUI frame. */
EMACS_INT
compute_display_string_pos (struct text_pos *position,
- struct bidi_string_data *string, int frame_window_p)
+ struct bidi_string_data *string,
+ int frame_window_p, int *disp_prop_p)
{
/* OBJECT = nil means current buffer. */
Lisp_Object object =
(string && STRINGP (string->lstring)) ? string->lstring : Qnil;
- Lisp_Object pos, spec;
+ Lisp_Object pos, spec, limpos;
int string_p = (string && (STRINGP (string->lstring) || string->s));
EMACS_INT eob = string_p ? string->schars : ZV;
EMACS_INT begb = string_p ? 0 : BEGV;
EMACS_INT bufpos, charpos = CHARPOS (*position);
+ EMACS_INT lim =
+ (charpos < eob - MAX_DISP_SCAN) ? charpos + MAX_DISP_SCAN : eob;
struct text_pos tpos;
struct buffer *b;
+ *disp_prop_p = 1;
+
if (charpos >= eob
/* We don't support display properties whose values are strings
that have display string properties. */
|| string->from_disp_str
/* C strings cannot have display properties. */
|| (string->s && !STRINGP (object)))
- return eob;
-
- /* Check the cached values. */
- if (!STRINGP (object))
{
- if (NILP (object))
- b = current_buffer;
- else
- b = XBUFFER (object);
- if (b == cached_disp_buffer
- && BUF_MODIFF (b) == cached_disp_modiff
- && BUF_OVERLAY_MODIFF (b) == cached_disp_overlay_modiff
- && !b->clip_changed)
- {
- if (cached_prev_pos >= 0
- && cached_prev_pos < charpos && charpos <= cached_disp_pos)
- return cached_disp_pos;
- /* Handle overstepping either end of the known interval. */
- if (charpos > cached_disp_pos)
- cached_prev_pos = cached_disp_pos;
- else /* charpos <= cached_prev_pos */
- cached_prev_pos = max (charpos - 1, 0);
- }
-
- /* Record new values in the cache. */
- if (b != cached_disp_buffer)
- {
- cached_disp_buffer = b;
- cached_prev_pos = max (charpos - 1, 0);
- }
- cached_disp_modiff = BUF_MODIFF (b);
- cached_disp_overlay_modiff = BUF_OVERLAY_MODIFF (b);
+ *disp_prop_p = 0;
+ return eob;
}
/* If the character at CHARPOS is where the display string begins,
@@ -3221,22 +3194,24 @@ compute_display_string_pos (struct text_pos *position,
&& handle_display_spec (NULL, spec, object, Qnil, &tpos, bufpos,
frame_window_p))
{
- if (!STRINGP (object))
- cached_disp_pos = charpos;
return charpos;
}
/* Look forward for the first character with a `display' property
that will replace the underlying text when displayed. */
+ limpos = make_number (lim);
do {
- pos = Fnext_single_char_property_change (pos, Qdisplay, object, Qnil);
+ pos = Fnext_single_char_property_change (pos, Qdisplay, object, limpos);
CHARPOS (tpos) = XFASTINT (pos);
+ if (CHARPOS (tpos) >= lim)
+ {
+ *disp_prop_p = 0;
+ break;
+ }
if (STRINGP (object))
BYTEPOS (tpos) = string_char_to_byte (object, CHARPOS (tpos));
else
BYTEPOS (tpos) = CHAR_TO_BYTE (CHARPOS (tpos));
- if (CHARPOS (tpos) >= eob)
- break;
spec = Fget_char_property (pos, Qdisplay, object);
if (!STRINGP (object))
bufpos = CHARPOS (tpos);
@@ -3244,8 +3219,6 @@ compute_display_string_pos (struct text_pos *position,
|| !handle_display_spec (NULL, spec, object, Qnil, &tpos, bufpos,
frame_window_p));
- if (!STRINGP (object))
- cached_disp_pos = CHARPOS (tpos);
return CHARPOS (tpos);
}
@@ -5494,6 +5467,9 @@ back_to_previous_line_start (struct it *it)
continuously over the text). Otherwise, don't change the value
of *SKIPPED_P.
+ If BIDI_IT_PREV is non-NULL, store into it the state of the bidi
+ iterator on the newline, if it was found.
+
Newlines may come from buffer text, overlay strings, or strings
displayed via the `display' property. That's the reason we can't
simply use find_next_newline_no_quit.
@@ -5506,7 +5482,8 @@ back_to_previous_line_start (struct it *it)
leads to wrong cursor motion. */
static int
-forward_to_next_line_start (struct it *it, int *skipped_p)
+forward_to_next_line_start (struct it *it, int *skipped_p,
+ struct bidi_it *bidi_it_prev)
{
EMACS_INT old_selective;
int newline_found_p, n;
@@ -5518,6 +5495,8 @@ forward_to_next_line_start (struct it *it, int *skipped_p)
&& it->c == '\n'
&& CHARPOS (it->position) == IT_CHARPOS (*it))
{
+ if (it->bidi_p && bidi_it_prev)
+ *bidi_it_prev = it->bidi_it;
set_iterator_to_next (it, 0);
it->c = 0;
return 1;
@@ -5539,6 +5518,8 @@ forward_to_next_line_start (struct it *it, int *skipped_p)
if (!get_next_display_element (it))
return 0;
newline_found_p = it->what == IT_CHARACTER && it->c == '\n';
+ if (newline_found_p && it->bidi_p && bidi_it_prev)
+ *bidi_it_prev = it->bidi_it;
set_iterator_to_next (it, 0);
}
@@ -5573,6 +5554,8 @@ forward_to_next_line_start (struct it *it, int *skipped_p)
&& !newline_found_p)
{
newline_found_p = ITERATOR_AT_END_OF_LINE_P (it);
+ if (newline_found_p && it->bidi_p && bidi_it_prev)
+ *bidi_it_prev = it->bidi_it;
set_iterator_to_next (it, 0);
}
}
@@ -5696,8 +5679,9 @@ static void
reseat_at_next_visible_line_start (struct it *it, int on_newline_p)
{
int newline_found_p, skipped_p = 0;
+ struct bidi_it bidi_it_prev;
- newline_found_p = forward_to_next_line_start (it, &skipped_p);
+ newline_found_p = forward_to_next_line_start (it, &skipped_p, &bidi_it_prev);
/* Skip over lines that are invisible because they are indented
more than the value of IT->selective. */
@@ -5708,7 +5692,8 @@ reseat_at_next_visible_line_start (struct it *it, int on_newline_p)
{
xassert (IT_BYTEPOS (*it) == BEGV
|| FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n');
- newline_found_p = forward_to_next_line_start (it, &skipped_p);
+ newline_found_p =
+ forward_to_next_line_start (it, &skipped_p, &bidi_it_prev);
}
/* Position on the newline if that's what's requested. */
@@ -5724,11 +5709,14 @@ reseat_at_next_visible_line_start (struct it *it, int on_newline_p)
--IT_STRING_BYTEPOS (*it);
}
else
- /* Setting this flag will cause
- bidi_move_to_visually_next not to advance, but
- instead deliver the current character (newline),
- which is what the ON_NEWLINE_P flag wants. */
- it->bidi_it.first_elt = 1;
+ {
+ /* We need to restore the bidi iterator to the state
+ it had on the newline, and resync the IT's
+ position with that. */
+ it->bidi_it = bidi_it_prev;
+ IT_STRING_CHARPOS (*it) = it->bidi_it.charpos;
+ IT_STRING_BYTEPOS (*it) = it->bidi_it.bytepos;
+ }
}
}
else if (IT_CHARPOS (*it) > BEGV)
@@ -5738,9 +5726,14 @@ reseat_at_next_visible_line_start (struct it *it, int on_newline_p)
--IT_CHARPOS (*it);
--IT_BYTEPOS (*it);
}
- /* With bidi iteration, the call to `reseat' will cause
- bidi_move_to_visually_next deliver the current character,
- the newline, instead of advancing. */
+ else
+ {
+ /* We need to restore the bidi iterator to the state it
+ had on the newline and resync IT with that. */
+ it->bidi_it = bidi_it_prev;
+ IT_CHARPOS (*it) = it->bidi_it.charpos;
+ IT_BYTEPOS (*it) = it->bidi_it.bytepos;
+ }
reseat (it, it->current.pos, 0);
}
}