emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] trunk r113221: Implement visual-order cursor motion.


From: Eli Zaretskii
Subject: [Emacs-diffs] trunk r113221: Implement visual-order cursor motion.
Date: Sat, 29 Jun 2013 13:37:51 +0000
User-agent: Bazaar (2.6b2)

------------------------------------------------------------
revno: 113221
revision-id: address@hidden
parent: address@hidden
committer: Eli Zaretskii <address@hidden>
branch nick: trunk
timestamp: Sat 2013-06-29 16:36:19 +0300
message:
  Implement visual-order cursor motion.
  
   src/xdisp.c (Fmove_point_visually): New function.
  
   lisp/bindings.el (visual-order-cursor-movement): New defcustom.
   (right-char, left-char): Provide visual-order cursor motion by
   calling move-point-visually.  Update the doc strings.
  
   doc/emacs/basic.texi (Moving Point): Document visual-order-cursor-movement
   and its effect on right-char and left-char.
  
   doc/lispref/display.texi (Bidirectional Display): Document 
move-point-visually.
  
   etc/NEWS: Document the new feature.
modified:
  doc/emacs/ChangeLog            changelog-20091113204419-o5vbwnq5f7feedwu-6227
  doc/emacs/basic.texi           basic.texi-20091113204419-o5vbwnq5f7feedwu-6233
  doc/emacs/mule.texi            mule.texi-20091113204419-o5vbwnq5f7feedwu-6270
  doc/lispref/ChangeLog          changelog-20091113204419-o5vbwnq5f7feedwu-6155
  doc/lispref/display.texi       
display.texi-20091113204419-o5vbwnq5f7feedwu-6172
  etc/NEWS                       news-20100311060928-aoit31wvzf25yr1z-1
  lisp/ChangeLog                 changelog-20091113204419-o5vbwnq5f7feedwu-1432
  lisp/bindings.el               
bindings.el-20091113204419-o5vbwnq5f7feedwu-1013
  src/ChangeLog                  changelog-20091113204419-o5vbwnq5f7feedwu-1438
  src/xdisp.c                    xdisp.c-20091113204419-o5vbwnq5f7feedwu-240
=== modified file 'doc/emacs/ChangeLog'
--- a/doc/emacs/ChangeLog       2013-06-28 16:08:27 +0000
+++ b/doc/emacs/ChangeLog       2013-06-29 13:36:19 +0000
@@ -1,3 +1,8 @@
+2013-06-29  Eli Zaretskii  <address@hidden>
+
+       * basic.texi (Moving Point): Document visual-order-cursor-movement
+       and its effect on right-char and left-char.
+
 2013-06-28  Glenn Morris  <address@hidden>
 
        * ack.texi (Acknowledgments): Small update.

=== modified file 'doc/emacs/basic.texi'
--- a/doc/emacs/basic.texi      2013-01-01 09:11:05 +0000
+++ b/doc/emacs/basic.texi      2013-06-29 13:36:19 +0000
@@ -153,10 +153,17 @@
 @item @key{right}
 @kindex RIGHT
 @findex right-char
address@hidden visual-order-cursor-movement
address@hidden cursor, visual-order motion
 This command (@code{right-char}) behaves like @kbd{C-f}, with one
 exception: when editing right-to-left scripts such as Arabic, it
 instead moves @emph{backward} if the current paragraph is a
-right-to-left paragraph.  @xref{Bidirectional Editing}.
+right-to-left paragraph.  @xref{Bidirectional Editing}.  If
address@hidden is address@hidden, this command
+moves to the character that is to the right of the current screen
+position, moving to the next or previous screen line as appropriate.
+Note that this might potentially move point many buffer positions
+away, depending on the surrounding bidirectional context.
 
 @item C-b
 @kindex C-b
@@ -168,7 +175,10 @@
 @findex left-char
 This command (@code{left-char}) behaves like @kbd{C-b}, except it
 moves @emph{forward} if the current paragraph is right-to-left.
address@hidden Editing}.
address@hidden Editing}.  If @code{visual-order-cursor-movement}
+is address@hidden, this command moves to the character that is to the
+left of the current screen position, moving to the previous or next
+screen line as appropriate.
 
 @item C-n
 @itemx @key{down}

=== modified file 'doc/emacs/mule.texi'
--- a/doc/emacs/mule.texi       2013-01-01 09:11:05 +0000
+++ b/doc/emacs/mule.texi       2013-06-29 13:36:19 +0000
@@ -1804,4 +1804,6 @@
 highlighted region covering a contiguous range of character positions
 may look discontinuous if the region spans reordered text.  This is
 normal and similar to the behavior of other programs that support
-bidirectional text.
+bidirectional text.  If you set @code{visual-order-cursor-movement} to
+a address@hidden value, cursor motion by the arrow keys follows the
+visual order on screen (@pxref{Moving Point, visual-order movement}).

=== modified file 'doc/lispref/ChangeLog'
--- a/doc/lispref/ChangeLog     2013-06-29 03:24:22 +0000
+++ b/doc/lispref/ChangeLog     2013-06-29 13:36:19 +0000
@@ -1,3 +1,7 @@
+2013-06-29  Eli Zaretskii  <address@hidden>
+
+       * display.texi (Bidirectional Display): Document move-point-visually.
+
 2013-06-29  Xue Fuqiao  <address@hidden>
 
        * buffers.texi (Buffer File Name): Fix typo.

=== modified file 'doc/lispref/display.texi'
--- a/doc/lispref/display.texi  2013-06-23 19:24:27 +0000
+++ b/doc/lispref/display.texi  2013-06-29 13:36:19 +0000
@@ -6431,6 +6431,26 @@
 buffers, this function always returns @code{left-to-right}.
 @end defun
 
address@hidden visual-order cursor motion
+  Sometimes there's a need to move point in strict visual order,
+either to the left or to the right of its current screen position.
+Emacs provides a primitive to do that.
+
address@hidden move-point-visually direction
+This function moves point of the currently selected window to the
+buffer position that appears immediately to the right or to the left
+of point on the screen.  If @var{direction} is positive, point will
+move one screen position to the right, otherwise it will move one
+screen position to the left.  Note that, depending on the surrounding
+bidirectional context, this could potentially move point many buffer
+positions away.  If invoked at the end of a screen line, the function
+moves point to the rightmost or leftmost screen position of the next
+or previous screen line, as appropriate for the value of
address@hidden
+
+The function returns the new buffer position as its value.
address@hidden defun
+
 @cindex layout on display, and bidirectional text
 @cindex jumbled display of bidirectional text
 @cindex concatenating bidirectional strings

=== modified file 'etc/NEWS'
--- a/etc/NEWS  2013-06-27 09:08:14 +0000
+++ b/etc/NEWS  2013-06-29 13:36:19 +0000
@@ -131,6 +131,13 @@
 ** In keymaps where SPC scrolls, S-SPC now scrolls in the reverse direction.
 Eg View mode, etc.
 
++++
+** New option `visual-order-cursor-movement'.
+If this is non-nil, cursor motion with arrow keys will follow the
+visual order of characters on the screen: <left> always moves to the
+left, <right> always moves to the right, disregarding the surrounding
+bidirectional context.
+
 ** New command `kmacro-to-register' to store keyboard macros in registers.
 
 ** Shell Script mode

=== modified file 'lisp/ChangeLog'
--- a/lisp/ChangeLog    2013-06-29 03:31:15 +0000
+++ b/lisp/ChangeLog    2013-06-29 13:36:19 +0000
@@ -1,3 +1,9 @@
+2013-06-29  Eli Zaretskii  <address@hidden>
+
+       * bindings.el (visual-order-cursor-movement): New defcustom.
+       (right-char, left-char): Provide visual-order cursor motion by
+       calling move-point-visually.  Update the doc strings.
+
 2013-06-28  Kenichi Handa  <address@hidden>
 
        * international/mule.el (define-coding-system): New coding system

=== modified file 'lisp/bindings.el'
--- a/lisp/bindings.el  2013-06-03 08:51:50 +0000
+++ b/lisp/bindings.el  2013-06-29 13:36:19 +0000
@@ -696,29 +696,63 @@
 (put 'narrow-to-region 'disabled t)
 
 ;; Moving with arrows in bidi-sensitive direction.
+(defcustom visual-order-cursor-movement nil
+  "If non-nil, moving cursor with arrow keys follows the visual order.
+
+When this is non-nil, \\[right-char] will move to the character that is
+to the right of point on display, and \\[left-char] will move to the left,
+disregarding the surrounding bidirectional context.  Depending on the
+bidirectional context of the surrounding characters, this can move point
+many buffer positions away.
+
+When the text is entirely left-to-right, logical-order and visual-order
+cursor movements produce identical results."
+  :type '(choice (const :tag "Logical-order cursor movement" nil)
+                (const :tag "Visual-order cursor movement" t))
+  :group 'display
+  :version "24.5")
+
 (defun right-char (&optional n)
   "Move point N characters to the right (to the left if N is negative).
 On reaching beginning or end of buffer, stop and signal error.
 
-Depending on the bidirectional context, this may move either forward
-or backward in the buffer.  This is in contrast with \\[forward-char]
-and \\[backward-char], which see."
+If `visual-order-cursor-movement' is non-nil, this always moves
+to the right on display, wherever that is in the buffer.
+Otherwise, depending on the bidirectional context, this may move
+one position either forward or backward in the buffer.  This is
+in contrast with \\[forward-char] and \\[backward-char], which
+see."
   (interactive "^p")
-  (if (eq (current-bidi-paragraph-direction) 'left-to-right)
-      (forward-char n)
-    (backward-char n)))
+  (if visual-order-cursor-movement
+      (dotimes (i (if (numberp n) (abs n) 1))
+       (if (< n 0)
+           (move-point-visually -1)
+         (move-point-visually 1))
+       (sit-for 0))
+    (if (eq (current-bidi-paragraph-direction) 'left-to-right)
+       (forward-char n)
+      (backward-char n))))
 
 (defun left-char ( &optional n)
   "Move point N characters to the left (to the right if N is negative).
 On reaching beginning or end of buffer, stop and signal error.
 
-Depending on the bidirectional context, this may move either backward
-or forward in the buffer.  This is in contrast with \\[backward-char]
-and \\[forward-char], which see."
+If `visual-order-cursor-movement' is non-nil, this always moves
+to the left on display, wherever that is in the buffer.
+Otherwise, depending on the bidirectional context, this may move
+one position either backward or forward in the buffer.  This is
+in contrast with \\[forward-char] and \\[backward-char], which
+see."
   (interactive "^p")
-  (if (eq (current-bidi-paragraph-direction) 'left-to-right)
-      (backward-char n)
-    (forward-char n)))
+  (if visual-order-cursor-movement
+      (dotimes (i (if (numberp n) (abs n) 1))
+       (if (< n 0)
+           (move-point-visually 1)
+         (move-point-visually -1))
+       (sit-for 0))
+    (if (eq (current-bidi-paragraph-direction) 'left-to-right)
+       (backward-char n)
+      (forward-char n))))
 
 (defun right-word (&optional n)
   "Move point N words to the right (to the left if N is negative).

=== modified file 'src/ChangeLog'
--- a/src/ChangeLog     2013-06-29 03:31:15 +0000
+++ b/src/ChangeLog     2013-06-29 13:36:19 +0000
@@ -1,3 +1,7 @@
+2013-06-29  Eli Zaretskii  <address@hidden>
+
+       * xdisp.c (Fmove_point_visually): New function.
+
 2013-06-28  Kenichi Handa  <address@hidden>
 
        * coding.h (define_coding_undecided_arg_index): New enum.

=== modified file 'src/xdisp.c'
--- a/src/xdisp.c       2013-06-15 09:34:20 +0000
+++ b/src/xdisp.c       2013-06-29 13:36:19 +0000
@@ -20051,6 +20051,398 @@
     }
 }
 
+DEFUN ("move-point-visually", Fmove_point_visually,
+       Smove_point_visually, 1, 1, 0,
+       doc: /* Move point in the visual order in the specified DIRECTION.
+DIRECTION can be 1, meaning move to the right, or -1, which moves to the
+left.
+
+Value is the new character position of point.  */)
+  (Lisp_Object direction)
+{
+  struct window *w = XWINDOW (selected_window);
+  struct buffer *b = NULL;
+  struct glyph_row *row;
+  int dir;
+  Lisp_Object paragraph_dir;
+
+#define ROW_GLYPH_NEWLINE_P(ROW,GLYPH)         \
+  (!(ROW)->continued_p                         \
+   && INTEGERP ((GLYPH)->object)               \
+   && (GLYPH)->type == CHAR_GLYPH              \
+   && (GLYPH)->u.ch == ' '                     \
+   && (GLYPH)->charpos >= 0                    \
+   && !(GLYPH)->avoid_cursor_p)
+
+  CHECK_NUMBER (direction);
+  dir = XINT (direction);
+  if (dir > 0)
+    dir = 1;
+  else
+    dir = -1;
+
+  if (BUFFERP (w->contents))
+    b = XBUFFER (w->contents);
+
+  /* If current matrix is up-to-date, we can use the information
+     recorded in the glyphs, at least as long as the goal is on the
+     screen.  */
+  if (w->window_end_valid
+      && !windows_or_buffers_changed
+      && b
+      && !b->clip_changed
+      && !b->prevent_redisplay_optimizations_p
+      && w->last_modified >= BUF_MODIFF (b)
+      && w->last_overlay_modified >= BUF_OVERLAY_MODIFF (b)
+      && w->cursor.vpos >= 0
+      && w->cursor.vpos < w->current_matrix->nrows
+      && (row = MATRIX_ROW (w->current_matrix, w->cursor.vpos))->enabled_p)
+    {
+      struct glyph *g = row->glyphs[TEXT_AREA];
+      struct glyph *e = dir > 0 ? g + row->used[TEXT_AREA] : g - 1;
+      struct glyph *gpt = g + w->cursor.hpos;
+
+      for (g = gpt + dir; (dir > 0 ? g < e : g > e); g += dir)
+       {
+         if (BUFFERP (g->object) && g->charpos != PT)
+           {
+             SET_PT (g->charpos);
+             return make_number (PT);
+           }
+         else if (!INTEGERP (g->object) && g->object != gpt->object)
+           {
+             ptrdiff_t new_pos;
+
+             if (BUFFERP (gpt->object))
+               {
+                 new_pos = PT;
+                 if ((gpt->resolved_level - row->reversed_p) % 2 == 0)
+                   new_pos += (row->reversed_p ? -dir : dir);
+                 else
+                   new_pos -= (row->reversed_p ? -dir : dir);;
+               }
+             else if (BUFFERP (g->object))
+               new_pos = g->charpos;
+             else
+               break;
+             SET_PT (new_pos);
+             return make_number (PT);
+           }
+         else if (ROW_GLYPH_NEWLINE_P (row, g))
+           {
+             /* Glyphs inserted at the end of a non-empty line for
+                positioning the cursor have zero charpos, so we must
+                deduce the value of point by other means.  */
+             if (g->charpos > 0)
+               SET_PT (g->charpos);
+             else if (row->ends_at_zv_p && PT != ZV)
+               SET_PT (ZV);
+             else if (PT != MATRIX_ROW_END_CHARPOS (row) - 1)
+               SET_PT (MATRIX_ROW_END_CHARPOS (row) - 1);
+             else
+               break;
+             return make_number (PT);
+           }
+       }
+      if (g == e || INTEGERP (g->object))
+       {
+         if (row->truncated_on_left_p || row->truncated_on_right_p)
+           goto simulate_display;
+         if (!row->reversed_p)
+           row += dir;
+         else
+           row -= dir;
+         if (row < MATRIX_FIRST_TEXT_ROW (w->current_matrix)
+             || row > MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w))
+           goto simulate_display;
+
+         if (dir > 0)
+           {
+             if (row->reversed_p && !row->continued_p)
+               {
+                 SET_PT (MATRIX_ROW_END_CHARPOS (row) - 1);
+                 return make_number (PT);
+               }
+             g = row->glyphs[TEXT_AREA];
+             e = g + row->used[TEXT_AREA];
+             for ( ; g < e; g++)
+               {
+                 if (BUFFERP (g->object)
+                     /* Empty lines have only one glyph, which stands
+                        for the newline, and whose charpos is the
+                        buffer position of the newline.  */
+                     || ROW_GLYPH_NEWLINE_P (row, g)
+                     /* When the buffer ends in a newline, the line at
+                        EOB also has one glyph, but its charpos is -1.  */
+                     || (row->ends_at_zv_p
+                         && !row->reversed_p
+                         && INTEGERP (g->object)
+                         && g->type == CHAR_GLYPH
+                         && g->u.ch == ' '))
+                   {
+                     if (g->charpos > 0)
+                       SET_PT (g->charpos);
+                     else if (!row->reversed_p
+                              && row->ends_at_zv_p
+                              && PT != ZV)
+                       SET_PT (ZV);
+                     else
+                       continue;
+                     return make_number (PT);
+                   }
+               }
+           }
+         else
+           {
+             if (!row->reversed_p && !row->continued_p)
+               {
+                 SET_PT (MATRIX_ROW_END_CHARPOS (row) - 1);
+                 return make_number (PT);
+               }
+             e = row->glyphs[TEXT_AREA];
+             g = e + row->used[TEXT_AREA] - 1;
+             for ( ; g >= e; g--)
+               {
+                 if (BUFFERP (g->object)
+                     || (ROW_GLYPH_NEWLINE_P (row, g)
+                         && g->charpos > 0)
+                     /* Empty R2L lines on GUI frames have the buffer
+                        position of the newline stored in the stretch
+                        glyph.  */
+                     || g->type == STRETCH_GLYPH
+                     || (row->ends_at_zv_p
+                         && row->reversed_p
+                         && INTEGERP (g->object)
+                         && g->type == CHAR_GLYPH
+                         && g->u.ch == ' '))
+                   {
+                     if (g->charpos > 0)
+                       SET_PT (g->charpos);
+                     else if (row->reversed_p
+                              && row->ends_at_zv_p
+                              && PT != ZV)
+                       SET_PT (ZV);
+                     else
+                       continue;
+                     return make_number (PT);
+                   }
+               }
+           }
+       }
+    }
+
+ simulate_display:
+
+  /* If we wind up here, we failed to move by using the glyphs, so we
+     need to simulate display instead.  */
+
+  if (b)
+    paragraph_dir = Fcurrent_bidi_paragraph_direction (w->contents);
+  else
+    paragraph_dir = Qleft_to_right;
+  if (EQ (paragraph_dir, Qright_to_left))
+    dir = -dir;
+  if (PT <= BEGV && dir < 0)
+    xsignal0 (Qbeginning_of_buffer);
+  else if (PT >= ZV && dir > 0)
+    xsignal0 (Qend_of_buffer);
+  else
+    {
+      struct text_pos pt;
+      struct it it;
+      int pt_x, target_x, pixel_width, pt_vpos;
+      bool at_eol_p;
+      bool disp_string_at_start_p = 0;
+      bool overshoot_expected = false;
+      bool target_is_eol_p = false;
+
+      /* Setup the arena.  */
+      SET_TEXT_POS (pt, PT, PT_BYTE);
+      start_display (&it, w, pt);
+
+      if (it.cmp_it.id < 0
+         && it.method == GET_FROM_STRING
+         && it.area == TEXT_AREA
+         && it.string_from_display_prop_p
+         && (it.sp > 0 && it.stack[it.sp - 1].method == GET_FROM_BUFFER))
+       overshoot_expected = true;
+
+      /* Find the X coordinate of point.  We start from the beginning
+        of this or previous line to make sure we are before point in
+        the logical order (since the move_it_* functions can only
+        move forward).  */
+      reseat_at_previous_visible_line_start (&it);
+      it.current_x = it.hpos = it.current_y = it.vpos = 0;
+      if (IT_CHARPOS (it) != PT)
+       move_it_to (&it, overshoot_expected ? PT - 1 : PT,
+                   -1, -1, -1, MOVE_TO_POS);
+      pt_x = it.current_x;
+      pt_vpos = it.vpos;
+      if (dir > 0 || overshoot_expected)
+       {
+         struct glyph_row *row = it.glyph_row;
+
+         /* When point is at beginning of line, we don't have
+            information about the glyph there loaded into struct
+            it.  Calling get_next_display_element fixes that.  */
+         if (pt_x == 0)
+           get_next_display_element (&it);
+         at_eol_p = ITERATOR_AT_END_OF_LINE_P (&it);
+         it.glyph_row = NULL;
+         PRODUCE_GLYPHS (&it); /* compute it.pixel_width */
+         it.glyph_row = row;
+         /* PRODUCE_GLYPHS advances it.current_x, so we must restore
+            it, lest it will become out of sync with it's buffer
+            position.  */
+         it.current_x = pt_x;
+       }
+      else
+       at_eol_p = ITERATOR_AT_END_OF_LINE_P (&it);
+      pixel_width = it.pixel_width;
+      if (overshoot_expected && at_eol_p)
+       pixel_width = 0;
+      else if (pixel_width <= 0)
+       pixel_width = 1;
+
+      /* If there's a display string at point, we are actually at the
+        glyph to the left of point, so we need to correct the X
+        coordinate.  */
+      if (overshoot_expected)
+       pt_x += pixel_width;
+
+      /* Compute target X coordinate, either to the left or to the
+        right of point.  On TTY frames, all characters have the same
+        pixel width of 1, so we can use that.  On GUI frames we don't
+        have an easy way of getting at the pixel width of the
+        character to the left of point, so we use a different method
+        of getting to that place.  */
+      if (dir > 0)
+       target_x = pt_x + pixel_width;
+      else
+       target_x = pt_x - (!FRAME_WINDOW_P (it.f)) * pixel_width;
+
+      /* Target X coordinate could be one line above or below the line
+        of point, in which case we need to adjust the target X
+        coordinate.  Also, if moving to the left, we need to begin at
+        the left edge of the point's screen line.  */
+      if (dir < 0)
+       {
+         if (pt_x > 0)
+           {
+             start_display (&it, w, pt);
+             reseat_at_previous_visible_line_start (&it);
+             it.current_x = it.current_y = it.hpos = 0;
+             if (pt_vpos != 0)
+               move_it_by_lines (&it, pt_vpos);
+           }
+         else
+           {
+             move_it_by_lines (&it, -1);
+             target_x = it.last_visible_x - !FRAME_WINDOW_P (it.f);
+             target_is_eol_p = true;
+           }
+       }
+      else
+       {
+         if (at_eol_p
+             || (target_x >= it.last_visible_x
+                 && it.line_wrap != TRUNCATE))
+           {
+             if (pt_x > 0)
+               move_it_by_lines (&it, 0);
+             move_it_by_lines (&it, 1);
+             target_x = 0;
+           }
+       }
+
+      /* Move to the target X coordinate.  */
+#ifdef HAVE_WINDOW_SYSTEM
+      /* On GUI frames, as we don't know the X coordinate of the
+        character to the left of point, moving point to the left
+        requires walking, one grapheme cluster at a time, until we
+        find ourself at a place immediately to the left of the
+        character at point.  */
+      if (FRAME_WINDOW_P (it.f) && dir < 0)
+       {
+         struct text_pos new_pos = it.current.pos;
+         enum move_it_result rc = MOVE_X_REACHED;
+
+         while (it.current_x + it.pixel_width <= target_x
+                && rc == MOVE_X_REACHED)
+           {
+             int new_x = it.current_x + it.pixel_width;
+
+             new_pos = it.current.pos;
+             if (new_x == it.current_x)
+               new_x++;
+             rc = move_it_in_display_line_to (&it, ZV, new_x,
+                                              MOVE_TO_POS | MOVE_TO_X);
+             if (ITERATOR_AT_END_OF_LINE_P (&it) && !target_is_eol_p)
+               break;
+           }
+         /* If we ended up on a composed character inside
+            bidi-reordered text (e.g., Hebrew text with diacriticals),
+            the iterator gives us the buffer position of the last (in
+            logical order) character of the composed grapheme cluster,
+            which is not what we want.  So we cheat: we compute the
+            character position of the character that follows (in the
+            logical order) the one where the above loop stopped.  That
+            character will appear on display to the left of point.  */
+         if (it.bidi_p
+             && it.bidi_it.scan_dir == -1
+             && new_pos.charpos - IT_CHARPOS (it) > 1)
+           {
+             new_pos.charpos = IT_CHARPOS (it) + 1;
+             new_pos.bytepos = CHAR_TO_BYTE (new_pos.charpos);
+           }
+         it.current.pos = new_pos;
+       }
+      else
+#endif
+      if (it.current_x != target_x)
+       move_it_in_display_line_to (&it, ZV, target_x, MOVE_TO_POS | MOVE_TO_X);
+
+      /* When lines are truncated, the above loop will stop at the
+        window edge.  But we want to get to the end of line, even if
+        it is beyond the window edge; automatic hscroll will then
+        scroll the window to show point as appropriate.  */
+      if (target_is_eol_p && it.line_wrap == TRUNCATE
+         && get_next_display_element (&it))
+       {
+         struct text_pos new_pos = it.current.pos;
+
+         while (!ITERATOR_AT_END_OF_LINE_P (&it))
+           {
+             set_iterator_to_next (&it, 0);
+             if (it.method == GET_FROM_BUFFER)
+               new_pos = it.current.pos;
+             if (!get_next_display_element (&it))
+               break;
+           }
+
+         it.current.pos = new_pos;
+       }
+
+      /* If we ended up in a display string that covers point, move to
+        buffer position to the right in the visual order.  */
+      if (dir > 0)
+       {
+         while (IT_CHARPOS (it) == PT)
+           {
+             set_iterator_to_next (&it, 0);
+             if (!get_next_display_element (&it))
+               break;
+           }
+       }
+
+      /* Move point to that position.  */
+      SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+    }
+
+  return make_number (PT);
+
+#undef ROW_GLYPH_NEWLINE_P
+}
 
 
 /***********************************************************************
@@ -28713,6 +29105,7 @@
   defsubr (&Sformat_mode_line);
   defsubr (&Sinvisible_p);
   defsubr (&Scurrent_bidi_paragraph_direction);
+  defsubr (&Smove_point_visually);
 
   DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook");
   DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map");


reply via email to

[Prev in Thread] Current Thread [Next in Thread]