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