1 /* Simple built-in editing commands.
2 
3 Copyright (C) 1985, 1993-1998, 2001-2021 Free Software Foundation, Inc.
4 
5 This file is part of GNU Emacs.
6 
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or (at
10 your option) any later version.
11 
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
19 
20 
21 #include <config.h>
22 
23 #include "lisp.h"
24 #include "commands.h"
25 #include "character.h"
26 #include "buffer.h"
27 #include "syntax.h"
28 #include "keyboard.h"
29 #include "keymap.h"
30 #include "frame.h"
31 
32 static int internal_self_insert (int, EMACS_INT);
33 
34 DEFUN ("forward-point", Fforward_point, Sforward_point, 1, 1, 0,
35        doc: /* Return buffer position N characters after (before if N negative) point.  */)
36   (Lisp_Object n)
37 {
38   CHECK_FIXNUM (n);
39 
40   return make_fixnum (PT + XFIXNUM (n));
41 }
42 
43 /* Add N to point; or subtract N if FORWARD is false.  N defaults to 1.
44    Validate the new location.  Return nil.  */
45 static Lisp_Object
move_point(Lisp_Object n,bool forward)46 move_point (Lisp_Object n, bool forward)
47 {
48   /* This used to just set point to point + XFIXNUM (n), and then check
49      to see if it was within boundaries.  But now that SET_PT can
50      potentially do a lot of stuff (calling entering and exiting
51      hooks, etcetera), that's not a good approach.  So we validate the
52      proposed position, then set point.  */
53 
54   EMACS_INT new_point;
55 
56   if (NILP (n))
57     XSETFASTINT (n, 1);
58   else
59     CHECK_FIXNUM (n);
60 
61   new_point = PT + (forward ? XFIXNUM (n) : - XFIXNUM (n));
62 
63   if (new_point < BEGV)
64     {
65       SET_PT (BEGV);
66       xsignal0 (Qbeginning_of_buffer);
67     }
68   if (new_point > ZV)
69     {
70       SET_PT (ZV);
71       xsignal0 (Qend_of_buffer);
72     }
73 
74   SET_PT (new_point);
75   return Qnil;
76 }
77 
78 DEFUN ("forward-char", Fforward_char, Sforward_char, 0, 1, "^p",
79        doc: /* Move point N characters forward (backward if N is negative).
80 On reaching end or beginning of buffer, stop and signal error.
81 Interactively, N is the numeric prefix argument.
82 If N is omitted or nil, move point 1 character forward.
83 
84 Depending on the bidirectional context, the movement may be to the
85 right or to the left on the screen.  This is in contrast with
86 \\[right-char], which see.  */)
87   (Lisp_Object n)
88 {
89   return move_point (n, 1);
90 }
91 
92 DEFUN ("backward-char", Fbackward_char, Sbackward_char, 0, 1, "^p",
93        doc: /* Move point N characters backward (forward if N is negative).
94 On attempt to pass beginning or end of buffer, stop and signal error.
95 Interactively, N is the numeric prefix argument.
96 If N is omitted or nil, move point 1 character backward.
97 
98 Depending on the bidirectional context, the movement may be to the
99 right or to the left on the screen.  This is in contrast with
100 \\[left-char], which see.  */)
101   (Lisp_Object n)
102 {
103   return move_point (n, 0);
104 }
105 
106 DEFUN ("forward-line", Fforward_line, Sforward_line, 0, 1, "^p",
107        doc: /* Move N lines forward (backward if N is negative).
108 Precisely, if point is on line I, move to the start of line I + N
109 \("start of line" in the logical order).
110 If there isn't room, go as far as possible (no error).
111 Interactively, N is the numeric prefix argument and defaults to 1.
112 
113 Returns the count of lines left to move.  If moving forward,
114 that is N minus number of lines moved; if backward, N plus number
115 moved.
116 
117 Exception: With positive N, a non-empty line at the end of the
118 buffer, or of its accessible portion, counts as one line
119 successfully moved (for the return value).  This means that the
120 function will move point to the end of such a line and will count
121 it as a line moved across, even though there is no next line to
122 go to its beginning.  */)
123   (Lisp_Object n)
124 {
125   ptrdiff_t opoint = PT, pos, pos_byte, count;
126   bool excessive = false;
127 
128   if (NILP (n))
129     count = 1;
130   else
131     {
132       CHECK_INTEGER (n);
133       if (FIXNUMP (n)
134 	  && -BUF_BYTES_MAX <= XFIXNUM (n) && XFIXNUM (n) <= BUF_BYTES_MAX)
135 	count = XFIXNUM (n);
136       else
137 	{
138 	  count = !NILP (Fnatnump (n)) ? BUF_BYTES_MAX : -BUF_BYTES_MAX;
139 	  excessive = true;
140 	}
141     }
142 
143   ptrdiff_t counted = scan_newline_from_point (count, &pos, &pos_byte);
144 
145   SET_PT_BOTH (pos, pos_byte);
146 
147   ptrdiff_t shortage = count - (count <= 0) - counted;
148   if (shortage != 0)
149     shortage -= (count <= 0 ? -1
150 		  : (BEGV < ZV && PT != opoint
151 		     && FETCH_BYTE (PT_BYTE - 1) != '\n'));
152   return (excessive
153 	  ? CALLN (Fplus, make_fixnum (shortage - count), n)
154 	  : make_fixnum (shortage));
155 }
156 
157 DEFUN ("beginning-of-line", Fbeginning_of_line, Sbeginning_of_line, 0, 1, "^p",
158        doc: /* Move point to beginning of current line (in the logical order).
159 With argument N not nil or 1, move forward N - 1 lines first.
160 If point reaches the beginning or end of buffer, it stops there.
161 
162 This function constrains point to the current field unless this moves
163 point to a different line from the original, unconstrained result.
164 If N is nil or 1, and a front-sticky field starts at point, the point
165 does not move.  To ignore field boundaries bind
166 `inhibit-field-text-motion' to t, or use the `forward-line' function
167 instead.  For instance, `(forward-line 0)' does the same thing as
168 `(beginning-of-line)', except that it ignores field boundaries.  */)
169   (Lisp_Object n)
170 {
171   if (NILP (n))
172     XSETFASTINT (n, 1);
173   else
174     CHECK_FIXNUM (n);
175 
176   SET_PT (XFIXNUM (Fline_beginning_position (n)));
177 
178   return Qnil;
179 }
180 
181 DEFUN ("end-of-line", Fend_of_line, Send_of_line, 0, 1, "^p",
182        doc: /* Move point to end of current line (in the logical order).
183 With argument N not nil or 1, move forward N - 1 lines first.
184 If point reaches the beginning or end of buffer, it stops there.
185 To ignore intangibility, bind `inhibit-point-motion-hooks' to t.
186 
187 This function constrains point to the current field unless this moves
188 point to a different line from the original, unconstrained result.  If
189 N is nil or 1, and a rear-sticky field ends at point, the point does
190 not move.  To ignore field boundaries bind `inhibit-field-text-motion'
191 to t.  */)
192   (Lisp_Object n)
193 {
194   ptrdiff_t newpos;
195 
196   if (NILP (n))
197     XSETFASTINT (n, 1);
198   else
199     CHECK_FIXNUM (n);
200 
201   while (1)
202     {
203       newpos = XFIXNUM (Fline_end_position (n));
204       SET_PT (newpos);
205 
206       if (PT > newpos
207 	  && FETCH_BYTE (PT_BYTE - 1) == '\n')
208 	{
209 	  /* If we skipped over a newline that follows
210 	     an invisible intangible run,
211 	     move back to the last tangible position
212 	     within the line.  */
213 
214 	  SET_PT (PT - 1);
215 	  break;
216 	}
217       else if (PT > newpos && PT < ZV
218 	       && FETCH_BYTE (PT_BYTE) != '\n')
219 	/* If we skipped something intangible
220 	   and now we're not really at eol,
221 	   keep going.  */
222 	n = make_fixnum (1);
223       else
224 	break;
225     }
226 
227   return Qnil;
228 }
229 
230 DEFUN ("delete-char", Fdelete_char, Sdelete_char, 1, 2, "p\nP",
231        doc: /* Delete the following N characters (previous if N is negative).
232 Optional second arg KILLFLAG non-nil means kill instead (save in kill ring).
233 Interactively, N is the prefix arg, and KILLFLAG is set if
234 N was explicitly specified.
235 
236 The command `delete-forward-char' is preferable for interactive use, e.g.
237 because it respects values of `delete-active-region' and `overwrite-mode'.  */)
238   (Lisp_Object n, Lisp_Object killflag)
239 {
240   EMACS_INT pos;
241 
242   CHECK_FIXNUM (n);
243 
244   if (eabs (XFIXNUM (n)) < 2)
245     call0 (Qundo_auto_amalgamate);
246 
247   pos = PT + XFIXNUM (n);
248   if (NILP (killflag))
249     {
250       if (XFIXNUM (n) < 0)
251 	{
252 	  if (pos < BEGV)
253 	    xsignal0 (Qbeginning_of_buffer);
254 	  else
255 	    del_range (pos, PT);
256 	}
257       else
258 	{
259 	  if (pos > ZV)
260 	    xsignal0 (Qend_of_buffer);
261 	  else
262 	    del_range (PT, pos);
263 	}
264     }
265   else
266     {
267       call1 (Qkill_forward_chars, n);
268     }
269   return Qnil;
270 }
271 
272 DEFUN ("self-insert-command", Fself_insert_command, Sself_insert_command, 1, 2,
273        "(list (prefix-numeric-value current-prefix-arg) last-command-event)",
274        doc: /* Insert the character you type.
275 Whichever character C you type to run this command is inserted.
276 The numeric prefix argument N says how many times to repeat the insertion.
277 Before insertion, `expand-abbrev' is executed if the inserted character does
278 not have word syntax and the previous character in the buffer does.
279 After insertion, `internal-auto-fill' is called if
280 `auto-fill-function' is non-nil and if the `auto-fill-chars' table has
281 a non-nil value for the inserted character.  At the end, it runs
282 `post-self-insert-hook'.  */)
283   (Lisp_Object n, Lisp_Object c)
284 {
285   CHECK_FIXNUM (n);
286 
287   /* Backward compatibility.  */
288   if (NILP (c))
289     c = last_command_event;
290 
291   if (XFIXNUM (n) < 0)
292     error ("Negative repetition argument %"pI"d", XFIXNUM (n));
293 
294   if (XFIXNAT (n) < 2)
295     call0 (Qundo_auto_amalgamate);
296 
297   /* Barf if the key that invoked this was not a character.  */
298   if (!CHARACTERP (c))
299     bitch_at_user ();
300   else {
301     int character = translate_char (Vtranslation_table_for_input,
302 				    XFIXNUM (c));
303     int val = internal_self_insert (character, XFIXNAT (n));
304     if (val == 2)
305       Fset (Qundo_auto__this_command_amalgamating, Qnil);
306     frame_make_pointer_invisible (SELECTED_FRAME ());
307   }
308 
309   return Qnil;
310 }
311 
312 /* Insert N times character C
313 
314    If this insertion is suitable for direct output (completely simple),
315    return 0.  A value of 1 indicates this *might* not have been simple.
316    A value of 2 means this did things that call for an undo boundary.  */
317 
318 static int
internal_self_insert(int c,EMACS_INT n)319 internal_self_insert (int c, EMACS_INT n)
320 {
321   int hairy = 0;
322   Lisp_Object tem;
323   register enum syntaxcode synt;
324   Lisp_Object overwrite;
325   /* Length of multi-byte form of C.  */
326   int len;
327   /* Working buffer and pointer for multi-byte form of C.  */
328   unsigned char str[MAX_MULTIBYTE_LENGTH];
329   ptrdiff_t chars_to_delete = 0;
330   ptrdiff_t spaces_to_insert = 0;
331 
332   overwrite = BVAR (current_buffer, overwrite_mode);
333   if (!NILP (Vbefore_change_functions) || !NILP (Vafter_change_functions))
334     hairy = 1;
335 
336   /* At first, get multi-byte form of C in STR.  */
337   if (!NILP (BVAR (current_buffer, enable_multibyte_characters)))
338     {
339       len = CHAR_STRING (c, str);
340       if (len == 1)
341 	/* If C has modifier bits, this makes C an appropriate
342            one-byte char.  */
343 	c = *str;
344     }
345   else
346     {
347       str[0] = SINGLE_BYTE_CHAR_P (c) ? c : CHAR_TO_BYTE8 (c);
348       len = 1;
349     }
350   if (!NILP (overwrite)
351       && PT < ZV)
352     {
353       /* In overwrite-mode, we substitute a character at point (C2,
354 	 hereafter) by C.  For that, we delete C2 in advance.  But,
355 	 just substituting C2 by C may move a remaining text in the
356 	 line to the right or to the left, which is not preferable.
357 	 So we insert more spaces or delete more characters in the
358 	 following cases: if C is narrower than C2, after deleting C2,
359 	 we fill columns with spaces, if C is wider than C2, we delete
360 	 C2 and several characters following C2.  */
361 
362       /* This is the character after point.  */
363       int c2 = FETCH_CHAR (PT_BYTE);
364 
365       int cwidth;
366 
367       /* Overwriting in binary-mode always replaces C2 by C.
368 	 Overwriting in textual-mode doesn't always do that.
369 	 It inserts newlines in the usual way,
370 	 and inserts any character at end of line
371 	 or before a tab if it doesn't use the whole width of the tab.  */
372       if (EQ (overwrite, Qoverwrite_mode_binary))
373 	chars_to_delete = min (n, PTRDIFF_MAX);
374       else if (c != '\n' && c2 != '\n'
375 	       && (cwidth = XFIXNAT (Fchar_width (make_fixnum (c)))) != 0)
376 	{
377 	  ptrdiff_t pos = PT;
378 	  ptrdiff_t pos_byte = PT_BYTE;
379 	  ptrdiff_t curcol = current_column ();
380 
381 	  if (n <= (min (MOST_POSITIVE_FIXNUM, PTRDIFF_MAX) - curcol) / cwidth)
382 	    {
383 	      /* Column the cursor should be placed at after this insertion.
384 		 The value should be calculated only when necessary.  */
385 	      ptrdiff_t target_clm = curcol + n * cwidth;
386 
387 	      /* The actual cursor position after the trial of moving
388 		 to column TARGET_CLM.  It is greater than TARGET_CLM
389 		 if the TARGET_CLM is middle of multi-column
390 		 character.  In that case, the new point is set after
391 		 that character.  */
392 	      ptrdiff_t actual_clm
393 		= XFIXNAT (Fmove_to_column (make_fixnum (target_clm), Qnil));
394 
395 	      chars_to_delete = PT - pos;
396 
397 	      if (actual_clm > target_clm)
398 		{
399 		  /* We will delete too many columns.  Let's fill columns
400 		     by spaces so that the remaining text won't move.  */
401 		  ptrdiff_t actual = PT_BYTE;
402 		  DEC_POS (actual);
403 		  if (FETCH_CHAR (actual) == '\t')
404 		    /* Rather than add spaces, let's just keep the tab. */
405 		    chars_to_delete--;
406 		  else
407 		    spaces_to_insert = actual_clm - target_clm;
408 		}
409 
410 	      SET_PT_BOTH (pos, pos_byte);
411 	    }
412 	}
413       hairy = 2;
414     }
415 
416   synt = SYNTAX (c);
417 
418   if (!NILP (BVAR (current_buffer, abbrev_mode))
419       && synt != Sword
420       && NILP (BVAR (current_buffer, read_only))
421       && PT > BEGV
422       && (SYNTAX (!NILP (BVAR (current_buffer, enable_multibyte_characters))
423 		  ? XFIXNAT (Fprevious_char ())
424 		  : UNIBYTE_TO_CHAR (XFIXNAT (Fprevious_char ())))
425 	  == Sword))
426     {
427       modiff_count modiff = MODIFF;
428       Lisp_Object sym;
429 
430       sym = call0 (Qexpand_abbrev);
431 
432       /* If we expanded an abbrev which has a hook,
433 	 and the hook has a non-nil `no-self-insert' property,
434 	 return right away--don't really self-insert.  */
435       if (SYMBOLP (sym) && ! NILP (sym)
436 	  && ! NILP (XSYMBOL (sym)->u.s.function)
437 	  && SYMBOLP (XSYMBOL (sym)->u.s.function))
438 	{
439 	  Lisp_Object prop;
440 	  prop = Fget (XSYMBOL (sym)->u.s.function, intern ("no-self-insert"));
441 	  if (! NILP (prop))
442 	    return 1;
443 	}
444 
445       if (MODIFF != modiff)
446 	hairy = 2;
447     }
448 
449   if (chars_to_delete)
450     {
451       int mc = ((NILP (BVAR (current_buffer, enable_multibyte_characters))
452 		 && SINGLE_BYTE_CHAR_P (c))
453 		? UNIBYTE_TO_CHAR (c) : c);
454       Lisp_Object string = Fmake_string (make_fixnum (n), make_fixnum (mc),
455 					 Qnil);
456 
457       if (spaces_to_insert)
458 	{
459 	  tem = Fmake_string (make_fixnum (spaces_to_insert),
460 			      make_fixnum (' '), Qnil);
461 	  string = concat2 (string, tem);
462 	}
463 
464       replace_range (PT, PT + chars_to_delete, string, 1, 1, 1, 0);
465       Fforward_char (make_fixnum (n));
466     }
467   else if (n > 1)
468     {
469       USE_SAFE_ALLOCA;
470       char *strn, *p;
471       SAFE_NALLOCA (strn, len, n);
472       for (p = strn; n > 0; n--, p += len)
473 	memcpy (p, str, len);
474       insert_and_inherit (strn, p - strn);
475       SAFE_FREE ();
476     }
477   else if (n > 0)
478     insert_and_inherit ((char *) str, len);
479 
480   if ((CHAR_TABLE_P (Vauto_fill_chars)
481        ? !NILP (CHAR_TABLE_REF (Vauto_fill_chars, c))
482        : (c == ' ' || c == '\n'))
483       && !NILP (BVAR (current_buffer, auto_fill_function)))
484     {
485       Lisp_Object auto_fill_result;
486 
487       if (c == '\n')
488 	/* After inserting a newline, move to previous line and fill
489 	   that.  Must have the newline in place already so filling and
490 	   justification, if any, know where the end is going to be.  */
491 	SET_PT_BOTH (PT - 1, PT_BYTE - 1);
492       auto_fill_result = call0 (Qinternal_auto_fill);
493       /* Test PT < ZV in case the auto-fill-function is strange.  */
494       if (c == '\n' && PT < ZV)
495 	SET_PT_BOTH (PT + 1, PT_BYTE + 1);
496       if (!NILP (auto_fill_result))
497 	hairy = 2;
498     }
499 
500   /* Run hooks for electric keys.  */
501   run_hook (Qpost_self_insert_hook);
502 
503   return hairy;
504 }
505 
506 /* module initialization */
507 
508 void
syms_of_cmds(void)509 syms_of_cmds (void)
510 {
511   DEFSYM (Qinternal_auto_fill, "internal-auto-fill");
512 
513   DEFSYM (Qundo_auto_amalgamate, "undo-auto-amalgamate");
514   DEFSYM (Qundo_auto__this_command_amalgamating,
515           "undo-auto--this-command-amalgamating");
516 
517   DEFSYM (Qkill_forward_chars, "kill-forward-chars");
518 
519   /* A possible value for a buffer's overwrite-mode variable.  */
520   DEFSYM (Qoverwrite_mode_binary, "overwrite-mode-binary");
521 
522   DEFSYM (Qexpand_abbrev, "expand-abbrev");
523   DEFSYM (Qpost_self_insert_hook, "post-self-insert-hook");
524 
525   DEFVAR_LISP ("post-self-insert-hook", Vpost_self_insert_hook,
526 	       doc: /* Hook run at the end of `self-insert-command'.
527 This is run after inserting the character.  */);
528   Vpost_self_insert_hook = Qnil;
529 
530   defsubr (&Sforward_point);
531   defsubr (&Sforward_char);
532   defsubr (&Sbackward_char);
533   defsubr (&Sforward_line);
534   defsubr (&Sbeginning_of_line);
535   defsubr (&Send_of_line);
536 
537   defsubr (&Sdelete_char);
538   defsubr (&Sself_insert_command);
539 }
540 
541 void
keys_of_cmds(void)542 keys_of_cmds (void)
543 {
544   int n;
545 
546   initial_define_key (global_map, Ctl ('I'), "self-insert-command");
547   for (n = 040; n < 0177; n++)
548     initial_define_key (global_map, n, "self-insert-command");
549 #ifdef MSDOS
550   for (n = 0200; n < 0240; n++)
551     initial_define_key (global_map, n, "self-insert-command");
552 #endif
553   for (n = 0240; n < 0400; n++)
554     initial_define_key (global_map, n, "self-insert-command");
555 
556   initial_define_key (global_map, Ctl ('A'), "beginning-of-line");
557   initial_define_key (global_map, Ctl ('B'), "backward-char");
558   initial_define_key (global_map, Ctl ('E'), "end-of-line");
559   initial_define_key (global_map, Ctl ('F'), "forward-char");
560 }
561