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