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 *) ¬abmap, "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