1 /* Simple built-in editing commands.
2 Copyright (C) 1985, 1993, 1994 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
28 Lisp_Object Qkill_forward_chars
, Qkill_backward_chars
, Vblink_paren_function
;
29 Lisp_Object Vuse_hard_newlines
;
31 /* A possible value for a buffer's overwrite-mode variable. */
32 Lisp_Object Qoverwrite_mode_binary
;
34 /* Non-nil means put this face on the next self-inserting character. */
35 Lisp_Object Vself_insert_face
;
37 /* This is the command that set up Vself_insert_face. */
38 Lisp_Object Vself_insert_face_command
;
40 #ifdef USE_TEXT_PROPERTIES
44 extern Lisp_Object Qface
;
46 DEFUN ("forward-char", Fforward_char
, Sforward_char
, 0, 1, "p",
47 "Move point right ARG characters (left if ARG negative).\n\
48 On reaching end of buffer, stop and signal error.")
57 /* This used to just set point to point + XINT (n), and then check
58 to see if it was within boundaries. But now that SET_PT can
59 potentially do a lot of stuff (calling entering and exiting
60 hooks, etcetera), that's not a good approach. So we validate the
61 proposed position, then set point. */
63 int new_point
= point
+ XINT (n
);
68 Fsignal (Qbeginning_of_buffer
, Qnil
);
73 Fsignal (Qend_of_buffer
, Qnil
);
82 DEFUN ("backward-char", Fbackward_char
, Sbackward_char
, 0, 1, "p",
83 "Move point left ARG characters (right if ARG negative).\n\
84 On attempt to pass beginning or end of buffer, stop and signal error.")
93 XSETINT (n
, - XINT (n
));
94 return Fforward_char (n
);
97 DEFUN ("forward-line", Fforward_line
, Sforward_line
, 0, 1, "p",
98 "Move ARG lines forward (backward if ARG is negative).\n\
99 Precisely, if point is on line I, move to the start of line I + ARG.\n\
100 If there isn't room, go as far as possible (no error).\n\
101 Returns the count of lines left to move. If moving forward,\n\
102 that is ARG - number of lines moved; if backward, ARG + number moved.\n\
103 With positive ARG, a non-empty line at the end counts as one line\n\
104 successfully moved (for the return value).")
110 int count
, shortage
, negp
;
121 pos
= scan_buffer ('\n', pos2
, 0, count
- negp
, &shortage
, 1);
126 && FETCH_CHAR (pos
- 1) != '\n')))
129 return make_number (negp
? - shortage
: shortage
);
132 DEFUN ("beginning-of-line", Fbeginning_of_line
, Sbeginning_of_line
,
134 "Move point to beginning of current line.\n\
135 With argument ARG not nil or 1, move forward ARG - 1 lines first.\n\
136 If scan reaches end of buffer, stop there without error.")
145 Fforward_line (make_number (XINT (n
) - 1));
149 DEFUN ("end-of-line", Fend_of_line
, Send_of_line
,
151 "Move point to end of current line.\n\
152 With argument ARG not nil or 1, move forward ARG - 1 lines first.\n\
153 If scan reaches end of buffer, stop there without error.")
165 SET_PT (find_before_next_newline (PT
, 0, XINT (n
) - (XINT (n
) <= 0)));
170 DEFUN ("delete-char", Fdelete_char
, Sdelete_char
, 1, 2, "p\nP",
171 "Delete the following ARG characters (previous, with negative arg).\n\
172 Optional second arg KILLFLAG non-nil means kill instead (save in kill ring).\n\
173 Interactively, ARG is the prefix arg, and KILLFLAG is set if\n\
174 ARG was explicitly specified.")
176 Lisp_Object n
, killflag
;
184 if (point
+ XINT (n
) < BEGV
)
185 Fsignal (Qbeginning_of_buffer
, Qnil
);
187 del_range (point
+ XINT (n
), point
);
191 if (point
+ XINT (n
) > ZV
)
192 Fsignal (Qend_of_buffer
, Qnil
);
194 del_range (point
, point
+ XINT (n
));
199 call1 (Qkill_forward_chars
, n
);
204 DEFUN ("delete-backward-char", Fdelete_backward_char
, Sdelete_backward_char
,
206 "Delete the previous ARG characters (following, with negative ARG).\n\
207 Optional second arg KILLFLAG non-nil means kill instead (save in kill ring).\n\
208 Interactively, ARG is the prefix arg, and KILLFLAG is set if\n\
209 ARG was explicitly specified.")
211 Lisp_Object n
, killflag
;
214 return Fdelete_char (make_number (-XINT (n
)), killflag
);
217 DEFUN ("self-insert-command", Fself_insert_command
, Sself_insert_command
, 1, 1, "p",
218 "Insert the character you type.\n\
219 Whichever character you type to run this command is inserted.")
223 CHECK_NUMBER (arg
, 0);
225 /* Barf if the key that invoked this was not a character. */
226 if (!INTEGERP (last_command_char
))
229 while (XINT (arg
) > 0)
231 /* Ok since old and new vals both nonneg */
232 XSETFASTINT (arg
, XFASTINT (arg
) - 1);
233 internal_self_insert (XINT (last_command_char
), XFASTINT (arg
) != 0);
239 DEFUN ("newline", Fnewline
, Snewline
, 0, 1, "P",
240 "Insert a newline. With arg, insert that many newlines.\n\
241 In Auto Fill mode, if no numeric arg, break the preceding line if it's long.")
249 arg
= Fprefix_numeric_value (arg1
);
251 if (!NILP (current_buffer
->read_only
))
252 Fbarf_if_buffer_read_only ();
254 /* Inserting a newline at the end of a line produces better
255 redisplay in try_window_id than inserting at the beginning of a
256 line, and the textual result is the same. So, if we're at
257 beginning of line, pretend to be at the end of the previous line.
259 We can't use internal_self_insert in that case since it won't do
260 the insertion correctly. Luckily, internal_self_insert's special
261 features all do nothing in that case. */
263 flag
= point
> BEGV
&& FETCH_CHAR (point
- 1) == '\n';
264 /* Don't do this if at the beginning of the window. */
265 if (XBUFFER (XWINDOW (selected_window
)->buffer
) == current_buffer
266 && marker_position (XWINDOW (selected_window
)->start
) == PT
)
269 #ifdef USE_TEXT_PROPERTIES
270 /* We cannot use this optimization if properties change
272 ??? We need to check for change hook properties, etc. */
274 if (! (point
- 1 > BEGV
&& ! property_change_between_p (point
- 2, point
)))
281 for (i
= XINT (arg
); i
> 0; i
--)
284 insert_and_inherit (&c1
, 1);
286 internal_self_insert ('\n', !NILP (arg1
));
289 #ifdef USE_TEXT_PROPERTIES
290 if (Vuse_hard_newlines
)
292 Lisp_Object from
, to
, sticky
;
293 XSETFASTINT (from
, PT
- arg
);
294 XSETFASTINT (to
, PT
);
295 Fput_text_property (from
, to
, Qhard
, Qt
, Qnil
);
296 /* If rear_nonsticky is not "t", locally add Qhard to the list. */
297 sticky
= Fget_text_property (from
, Qrear_nonsticky
, Qnil
);
299 || (CONSP (sticky
) && NILP (Fmemq (Qhard
, sticky
))))
301 sticky
= Fcons (Qhard
, sticky
);
302 Fput_text_property (from
, to
, Qrear_nonsticky
, sticky
, Qnil
);
314 /* Insert character C1. If NOAUTOFILL is nonzero, don't do autofill
315 even if it is enabled.
317 If this insertion is suitable for direct output (completely simple),
318 return 0. A value of 1 indicates this *might* not have been simple.
319 A value of 2 means this did things that call for an undo boundary. */
321 internal_self_insert (c1
, noautofill
)
325 extern Lisp_Object
Fexpand_abbrev ();
328 register enum syntaxcode synt
;
330 Lisp_Object overwrite
;
332 overwrite
= current_buffer
->overwrite_mode
;
333 if (!NILP (Vbefore_change_function
) || !NILP (Vafter_change_function
)
334 || !NILP (Vbefore_change_functions
) || !NILP (Vafter_change_functions
))
337 if (!NILP (overwrite
)
339 && (EQ (overwrite
, Qoverwrite_mode_binary
)
340 || (c
!= '\n' && FETCH_CHAR (point
) != '\n'))
341 && (EQ (overwrite
, Qoverwrite_mode_binary
)
342 || FETCH_CHAR (point
) != '\t'
343 || XINT (current_buffer
->tab_width
) <= 0
344 || XFASTINT (current_buffer
->tab_width
) > 20
345 || !((current_column () + 1) % XFASTINT (current_buffer
->tab_width
))))
347 del_range (point
, point
+ 1);
350 if (!NILP (current_buffer
->abbrev_mode
)
351 && SYNTAX (c
) != Sword
352 && NILP (current_buffer
->read_only
)
353 && point
> BEGV
&& SYNTAX (FETCH_CHAR (point
- 1)) == Sword
)
357 /* We can't trust the value of Fexpand_abbrev,
358 but if Fexpand_abbrev changed the buffer,
359 assume it expanded something. */
360 if (MODIFF
!= modiff
)
363 if ((c
== ' ' || c
== '\n')
365 && !NILP (current_buffer
->auto_fill_function
))
368 insert_and_inherit (&c1
, 1);
369 call0 (current_buffer
->auto_fill_function
);
371 insert_and_inherit (&c1
, 1);
375 insert_and_inherit (&c1
, 1);
377 /* If previous command specified a face to use, use it. */
378 if (!NILP (Vself_insert_face
)
379 && EQ (last_command
, Vself_insert_face_command
))
381 Lisp_Object before
, after
;
382 XSETINT (before
, PT
- 1);
384 Fput_text_property (before
, after
, Qface
, Vself_insert_face
, Qnil
);
385 Vself_insert_face
= Qnil
;
388 if ((synt
== Sclose
|| synt
== Smath
)
389 && !NILP (Vblink_paren_function
) && INTERACTIVE
)
391 call0 (Vblink_paren_function
);
397 /* module initialization */
401 Qkill_backward_chars
= intern ("kill-backward-chars");
402 staticpro (&Qkill_backward_chars
);
404 Qkill_forward_chars
= intern ("kill-forward-chars");
405 staticpro (&Qkill_forward_chars
);
407 Qoverwrite_mode_binary
= intern ("overwrite-mode-binary");
408 staticpro (&Qoverwrite_mode_binary
);
410 Qhard
= intern ("hard");
413 DEFVAR_BOOL ("use-hard-newlines", &Vuse_hard_newlines
,
414 "Non-nil means to distinguish hard and soft newlines.\n\
415 When this is non-nil, the functions `newline' and `open-line' add the\n\
416 text-property `hard' to newlines that they insert. Also, a line is\n\
417 only considered as a candidate to match `paragraph-start' or\n\
418 `paragraph-separate' if it follows a hard newline. Newlines not\n\
419 marked hard are called \"soft\", and are always internal to\n\
420 paragraphs. The fill functions always insert soft newlines.");
421 Vuse_hard_newlines
= 0;
423 DEFVAR_LISP ("self-insert-face", &Vself_insert_face
,
424 "If non-nil, set the face of the next self-inserting character to this.\n\
425 See also `self-insert-face-command'.");
426 Vself_insert_face
= Qnil
;
428 DEFVAR_LISP ("self-insert-face-command", &Vself_insert_face_command
,
429 "This is the command that set up `self-insert-face'.\n\
430 If `last-command' does not equal this value, we ignore `self-insert-face'.");
431 Vself_insert_face_command
= Qnil
;
433 DEFVAR_LISP ("blink-paren-function", &Vblink_paren_function
,
434 "Function called, if non-nil, whenever a close parenthesis is inserted.\n\
435 More precisely, a char with closeparen syntax is self-inserted.");
436 Vblink_paren_function
= Qnil
;
438 defsubr (&Sforward_char
);
439 defsubr (&Sbackward_char
);
440 defsubr (&Sforward_line
);
441 defsubr (&Sbeginning_of_line
);
442 defsubr (&Send_of_line
);
444 defsubr (&Sdelete_char
);
445 defsubr (&Sdelete_backward_char
);
447 defsubr (&Sself_insert_command
);
455 initial_define_key (global_map
, Ctl ('M'), "newline");
456 initial_define_key (global_map
, Ctl ('I'), "self-insert-command");
457 for (n
= 040; n
< 0177; n
++)
458 initial_define_key (global_map
, n
, "self-insert-command");
460 for (n
= 0200; n
< 0240; n
++)
461 initial_define_key (global_map
, n
, "self-insert-command");
463 for (n
= 0240; n
< 0400; n
++)
464 initial_define_key (global_map
, n
, "self-insert-command");
466 initial_define_key (global_map
, Ctl ('A'), "beginning-of-line");
467 initial_define_key (global_map
, Ctl ('B'), "backward-char");
468 initial_define_key (global_map
, Ctl ('D'), "delete-char");
469 initial_define_key (global_map
, Ctl ('E'), "end-of-line");
470 initial_define_key (global_map
, Ctl ('F'), "forward-char");
471 initial_define_key (global_map
, 0177, "delete-backward-char");