(mouse-major-mode-menu): Avoid confusing error message when there's no current
[bpt/emacs.git] / src / cmds.c
CommitLineData
cd645247 1/* Simple built-in editing commands.
3a22ee35 2 Copyright (C) 1985, 1993, 1994 Free Software Foundation, Inc.
cd645247
JB
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
502ddf23 8the Free Software Foundation; either version 2, or (at your option)
cd645247
JB
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
18160b98 21#include <config.h>
cd645247
JB
22#include "lisp.h"
23#include "commands.h"
24#include "buffer.h"
25#include "syntax.h"
f109dfa2 26#include "window.h"
cd645247
JB
27
28Lisp_Object Qkill_forward_chars, Qkill_backward_chars, Vblink_paren_function;
29
6bbb0d4a
JB
30/* A possible value for a buffer's overwrite-mode variable. */
31Lisp_Object Qoverwrite_mode_binary;
32
189fad68
RS
33/* Non-nil means put this face on the next self-inserting character. */
34Lisp_Object Vself_insert_face;
35
36/* This is the command that set up Vself_insert_face. */
37Lisp_Object Vself_insert_face_command;
38
189fad68 39extern Lisp_Object Qface;
cd645247
JB
40\f
41DEFUN ("forward-char", Fforward_char, Sforward_char, 0, 1, "p",
42 "Move point right ARG characters (left if ARG negative).\n\
43On reaching end of buffer, stop and signal error.")
44 (n)
45 Lisp_Object n;
46{
265a9e55 47 if (NILP (n))
48c7cef2 48 XSETFASTINT (n, 1);
cd645247
JB
49 else
50 CHECK_NUMBER (n, 0);
51
7b502dc3
JB
52 /* This used to just set point to point + XINT (n), and then check
53 to see if it was within boundaries. But now that SET_PT can
54 potentially do a lot of stuff (calling entering and exiting
55 hooks, etcetera), that's not a good approach. So we validate the
56 proposed position, then set point. */
57 {
58 int new_point = point + XINT (n);
59
60 if (new_point < BEGV)
61 {
62 SET_PT (BEGV);
63 Fsignal (Qbeginning_of_buffer, Qnil);
64 }
65 if (new_point > ZV)
66 {
67 SET_PT (ZV);
68 Fsignal (Qend_of_buffer, Qnil);
69 }
70
71 SET_PT (new_point);
72 }
73
cd645247
JB
74 return Qnil;
75}
76
77DEFUN ("backward-char", Fbackward_char, Sbackward_char, 0, 1, "p",
78 "Move point left ARG characters (right if ARG negative).\n\
79On attempt to pass beginning or end of buffer, stop and signal error.")
80 (n)
81 Lisp_Object n;
82{
265a9e55 83 if (NILP (n))
48c7cef2 84 XSETFASTINT (n, 1);
cd645247
JB
85 else
86 CHECK_NUMBER (n, 0);
87
88 XSETINT (n, - XINT (n));
89 return Fforward_char (n);
90}
91
92DEFUN ("forward-line", Fforward_line, Sforward_line, 0, 1, "p",
93 "Move ARG lines forward (backward if ARG is negative).\n\
94Precisely, if point is on line I, move to the start of line I + ARG.\n\
95If there isn't room, go as far as possible (no error).\n\
96Returns the count of lines left to move. If moving forward,\n\
97that is ARG - number of lines moved; if backward, ARG + number moved.\n\
98With positive ARG, a non-empty line at the end counts as one line\n\
99 successfully moved (for the return value).")
100 (n)
101 Lisp_Object n;
102{
103 int pos2 = point;
104 int pos;
105 int count, shortage, negp;
106
265a9e55 107 if (NILP (n))
cd645247
JB
108 count = 1;
109 else
110 {
111 CHECK_NUMBER (n, 0);
112 count = XINT (n);
113 }
114
115 negp = count <= 0;
4f5d0c3c 116 pos = scan_buffer ('\n', pos2, 0, count - negp, &shortage, 1);
cd645247
JB
117 if (shortage > 0
118 && (negp
502ddf23
JB
119 || (ZV > BEGV
120 && pos != pos2
cd645247
JB
121 && FETCH_CHAR (pos - 1) != '\n')))
122 shortage--;
123 SET_PT (pos);
124 return make_number (negp ? - shortage : shortage);
125}
126
127DEFUN ("beginning-of-line", Fbeginning_of_line, Sbeginning_of_line,
128 0, 1, "p",
129 "Move point to beginning of current line.\n\
130With argument ARG not nil or 1, move forward ARG - 1 lines first.\n\
131If scan reaches end of buffer, stop there without error.")
132 (n)
133 Lisp_Object n;
134{
265a9e55 135 if (NILP (n))
48c7cef2 136 XSETFASTINT (n, 1);
cd645247
JB
137 else
138 CHECK_NUMBER (n, 0);
139
140 Fforward_line (make_number (XINT (n) - 1));
141 return Qnil;
142}
143
144DEFUN ("end-of-line", Fend_of_line, Send_of_line,
145 0, 1, "p",
146 "Move point to end of current line.\n\
147With argument ARG not nil or 1, move forward ARG - 1 lines first.\n\
148If scan reaches end of buffer, stop there without error.")
149 (n)
150 Lisp_Object n;
151{
152 register int pos;
153 register int stop;
154
265a9e55 155 if (NILP (n))
48c7cef2 156 XSETFASTINT (n, 1);
cd645247
JB
157 else
158 CHECK_NUMBER (n, 0);
159
4f5d0c3c 160 SET_PT (find_before_next_newline (PT, 0, XINT (n) - (XINT (n) <= 0)));
cd645247
JB
161
162 return Qnil;
163}
164
165DEFUN ("delete-char", Fdelete_char, Sdelete_char, 1, 2, "p\nP",
166 "Delete the following ARG characters (previous, with negative arg).\n\
167Optional second arg KILLFLAG non-nil means kill instead (save in kill ring).\n\
168Interactively, ARG is the prefix arg, and KILLFLAG is set if\n\
169ARG was explicitly specified.")
170 (n, killflag)
171 Lisp_Object n, killflag;
172{
173 CHECK_NUMBER (n, 0);
174
265a9e55 175 if (NILP (killflag))
cd645247
JB
176 {
177 if (XINT (n) < 0)
178 {
179 if (point + XINT (n) < BEGV)
180 Fsignal (Qbeginning_of_buffer, Qnil);
181 else
182 del_range (point + XINT (n), point);
183 }
184 else
185 {
186 if (point + XINT (n) > ZV)
187 Fsignal (Qend_of_buffer, Qnil);
188 else
189 del_range (point, point + XINT (n));
190 }
191 }
192 else
193 {
194 call1 (Qkill_forward_chars, n);
195 }
196 return Qnil;
197}
198
199DEFUN ("delete-backward-char", Fdelete_backward_char, Sdelete_backward_char,
200 1, 2, "p\nP",
201 "Delete the previous ARG characters (following, with negative ARG).\n\
202Optional second arg KILLFLAG non-nil means kill instead (save in kill ring).\n\
203Interactively, ARG is the prefix arg, and KILLFLAG is set if\n\
204ARG was explicitly specified.")
205 (n, killflag)
206 Lisp_Object n, killflag;
207{
208 CHECK_NUMBER (n, 0);
209 return Fdelete_char (make_number (-XINT (n)), killflag);
210}
211
212DEFUN ("self-insert-command", Fself_insert_command, Sself_insert_command, 1, 1, "p",
213 "Insert the character you type.\n\
214Whichever character you type to run this command is inserted.")
215 (arg)
216 Lisp_Object arg;
217{
218 CHECK_NUMBER (arg, 0);
219
220 /* Barf if the key that invoked this was not a character. */
ed76f667 221 if (!INTEGERP (last_command_char))
cd645247
JB
222 bitch_at_user ();
223 else
224 while (XINT (arg) > 0)
225 {
f58dd69b
KH
226 /* Ok since old and new vals both nonneg */
227 XSETFASTINT (arg, XFASTINT (arg) - 1);
cd645247
JB
228 internal_self_insert (XINT (last_command_char), XFASTINT (arg) != 0);
229 }
230
231 return Qnil;
232}
233
4c6e656f
RS
234/* Insert character C1. If NOAUTOFILL is nonzero, don't do autofill
235 even if it is enabled.
236
237 If this insertion is suitable for direct output (completely simple),
aa52fef9
RS
238 return 0. A value of 1 indicates this *might* not have been simple.
239 A value of 2 means this did things that call for an undo boundary. */
4c6e656f 240
cd645247
JB
241internal_self_insert (c1, noautofill)
242 char c1;
243 int noautofill;
244{
245 extern Lisp_Object Fexpand_abbrev ();
246 int hairy = 0;
247 Lisp_Object tem;
248 register enum syntaxcode synt;
249 register int c = c1;
e7aacab7 250 Lisp_Object overwrite;
cd645247 251
e7aacab7 252 overwrite = current_buffer->overwrite_mode;
166a4263
RS
253 if (!NILP (Vbefore_change_function) || !NILP (Vafter_change_function)
254 || !NILP (Vbefore_change_functions) || !NILP (Vafter_change_functions))
cd645247
JB
255 hairy = 1;
256
6bbb0d4a 257 if (!NILP (overwrite)
cd645247 258 && point < ZV
6bbb0d4a
JB
259 && (EQ (overwrite, Qoverwrite_mode_binary)
260 || (c != '\n' && FETCH_CHAR (point) != '\n'))
261 && (EQ (overwrite, Qoverwrite_mode_binary)
e686c647 262 || FETCH_CHAR (point) != '\t'
cd645247 263 || XINT (current_buffer->tab_width) <= 0
2234dd63 264 || XFASTINT (current_buffer->tab_width) > 20
cd645247
JB
265 || !((current_column () + 1) % XFASTINT (current_buffer->tab_width))))
266 {
267 del_range (point, point + 1);
aa52fef9 268 hairy = 2;
cd645247 269 }
265a9e55 270 if (!NILP (current_buffer->abbrev_mode)
cd645247 271 && SYNTAX (c) != Sword
265a9e55 272 && NILP (current_buffer->read_only)
cd645247
JB
273 && point > BEGV && SYNTAX (FETCH_CHAR (point - 1)) == Sword)
274 {
ee8caabb 275 int modiff = MODIFF;
4c6e656f
RS
276 Fexpand_abbrev ();
277 /* We can't trust the value of Fexpand_abbrev,
ee8caabb
RS
278 but if Fexpand_abbrev changed the buffer,
279 assume it expanded something. */
280 if (MODIFF != modiff)
aa52fef9 281 hairy = 2;
cd645247
JB
282 }
283 if ((c == ' ' || c == '\n')
284 && !noautofill
3de15b7a 285 && !NILP (current_buffer->auto_fill_function))
cd645247 286 {
2e16553c
BG
287 insert_and_inherit (&c1, 1);
288 if (c1 == '\n')
289 /* After inserting a newline, move to previous line and fill */
290 /* that. Must have the newline in place already so filling and */
291 /* justification, if any, know where the end is going to be. */
292 SET_PT (point - 1);
cd645247
JB
293 call0 (current_buffer->auto_fill_function);
294 if (c1 == '\n')
2e16553c 295 SET_PT (point + 1);
aa52fef9 296 hairy = 2;
cd645247
JB
297 }
298 else
b9a7407f 299 insert_and_inherit (&c1, 1);
189fad68
RS
300
301 /* If previous command specified a face to use, use it. */
302 if (!NILP (Vself_insert_face)
303 && EQ (last_command, Vself_insert_face_command))
304 {
305 Lisp_Object before, after;
306 XSETINT (before, PT - 1);
307 XSETINT (after, PT);
308 Fput_text_property (before, after, Qface, Vself_insert_face, Qnil);
309 Vself_insert_face = Qnil;
310 }
cd645247
JB
311 synt = SYNTAX (c);
312 if ((synt == Sclose || synt == Smath)
265a9e55 313 && !NILP (Vblink_paren_function) && INTERACTIVE)
cd645247
JB
314 {
315 call0 (Vblink_paren_function);
aa52fef9 316 hairy = 2;
cd645247
JB
317 }
318 return hairy;
319}
320\f
321/* module initialization */
322
323syms_of_cmds ()
324{
325 Qkill_backward_chars = intern ("kill-backward-chars");
326 staticpro (&Qkill_backward_chars);
327
328 Qkill_forward_chars = intern ("kill-forward-chars");
329 staticpro (&Qkill_forward_chars);
330
6bbb0d4a
JB
331 Qoverwrite_mode_binary = intern ("overwrite-mode-binary");
332 staticpro (&Qoverwrite_mode_binary);
e686c647 333
189fad68
RS
334 DEFVAR_LISP ("self-insert-face", &Vself_insert_face,
335 "If non-nil, set the face of the next self-inserting character to this.\n\
336See also `self-insert-face-command'.");
337 Vself_insert_face = Qnil;
338
339 DEFVAR_LISP ("self-insert-face-command", &Vself_insert_face_command,
340 "This is the command that set up `self-insert-face'.\n\
341If `last-command' does not equal this value, we ignore `self-insert-face'.");
342 Vself_insert_face_command = Qnil;
343
cd645247
JB
344 DEFVAR_LISP ("blink-paren-function", &Vblink_paren_function,
345 "Function called, if non-nil, whenever a close parenthesis is inserted.\n\
346More precisely, a char with closeparen syntax is self-inserted.");
347 Vblink_paren_function = Qnil;
348
349 defsubr (&Sforward_char);
350 defsubr (&Sbackward_char);
351 defsubr (&Sforward_line);
352 defsubr (&Sbeginning_of_line);
353 defsubr (&Send_of_line);
354
355 defsubr (&Sdelete_char);
356 defsubr (&Sdelete_backward_char);
357
358 defsubr (&Sself_insert_command);
cd645247
JB
359}
360
361keys_of_cmds ()
362{
363 int n;
364
cbf65115 365 initial_define_key (global_map, Ctl ('I'), "self-insert-command");
cd645247
JB
366 for (n = 040; n < 0177; n++)
367 initial_define_key (global_map, n, "self-insert-command");
cf9cdc11
RS
368#ifdef MSDOS
369 for (n = 0200; n < 0240; n++)
370 initial_define_key (global_map, n, "self-insert-command");
371#endif
94748cb9 372 for (n = 0240; n < 0400; n++)
eb46da6a 373 initial_define_key (global_map, n, "self-insert-command");
cd645247
JB
374
375 initial_define_key (global_map, Ctl ('A'), "beginning-of-line");
376 initial_define_key (global_map, Ctl ('B'), "backward-char");
377 initial_define_key (global_map, Ctl ('D'), "delete-char");
378 initial_define_key (global_map, Ctl ('E'), "end-of-line");
379 initial_define_key (global_map, Ctl ('F'), "forward-char");
380 initial_define_key (global_map, 0177, "delete-backward-char");
381}