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
13static 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 */
31VIKEYS 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