aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2013-06-29 16:36:19 +0300
committerEli Zaretskii2013-06-29 16:36:19 +0300
commit4c672a0fec1d18cc1a445acf3e6935d681d4048f (patch)
treec8fb2626c93a226bed5eaa0b92f95925734e893f /src
parent73b1b3ad6196234984a29298bc66eabf1299de66 (diff)
downloademacs-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.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog4
-rw-r--r--src/xdisp.c393
2 files changed, 397 insertions, 0 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index b279f42e6b6..1e1b54a72d0 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,7 @@
12013-06-29 Eli Zaretskii <eliz@gnu.org>
2
3 * xdisp.c (Fmove_point_visually): New function.
4
12013-06-28 Kenichi Handa <handa@gnu.org> 52013-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
20054DEFUN ("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.
20057DIRECTION can be 1, meaning move to the right, or -1, which moves to the
20058left.
20059
20060Value 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");