diff options
| author | Joakim Verona | 2012-05-30 14:08:12 +0200 |
|---|---|---|
| committer | Joakim Verona | 2012-05-30 14:08:12 +0200 |
| commit | 70700d8c47a35b19e29607ac5f0ed322bdd78249 (patch) | |
| tree | 4fa00d3fac00025354f0b6e23dcda1b58689a094 /src/cmds.c | |
| parent | 44fce8ffe7198991c41c985ff4e67ec7d407907e (diff) | |
| parent | 72cb32cf2f0938dd7dc733eed77b1ed1e497b053 (diff) | |
| download | emacs-70700d8c47a35b19e29607ac5f0ed322bdd78249.tar.gz emacs-70700d8c47a35b19e29607ac5f0ed322bdd78249.zip | |
upstream
Diffstat (limited to 'src/cmds.c')
| -rw-r--r-- | src/cmds.c | 155 |
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. */ | ||
| 52 | static Lisp_Object | ||
| 53 | move_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 | |||
| 50 | DEFUN ("forward-char", Fforward_char, Sforward_char, 0, 1, "^p", | 85 | DEFUN ("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). |
| 52 | On reaching end or beginning of buffer, stop and signal error. | 87 | On 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 | ||
| 89 | DEFUN ("backward-char", Fbackward_char, Sbackward_char, 0, 1, "^p", | 97 | DEFUN ("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 | ||
| 107 | DEFUN ("forward-line", Fforward_line, Sforward_line, 0, 1, "^p", | 109 | DEFUN ("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 | |||
| 115 | successfully moved (for the return value). */) | 117 | successfully 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' | |||
| 187 | to t. */) | 189 | to 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 | } |