From ac268e6786fbbb4eeb5b069b462bfb9c29272c67 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 13 May 2012 18:35:13 +0300 Subject: [PATCH] Fix bug #11417 with infloop when left-fringe/right-fringe spec is used on TTY. src/xdisp.c (handle_stop): Don't call get_overlay_strings_1 if we already have overlays loaded. (handle_single_display_spec): Before returning without displaying fringe bitmap, synchronize the bidi iterator with the main display iterator, by calling iterate_out_of_display_property. (iterate_out_of_display_property): Detect buffer iteration by testing that it->string is a Lisp string. (get_next_display_element): When the current object is exhausted, and there's something on it->stack, call set_iterator_to_next to proceed with what's on the stack, instead of returning zero. (set_iterator_to_next): If called at the end of a Lisp string, proceed to consider_string_end without incrementing string position. Don't increment display vector index past the end of the display vector. --- src/ChangeLog | 17 +++++++++++++ src/xdisp.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 81 insertions(+), 5 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 9245e81a53..7352d8e008 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,20 @@ +2012-05-13 Eli Zaretskii + + * xdisp.c (handle_stop): Don't call get_overlay_strings_1 if we + already have overlays loaded. + (handle_single_display_spec): Before returning without displaying + fringe bitmap, synchronize the bidi iterator with the main display + iterator, by calling iterate_out_of_display_property. + (iterate_out_of_display_property): Detect buffer iteration by + testing that it->string is a Lisp string. + (get_next_display_element): When the current object is exhausted, + and there's something on it->stack, call set_iterator_to_next to + proceed with what's on the stack, instead of returning zero. + (set_iterator_to_next): If called at the end of a Lisp string, + proceed to consider_string_end without incrementing string + position. Don't increment display vector index past the end of + the display vector. (Bug#11417) + 2012-05-11 Eli Zaretskii * xdisp.c (handle_single_display_spec): Return 1 for left-margin diff --git a/src/xdisp.c b/src/xdisp.c index fd26853e09..b1e2a925bc 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -839,6 +839,7 @@ static int try_cursor_movement (Lisp_Object, struct text_pos, int *); static int trailing_whitespace_p (EMACS_INT); static intmax_t message_log_check_duplicate (EMACS_INT, EMACS_INT); static void push_it (struct it *, struct text_pos *); +static void iterate_out_of_display_property (struct it *); static void pop_it (struct it *); static void sync_frame_with_window_matrix_rows (struct window *); static void select_frame_for_redisplay (Lisp_Object); @@ -3125,7 +3126,15 @@ handle_stop (struct it *it) overlays even if the actual buffer text is replaced. */ if (!handle_overlay_change_p || it->sp > 1 - || !get_overlay_strings_1 (it, 0, 0)) + /* Don't call get_overlay_strings_1 if we already + have overlay strings loaded, because doing so + will load them again and push the iterator state + onto the stack one more time, which is not + expected by the rest of the code that processes + overlay strings. */ + || (it->n_overlay_strings <= 0 + ? !get_overlay_strings_1 (it, 0, 0) + : 0)) { if (it->ellipsis_p) setup_for_ellipsis (it, 0); @@ -4681,7 +4690,19 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, if (!FRAME_WINDOW_P (it->f)) /* If we return here, POSITION has been advanced across the text with this property. */ - return 1; + { + /* Synchronize the bidi iterator with POSITION. This is + needed because we are not going to push the iterator + on behalf of this display property, so there will be + no pop_it call to do this synchronization for us. */ + if (it->bidi_p) + { + it->position = *position; + iterate_out_of_display_property (it); + *position = it->position; + } + return 1; + } } else if (!frame_window_p) return 1; @@ -4692,7 +4713,15 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, || !(fringe_bitmap = lookup_fringe_bitmap (value))) /* If we return here, POSITION has been advanced across the text with this property. */ - return 1; + { + if (it && it->bidi_p) + { + it->position = *position; + iterate_out_of_display_property (it); + *position = it->position; + } + return 1; + } if (it) { @@ -5611,7 +5640,7 @@ push_it (struct it *it, struct text_pos *position) static void iterate_out_of_display_property (struct it *it) { - int buffer_p = BUFFERP (it->object); + int buffer_p = !STRINGP (it->string); EMACS_INT eob = (buffer_p ? ZV : it->end_charpos); EMACS_INT bob = (buffer_p ? BEGV : 0); @@ -6780,6 +6809,16 @@ get_next_display_element (struct it *it) && FACE_FROM_ID (it->f, face_id)->box == FACE_NO_BOX); } } + /* If we reached the end of the object we've been iterating (e.g., a + display string or an overlay string), and there's something on + IT->stack, proceed with what's on the stack. It doesn't make + sense to return zero if there's unprocessed stuff on the stack, + because otherwise that stuff will never be displayed. */ + if (!success_p && it->sp > 0) + { + set_iterator_to_next (it, 0); + success_p = get_next_display_element (it); + } /* Value is 0 if end of buffer or string reached. */ return success_p; @@ -6961,7 +7000,7 @@ set_iterator_to_next (struct it *it, int reseat_p) display vector entry (these entries may contain faces). */ it->face_id = it->saved_face_id; - if (it->dpvec + it->current.dpvec_index == it->dpend) + if (it->dpvec + it->current.dpvec_index >= it->dpend) { int recheck_faces = it->ellipsis_p; @@ -6999,6 +7038,26 @@ set_iterator_to_next (struct it *it, int reseat_p) case GET_FROM_STRING: /* Current display element is a character from a Lisp string. */ xassert (it->s == NULL && STRINGP (it->string)); + /* Don't advance past string end. These conditions are true + when set_iterator_to_next is called at the end of + get_next_display_element, in which case the Lisp string is + already exhausted, and all we want is pop the iterator + stack. */ + if (it->current.overlay_string_index >= 0) + { + /* This is an overlay string, so there's no padding with + spaces, and the number of characters in the string is + where the string ends. */ + if (IT_STRING_CHARPOS (*it) >= SCHARS (it->string)) + goto consider_string_end; + } + else + { + /* Not an overlay string. There could be padding, so test + against it->end_charpos . */ + if (IT_STRING_CHARPOS (*it) >= it->end_charpos) + goto consider_string_end; + } if (it->cmp_it.id >= 0) { int i; -- 2.20.1