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