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 */
29VIKEYS 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