/* Holds the list (error). */
static Lisp_Object list_of_error;
-static Lisp_Object Qfontification_functions;
+Lisp_Object Qfontification_functions;
static Lisp_Object Qwrap_prefix;
static Lisp_Object Qline_prefix;
static void pop_it (struct it *);
static void sync_frame_with_window_matrix_rows (struct window *);
static void redisplay_internal (void);
-static int echo_area_display (int);
+static bool echo_area_display (bool);
static void redisplay_windows (Lisp_Object);
static void redisplay_window (Lisp_Object, bool);
static Lisp_Object redisplay_window_error (Lisp_Object);
struct text_pos top;
int visible_p = 0;
struct buffer *old_buffer = NULL;
+ bool r2l = false;
if (FRAME_INITIAL_P (XFRAME (WINDOW_FRAME (w))))
return visible_p;
*rowh = max (0, (min (bottom_y, it.last_visible_y)
- max (top_y, window_top_y)));
*vpos = it.vpos;
+ if (it.bidi_it.paragraph_dir == R2L)
+ r2l = true;
}
}
else
- max (it2.current_y,
WINDOW_HEADER_LINE_HEIGHT (w))));
*vpos = it2.vpos;
+ if (it2.bidi_it.paragraph_dir == R2L)
+ r2l = true;
}
else
bidi_unshelve_cache (it2data, 1);
if (old_buffer)
set_buffer_internal_1 (old_buffer);
- if (visible_p && w->hscroll > 0)
- *x -=
- window_hscroll_limited (w, WINDOW_XFRAME (w))
- * WINDOW_FRAME_COLUMN_WIDTH (w);
+ if (visible_p)
+ {
+ if (w->hscroll > 0)
+ *x -=
+ window_hscroll_limited (w, WINDOW_XFRAME (w))
+ * WINDOW_FRAME_COLUMN_WIDTH (w);
+ /* For lines in an R2L paragraph, we need to mirror the X pixel
+ coordinate wrt the text area. For the reasons, see the
+ commentary in buffer_posn_from_coords and the explanation of
+ the geometry used by the move_it_* functions at the end of
+ the large commentary near the beginning of this file. */
+ if (r2l)
+ *x = window_box_width (w, TEXT_AREA) - *x - 1;
+ }
#if 0
/* Debugging code. */
iterate_out_of_display_property (it);
*position = it->position;
}
+ /* If we were to display this fringe bitmap,
+ next_element_from_image would have reset this flag.
+ Do the same, to avoid affecting overlays that
+ follow. */
+ it->ignore_overlay_strings_at_pos_p = 0;
return 1;
}
}
iterate_out_of_display_property (it);
*position = it->position;
}
+ if (it)
+ /* Reset this flag like next_element_from_image would. */
+ it->ignore_overlay_strings_at_pos_p = 0;
return 1;
}
else if (it->cmp_it.id >= 0)
{
/* We are currently getting glyphs from a composition. */
- int i;
-
if (! it->bidi_p)
{
IT_CHARPOS (*it) += it->cmp_it.nchars;
IT_BYTEPOS (*it) += it->cmp_it.nbytes;
- if (it->cmp_it.to < it->cmp_it.nglyphs)
- {
- it->cmp_it.from = it->cmp_it.to;
- }
- else
- {
- it->cmp_it.id = -1;
- composition_compute_stop_pos (&it->cmp_it, IT_CHARPOS (*it),
- IT_BYTEPOS (*it),
- it->end_charpos, Qnil);
- }
}
- else if (! it->cmp_it.reversed_p)
+ else
{
- /* Composition created while scanning forward. */
+ int i;
+
/* Update IT's char/byte positions to point to the first
character of the next grapheme cluster, or to the
character visually after the current composition. */
bidi_move_to_visually_next (&it->bidi_it);
IT_BYTEPOS (*it) = it->bidi_it.bytepos;
IT_CHARPOS (*it) = it->bidi_it.charpos;
+ }
- if (it->cmp_it.to < it->cmp_it.nglyphs)
- {
- /* Proceed to the next grapheme cluster. */
- it->cmp_it.from = it->cmp_it.to;
- }
- else
- {
- /* No more grapheme clusters in this composition.
- Find the next stop position. */
- ptrdiff_t stop = it->end_charpos;
- if (it->bidi_it.scan_dir < 0)
- /* Now we are scanning backward and don't know
- where to stop. */
- stop = -1;
- composition_compute_stop_pos (&it->cmp_it, IT_CHARPOS (*it),
- IT_BYTEPOS (*it), stop, Qnil);
- }
+ if ((! it->bidi_p || ! it->cmp_it.reversed_p)
+ && it->cmp_it.to < it->cmp_it.nglyphs)
+ {
+ /* Composition created while scanning forward. Proceed
+ to the next grapheme cluster. */
+ it->cmp_it.from = it->cmp_it.to;
+ }
+ else if ((it->bidi_p && it->cmp_it.reversed_p)
+ && it->cmp_it.from > 0)
+ {
+ /* Composition created while scanning backward. Proceed
+ to the previous grapheme cluster. */
+ it->cmp_it.to = it->cmp_it.from;
}
else
{
- /* Composition created while scanning backward. */
- /* Update IT's char/byte positions to point to the last
- character of the previous grapheme cluster, or the
- character visually after the current composition. */
- for (i = 0; i < it->cmp_it.nchars; i++)
- bidi_move_to_visually_next (&it->bidi_it);
- IT_BYTEPOS (*it) = it->bidi_it.bytepos;
- IT_CHARPOS (*it) = it->bidi_it.charpos;
- if (it->cmp_it.from > 0)
- {
- /* Proceed to the previous grapheme cluster. */
- it->cmp_it.to = it->cmp_it.from;
- }
- else
- {
- /* No more grapheme clusters in this composition.
- Find the next stop position. */
- ptrdiff_t stop = it->end_charpos;
- if (it->bidi_it.scan_dir < 0)
- /* Now we are scanning backward and don't know
- where to stop. */
- stop = -1;
- composition_compute_stop_pos (&it->cmp_it, IT_CHARPOS (*it),
- IT_BYTEPOS (*it), stop, Qnil);
- }
+ /* No more grapheme clusters in this composition.
+ Find the next stop position. */
+ ptrdiff_t stop = it->end_charpos;
+
+ if (it->bidi_it.scan_dir < 0)
+ /* Now we are scanning backward and don't know
+ where to stop. */
+ stop = -1;
+ composition_compute_stop_pos (&it->cmp_it, IT_CHARPOS (*it),
+ IT_BYTEPOS (*it), stop, Qnil);
}
}
else
}
if (it->cmp_it.id >= 0)
{
- int i;
-
+ /* We are delivering display elements from a composition.
+ Update the string position past the grapheme cluster
+ we've just processed. */
if (! it->bidi_p)
{
IT_STRING_CHARPOS (*it) += it->cmp_it.nchars;
IT_STRING_BYTEPOS (*it) += it->cmp_it.nbytes;
- if (it->cmp_it.to < it->cmp_it.nglyphs)
- it->cmp_it.from = it->cmp_it.to;
- else
- {
- it->cmp_it.id = -1;
- composition_compute_stop_pos (&it->cmp_it,
- IT_STRING_CHARPOS (*it),
- IT_STRING_BYTEPOS (*it),
- it->end_charpos, it->string);
- }
}
- else if (! it->cmp_it.reversed_p)
+ else
{
+ int i;
+
for (i = 0; i < it->cmp_it.nchars; i++)
bidi_move_to_visually_next (&it->bidi_it);
IT_STRING_BYTEPOS (*it) = it->bidi_it.bytepos;
IT_STRING_CHARPOS (*it) = it->bidi_it.charpos;
+ }
- if (it->cmp_it.to < it->cmp_it.nglyphs)
- it->cmp_it.from = it->cmp_it.to;
- else
- {
- ptrdiff_t stop = it->end_charpos;
- if (it->bidi_it.scan_dir < 0)
- stop = -1;
- composition_compute_stop_pos (&it->cmp_it,
- IT_STRING_CHARPOS (*it),
- IT_STRING_BYTEPOS (*it), stop,
- it->string);
- }
+ /* Did we exhaust all the grapheme clusters of this
+ composition? */
+ if ((! it->bidi_p || ! it->cmp_it.reversed_p)
+ && (it->cmp_it.to < it->cmp_it.nglyphs))
+ {
+ /* Not all the grapheme clusters were processed yet;
+ advance to the next cluster. */
+ it->cmp_it.from = it->cmp_it.to;
+ }
+ else if ((it->bidi_p && it->cmp_it.reversed_p)
+ && it->cmp_it.from > 0)
+ {
+ /* Likewise: advance to the next cluster, but going in
+ the reverse direction. */
+ it->cmp_it.to = it->cmp_it.from;
}
else
{
- for (i = 0; i < it->cmp_it.nchars; i++)
- bidi_move_to_visually_next (&it->bidi_it);
- IT_STRING_BYTEPOS (*it) = it->bidi_it.bytepos;
- IT_STRING_CHARPOS (*it) = it->bidi_it.charpos;
- if (it->cmp_it.from > 0)
- it->cmp_it.to = it->cmp_it.from;
- else
+ /* This composition was fully processed; find the next
+ candidate place for checking for composed
+ characters. */
+ /* Always limit string searches to the string length;
+ any padding spaces are not part of the string, and
+ there cannot be any compositions in that padding. */
+ ptrdiff_t stop = SCHARS (it->string);
+
+ if (it->bidi_p && it->bidi_it.scan_dir < 0)
+ stop = -1;
+ else if (it->end_charpos < stop)
{
- ptrdiff_t stop = it->end_charpos;
- if (it->bidi_it.scan_dir < 0)
- stop = -1;
- composition_compute_stop_pos (&it->cmp_it,
- IT_STRING_CHARPOS (*it),
- IT_STRING_BYTEPOS (*it), stop,
- it->string);
+ /* Cf. PRECISION in reseat_to_string: we might be
+ limited in how many of the string characters we
+ need to deliver. */
+ stop = it->end_charpos;
}
+ composition_compute_stop_pos (&it->cmp_it,
+ IT_STRING_CHARPOS (*it),
+ IT_STRING_BYTEPOS (*it), stop,
+ it->string);
}
}
else
bidi_move_to_visually_next (&it->bidi_it);
IT_STRING_BYTEPOS (*it) = it->bidi_it.bytepos;
IT_STRING_CHARPOS (*it) = it->bidi_it.charpos;
+ /* If the scan direction changes, we may need to update
+ the place where to check for composed characters. */
if (prev_scan_dir != it->bidi_it.scan_dir)
{
- ptrdiff_t stop = it->end_charpos;
+ ptrdiff_t stop = SCHARS (it->string);
if (it->bidi_it.scan_dir < 0)
stop = -1;
+ else if (it->end_charpos < stop)
+ stop = it->end_charpos;
+
composition_compute_stop_pos (&it->cmp_it,
IT_STRING_CHARPOS (*it),
IT_STRING_BYTEPOS (*it), stop,
unsigned char *p;
ptrdiff_t stop;
+ /* We moved to the next buffer position, so any info about
+ previously seen overlays is no longer valid. */
+ it->ignore_overlay_strings_at_pos_p = 0;
+
/* Maybe run the redisplay end trigger hook. Performance note:
This doesn't seem to cost measurable time. */
if (it->redisplay_end_trigger_charpos
doesn't fit on the line, e.g. a wide image. */
it->hpos == 0
|| (new_x == it->last_visible_x
- && FRAME_WINDOW_P (it->f)
- /* When word-wrap is ON and we have a valid
- wrap point, we don't allow the last glyph
- to "just barely fit" on the line. */
- && (it->line_wrap != WORD_WRAP
- || wrap_it.sp < 0)))
+ && FRAME_WINDOW_P (it->f)))
{
++it->hpos;
it->current_x = new_x;
}
if (ITERATOR_AT_END_OF_LINE_P (it)
&& (it->line_wrap != WORD_WRAP
- || wrap_it.sp < 0))
+ || wrap_it.sp < 0
+ || IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)))
{
result = MOVE_NEWLINE_OR_CR;
break;
else
clear_message (true, true);
- do_pending_window_change (0);
- echo_area_display (1);
- do_pending_window_change (0);
+ do_pending_window_change (false);
+ echo_area_display (true);
+ do_pending_window_change (false);
if (FRAME_TERMINAL (f)->frame_up_to_date_hook)
(*FRAME_TERMINAL (f)->frame_up_to_date_hook) (f);
}
is non-zero update selected_frame. Value is non-zero if the
mini-windows height has been changed. */
-static int
-echo_area_display (int update_frame_p)
+static bool
+echo_area_display (bool update_frame_p)
{
Lisp_Object mini_window;
struct window *w;
struct frame *f;
- int window_height_changed_p = 0;
+ bool window_height_changed_p = false;
struct frame *sf = SELECTED_FRAME ();
mini_window = FRAME_MINIBUF_WINDOW (sf);
/* Window configuration is the same as before.
Can do with a display update of the echo area,
unless we displayed some mode lines. */
- update_single_window (w, 1);
+ update_single_window (w);
flush_frame (f);
}
else
- update_frame (f, 1, 1);
+ update_frame (f, true, true);
/* If cursor is in the echo area, make sure that the next
redisplay displays the minibuffer, so that the cursor will
menu_bar_hooks_run = update_menu_bar (f, 0, menu_bar_hooks_run);
#ifdef HAVE_WINDOW_SYSTEM
update_tool_bar (f, 0);
-#endif
-#ifdef HAVE_NS
- if (windows_or_buffers_changed
- && FRAME_NS_P (f))
- ns_set_doc_edited
- (f, Fbuffer_modified_p (XWINDOW (f->selected_window)->contents));
#endif
UNGCPRO;
}
struct window *w = XWINDOW (selected_window);
struct window *sw;
struct frame *fr;
- int pending;
+ bool pending;
bool must_finish = 0, match_p;
struct text_pos tlbufpos, tlendpos;
int number_of_visible_frames;
/* Remember the currently selected window. */
sw = w;
- pending = 0;
+ pending = false;
last_escape_glyph_frame = NULL;
last_escape_glyph_face_id = (1 << FACE_ID_BITS);
last_glyphless_glyph_frame = NULL;
}
/* Notice any pending interrupt request to change frame size. */
- do_pending_window_change (1);
+ do_pending_window_change (true);
/* do_pending_window_change could change the selected_window due to
frame resizing which makes the selected window too small. */
echo-area doesn't show through. */
&& !MINI_WINDOW_P (XWINDOW (selected_window))))
{
- int window_height_changed_p = echo_area_display (0);
+ int window_height_changed_p = echo_area_display (false);
if (message_cleared_p)
update_miniwindow_p = true;
{
if (!must_finish)
{
- do_pending_window_change (1);
+ do_pending_window_change (true);
/* If selected_window changed, redisplay again. */
if (WINDOWP (selected_window)
&& (w = XWINDOW (selected_window)) != sw)
if (f->fonts_changed)
{
adjust_frame_glyphs (f);
- f->fonts_changed = 0;
+ f->fonts_changed = false;
goto retry_frame;
}
/* See if we have to hscroll. */
if (!f->already_hscrolled_p)
{
- f->already_hscrolled_p = 1;
+ f->already_hscrolled_p = true;
if (hscroll_windows (f->root_window))
goto retry_frame;
}
unrequest_sigio ();
STOP_POLLING;
- pending |= update_frame (f, 0, 0);
- f->cursor_type_changed = 0;
- f->updated_p = 1;
+ pending |= update_frame (f, false, false);
+ f->cursor_type_changed = false;
+ f->updated_p = true;
}
}
}
goto retry;
XWINDOW (selected_window)->must_be_updated_p = true;
- pending = update_frame (sf, 0, 0);
- sf->cursor_type_changed = 0;
+ pending = update_frame (sf, false, false);
+ sf->cursor_type_changed = false;
}
/* We may have called echo_area_display at the top of this
if (mini_frame != sf && FRAME_WINDOW_P (mini_frame))
{
XWINDOW (mini_window)->must_be_updated_p = true;
- pending |= update_frame (mini_frame, 0, 0);
- mini_frame->cursor_type_changed = 0;
+ pending |= update_frame (mini_frame, false, false);
+ mini_frame->cursor_type_changed = false;
if (!pending && hscroll_windows (mini_window))
goto retry;
}
}
/* Change frame size now if a change is pending. */
- do_pending_window_change (1);
+ do_pending_window_change (true);
/* If we just did a pending size change, or have additional
visible frames, or selected_window changed, redisplay again. */
if (clear_face_cache_count > CLEAR_FACE_CACHE_COUNT)
{
- clear_face_cache (0);
+ clear_face_cache (false);
clear_face_cache_count = 0;
}
#endif /* HAVE_WINDOW_SYSTEM */
end_of_redisplay:
+#ifdef HAVE_NS
+ ns_set_doc_edited ();
+#endif
if (interrupt_input && interrupts_deferred)
request_sigio ();
{
/* We have a previously displayed message, but no current
message. Redisplay the previous message. */
- display_last_displayed_message_p = 1;
+ display_last_displayed_message_p = true;
redisplay_internal ();
- display_last_displayed_message_p = 0;
+ display_last_displayed_message_p = false;
}
else
redisplay_internal ();
non-zero margins, because scroll_up_aggressively
means put point that fraction of window height
_from_the_bottom_margin_. */
- if (aggressive_scroll + 2*this_scroll_margin > height)
- aggressive_scroll = height - 2*this_scroll_margin;
+ if (aggressive_scroll + 2 * this_scroll_margin > height)
+ aggressive_scroll = height - 2 * this_scroll_margin;
amount_to_scroll = dy + aggressive_scroll;
}
}
start_display (&it, w, startp);
if (arg_scroll_conservatively)
- amount_to_scroll = max (dy, frame_line_height *
- max (scroll_step, temp_scroll_step));
+ amount_to_scroll = max (dy, frame_line_height
+ * max (scroll_step, temp_scroll_step));
else if (scroll_step || temp_scroll_step)
amount_to_scroll = scroll_max;
else
bottom of the window, if the value of
scroll_down_aggressively happens to be too
large. */
- if (aggressive_scroll + 2*this_scroll_margin > height)
- aggressive_scroll = height - 2*this_scroll_margin;
+ if (aggressive_scroll + 2 * this_scroll_margin > height)
+ aggressive_scroll = height - 2 * this_scroll_margin;
amount_to_scroll = dy + aggressive_scroll;
}
}
{
int window_total_lines
= WINDOW_TOTAL_LINES (w) * FRAME_LINE_HEIGHT (f) / frame_line_height;
- int margin =
- scroll_margin > 0
+ int margin
+ = scroll_margin > 0
? min (scroll_margin, window_total_lines / 4)
: 0;
ptrdiff_t margin_pos = CHARPOS (startp);
doc: /* Dump the current matrix of the selected window to stderr.
Shows contents of glyph row structures. With non-nil
parameter GLYPHS, dump glyphs as well. If GLYPHS is 1 show
-glyphs in short form, otherwise show glyphs in long form. */)
+glyphs in short form, otherwise show glyphs in long form.
+
+Interactively, no argument means show glyphs in short form;
+with numeric argument, its value is passed as the GLYPHS flag. */)
(Lisp_Object glyphs)
{
struct window *w = XWINDOW (selected_window);
DEFUN ("dump-frame-glyph-matrix", Fdump_frame_glyph_matrix,
- Sdump_frame_glyph_matrix, 0, 0, "", doc: /* */)
+ Sdump_frame_glyph_matrix, 0, 0, "", doc: /* Dump the current glyph matrix of the selected frame to stderr.
+Only text-mode frames have frame glyph matrices. */)
(void)
{
struct frame *f = XFRAME (selected_frame);
- dump_glyph_matrix (f->current_matrix, 1);
+
+ if (f->current_matrix)
+ dump_glyph_matrix (f->current_matrix, 1);
+ else
+ fprintf (stderr, "*** This frame doesn't have a frame glyph matrix ***\n");
return Qnil;
}
{
/* If line-wrap is on, check if a previous
wrap point was found. */
- if (wrap_row_used > 0
+ if (!IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)
+ && wrap_row_used > 0
/* Even if there is a previous wrap
point, continue the line here as
usual, if (i) the previous character
row->continued_p = 0;
row->exact_window_width_line_p = 1;
}
+ /* If line-wrap is on, check if a
+ previous wrap point was found. */
+ else if (wrap_row_used > 0
+ /* Even if there is a previous wrap
+ point, continue the line here as
+ usual, if (i) the previous character
+ was a space or tab AND (ii) the
+ current character is not. */
+ && (!may_wrap
+ || IT_DISPLAYING_WHITESPACE (it)))
+ goto back_to_wrap;
+
}
}
else if (it->bidi_p)
}
}
+DEFUN ("bidi-find-overridden-directionality",
+ Fbidi_find_overridden_directionality,
+ Sbidi_find_overridden_directionality, 2, 3, 0,
+ doc: /* Return position between FROM and TO where directionality was overridden.
+
+This function returns the first character position in the specified
+region of OBJECT where there is a character whose `bidi-class' property
+is `L', but which was forced to display as `R' by a directional
+override, and likewise with characters whose `bidi-class' is `R'
+or `AL' that were forced to display as `L'.
+
+If no such character is found, the function returns nil.
+
+OBJECT is a Lisp string or buffer to search for overridden
+directionality, and defaults to the current buffer if nil or omitted.
+OBJECT can also be a window, in which case the function will search
+the buffer displayed in that window. Passing the window instead of
+a buffer is preferable when the buffer is displayed in some window,
+because this function will then be able to correctly account for
+window-specific overlays, which can affect the results.
+
+Strong directional characters `L', `R', and `AL' can have their
+intrinsic directionality overridden by directional override
+control characters RLO \(u+202e) and LRO \(u+202d). See the
+function `get-char-code-property' for a way to inquire about
+the `bidi-class' property of a character. */)
+ (Lisp_Object from, Lisp_Object to, Lisp_Object object)
+{
+ struct buffer *buf = current_buffer;
+ struct buffer *old = buf;
+ struct window *w = NULL;
+ bool frame_window_p = FRAME_WINDOW_P (SELECTED_FRAME ());
+ struct bidi_it itb;
+ ptrdiff_t from_pos, to_pos, from_bpos;
+ void *itb_data;
+
+ if (!NILP (object))
+ {
+ if (BUFFERP (object))
+ buf = XBUFFER (object);
+ else if (WINDOWP (object))
+ {
+ w = decode_live_window (object);
+ buf = XBUFFER (w->contents);
+ frame_window_p = FRAME_WINDOW_P (XFRAME (w->frame));
+ }
+ else
+ CHECK_STRING (object);
+ }
+
+ if (STRINGP (object))
+ {
+ /* Characters in unibyte strings are always treated by bidi.c as
+ strong LTR. */
+ if (!STRING_MULTIBYTE (object)
+ /* When we are loading loadup.el, the character property
+ tables needed for bidi iteration are not yet
+ available. */
+ || !NILP (Vpurify_flag))
+ return Qnil;
+
+ validate_subarray (object, from, to, SCHARS (object), &from_pos, &to_pos);
+ if (from_pos >= SCHARS (object))
+ return Qnil;
+
+ /* Set up the bidi iterator. */
+ itb_data = bidi_shelve_cache ();
+ itb.paragraph_dir = NEUTRAL_DIR;
+ itb.string.lstring = object;
+ itb.string.s = NULL;
+ itb.string.schars = SCHARS (object);
+ itb.string.bufpos = 0;
+ itb.string.from_disp_str = 0;
+ itb.string.unibyte = 0;
+ itb.w = w;
+ bidi_init_it (0, 0, frame_window_p, &itb);
+ }
+ else
+ {
+ /* Nothing this fancy can happen in unibyte buffers, or in a
+ buffer that disabled reordering, or if FROM is at EOB. */
+ if (NILP (BVAR (buf, bidi_display_reordering))
+ || NILP (BVAR (buf, enable_multibyte_characters))
+ /* When we are loading loadup.el, the character property
+ tables needed for bidi iteration are not yet
+ available. */
+ || !NILP (Vpurify_flag))
+ return Qnil;
+
+ set_buffer_temp (buf);
+ validate_region (&from, &to);
+ from_pos = XINT (from);
+ to_pos = XINT (to);
+ if (from_pos >= ZV)
+ return Qnil;
+
+ /* Set up the bidi iterator. */
+ itb_data = bidi_shelve_cache ();
+ from_bpos = CHAR_TO_BYTE (from_pos);
+ if (from_pos == BEGV)
+ {
+ itb.charpos = BEGV;
+ itb.bytepos = BEGV_BYTE;
+ }
+ else if (FETCH_CHAR (from_bpos - 1) == '\n')
+ {
+ itb.charpos = from_pos;
+ itb.bytepos = from_bpos;
+ }
+ else
+ itb.charpos = find_newline_no_quit (from_pos, CHAR_TO_BYTE (from_pos),
+ -1, &itb.bytepos);
+ itb.paragraph_dir = NEUTRAL_DIR;
+ itb.string.s = NULL;
+ itb.string.lstring = Qnil;
+ itb.string.bufpos = 0;
+ itb.string.from_disp_str = 0;
+ itb.string.unibyte = 0;
+ itb.w = w;
+ bidi_init_it (itb.charpos, itb.bytepos, frame_window_p, &itb);
+ }
+
+ ptrdiff_t found;
+ do {
+ /* For the purposes of this function, the actual base direction of
+ the paragraph doesn't matter, so just set it to L2R. */
+ bidi_paragraph_init (L2R, &itb, 0);
+ while ((found = bidi_find_first_overridden (&itb)) < from_pos)
+ ;
+ } while (found == ZV && itb.ch == '\n' && itb.charpos < to_pos);
+
+ bidi_unshelve_cache (itb_data, 0);
+ set_buffer_temp (old);
+
+ return (from_pos <= found && found < to_pos) ? make_number (found) : Qnil;
+}
+
DEFUN ("move-point-visually", Fmove_point_visually,
Smove_point_visually, 1, 1, 0,
doc: /* Move point in the visual order in the specified DIRECTION.
defsubr (&Scurrent_bidi_paragraph_direction);
defsubr (&Swindow_text_pixel_size);
defsubr (&Smove_point_visually);
+ defsubr (&Sbidi_find_overridden_directionality);
DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook");
DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map");
DEFVAR_LISP ("window-scroll-functions", Vwindow_scroll_functions,
doc: /* List of functions to call before redisplaying a window with scrolling.
Each function is called with two arguments, the window and its new
-display-start position. Note that these functions are also called by
-`set-window-buffer'. Also note that the value of `window-end' is not
-valid when these functions are called.
+display-start position.
+These functions are called whenever the `window-start' marker is modified,
+either to point into another buffer (e.g. via `set-window-buffer') or another
+place in the same buffer.
+Note that the value of `window-end' is not valid when these functions are
+called.
Warning: Do not use this feature to alter the way the window
is scrolled. It is not designed for that, and such use probably won't