diff options
| author | Eli Zaretskii | 2013-06-29 16:36:19 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2013-06-29 16:36:19 +0300 |
| commit | 4c672a0fec1d18cc1a445acf3e6935d681d4048f (patch) | |
| tree | c8fb2626c93a226bed5eaa0b92f95925734e893f | |
| parent | 73b1b3ad6196234984a29298bc66eabf1299de66 (diff) | |
| download | emacs-4c672a0fec1d18cc1a445acf3e6935d681d4048f.tar.gz emacs-4c672a0fec1d18cc1a445acf3e6935d681d4048f.zip | |
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.
| -rw-r--r-- | doc/emacs/ChangeLog | 5 | ||||
| -rw-r--r-- | doc/emacs/basic.texi | 14 | ||||
| -rw-r--r-- | doc/emacs/mule.texi | 4 | ||||
| -rw-r--r-- | doc/lispref/ChangeLog | 4 | ||||
| -rw-r--r-- | doc/lispref/display.texi | 20 | ||||
| -rw-r--r-- | etc/NEWS | 7 | ||||
| -rw-r--r-- | lisp/ChangeLog | 6 | ||||
| -rw-r--r-- | lisp/bindings.el | 58 | ||||
| -rw-r--r-- | src/ChangeLog | 4 | ||||
| -rw-r--r-- | src/xdisp.c | 393 |
10 files changed, 500 insertions, 15 deletions
diff --git a/doc/emacs/ChangeLog b/doc/emacs/ChangeLog index 45f08499215..d5f3095908b 100644 --- a/doc/emacs/ChangeLog +++ b/doc/emacs/ChangeLog | |||
| @@ -1,3 +1,8 @@ | |||
| 1 | 2013-06-29 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | * basic.texi (Moving Point): Document visual-order-cursor-movement | ||
| 4 | and its effect on right-char and left-char. | ||
| 5 | |||
| 1 | 2013-06-28 Glenn Morris <rgm@gnu.org> | 6 | 2013-06-28 Glenn Morris <rgm@gnu.org> |
| 2 | 7 | ||
| 3 | * ack.texi (Acknowledgments): Small update. | 8 | * ack.texi (Acknowledgments): Small update. |
diff --git a/doc/emacs/basic.texi b/doc/emacs/basic.texi index b9bc391d1cf..a840f912656 100644 --- a/doc/emacs/basic.texi +++ b/doc/emacs/basic.texi | |||
| @@ -153,10 +153,17 @@ Move forward one character (@code{forward-char}). | |||
| 153 | @item @key{right} | 153 | @item @key{right} |
| 154 | @kindex RIGHT | 154 | @kindex RIGHT |
| 155 | @findex right-char | 155 | @findex right-char |
| 156 | @vindex visual-order-cursor-movement | ||
| 157 | @cindex cursor, visual-order motion | ||
| 156 | This command (@code{right-char}) behaves like @kbd{C-f}, with one | 158 | This command (@code{right-char}) behaves like @kbd{C-f}, with one |
| 157 | exception: when editing right-to-left scripts such as Arabic, it | 159 | exception: when editing right-to-left scripts such as Arabic, it |
| 158 | instead moves @emph{backward} if the current paragraph is a | 160 | instead moves @emph{backward} if the current paragraph is a |
| 159 | right-to-left paragraph. @xref{Bidirectional Editing}. | 161 | right-to-left paragraph. @xref{Bidirectional Editing}. If |
| 162 | @code{visual-order-cursor-movement} is non-@code{nil}, this command | ||
| 163 | moves to the character that is to the right of the current screen | ||
| 164 | position, moving to the next or previous screen line as appropriate. | ||
| 165 | Note that this might potentially move point many buffer positions | ||
| 166 | away, depending on the surrounding bidirectional context. | ||
| 160 | 167 | ||
| 161 | @item C-b | 168 | @item C-b |
| 162 | @kindex C-b | 169 | @kindex C-b |
| @@ -168,7 +175,10 @@ Move backward one character (@code{backward-char}). | |||
| 168 | @findex left-char | 175 | @findex left-char |
| 169 | This command (@code{left-char}) behaves like @kbd{C-b}, except it | 176 | This command (@code{left-char}) behaves like @kbd{C-b}, except it |
| 170 | moves @emph{forward} if the current paragraph is right-to-left. | 177 | moves @emph{forward} if the current paragraph is right-to-left. |
| 171 | @xref{Bidirectional Editing}. | 178 | @xref{Bidirectional Editing}. If @code{visual-order-cursor-movement} |
| 179 | is non-@code{nil}, this command moves to the character that is to the | ||
| 180 | left of the current screen position, moving to the previous or next | ||
| 181 | screen line as appropriate. | ||
| 172 | 182 | ||
| 173 | @item C-n | 183 | @item C-n |
| 174 | @itemx @key{down} | 184 | @itemx @key{down} |
diff --git a/doc/emacs/mule.texi b/doc/emacs/mule.texi index de3e05777cd..c8bd5027fa0 100644 --- a/doc/emacs/mule.texi +++ b/doc/emacs/mule.texi | |||
| @@ -1804,4 +1804,6 @@ jump when point traverses reordered bidirectional text. Similarly, a | |||
| 1804 | highlighted region covering a contiguous range of character positions | 1804 | highlighted region covering a contiguous range of character positions |
| 1805 | may look discontinuous if the region spans reordered text. This is | 1805 | may look discontinuous if the region spans reordered text. This is |
| 1806 | normal and similar to the behavior of other programs that support | 1806 | normal and similar to the behavior of other programs that support |
| 1807 | bidirectional text. | 1807 | bidirectional text. If you set @code{visual-order-cursor-movement} to |
| 1808 | a non-@code{nil} value, cursor motion by the arrow keys follows the | ||
| 1809 | visual order on screen (@pxref{Moving Point, visual-order movement}). | ||
diff --git a/doc/lispref/ChangeLog b/doc/lispref/ChangeLog index 199d94585e3..dc0c1564735 100644 --- a/doc/lispref/ChangeLog +++ b/doc/lispref/ChangeLog | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | 2013-06-29 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | * display.texi (Bidirectional Display): Document move-point-visually. | ||
| 4 | |||
| 1 | 2013-06-29 Xue Fuqiao <xfq.free@gmail.com> | 5 | 2013-06-29 Xue Fuqiao <xfq.free@gmail.com> |
| 2 | 6 | ||
| 3 | * buffers.texi (Buffer File Name): Fix typo. | 7 | * buffers.texi (Buffer File Name): Fix typo. |
diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index d82b9a4c5a2..ecefb684ee6 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi | |||
| @@ -6431,6 +6431,26 @@ determined dynamically by Emacs. For buffers whose value of | |||
| 6431 | buffers, this function always returns @code{left-to-right}. | 6431 | buffers, this function always returns @code{left-to-right}. |
| 6432 | @end defun | 6432 | @end defun |
| 6433 | 6433 | ||
| 6434 | @cindex visual-order cursor motion | ||
| 6435 | Sometimes there's a need to move point in strict visual order, | ||
| 6436 | either to the left or to the right of its current screen position. | ||
| 6437 | Emacs provides a primitive to do that. | ||
| 6438 | |||
| 6439 | @defun move-point-visually direction | ||
| 6440 | This function moves point of the currently selected window to the | ||
| 6441 | buffer position that appears immediately to the right or to the left | ||
| 6442 | of point on the screen. If @var{direction} is positive, point will | ||
| 6443 | move one screen position to the right, otherwise it will move one | ||
| 6444 | screen position to the left. Note that, depending on the surrounding | ||
| 6445 | bidirectional context, this could potentially move point many buffer | ||
| 6446 | positions away. If invoked at the end of a screen line, the function | ||
| 6447 | moves point to the rightmost or leftmost screen position of the next | ||
| 6448 | or previous screen line, as appropriate for the value of | ||
| 6449 | @var{direction}. | ||
| 6450 | |||
| 6451 | The function returns the new buffer position as its value. | ||
| 6452 | @end defun | ||
| 6453 | |||
| 6434 | @cindex layout on display, and bidirectional text | 6454 | @cindex layout on display, and bidirectional text |
| 6435 | @cindex jumbled display of bidirectional text | 6455 | @cindex jumbled display of bidirectional text |
| 6436 | @cindex concatenating bidirectional strings | 6456 | @cindex concatenating bidirectional strings |
| @@ -131,6 +131,13 @@ bound to <f11> and M-<f10>, respectively. | |||
| 131 | ** In keymaps where SPC scrolls, S-SPC now scrolls in the reverse direction. | 131 | ** In keymaps where SPC scrolls, S-SPC now scrolls in the reverse direction. |
| 132 | Eg View mode, etc. | 132 | Eg View mode, etc. |
| 133 | 133 | ||
| 134 | +++ | ||
| 135 | ** New option `visual-order-cursor-movement'. | ||
| 136 | If this is non-nil, cursor motion with arrow keys will follow the | ||
| 137 | visual order of characters on the screen: <left> always moves to the | ||
| 138 | left, <right> always moves to the right, disregarding the surrounding | ||
| 139 | bidirectional context. | ||
| 140 | |||
| 134 | ** New command `kmacro-to-register' to store keyboard macros in registers. | 141 | ** New command `kmacro-to-register' to store keyboard macros in registers. |
| 135 | 142 | ||
| 136 | ** Shell Script mode | 143 | ** Shell Script mode |
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 826f270d8f8..1e1fff6fc25 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,9 @@ | |||
| 1 | 2013-06-29 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | * bindings.el (visual-order-cursor-movement): New defcustom. | ||
| 4 | (right-char, left-char): Provide visual-order cursor motion by | ||
| 5 | calling move-point-visually. Update the doc strings. | ||
| 6 | |||
| 1 | 2013-06-28 Kenichi Handa <handa@gnu.org> | 7 | 2013-06-28 Kenichi Handa <handa@gnu.org> |
| 2 | 8 | ||
| 3 | * international/mule.el (define-coding-system): New coding system | 9 | * international/mule.el (define-coding-system): New coding system |
diff --git a/lisp/bindings.el b/lisp/bindings.el index 2013c079820..7c42cc6c0a8 100644 --- a/lisp/bindings.el +++ b/lisp/bindings.el | |||
| @@ -696,29 +696,63 @@ language you are using." | |||
| 696 | (put 'narrow-to-region 'disabled t) | 696 | (put 'narrow-to-region 'disabled t) |
| 697 | 697 | ||
| 698 | ;; Moving with arrows in bidi-sensitive direction. | 698 | ;; Moving with arrows in bidi-sensitive direction. |
| 699 | (defcustom visual-order-cursor-movement nil | ||
| 700 | "If non-nil, moving cursor with arrow keys follows the visual order. | ||
| 701 | |||
| 702 | When this is non-nil, \\[right-char] will move to the character that is | ||
| 703 | to the right of point on display, and \\[left-char] will move to the left, | ||
| 704 | disregarding the surrounding bidirectional context. Depending on the | ||
| 705 | bidirectional context of the surrounding characters, this can move point | ||
| 706 | many buffer positions away. | ||
| 707 | |||
| 708 | When the text is entirely left-to-right, logical-order and visual-order | ||
| 709 | cursor movements produce identical results." | ||
| 710 | :type '(choice (const :tag "Logical-order cursor movement" nil) | ||
| 711 | (const :tag "Visual-order cursor movement" t)) | ||
| 712 | :group 'display | ||
| 713 | :version "24.5") | ||
| 714 | |||
| 699 | (defun right-char (&optional n) | 715 | (defun right-char (&optional n) |
| 700 | "Move point N characters to the right (to the left if N is negative). | 716 | "Move point N characters to the right (to the left if N is negative). |
| 701 | On reaching beginning or end of buffer, stop and signal error. | 717 | On reaching beginning or end of buffer, stop and signal error. |
| 702 | 718 | ||
| 703 | Depending on the bidirectional context, this may move either forward | 719 | If `visual-order-cursor-movement' is non-nil, this always moves |
| 704 | or backward in the buffer. This is in contrast with \\[forward-char] | 720 | to the right on display, wherever that is in the buffer. |
| 705 | and \\[backward-char], which see." | 721 | Otherwise, depending on the bidirectional context, this may move |
| 722 | one position either forward or backward in the buffer. This is | ||
| 723 | in contrast with \\[forward-char] and \\[backward-char], which | ||
| 724 | see." | ||
| 706 | (interactive "^p") | 725 | (interactive "^p") |
| 707 | (if (eq (current-bidi-paragraph-direction) 'left-to-right) | 726 | (if visual-order-cursor-movement |
| 708 | (forward-char n) | 727 | (dotimes (i (if (numberp n) (abs n) 1)) |
| 709 | (backward-char n))) | 728 | (if (< n 0) |
| 729 | (move-point-visually -1) | ||
| 730 | (move-point-visually 1)) | ||
| 731 | (sit-for 0)) | ||
| 732 | (if (eq (current-bidi-paragraph-direction) 'left-to-right) | ||
| 733 | (forward-char n) | ||
| 734 | (backward-char n)))) | ||
| 710 | 735 | ||
| 711 | (defun left-char ( &optional n) | 736 | (defun left-char ( &optional n) |
| 712 | "Move point N characters to the left (to the right if N is negative). | 737 | "Move point N characters to the left (to the right if N is negative). |
| 713 | On reaching beginning or end of buffer, stop and signal error. | 738 | On reaching beginning or end of buffer, stop and signal error. |
| 714 | 739 | ||
| 715 | Depending on the bidirectional context, this may move either backward | 740 | If `visual-order-cursor-movement' is non-nil, this always moves |
| 716 | or forward in the buffer. This is in contrast with \\[backward-char] | 741 | to the left on display, wherever that is in the buffer. |
| 717 | and \\[forward-char], which see." | 742 | Otherwise, depending on the bidirectional context, this may move |
| 743 | one position either backward or forward in the buffer. This is | ||
| 744 | in contrast with \\[forward-char] and \\[backward-char], which | ||
| 745 | see." | ||
| 718 | (interactive "^p") | 746 | (interactive "^p") |
| 719 | (if (eq (current-bidi-paragraph-direction) 'left-to-right) | 747 | (if visual-order-cursor-movement |
| 720 | (backward-char n) | 748 | (dotimes (i (if (numberp n) (abs n) 1)) |
| 721 | (forward-char n))) | 749 | (if (< n 0) |
| 750 | (move-point-visually 1) | ||
| 751 | (move-point-visually -1)) | ||
| 752 | (sit-for 0)) | ||
| 753 | (if (eq (current-bidi-paragraph-direction) 'left-to-right) | ||
| 754 | (backward-char n) | ||
| 755 | (forward-char n)))) | ||
| 722 | 756 | ||
| 723 | (defun right-word (&optional n) | 757 | (defun right-word (&optional n) |
| 724 | "Move point N words to the right (to the left if N is negative). | 758 | "Move point N words to the right (to the left if N is negative). |
diff --git a/src/ChangeLog b/src/ChangeLog index b279f42e6b6..1e1b54a72d0 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | 2013-06-29 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | * xdisp.c (Fmove_point_visually): New function. | ||
| 4 | |||
| 1 | 2013-06-28 Kenichi Handa <handa@gnu.org> | 5 | 2013-06-28 Kenichi Handa <handa@gnu.org> |
| 2 | 6 | ||
| 3 | * coding.h (define_coding_undecided_arg_index): New enum. | 7 | * coding.h (define_coding_undecided_arg_index): New enum. |
diff --git a/src/xdisp.c b/src/xdisp.c index 54ea325f642..420ff0c918b 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -20051,6 +20051,398 @@ See also `bidi-paragraph-direction'. */) | |||
| 20051 | } | 20051 | } |
| 20052 | } | 20052 | } |
| 20053 | 20053 | ||
| 20054 | DEFUN ("move-point-visually", Fmove_point_visually, | ||
| 20055 | Smove_point_visually, 1, 1, 0, | ||
| 20056 | doc: /* Move point in the visual order in the specified DIRECTION. | ||
| 20057 | DIRECTION can be 1, meaning move to the right, or -1, which moves to the | ||
| 20058 | left. | ||
| 20059 | |||
| 20060 | Value is the new character position of point. */) | ||
| 20061 | (Lisp_Object direction) | ||
| 20062 | { | ||
| 20063 | struct window *w = XWINDOW (selected_window); | ||
| 20064 | struct buffer *b = NULL; | ||
| 20065 | struct glyph_row *row; | ||
| 20066 | int dir; | ||
| 20067 | Lisp_Object paragraph_dir; | ||
| 20068 | |||
| 20069 | #define ROW_GLYPH_NEWLINE_P(ROW,GLYPH) \ | ||
| 20070 | (!(ROW)->continued_p \ | ||
| 20071 | && INTEGERP ((GLYPH)->object) \ | ||
| 20072 | && (GLYPH)->type == CHAR_GLYPH \ | ||
| 20073 | && (GLYPH)->u.ch == ' ' \ | ||
| 20074 | && (GLYPH)->charpos >= 0 \ | ||
| 20075 | && !(GLYPH)->avoid_cursor_p) | ||
| 20076 | |||
| 20077 | CHECK_NUMBER (direction); | ||
| 20078 | dir = XINT (direction); | ||
| 20079 | if (dir > 0) | ||
| 20080 | dir = 1; | ||
| 20081 | else | ||
| 20082 | dir = -1; | ||
| 20083 | |||
| 20084 | if (BUFFERP (w->contents)) | ||
| 20085 | b = XBUFFER (w->contents); | ||
| 20086 | |||
| 20087 | /* If current matrix is up-to-date, we can use the information | ||
| 20088 | recorded in the glyphs, at least as long as the goal is on the | ||
| 20089 | screen. */ | ||
| 20090 | if (w->window_end_valid | ||
| 20091 | && !windows_or_buffers_changed | ||
| 20092 | && b | ||
| 20093 | && !b->clip_changed | ||
| 20094 | && !b->prevent_redisplay_optimizations_p | ||
| 20095 | && w->last_modified >= BUF_MODIFF (b) | ||
| 20096 | && w->last_overlay_modified >= BUF_OVERLAY_MODIFF (b) | ||
| 20097 | && w->cursor.vpos >= 0 | ||
| 20098 | && w->cursor.vpos < w->current_matrix->nrows | ||
| 20099 | && (row = MATRIX_ROW (w->current_matrix, w->cursor.vpos))->enabled_p) | ||
| 20100 | { | ||
| 20101 | struct glyph *g = row->glyphs[TEXT_AREA]; | ||
| 20102 | struct glyph *e = dir > 0 ? g + row->used[TEXT_AREA] : g - 1; | ||
| 20103 | struct glyph *gpt = g + w->cursor.hpos; | ||
| 20104 | |||
| 20105 | for (g = gpt + dir; (dir > 0 ? g < e : g > e); g += dir) | ||
| 20106 | { | ||
| 20107 | if (BUFFERP (g->object) && g->charpos != PT) | ||
| 20108 | { | ||
| 20109 | SET_PT (g->charpos); | ||
| 20110 | return make_number (PT); | ||
| 20111 | } | ||
| 20112 | else if (!INTEGERP (g->object) && g->object != gpt->object) | ||
| 20113 | { | ||
| 20114 | ptrdiff_t new_pos; | ||
| 20115 | |||
| 20116 | if (BUFFERP (gpt->object)) | ||
| 20117 | { | ||
| 20118 | new_pos = PT; | ||
| 20119 | if ((gpt->resolved_level - row->reversed_p) % 2 == 0) | ||
| 20120 | new_pos += (row->reversed_p ? -dir : dir); | ||
| 20121 | else | ||
| 20122 | new_pos -= (row->reversed_p ? -dir : dir);; | ||
| 20123 | } | ||
| 20124 | else if (BUFFERP (g->object)) | ||
| 20125 | new_pos = g->charpos; | ||
| 20126 | else | ||
| 20127 | break; | ||
| 20128 | SET_PT (new_pos); | ||
| 20129 | return make_number (PT); | ||
| 20130 | } | ||
| 20131 | else if (ROW_GLYPH_NEWLINE_P (row, g)) | ||
| 20132 | { | ||
| 20133 | /* Glyphs inserted at the end of a non-empty line for | ||
| 20134 | positioning the cursor have zero charpos, so we must | ||
| 20135 | deduce the value of point by other means. */ | ||
| 20136 | if (g->charpos > 0) | ||
| 20137 | SET_PT (g->charpos); | ||
| 20138 | else if (row->ends_at_zv_p && PT != ZV) | ||
| 20139 | SET_PT (ZV); | ||
| 20140 | else if (PT != MATRIX_ROW_END_CHARPOS (row) - 1) | ||
| 20141 | SET_PT (MATRIX_ROW_END_CHARPOS (row) - 1); | ||
| 20142 | else | ||
| 20143 | break; | ||
| 20144 | return make_number (PT); | ||
| 20145 | } | ||
| 20146 | } | ||
| 20147 | if (g == e || INTEGERP (g->object)) | ||
| 20148 | { | ||
| 20149 | if (row->truncated_on_left_p || row->truncated_on_right_p) | ||
| 20150 | goto simulate_display; | ||
| 20151 | if (!row->reversed_p) | ||
| 20152 | row += dir; | ||
| 20153 | else | ||
| 20154 | row -= dir; | ||
| 20155 | if (row < MATRIX_FIRST_TEXT_ROW (w->current_matrix) | ||
| 20156 | || row > MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w)) | ||
| 20157 | goto simulate_display; | ||
| 20158 | |||
| 20159 | if (dir > 0) | ||
| 20160 | { | ||
| 20161 | if (row->reversed_p && !row->continued_p) | ||
| 20162 | { | ||
| 20163 | SET_PT (MATRIX_ROW_END_CHARPOS (row) - 1); | ||
| 20164 | return make_number (PT); | ||
| 20165 | } | ||
| 20166 | g = row->glyphs[TEXT_AREA]; | ||
| 20167 | e = g + row->used[TEXT_AREA]; | ||
| 20168 | for ( ; g < e; g++) | ||
| 20169 | { | ||
| 20170 | if (BUFFERP (g->object) | ||
| 20171 | /* Empty lines have only one glyph, which stands | ||
| 20172 | for the newline, and whose charpos is the | ||
| 20173 | buffer position of the newline. */ | ||
| 20174 | || ROW_GLYPH_NEWLINE_P (row, g) | ||
| 20175 | /* When the buffer ends in a newline, the line at | ||
| 20176 | EOB also has one glyph, but its charpos is -1. */ | ||
| 20177 | || (row->ends_at_zv_p | ||
| 20178 | && !row->reversed_p | ||
| 20179 | && INTEGERP (g->object) | ||
| 20180 | && g->type == CHAR_GLYPH | ||
| 20181 | && g->u.ch == ' ')) | ||
| 20182 | { | ||
| 20183 | if (g->charpos > 0) | ||
| 20184 | SET_PT (g->charpos); | ||
| 20185 | else if (!row->reversed_p | ||
| 20186 | && row->ends_at_zv_p | ||
| 20187 | && PT != ZV) | ||
| 20188 | SET_PT (ZV); | ||
| 20189 | else | ||
| 20190 | continue; | ||
| 20191 | return make_number (PT); | ||
| 20192 | } | ||
| 20193 | } | ||
| 20194 | } | ||
| 20195 | else | ||
| 20196 | { | ||
| 20197 | if (!row->reversed_p && !row->continued_p) | ||
| 20198 | { | ||
| 20199 | SET_PT (MATRIX_ROW_END_CHARPOS (row) - 1); | ||
| 20200 | return make_number (PT); | ||
| 20201 | } | ||
| 20202 | e = row->glyphs[TEXT_AREA]; | ||
| 20203 | g = e + row->used[TEXT_AREA] - 1; | ||
| 20204 | for ( ; g >= e; g--) | ||
| 20205 | { | ||
| 20206 | if (BUFFERP (g->object) | ||
| 20207 | || (ROW_GLYPH_NEWLINE_P (row, g) | ||
| 20208 | && g->charpos > 0) | ||
| 20209 | /* Empty R2L lines on GUI frames have the buffer | ||
| 20210 | position of the newline stored in the stretch | ||
| 20211 | glyph. */ | ||
| 20212 | || g->type == STRETCH_GLYPH | ||
| 20213 | || (row->ends_at_zv_p | ||
| 20214 | && row->reversed_p | ||
| 20215 | && INTEGERP (g->object) | ||
| 20216 | && g->type == CHAR_GLYPH | ||
| 20217 | && g->u.ch == ' ')) | ||
| 20218 | { | ||
| 20219 | if (g->charpos > 0) | ||
| 20220 | SET_PT (g->charpos); | ||
| 20221 | else if (row->reversed_p | ||
| 20222 | && row->ends_at_zv_p | ||
| 20223 | && PT != ZV) | ||
| 20224 | SET_PT (ZV); | ||
| 20225 | else | ||
| 20226 | continue; | ||
| 20227 | return make_number (PT); | ||
| 20228 | } | ||
| 20229 | } | ||
| 20230 | } | ||
| 20231 | } | ||
| 20232 | } | ||
| 20233 | |||
| 20234 | simulate_display: | ||
| 20235 | |||
| 20236 | /* If we wind up here, we failed to move by using the glyphs, so we | ||
| 20237 | need to simulate display instead. */ | ||
| 20238 | |||
| 20239 | if (b) | ||
| 20240 | paragraph_dir = Fcurrent_bidi_paragraph_direction (w->contents); | ||
| 20241 | else | ||
| 20242 | paragraph_dir = Qleft_to_right; | ||
| 20243 | if (EQ (paragraph_dir, Qright_to_left)) | ||
| 20244 | dir = -dir; | ||
| 20245 | if (PT <= BEGV && dir < 0) | ||
| 20246 | xsignal0 (Qbeginning_of_buffer); | ||
| 20247 | else if (PT >= ZV && dir > 0) | ||
| 20248 | xsignal0 (Qend_of_buffer); | ||
| 20249 | else | ||
| 20250 | { | ||
| 20251 | struct text_pos pt; | ||
| 20252 | struct it it; | ||
| 20253 | int pt_x, target_x, pixel_width, pt_vpos; | ||
| 20254 | bool at_eol_p; | ||
| 20255 | bool disp_string_at_start_p = 0; | ||
| 20256 | bool overshoot_expected = false; | ||
| 20257 | bool target_is_eol_p = false; | ||
| 20258 | |||
| 20259 | /* Setup the arena. */ | ||
| 20260 | SET_TEXT_POS (pt, PT, PT_BYTE); | ||
| 20261 | start_display (&it, w, pt); | ||
| 20262 | |||
| 20263 | if (it.cmp_it.id < 0 | ||
| 20264 | && it.method == GET_FROM_STRING | ||
| 20265 | && it.area == TEXT_AREA | ||
| 20266 | && it.string_from_display_prop_p | ||
| 20267 | && (it.sp > 0 && it.stack[it.sp - 1].method == GET_FROM_BUFFER)) | ||
| 20268 | overshoot_expected = true; | ||
| 20269 | |||
| 20270 | /* Find the X coordinate of point. We start from the beginning | ||
| 20271 | of this or previous line to make sure we are before point in | ||
| 20272 | the logical order (since the move_it_* functions can only | ||
| 20273 | move forward). */ | ||
| 20274 | reseat_at_previous_visible_line_start (&it); | ||
| 20275 | it.current_x = it.hpos = it.current_y = it.vpos = 0; | ||
| 20276 | if (IT_CHARPOS (it) != PT) | ||
| 20277 | move_it_to (&it, overshoot_expected ? PT - 1 : PT, | ||
| 20278 | -1, -1, -1, MOVE_TO_POS); | ||
| 20279 | pt_x = it.current_x; | ||
| 20280 | pt_vpos = it.vpos; | ||
| 20281 | if (dir > 0 || overshoot_expected) | ||
| 20282 | { | ||
| 20283 | struct glyph_row *row = it.glyph_row; | ||
| 20284 | |||
| 20285 | /* When point is at beginning of line, we don't have | ||
| 20286 | information about the glyph there loaded into struct | ||
| 20287 | it. Calling get_next_display_element fixes that. */ | ||
| 20288 | if (pt_x == 0) | ||
| 20289 | get_next_display_element (&it); | ||
| 20290 | at_eol_p = ITERATOR_AT_END_OF_LINE_P (&it); | ||
| 20291 | it.glyph_row = NULL; | ||
| 20292 | PRODUCE_GLYPHS (&it); /* compute it.pixel_width */ | ||
| 20293 | it.glyph_row = row; | ||
| 20294 | /* PRODUCE_GLYPHS advances it.current_x, so we must restore | ||
| 20295 | it, lest it will become out of sync with it's buffer | ||
| 20296 | position. */ | ||
| 20297 | it.current_x = pt_x; | ||
| 20298 | } | ||
| 20299 | else | ||
| 20300 | at_eol_p = ITERATOR_AT_END_OF_LINE_P (&it); | ||
| 20301 | pixel_width = it.pixel_width; | ||
| 20302 | if (overshoot_expected && at_eol_p) | ||
| 20303 | pixel_width = 0; | ||
| 20304 | else if (pixel_width <= 0) | ||
| 20305 | pixel_width = 1; | ||
| 20306 | |||
| 20307 | /* If there's a display string at point, we are actually at the | ||
| 20308 | glyph to the left of point, so we need to correct the X | ||
| 20309 | coordinate. */ | ||
| 20310 | if (overshoot_expected) | ||
| 20311 | pt_x += pixel_width; | ||
| 20312 | |||
| 20313 | /* Compute target X coordinate, either to the left or to the | ||
| 20314 | right of point. On TTY frames, all characters have the same | ||
| 20315 | pixel width of 1, so we can use that. On GUI frames we don't | ||
| 20316 | have an easy way of getting at the pixel width of the | ||
| 20317 | character to the left of point, so we use a different method | ||
| 20318 | of getting to that place. */ | ||
| 20319 | if (dir > 0) | ||
| 20320 | target_x = pt_x + pixel_width; | ||
| 20321 | else | ||
| 20322 | target_x = pt_x - (!FRAME_WINDOW_P (it.f)) * pixel_width; | ||
| 20323 | |||
| 20324 | /* Target X coordinate could be one line above or below the line | ||
| 20325 | of point, in which case we need to adjust the target X | ||
| 20326 | coordinate. Also, if moving to the left, we need to begin at | ||
| 20327 | the left edge of the point's screen line. */ | ||
| 20328 | if (dir < 0) | ||
| 20329 | { | ||
| 20330 | if (pt_x > 0) | ||
| 20331 | { | ||
| 20332 | start_display (&it, w, pt); | ||
| 20333 | reseat_at_previous_visible_line_start (&it); | ||
| 20334 | it.current_x = it.current_y = it.hpos = 0; | ||
| 20335 | if (pt_vpos != 0) | ||
| 20336 | move_it_by_lines (&it, pt_vpos); | ||
| 20337 | } | ||
| 20338 | else | ||
| 20339 | { | ||
| 20340 | move_it_by_lines (&it, -1); | ||
| 20341 | target_x = it.last_visible_x - !FRAME_WINDOW_P (it.f); | ||
| 20342 | target_is_eol_p = true; | ||
| 20343 | } | ||
| 20344 | } | ||
| 20345 | else | ||
| 20346 | { | ||
| 20347 | if (at_eol_p | ||
| 20348 | || (target_x >= it.last_visible_x | ||
| 20349 | && it.line_wrap != TRUNCATE)) | ||
| 20350 | { | ||
| 20351 | if (pt_x > 0) | ||
| 20352 | move_it_by_lines (&it, 0); | ||
| 20353 | move_it_by_lines (&it, 1); | ||
| 20354 | target_x = 0; | ||
| 20355 | } | ||
| 20356 | } | ||
| 20357 | |||
| 20358 | /* Move to the target X coordinate. */ | ||
| 20359 | #ifdef HAVE_WINDOW_SYSTEM | ||
| 20360 | /* On GUI frames, as we don't know the X coordinate of the | ||
| 20361 | character to the left of point, moving point to the left | ||
| 20362 | requires walking, one grapheme cluster at a time, until we | ||
| 20363 | find ourself at a place immediately to the left of the | ||
| 20364 | character at point. */ | ||
| 20365 | if (FRAME_WINDOW_P (it.f) && dir < 0) | ||
| 20366 | { | ||
| 20367 | struct text_pos new_pos = it.current.pos; | ||
| 20368 | enum move_it_result rc = MOVE_X_REACHED; | ||
| 20369 | |||
| 20370 | while (it.current_x + it.pixel_width <= target_x | ||
| 20371 | && rc == MOVE_X_REACHED) | ||
| 20372 | { | ||
| 20373 | int new_x = it.current_x + it.pixel_width; | ||
| 20374 | |||
| 20375 | new_pos = it.current.pos; | ||
| 20376 | if (new_x == it.current_x) | ||
| 20377 | new_x++; | ||
| 20378 | rc = move_it_in_display_line_to (&it, ZV, new_x, | ||
| 20379 | MOVE_TO_POS | MOVE_TO_X); | ||
| 20380 | if (ITERATOR_AT_END_OF_LINE_P (&it) && !target_is_eol_p) | ||
| 20381 | break; | ||
| 20382 | } | ||
| 20383 | /* If we ended up on a composed character inside | ||
| 20384 | bidi-reordered text (e.g., Hebrew text with diacriticals), | ||
| 20385 | the iterator gives us the buffer position of the last (in | ||
| 20386 | logical order) character of the composed grapheme cluster, | ||
| 20387 | which is not what we want. So we cheat: we compute the | ||
| 20388 | character position of the character that follows (in the | ||
| 20389 | logical order) the one where the above loop stopped. That | ||
| 20390 | character will appear on display to the left of point. */ | ||
| 20391 | if (it.bidi_p | ||
| 20392 | && it.bidi_it.scan_dir == -1 | ||
| 20393 | && new_pos.charpos - IT_CHARPOS (it) > 1) | ||
| 20394 | { | ||
| 20395 | new_pos.charpos = IT_CHARPOS (it) + 1; | ||
| 20396 | new_pos.bytepos = CHAR_TO_BYTE (new_pos.charpos); | ||
| 20397 | } | ||
| 20398 | it.current.pos = new_pos; | ||
| 20399 | } | ||
| 20400 | else | ||
| 20401 | #endif | ||
| 20402 | if (it.current_x != target_x) | ||
| 20403 | move_it_in_display_line_to (&it, ZV, target_x, MOVE_TO_POS | MOVE_TO_X); | ||
| 20404 | |||
| 20405 | /* When lines are truncated, the above loop will stop at the | ||
| 20406 | window edge. But we want to get to the end of line, even if | ||
| 20407 | it is beyond the window edge; automatic hscroll will then | ||
| 20408 | scroll the window to show point as appropriate. */ | ||
| 20409 | if (target_is_eol_p && it.line_wrap == TRUNCATE | ||
| 20410 | && get_next_display_element (&it)) | ||
| 20411 | { | ||
| 20412 | struct text_pos new_pos = it.current.pos; | ||
| 20413 | |||
| 20414 | while (!ITERATOR_AT_END_OF_LINE_P (&it)) | ||
| 20415 | { | ||
| 20416 | set_iterator_to_next (&it, 0); | ||
| 20417 | if (it.method == GET_FROM_BUFFER) | ||
| 20418 | new_pos = it.current.pos; | ||
| 20419 | if (!get_next_display_element (&it)) | ||
| 20420 | break; | ||
| 20421 | } | ||
| 20422 | |||
| 20423 | it.current.pos = new_pos; | ||
| 20424 | } | ||
| 20425 | |||
| 20426 | /* If we ended up in a display string that covers point, move to | ||
| 20427 | buffer position to the right in the visual order. */ | ||
| 20428 | if (dir > 0) | ||
| 20429 | { | ||
| 20430 | while (IT_CHARPOS (it) == PT) | ||
| 20431 | { | ||
| 20432 | set_iterator_to_next (&it, 0); | ||
| 20433 | if (!get_next_display_element (&it)) | ||
| 20434 | break; | ||
| 20435 | } | ||
| 20436 | } | ||
| 20437 | |||
| 20438 | /* Move point to that position. */ | ||
| 20439 | SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it)); | ||
| 20440 | } | ||
| 20441 | |||
| 20442 | return make_number (PT); | ||
| 20443 | |||
| 20444 | #undef ROW_GLYPH_NEWLINE_P | ||
| 20445 | } | ||
| 20054 | 20446 | ||
| 20055 | 20447 | ||
| 20056 | /*********************************************************************** | 20448 | /*********************************************************************** |
| @@ -28713,6 +29105,7 @@ syms_of_xdisp (void) | |||
| 28713 | defsubr (&Sformat_mode_line); | 29105 | defsubr (&Sformat_mode_line); |
| 28714 | defsubr (&Sinvisible_p); | 29106 | defsubr (&Sinvisible_p); |
| 28715 | defsubr (&Scurrent_bidi_paragraph_direction); | 29107 | defsubr (&Scurrent_bidi_paragraph_direction); |
| 29108 | defsubr (&Smove_point_visually); | ||
| 28716 | 29109 | ||
| 28717 | DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook"); | 29110 | DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook"); |
| 28718 | DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map"); | 29111 | DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map"); |