xref: /freebsd/contrib/nvi/vi/v_cmd.c (revision fcb560670601b2a4d87bb31d7531c8dcc37ee71b)
1 /*-
2  * Copyright (c) 1992, 1993, 1994
3  *	The Regents of the University of California.  All rights reserved.
4  * Copyright (c) 1992, 1993, 1994, 1995, 1996
5  *	Keith Bostic.  All rights reserved.
6  *
7  * See the LICENSE file for redistribution information.
8  */
9 
10 #include "config.h"
11 
12 #ifndef lint
13 static const char sccsid[] = "$Id: v_cmd.c,v 10.9 1996/03/28 15:18:39 bostic Exp $";
14 #endif /* not lint */
15 
16 #include <sys/types.h>
17 #include <sys/queue.h>
18 #include <sys/time.h>
19 
20 #include <bitstring.h>
21 #include <limits.h>
22 #include <stdio.h>
23 
24 #include "../common/common.h"
25 #include "vi.h"
26 
27 /*
28  * This array maps keystrokes to vi command functions.  It is known
29  * in ex/ex_usage.c that it takes four columns to name a vi character.
30  */
31 VIKEYS const vikeys [MAXVIKEY + 1] = {
32 /* 000 NUL -- The code in vi.c expects key 0 to be undefined. */
33 	{NULL},
34 /* 001  ^A */
35 	{v_searchw,	V_ABS|V_CNT|V_MOVE|V_KEYW|VM_CUTREQ|VM_RCM_SET,
36 	    "[count]^A",
37 	    "^A search forward for cursor word"},
38 /* 002  ^B */
39 	{v_pageup,	V_CNT|VM_RCM_SET,
40 	    "[count]^B",
41 	    "^B scroll up by screens"},
42 /* 003  ^C */
43 	{NULL,		0,
44 	    "^C",
45 	    "^C interrupt an operation (e.g. read, write, search)"},
46 /* 004  ^D */
47 	{v_hpagedown,	V_CNT|VM_RCM_SET,
48 	    "[count]^D",
49 	    "^D scroll down by half screens (setting count)"},
50 /* 005  ^E */
51 	{v_linedown,	V_CNT,
52 	    "[count]^E",
53 	    "^E scroll down by lines"},
54 /* 006  ^F */
55 	{v_pagedown,	V_CNT|VM_RCM_SET,
56 	    "[count]^F",
57 	    "^F scroll down by screens"},
58 /* 007  ^G */
59 	{v_status,	0,
60 	    "^G",
61 	    "^G file status"},
62 /* 010  ^H */
63 	{v_left,	V_CNT|V_MOVE|VM_RCM_SET,
64 	    "[count]^H",
65 	    "^H move left by characters"},
66 /* 011  ^I */
67 	{NULL},
68 /* 012  ^J */
69 	{v_down,	V_CNT|V_MOVE|VM_LMODE|VM_RCM,
70 	    "[count]^J",
71 	    "^J move down by lines"},
72 /* 013  ^K */
73 	{NULL},
74 /* 014  ^L */
75 	{v_redraw,	0,
76 	    "^L",
77 	    "^L redraw screen"},
78 /* 015  ^M */
79 	{v_cr,		V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB,
80 	    "[count]^M",
81 	    "^M move down by lines (to first non-blank)"},
82 /* 016  ^N */
83 	{v_down,	V_CNT|V_MOVE|VM_LMODE|VM_RCM,
84 	    "[count]^N",
85 	    "^N move down by lines"},
86 /* 017  ^O */
87 	{NULL},
88 /* 020  ^P */
89 	{v_up,		V_CNT|V_MOVE|VM_LMODE|VM_RCM,
90 	    "[count]^P",
91 	    "^P move up by lines"},
92 /* 021  ^Q -- same as ^V if not used for hardware flow control. */
93 	{NULL},
94 /* 022  ^R */
95 	{v_redraw,	0,
96 	    "^R",
97 	    "^R redraw screen"},
98 /* 023  ^S -- not available, used for hardware flow control. */
99 	{NULL},
100 /* 024  ^T */
101 	{v_tagpop,	V_ABS|VM_RCM_SET,
102 	    "^T",
103 	    "^T tag pop"},
104 /* 025  ^U */
105 	{v_hpageup,	V_CNT|VM_RCM_SET,
106 	    "[count]^U",
107 	    "^U half page up (set count)"},
108 /* 026  ^V */
109 	{NULL,		0,
110 	    "^V",
111 	    "^V input a literal character"},
112 /* 027  ^W */
113 	{v_screen,	0,
114 	    "^W",
115 	    "^W move to next screen"},
116 /* 030  ^X */
117 	{NULL},
118 /* 031  ^Y */
119 	{v_lineup,	V_CNT,
120 	    "[count]^Y",
121 	    "^Y page up by lines"},
122 /* 032  ^Z */
123 	{v_suspend,	V_SECURE,
124 	    "^Z",
125 	    "^Z suspend editor"},
126 /* 033  ^[ */
127 	{NULL,		0,
128 	    "^[ <escape>",
129 	    "^[ <escape> exit input mode, cancel partial commands"},
130 /* 034  ^\ */
131 	{v_exmode,	0,
132 	    "^\\",
133 	    " ^\\ switch to ex mode"},
134 /* 035  ^] */
135 	{v_tagpush,	V_ABS|V_KEYW|VM_RCM_SET,
136 	    "^]",
137 	    "^] tag push cursor word"},
138 /* 036  ^^ */
139 	{v_switch,	0,
140 	    "^^",
141 	    "^^ switch to previous file"},
142 /* 037  ^_ */
143 	{NULL},
144 /* 040 ' ' */
145 	{v_right,	V_CNT|V_MOVE|VM_RCM_SET,
146 	    "[count]' '",
147 	    "   <space> move right by columns"},
148 /* 041   ! */
149 	{v_filter,	V_CNT|V_DOT|V_MOTION|V_SECURE|VM_RCM_SET,
150 	    "[count]![count]motion command(s)",
151 	    " ! filter through command(s) to motion"},
152 /* 042   " */
153 	{NULL},
154 /* 043   # */
155 	{v_increment,	V_CHAR|V_CNT|V_DOT|VM_RCM_SET,
156 	    "[count]# +|-|#",
157 	    " # number increment/decrement"},
158 /* 044   $ */
159 	{v_dollar,	V_CNT|V_MOVE|VM_RCM_SETLAST,
160 	    " [count]$",
161 	    " $ move to last column"},
162 /* 045   % */
163 	{v_match,	V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET,
164 	    "%",
165 	    " % move to match"},
166 /* 046   & */
167 	{v_again,	0,
168 	    "&",
169 	    " & repeat substitution"},
170 /* 047   ' */
171 	{v_fmark,	V_ABS_L|V_CHAR|V_MOVE|VM_LMODE|VM_RCM_SET,
172 	    "'['a-z]",
173 	    " ' move to mark (to first non-blank)"},
174 /* 050   ( */
175 	{v_sentenceb,	V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET,
176 	    "[count](",
177 	    " ( move back sentence"},
178 /* 051   ) */
179 	{v_sentencef,	V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET,
180 	    "[count])",
181 	    " ) move forward sentence"},
182 /* 052   * */
183 	{NULL},
184 /* 053   + */
185 	{v_down,	V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB,
186 	    "[count]+",
187 	    " + move down by lines (to first non-blank)"},
188 /* 054   , */
189 	{v_chrrepeat,	V_CNT|V_MOVE|VM_RCM_SET,
190 	    "[count],",
191 	    " , reverse last F, f, T or t search"},
192 /* 055   - */
193 	{v_up,		V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB,
194 	    "[count]-",
195 	    " - move up by lines (to first non-blank)"},
196 /* 056   . */
197 	{NULL,		0,
198 	    ".",
199 	    " . repeat the last command"},
200 /* 057   / */
201 	{v_searchf,	V_ABS_C|V_MOVE|VM_CUTREQ|VM_RCM_SET,
202 	    "/RE[/ offset]",
203 	    " / search forward"},
204 /* 060   0 */
205 	{v_zero,	V_MOVE|VM_RCM_SET,
206 	    "0",
207 	    " 0 move to first character"},
208 /* 061   1 */
209 	{NULL},
210 /* 062   2 */
211 	{NULL},
212 /* 063   3 */
213 	{NULL},
214 /* 064   4 */
215 	{NULL},
216 /* 065   5 */
217 	{NULL},
218 /* 066   6 */
219 	{NULL},
220 /* 067   7 */
221 	{NULL},
222 /* 070   8 */
223 	{NULL},
224 /* 071   9 */
225 	{NULL},
226 /* 072   : */
227 	{v_ex,		0,
228 	    ":command [| command] ...",
229 	    " : ex command"},
230 /* 073   ; */
231 	{v_chrepeat,	V_CNT|V_MOVE|VM_RCM_SET,
232 	    "[count];",
233 	    " ; repeat last F, f, T or t search"},
234 /* 074   < */
235 	{v_shiftl,	V_CNT|V_DOT|V_MOTION|VM_RCM_SET,
236 	    "[count]<[count]motion",
237 	    " < shift lines left to motion"},
238 /* 075   = */
239 	{NULL},
240 /* 076   > */
241 	{v_shiftr,	V_CNT|V_DOT|V_MOTION|VM_RCM_SET,
242 	    "[count]>[count]motion",
243 	    " > shift lines right to motion"},
244 /* 077   ? */
245 	{v_searchb,	V_ABS_C|V_MOVE|VM_CUTREQ|VM_RCM_SET,
246 	    "?RE[? offset]",
247 	    " ? search backward"},
248 /* 100   @ */
249 	{v_at,		V_CNT|V_RBUF|VM_RCM_SET,
250 	    "@buffer",
251 	    " @ execute buffer"},
252 /* 101   A */
253 	{v_iA,		V_CNT|V_DOT|VM_RCM_SET,
254 	    "[count]A",
255 	    " A append to the line"},
256 /* 102   B */
257 	{v_wordB,	V_CNT|V_MOVE|VM_RCM_SET,
258 	    "[count]B",
259 	    " B move back bigword"},
260 /* 103   C */
261 	{NULL,		0,
262 	    "[buffer][count]C",
263 	    " C change to end-of-line"},
264 /* 104   D */
265 	{NULL,		0,
266 	    "[buffer]D",
267 	    " D delete to end-of-line"},
268 /* 105   E */
269 	{v_wordE,	V_CNT|V_MOVE|VM_RCM_SET,
270 	    "[count]E",
271 	    " E move to end of bigword"},
272 /* 106   F */
273 	{v_chF,		V_CHAR|V_CNT|V_MOVE|VM_RCM_SET,
274 	    "[count]F character",
275 	    " F character in line backward search"},
276 /* 107   G */
277 	{v_lgoto,	V_ABS_L|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETFNB,
278 	    "[count]G",
279 	    " G move to line"},
280 /* 110   H */
281 	{v_home,	V_ABS_L|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETNNB,
282 	    "[count]H",
283 	    " H move to count lines from screen top"},
284 /* 111   I */
285 	{v_iI,		V_CNT|V_DOT|VM_RCM_SET,
286 	    "[count]I",
287 	    " I insert before first nonblank"},
288 /* 112   J */
289 	{v_join,	V_CNT|V_DOT|VM_RCM_SET,
290 	    "[count]J",
291 	    " J join lines"},
292 /* 113   K */
293 	{NULL},
294 /* 114   L */
295 	{v_bottom,	V_ABS_L|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETNNB,
296 	    "[count]L",
297 	    " L move to screen bottom"},
298 /* 115   M */
299 	{v_middle,	V_ABS_L|V_CNT|V_MOVE|VM_LMODE|VM_RCM_SETNNB,
300 	    "M",
301 	    " M move to screen middle"},
302 /* 116   N */
303 	{v_searchN,	V_ABS_C|V_MOVE|VM_CUTREQ|VM_RCM_SET,
304 	    "n",
305 	    " N reverse last search"},
306 /* 117   O */
307 	{v_iO,		V_CNT|V_DOT|VM_RCM_SET,
308 	    "[count]O",
309 	    " O insert above line"},
310 /* 120   P */
311 	{v_Put,		V_CNT|V_DOT|V_OBUF|VM_RCM_SET,
312 	    "[buffer]P",
313 	    " P insert before cursor from buffer"},
314 /* 121   Q */
315 	{v_exmode,	0,
316 	    "Q",
317 	    " Q switch to ex mode"},
318 /* 122   R */
319 	{v_Replace,	V_CNT|V_DOT|VM_RCM_SET,
320 	    "[count]R",
321 	    " R replace characters"},
322 /* 123   S */
323 	{NULL,		0,
324 	    "[buffer][count]S",
325 	    " S substitute for the line(s)"},
326 /* 124   T */
327 	{v_chT,		V_CHAR|V_CNT|V_MOVE|VM_RCM_SET,
328 	    "[count]T character",
329 	    " T before character in line backward search"},
330 /* 125   U */
331 	{v_Undo,	VM_RCM_SET,
332 	    "U",
333 	    " U Restore the current line"},
334 /* 126   V */
335 	{NULL},
336 /* 127   W */
337 	{v_wordW,	V_CNT|V_MOVE|VM_RCM_SET,
338 	    "[count]W",
339 	    " W move to next bigword"},
340 /* 130   X */
341 	{v_Xchar,	V_CNT|V_DOT|V_OBUF|VM_RCM_SET,
342 	    "[buffer][count]X",
343 	    " X delete character before cursor"},
344 /* 131   Y */
345 	{NULL,		0,
346 	    "[buffer][count]Y",
347 	    " Y copy line"},
348 /* 132   Z */
349 	{v_zexit,	0,
350 	    "ZZ",
351 	    "ZZ save file and exit"},
352 /* 133   [ */
353 	{v_sectionb,	V_ABS|V_CNT|V_MOVE|VM_RCM_SET,
354 	    "[[",
355 	    "[[ move back section"},
356 /* 134   \ */
357 	{NULL},
358 /* 135   ] */
359 	{v_sectionf,	V_ABS|V_CNT|V_MOVE|VM_RCM_SET,
360 	    "]]",
361 	    "]] move forward section"},
362 /* 136   ^ */
363 	/*
364 	 * DON'T set the VM_RCM_SETFNB flag, the function has to do the work
365 	 * anyway, in case it's a motion component.  DO set VM_RCM_SET, so
366 	 * that any motion that's part of a command is preserved.
367 	 */
368 	{v_first,	V_CNT|V_MOVE|VM_RCM_SET,
369 	    "^",
370 	    " ^ move to first non-blank"},
371 /* 137   _ */
372 	/*
373 	 * Needs both to set the VM_RCM_SETFNB flag, and to do the work
374 	 * in the function, in case it's a delete.
375 	 */
376 	{v_cfirst,	V_CNT|V_MOVE|VM_RCM_SETFNB,
377 	    "_",
378 	    " _ move to first non-blank"},
379 /* 140   ` */
380 	{v_bmark,	V_ABS_C|V_CHAR|V_MOVE|VM_CUTREQ|VM_RCM_SET,
381 	    "`[`a-z]",
382 	    " ` move to mark"},
383 /* 141   a */
384 	{v_ia,		V_CNT|V_DOT|VM_RCM_SET,
385 	    "[count]a",
386 	    " a append after cursor"},
387 /* 142   b */
388 	{v_wordb,	V_CNT|V_MOVE|VM_RCM_SET,
389 	    "[count]b",
390 	    " b move back word"},
391 /* 143   c */
392 	{v_change,	V_CNT|V_DOT|V_MOTION|V_OBUF|VM_RCM_SET,
393 	    "[buffer][count]c[count]motion",
394 	    " c change to motion"},
395 /* 144   d */
396 	{v_delete,	V_CNT|V_DOT|V_MOTION|V_OBUF|VM_RCM_SET,
397 	    "[buffer][count]d[count]motion",
398 	    " d delete to motion"},
399 /* 145   e */
400 	{v_worde,	V_CNT|V_MOVE|VM_RCM_SET,
401 	    "[count]e",
402 	    " e move to end of word"},
403 /* 146   f */
404 	{v_chf,		V_CHAR|V_CNT|V_MOVE|VM_RCM_SET,
405 	    "[count]f character",
406 	    " f character in line forward search"},
407 /* 147   g */
408 	{NULL},
409 /* 150   h */
410 	{v_left,	V_CNT|V_MOVE|VM_RCM_SET,
411 	    "[count]h",
412 	    " h move left by columns"},
413 /* 151   i */
414 	{v_ii,		V_CNT|V_DOT|VM_RCM_SET,
415 	    "[count]i",
416 	    " i insert before cursor"},
417 /* 152   j */
418 	{v_down,	V_CNT|V_MOVE|VM_LMODE|VM_RCM,
419 	    "[count]j",
420 	    " j move down by lines"},
421 /* 153   k */
422 	{v_up,		V_CNT|V_MOVE|VM_LMODE|VM_RCM,
423 	    "[count]k",
424 	    " k move up by lines"},
425 /* 154   l */
426 	{v_right,	V_CNT|V_MOVE|VM_RCM_SET,
427 	    "[count]l",
428 	    " l move right by columns"},
429 /* 155   m */
430 	{v_mark,	V_CHAR,
431 	    "m[a-z]",
432 	    " m set mark"},
433 /* 156   n */
434 	{v_searchn,	V_ABS_C|V_MOVE|VM_CUTREQ|VM_RCM_SET,
435 	    "n",
436 	    " n repeat last search"},
437 /* 157   o */
438 	{v_io,		V_CNT|V_DOT|VM_RCM_SET,
439 	    "[count]o",
440 	    " o append after line"},
441 /* 160   p */
442 	{v_put,		V_CNT|V_DOT|V_OBUF|VM_RCM_SET,
443 	    "[buffer]p",
444 	    " p insert after cursor from buffer"},
445 /* 161   q */
446 	{NULL},
447 /* 162   r */
448 	{v_replace,	V_CNT|V_DOT|VM_RCM_SET,
449 	    "[count]r character",
450 	    " r replace character"},
451 /* 163   s */
452 	{v_subst,	V_CNT|V_DOT|V_OBUF|VM_RCM_SET,
453 	    "[buffer][count]s",
454 	    " s substitute character"},
455 /* 164   t */
456 	{v_cht,		V_CHAR|V_CNT|V_MOVE|VM_RCM_SET,
457 	    "[count]t character",
458 	    " t before character in line forward search"},
459 /* 165   u */
460 	/*
461 	 * DON'T set the V_DOT flag, it' more complicated than that.
462 	 * See vi/vi.c for details.
463 	 */
464 	{v_undo,	VM_RCM_SET,
465 	    "u",
466 	    " u undo last change"},
467 /* 166   v */
468 	{NULL},
469 /* 167   w */
470 	{v_wordw,	V_CNT|V_MOVE|VM_RCM_SET,
471 	    "[count]w",
472 	    " w move to next word"},
473 /* 170   x */
474 	{v_xchar,	V_CNT|V_DOT|V_OBUF|VM_RCM_SET,
475 	    "[buffer][count]x",
476 	    " x delete character"},
477 /* 171   y */
478 	{v_yank,	V_CNT|V_DOT|V_MOTION|V_OBUF|VM_RCM_SET,
479 	    "[buffer][count]y[count]motion",
480 	    " y copy text to motion into a cut buffer"},
481 /* 172   z */
482 	/*
483 	 * DON'T set the V_CHAR flag, the char isn't required,
484 	 * so it's handled specially in getcmd().
485 	 */
486 	{v_z, 		V_ABS_L|V_CNT|VM_RCM_SETFNB,
487 	    "[line]z[window_size][-|.|+|^|<CR>]",
488 	    " z reposition the screen"},
489 /* 173   { */
490 	{v_paragraphb,	V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET,
491 	    "[count]{",
492 	    " { move back paragraph"},
493 /* 174   | */
494 	{v_ncol,	V_CNT|V_MOVE|VM_RCM_SET,
495 	    "[count]|",
496 	    " | move to column"},
497 /* 175   } */
498 	{v_paragraphf,	V_ABS|V_CNT|V_MOVE|VM_CUTREQ|VM_RCM_SET,
499 	    "[count]}",
500 	    " } move forward paragraph"},
501 /* 176   ~ */
502 	{v_ulcase,	V_CNT|V_DOT|VM_RCM_SET,
503 	    "[count]~",
504 	    " ~ reverse case"},
505 };
506