xref: /openbsd/usr.bin/mg/keymap.c (revision 38733382)
1 /*	$OpenBSD: keymap.c,v 1.61 2023/04/17 09:49:04 op Exp $	*/
2 
3 /* This file is in the public domain. */
4 
5 /*
6  * Keyboard maps.  This is character set dependent.  The terminal specific
7  * parts of building the keymap has been moved to a better place.
8  */
9 
10 #include <sys/queue.h>
11 #include <signal.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 
16 #include "def.h"
17 #include "kbd.h"
18 
19 /*
20  * initial keymap declarations, deepest first
21  */
22 
23 static PF cHcG[] = {
24 	ctrlg,			/* ^G */
25 	help_help		/* ^H */
26 };
27 
28 static PF cHa[] = {
29 	apropos_command,	/* a */
30 	wallchart,		/* b */
31 	desckey			/* c */
32 };
33 
34 struct KEYMAPE (2) helpmap = {
35 	2,
36 	2,
37 	rescan,
38 	{
39 		{
40 			CCHR('G'), CCHR('H'), cHcG, NULL
41 		},
42 		{
43 			'a', 'c', cHa, NULL
44 		}
45 	}
46 };
47 
48 static PF cCsc[] = {
49 	cscallerfuncs,		/* c */
50 	csdefinition,		/* d */
51 	csegrep,		/* e */
52 	csfindfile,		/* f */
53 	rescan,			/* g */
54 	rescan,			/* h */
55 	csfindinc,		/* i */
56 	rescan,			/* j */
57 	rescan,			/* k */
58 	rescan,			/* l */
59 	rescan,			/* m */
60 	csnextmatch,		/* n */
61 	rescan,			/* o */
62 	csprevmatch,		/* p */
63 	rescan,			/* q */
64 	rescan, 		/* r */
65 	cssymbol,		/* s */
66 	csfindtext		/* t */
67 };
68 
69 static struct KEYMAPE (1) cCsmap = {
70 	1,
71 	1,
72 	rescan,
73 	{
74 		{
75 			'c', 't', cCsc, NULL
76 		}
77 	}
78 };
79 
80 static PF cCs[] = {
81 	NULL			/* s */
82 };
83 
84 struct KEYMAPE (2) ccmap = {
85 	2,
86 	2,
87 	rescan,
88 	{
89 		{
90 			CCHR('@'), CCHR('@'), (PF[]){ rescan }, NULL
91 		},
92 		{
93 			's', 's', cCs, (KEYMAP *) & cCsmap
94 		}
95 	}
96 };
97 
98 static PF cX4cF[] = {
99 	poptofile,		/* ^f */
100 	ctrlg			/* ^g */
101 };
102 static PF cX4b[] = {
103 	poptobuffer,		/* b */
104 	rescan,			/* c */
105 	rescan,			/* d */
106 	rescan,			/* e */
107 	poptofile		/* f */
108 };
109 static struct KEYMAPE (2) cX4map = {
110 	2,
111 	2,
112 	rescan,
113 	{
114 		{
115 			CCHR('F'), CCHR('G'), cX4cF, NULL
116 		},
117 		{
118 			'b', 'f', cX4b, NULL
119 		}
120 	}
121 };
122 
123 static PF cXcB[] = {
124 	listbuffers,		/* ^B */
125 	quit,			/* ^C */
126 	rescan,			/* ^D */
127 	rescan,			/* ^E */
128 	filevisit,		/* ^F */
129 	ctrlg			/* ^G */
130 };
131 
132 static PF cXcJ[] = {
133 	dired_jump,		/* ^J */
134 	rescan,			/* ^K */
135 	lowerregion,		/* ^L */
136 	rescan,			/* ^M */
137 	rescan,			/* ^N */
138 	deblank,		/* ^O */
139 	rescan,			/* ^P */
140 	togglereadonly,		/* ^Q */
141 	filevisitro,		/* ^R */
142 	filesave,		/* ^S */
143 	rescan,			/* ^T */
144 	upperregion,		/* ^U */
145 	filevisitalt,		/* ^V */
146 	filewrite,		/* ^W */
147 	swapmark		/* ^X */
148 };
149 
150 static PF cXlp[] = {
151 	definemacro,		/* ( */
152 	finishmacro		/* ) */
153 };
154 
155 static PF cX0[] = {
156 	delwind,		/* 0 */
157 	onlywind,		/* 1 */
158 	splitwind,		/* 2 */
159 	rescan,			/* 3 */
160 	NULL			/* 4 */
161 };
162 
163 static PF cXeq[] = {
164 	showcpos		/* = */
165 };
166 
167 static PF cXcar[] = {
168 	enlargewind,		/* ^ */
169 	rescan,			/* _ */
170 	next_error,		/* ` */
171 	rescan,			/* a */
172 	usebuffer,		/* b */
173 	rescan,			/* c */
174 	rescan,			/* d */
175 	executemacro,		/* e */
176 	setfillcol,		/* f */
177 	gotoline,		/* g */
178 	markbuffer,		/* h */
179 	fileinsert,		/* i */
180 	rescan,			/* j */
181 	killbuffer_cmd,		/* k */
182 	rescan,			/* l */
183 	rescan,			/* m */
184 	nextwind,		/* n */
185 	nextwind,		/* o */
186 	prevwind,		/* p */
187 	rescan,			/* q */
188 	rescan,			/* r */
189 	savebuffers,		/* s */
190 	rescan,			/* t */
191 	undo			/* u */
192 };
193 
194 struct KEYMAPE (6) cXmap = {
195 	6,
196 	6,
197 	rescan,
198 	{
199 		{
200 			CCHR('B'), CCHR('G'), cXcB, NULL
201 		},
202 		{
203 			CCHR('J'), CCHR('X'), cXcJ, NULL
204 		},
205 		{
206 			'(', ')', cXlp, NULL
207 		},
208 		{
209 			'0', '4', cX0, (KEYMAP *) & cX4map
210 		},
211 		{
212 			'=', '=', cXeq, NULL
213 		},
214 		{
215 			'^', 'u', cXcar, NULL
216 		}
217 	}
218 };
219 
220 static PF metacG[] = {
221 	ctrlg			/* ^G */
222 };
223 
224 static PF metacV[] = {
225 	pagenext		/* ^V */
226 };
227 
228 static PF metaspex[] = {
229 	justone,		/* space */
230 	shellcommand		/* ! */
231 };
232 
233 static PF metapct[] = {
234 	queryrepl		/* % */
235 };
236 
237 static PF metami[] = {
238 	poptag,                 /* * */
239 	rescan,                 /* + */
240 	rescan,                 /* , */
241 	negative_argument,	/* - */
242 	findtag,		/* . */
243 	rescan,			/* / */
244 	digit_argument,		/* 0 */
245 	digit_argument,		/* 1 */
246 	digit_argument,		/* 2 */
247 	digit_argument,		/* 3 */
248 	digit_argument,		/* 4 */
249 	digit_argument,		/* 5 */
250 	digit_argument,		/* 6 */
251 	digit_argument,		/* 7 */
252 	digit_argument,		/* 8 */
253 	digit_argument,		/* 9 */
254 	rescan,			/* : */
255 	rescan,			/* ; */
256 	gotobob,		/* < */
257 	rescan,			/* = */
258 	gotoeob			/* > */
259 };
260 
261 static PF metasqf[] = {
262 	NULL,			/* [ */
263 	delwhite,		/* \ */
264 	rescan,			/* ] */
265 	joinline,		/* ^ */
266 	rescan,			/* _ */
267 	rescan,			/* ` */
268 	rescan,			/* a */
269 	backword,		/* b */
270 	capword,		/* c */
271 	delfword,		/* d */
272 	rescan,			/* e */
273 	forwword,		/* f */
274 	rescan,			/* g */
275 	markpara		/* h */
276 };
277 
278 static PF metal[] = {
279 	lowerword,		/* l */
280 	backtoindent,		/* m */
281 	rescan,			/* n */
282 	rescan,			/* o */
283 	rescan,			/* p */
284 	fillpara,		/* q */
285 	backsearch,		/* r */
286 	forwsearch,		/* s */
287 	transposeword,		/* t */
288 	upperword,		/* u */
289 	backpage,		/* v */
290 	copyregion,		/* w */
291 	extend,			/* x */
292 	rescan,			/* y */
293 	zaptochar,		/* z */
294 	gotobop,		/* { */
295 	piperegion,		/* | */
296 	gotoeop			/* } */
297 };
298 
299 static PF metasqlZ[] = {
300 	rescan			/* Z */
301 };
302 
303 static PF metatilde[] = {
304 	notmodified,		/* ~ */
305 	delbword		/* DEL */
306 };
307 
308 struct KEYMAPE (1) metasqlmap = {
309 	1,
310 	1,
311 	rescan,
312 	{
313 		{
314 			'Z', 'Z', metasqlZ, NULL
315 		}
316 	}
317 };
318 
319 struct KEYMAPE (8) metamap = {
320 	8,
321 	8,
322 	rescan,
323 	{
324 		{
325 			CCHR('G'), CCHR('G'), metacG, NULL
326 		},
327 		{
328 			CCHR('V'), CCHR('V'), metacV, NULL
329 		},
330 		{
331 			' ', '!', metaspex, NULL
332 		},
333 		{
334 			'%', '%', metapct, NULL
335 		},
336 		{
337 			'*', '>', metami, NULL
338 		},
339 		{
340 			'[', 'h', metasqf, (KEYMAP *) &metasqlmap
341 		},
342 		{
343 			'l', '}', metal, NULL
344 		},
345 		{
346 			'~', CCHR('?'), metatilde, NULL
347 		}
348 	}
349 };
350 
351 static PF fund_at[] = {
352 	setmark,		/* ^@ */
353 	gotobol,		/* ^A */
354 	backchar,		/* ^B */
355 	NULL,			/* ^C */
356 	forwdel,		/* ^D */
357 	gotoeol,		/* ^E */
358 	forwchar,		/* ^F */
359 	ctrlg,			/* ^G */
360 };
361 
362 static PF fund_h[] = {
363 	NULL,			/* ^H */
364 };
365 
366 
367 /* ^I is selfinsert */
368 static PF fund_CJ[] = {
369 	lfindent,		/* ^J */
370 	killline,		/* ^K */
371 	reposition,		/* ^L */
372 	enewline,		/* ^M */
373 	forwline,		/* ^N */
374 	openline,		/* ^O */
375 	backline,		/* ^P */
376 	quote,			/* ^Q */
377 	backisearch,		/* ^R */
378 	forwisearch,		/* ^S */
379 	twiddle,		/* ^T */
380 	universal_argument,	/* ^U */
381 	forwpage,		/* ^V */
382 	killregion,		/* ^W */
383 	NULL,			/* ^X */
384 	yank,			/* ^Y */
385 	spawncli		/* ^Z */
386 };
387 
388 static PF fund_esc[] = {
389 	NULL,			/* esc */
390 	rescan,			/* ^\ selfinsert is default on fundamental */
391 	rescan,			/* ^] */
392 	rescan,			/* ^^ */
393 	undo			/* ^_ */
394 };
395 
396 static PF fund_del[] = {
397 	backdel			/* DEL */
398 };
399 
400 static PF fund_cb[] = {
401 	showmatch		/* ) ] }  */
402 };
403 
404 static struct KEYMAPE (8) fundmap = {
405 	8,
406 	8,
407 	selfinsert,
408 	{
409 		{
410 			CCHR('@'), CCHR('G'), fund_at, (KEYMAP *) & ccmap
411 		},
412 		{
413 			CCHR('H'), CCHR('H'), fund_h, (KEYMAP *) & helpmap
414 		},
415 		{
416 			CCHR('J'), CCHR('Z'), fund_CJ, (KEYMAP *) & cXmap
417 		},
418 		{
419 			CCHR('['), CCHR('_'), fund_esc, (KEYMAP *) & metamap
420 		},
421 		{
422 			')', ')', fund_cb, NULL
423 		},
424 		{
425 			']', ']', fund_cb, NULL
426 		},
427 		{
428 			'}', '}', fund_cb, NULL
429 		},
430 		{
431 			CCHR('?'), CCHR('?'), fund_del, NULL
432 		},
433 	}
434 };
435 
436 static PF fill_sp[] = {
437 	fillword		/* ' ' */
438 };
439 
440 static struct KEYMAPE (1) fillmap = {
441 	1,
442 	1,
443 	rescan,
444 	{
445 		{ ' ', ' ', fill_sp, NULL }
446 	}
447 };
448 
449 static PF indent_lf[] = {
450 	enewline,		/* ^J */
451 	rescan,			/* ^K */
452 	rescan,			/* ^L */
453 	lfindent		/* ^M */
454 };
455 
456 static struct KEYMAPE (1) indntmap = {
457 	1,
458 	1,
459 	rescan,
460 	{
461 		{
462 			CCHR('J'), CCHR('M'), indent_lf, NULL
463 		}
464 	}
465 };
466 
467 static PF notab_tab[] = {
468 	space_to_tabstop	/* ^I */
469 };
470 
471 static struct KEYMAPE (1) notabmap = {
472 	1,
473 	1,
474 	rescan,
475 	{
476 		{
477 			CCHR('I'), CCHR('I'), notab_tab, NULL
478 		}
479 	}
480 };
481 
482 static struct KEYMAPE (1) overwmap = {
483 	0,
484 	1,		/* 1 to avoid 0 sized array */
485 	rescan,
486 	{
487 		/* unused dummy entry for VMS C */
488 		{
489 			(KCHAR)0, (KCHAR)0, NULL, NULL
490 		}
491 	}
492 };
493 
494 
495 /*
496  * The basic (root) keyboard map
497  */
498 struct maps_s	fundamental_mode = { (KEYMAP *)&fundmap, "fundamental" };
499 
500 /*
501  * give names to the maps, for use by help etc. If the map is to be bindable,
502  * it must also be listed in the function name table below with the same
503  * name. Maps created dynamically currently don't get added here, thus are
504  * unnamed. Modes are just named keymaps with functions to add/subtract them
505  * from a buffer's list of modes.  If you change a mode name, change it in
506  * modes.c also.
507  */
508 
509 static struct maps_s map_table[] = {
510 	{(KEYMAP *) &fillmap, "fill",},
511 	{(KEYMAP *) &indntmap, "indent",},
512 	{(KEYMAP *) &notabmap, "notab",},
513 	{(KEYMAP *) &overwmap, "overwrite",},
514 	{(KEYMAP *) &metamap, "esc prefix",},
515 	{(KEYMAP *) &cXmap, "c-x prefix",},
516 	{(KEYMAP *) &cX4map, "c-x 4 prefix",},
517 	{(KEYMAP *) &helpmap, "help",},
518 	{NULL, NULL}
519 };
520 
521 struct maps_s *maps;
522 
523 void
maps_init(void)524 maps_init(void)
525 {
526 	int	 i;
527 	struct maps_s	*mp;
528 
529 	maps = &fundamental_mode;
530 	for (i = 0; map_table[i].p_name != NULL; i++) {
531 		mp = &map_table[i];
532 		mp->p_next = maps;
533 		maps = mp;
534 	}
535 }
536 
537 /*
538  * Insert a new (named) keymap at the head of the keymap list.
539  */
540 int
maps_add(KEYMAP * map,const char * name)541 maps_add(KEYMAP *map, const char *name)
542 {
543 	struct maps_s	*mp;
544 
545 	if ((mp = malloc(sizeof(*mp))) == NULL)
546 		return (FALSE);
547 
548 	mp->p_name = name;
549 	mp->p_map = map;
550 	mp->p_next = maps;
551 	maps = mp;
552 
553 	return (TRUE);
554 }
555 
556 struct maps_s *
name_mode(const char * name)557 name_mode(const char *name)
558 {
559 	struct maps_s	*mp;
560 
561 	for (mp = maps; mp != NULL; mp = mp->p_next)
562 		if (strcmp(mp->p_name, name) == 0)
563 			return (mp);
564 	return (NULL);
565 }
566 
567 KEYMAP *
name_map(const char * name)568 name_map(const char *name)
569 {
570 	struct maps_s	*mp;
571 
572 	return ((mp = name_mode(name)) == NULL ? NULL : mp->p_map);
573 }
574