aboutsummaryrefslogtreecommitdiffstats
path: root/src/cmds.c
diff options
context:
space:
mode:
authorJoakim Verona2012-05-30 14:08:12 +0200
committerJoakim Verona2012-05-30 14:08:12 +0200
commit70700d8c47a35b19e29607ac5f0ed322bdd78249 (patch)
tree4fa00d3fac00025354f0b6e23dcda1b58689a094 /src/cmds.c
parent44fce8ffe7198991c41c985ff4e67ec7d407907e (diff)
parent72cb32cf2f0938dd7dc733eed77b1ed1e497b053 (diff)
downloademacs-70700d8c47a35b19e29607ac5f0ed322bdd78249.tar.gz
emacs-70700d8c47a35b19e29607ac5f0ed322bdd78249.zip
upstream
Diffstat (limited to 'src/cmds.c')
-rw-r--r--src/cmds.c155
1 files changed, 80 insertions, 75 deletions
diff --git a/src/cmds.c b/src/cmds.c
index a020a447eb1..225c26b082c 100644
--- a/src/cmds.c
+++ b/src/cmds.c
@@ -47,6 +47,41 @@ DEFUN ("forward-point", Fforward_point, Sforward_point, 1, 1, 0,
47 return make_number (PT + XINT (n)); 47 return make_number (PT + XINT (n));
48} 48}
49 49
50/* Add N to point; or subtract N if FORWARD is zero. N defaults to 1.
51 Validate the new location. Return nil. */
52static Lisp_Object
53move_point (Lisp_Object n, int forward)
54{
55 /* This used to just set point to point + XINT (n), and then check
56 to see if it was within boundaries. But now that SET_PT can
57 potentially do a lot of stuff (calling entering and exiting
58 hooks, etcetera), that's not a good approach. So we validate the
59 proposed position, then set point. */
60
61 EMACS_INT new_point;
62
63 if (NILP (n))
64 XSETFASTINT (n, 1);
65 else
66 CHECK_NUMBER (n);
67
68 new_point = PT + (forward ? XINT (n) : - XINT (n));
69
70 if (new_point < BEGV)
71 {
72 SET_PT (BEGV);
73 xsignal0 (Qbeginning_of_buffer);
74 }
75 if (new_point > ZV)
76 {
77 SET_PT (ZV);
78 xsignal0 (Qend_of_buffer);
79 }
80
81 SET_PT (new_point);
82 return Qnil;
83}
84
50DEFUN ("forward-char", Fforward_char, Sforward_char, 0, 1, "^p", 85DEFUN ("forward-char", Fforward_char, Sforward_char, 0, 1, "^p",
51 doc: /* Move point N characters forward (backward if N is negative). 86 doc: /* Move point N characters forward (backward if N is negative).
52On reaching end or beginning of buffer, stop and signal error. 87On reaching end or beginning of buffer, stop and signal error.
@@ -56,34 +91,7 @@ right or to the left on the screen. This is in contrast with
56\\[right-char], which see. */) 91\\[right-char], which see. */)
57 (Lisp_Object n) 92 (Lisp_Object n)
58{ 93{
59 if (NILP (n)) 94 return move_point (n, 1);
60 XSETFASTINT (n, 1);
61 else
62 CHECK_NUMBER (n);
63
64 /* This used to just set point to point + XINT (n), and then check
65 to see if it was within boundaries. But now that SET_PT can
66 potentially do a lot of stuff (calling entering and exiting
67 hooks, etcetera), that's not a good approach. So we validate the
68 proposed position, then set point. */
69 {
70 EMACS_INT new_point = PT + XINT (n);
71
72 if (new_point < BEGV)
73 {
74 SET_PT (BEGV);
75 xsignal0 (Qbeginning_of_buffer);
76 }
77 if (new_point > ZV)
78 {
79 SET_PT (ZV);
80 xsignal0 (Qend_of_buffer);
81 }
82
83 SET_PT (new_point);
84 }
85
86 return Qnil;
87} 95}
88 96
89DEFUN ("backward-char", Fbackward_char, Sbackward_char, 0, 1, "^p", 97DEFUN ("backward-char", Fbackward_char, Sbackward_char, 0, 1, "^p",
@@ -95,13 +103,7 @@ right or to the left on the screen. This is in contrast with
95\\[left-char], which see. */) 103\\[left-char], which see. */)
96 (Lisp_Object n) 104 (Lisp_Object n)
97{ 105{
98 if (NILP (n)) 106 return move_point (n, 0);
99 XSETFASTINT (n, 1);
100 else
101 CHECK_NUMBER (n);
102
103 XSETINT (n, - XINT (n));
104 return Fforward_char (n);
105} 107}
106 108
107DEFUN ("forward-line", Fforward_line, Sforward_line, 0, 1, "^p", 109DEFUN ("forward-line", Fforward_line, Sforward_line, 0, 1, "^p",
@@ -115,8 +117,8 @@ With positive N, a non-empty line at the end counts as one line
115successfully moved (for the return value). */) 117successfully moved (for the return value). */)
116 (Lisp_Object n) 118 (Lisp_Object n)
117{ 119{
118 EMACS_INT opoint = PT, opoint_byte = PT_BYTE; 120 ptrdiff_t opoint = PT, opoint_byte = PT_BYTE;
119 EMACS_INT pos, pos_byte; 121 ptrdiff_t pos, pos_byte;
120 EMACS_INT count, shortage; 122 EMACS_INT count, shortage;
121 123
122 if (NILP (n)) 124 if (NILP (n))
@@ -187,7 +189,7 @@ not move. To ignore field boundaries bind `inhibit-field-text-motion'
187to t. */) 189to t. */)
188 (Lisp_Object n) 190 (Lisp_Object n)
189{ 191{
190 EMACS_INT newpos; 192 ptrdiff_t newpos;
191 193
192 if (NILP (n)) 194 if (NILP (n))
193 XSETFASTINT (n, 1); 195 XSETFASTINT (n, 1);
@@ -303,7 +305,7 @@ At the end, it runs `post-self-insert-hook'. */)
303 bitch_at_user (); 305 bitch_at_user ();
304 { 306 {
305 int character = translate_char (Vtranslation_table_for_input, 307 int character = translate_char (Vtranslation_table_for_input,
306 (int) XINT (last_command_event)); 308 XINT (last_command_event));
307 int val = internal_self_insert (character, XFASTINT (n)); 309 int val = internal_self_insert (character, XFASTINT (n));
308 if (val == 2) 310 if (val == 2)
309 nonundocount = 0; 311 nonundocount = 0;
@@ -333,8 +335,8 @@ internal_self_insert (int c, EMACS_INT n)
333 int len; 335 int len;
334 /* Working buffer and pointer for multi-byte form of C. */ 336 /* Working buffer and pointer for multi-byte form of C. */
335 unsigned char str[MAX_MULTIBYTE_LENGTH]; 337 unsigned char str[MAX_MULTIBYTE_LENGTH];
336 EMACS_INT chars_to_delete = 0; 338 ptrdiff_t chars_to_delete = 0;
337 EMACS_INT spaces_to_insert = 0; 339 ptrdiff_t spaces_to_insert = 0;
338 340
339 overwrite = BVAR (current_buffer, overwrite_mode); 341 overwrite = BVAR (current_buffer, overwrite_mode);
340 if (!NILP (Vbefore_change_functions) || !NILP (Vafter_change_functions)) 342 if (!NILP (Vbefore_change_functions) || !NILP (Vafter_change_functions))
@@ -371,50 +373,53 @@ internal_self_insert (int c, EMACS_INT n)
371 /* This is the character after point. */ 373 /* This is the character after point. */
372 int c2 = FETCH_CHAR (PT_BYTE); 374 int c2 = FETCH_CHAR (PT_BYTE);
373 375
376 int cwidth;
377
374 /* Overwriting in binary-mode always replaces C2 by C. 378 /* Overwriting in binary-mode always replaces C2 by C.
375 Overwriting in textual-mode doesn't always do that. 379 Overwriting in textual-mode doesn't always do that.
376 It inserts newlines in the usual way, 380 It inserts newlines in the usual way,
377 and inserts any character at end of line 381 and inserts any character at end of line
378 or before a tab if it doesn't use the whole width of the tab. */ 382 or before a tab if it doesn't use the whole width of the tab. */
379 if (EQ (overwrite, Qoverwrite_mode_binary)) 383 if (EQ (overwrite, Qoverwrite_mode_binary))
380 chars_to_delete = n; 384 chars_to_delete = min (n, PTRDIFF_MAX);
381 else if (c != '\n' && c2 != '\n') 385 else if (c != '\n' && c2 != '\n'
386 && (cwidth = XFASTINT (Fchar_width (make_number (c)))) != 0)
382 { 387 {
383 EMACS_INT pos = PT; 388 ptrdiff_t pos = PT;
384 EMACS_INT pos_byte = PT_BYTE; 389 ptrdiff_t pos_byte = PT_BYTE;
390 ptrdiff_t curcol = current_column ();
385 391
386 /* FIXME: Check for integer overflow when calculating 392 if (n <= (min (MOST_POSITIVE_FIXNUM, PTRDIFF_MAX) - curcol) / cwidth)
387 target_clm and actual_clm. */
388
389 /* Column the cursor should be placed at after this insertion.
390 The correct value should be calculated only when necessary. */
391 EMACS_INT target_clm = (current_column ()
392 + n * XINT (Fchar_width (make_number (c))));
393
394 /* The actual cursor position after the trial of moving
395 to column TARGET_CLM. It is greater than TARGET_CLM
396 if the TARGET_CLM is middle of multi-column
397 character. In that case, the new point is set after
398 that character. */
399 EMACS_INT actual_clm
400 = XFASTINT (Fmove_to_column (make_number (target_clm), Qnil));
401
402 chars_to_delete = PT - pos;
403
404 if (actual_clm > target_clm)
405 { 393 {
406 /* We will delete too many columns. Let's fill columns 394 /* Column the cursor should be placed at after this insertion.
407 by spaces so that the remaining text won't move. */ 395 The value should be calculated only when necessary. */
408 EMACS_INT actual = PT_BYTE; 396 ptrdiff_t target_clm = curcol + n * cwidth;
409 DEC_POS (actual); 397
410 if (FETCH_CHAR (actual) == '\t') 398 /* The actual cursor position after the trial of moving
411 /* Rather than add spaces, let's just keep the tab. */ 399 to column TARGET_CLM. It is greater than TARGET_CLM
412 chars_to_delete--; 400 if the TARGET_CLM is middle of multi-column
413 else 401 character. In that case, the new point is set after
414 spaces_to_insert = actual_clm - target_clm; 402 that character. */
403 ptrdiff_t actual_clm
404 = XFASTINT (Fmove_to_column (make_number (target_clm), Qnil));
405
406 chars_to_delete = PT - pos;
407
408 if (actual_clm > target_clm)
409 {
410 /* We will delete too many columns. Let's fill columns
411 by spaces so that the remaining text won't move. */
412 ptrdiff_t actual = PT_BYTE;
413 DEC_POS (actual);
414 if (FETCH_CHAR (actual) == '\t')
415 /* Rather than add spaces, let's just keep the tab. */
416 chars_to_delete--;
417 else
418 spaces_to_insert = actual_clm - target_clm;
419 }
420
421 SET_PT_BOTH (pos, pos_byte);
415 } 422 }
416
417 SET_PT_BOTH (pos, pos_byte);
418 } 423 }
419 hairy = 2; 424 hairy = 2;
420 } 425 }