1 /* $OpenBSD: keymap.c,v 1.59 2021/04/20 10:02:50 lum 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 rescan, /* 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 #ifdef NOTAB 468 static PF notab_tab[] = { 469 space_to_tabstop /* ^I */ 470 }; 471 472 static struct KEYMAPE (1) notabmap = { 473 1, 474 1, 475 rescan, 476 { 477 { 478 CCHR('I'), CCHR('I'), notab_tab, NULL 479 } 480 } 481 }; 482 #endif /* NOTAB */ 483 484 static struct KEYMAPE (1) overwmap = { 485 0, 486 1, /* 1 to avoid 0 sized array */ 487 rescan, 488 { 489 /* unused dummy entry for VMS C */ 490 { 491 (KCHAR)0, (KCHAR)0, NULL, NULL 492 } 493 } 494 }; 495 496 497 /* 498 * The basic (root) keyboard map 499 */ 500 struct maps_s fundamental_mode = { (KEYMAP *)&fundmap, "fundamental" }; 501 502 /* 503 * give names to the maps, for use by help etc. If the map is to be bindable, 504 * it must also be listed in the function name table below with the same 505 * name. Maps created dynamically currently don't get added here, thus are 506 * unnamed. Modes are just named keymaps with functions to add/subtract them 507 * from a buffer's list of modes. If you change a mode name, change it in 508 * modes.c also. 509 */ 510 511 static struct maps_s map_table[] = { 512 {(KEYMAP *) &fillmap, "fill",}, 513 {(KEYMAP *) &indntmap, "indent",}, 514 #ifdef NOTAB 515 {(KEYMAP *) ¬abmap, "notab",}, 516 #endif /* NOTAB */ 517 {(KEYMAP *) &overwmap, "overwrite",}, 518 {(KEYMAP *) &metamap, "esc prefix",}, 519 {(KEYMAP *) &cXmap, "c-x prefix",}, 520 {(KEYMAP *) &cX4map, "c-x 4 prefix",}, 521 {(KEYMAP *) &helpmap, "help",}, 522 {NULL, NULL} 523 }; 524 525 struct maps_s *maps; 526 527 void 528 maps_init(void) 529 { 530 int i; 531 struct maps_s *mp; 532 533 maps = &fundamental_mode; 534 for (i = 0; map_table[i].p_name != NULL; i++) { 535 mp = &map_table[i]; 536 mp->p_next = maps; 537 maps = mp; 538 } 539 } 540 541 /* 542 * Insert a new (named) keymap at the head of the keymap list. 543 */ 544 int 545 maps_add(KEYMAP *map, const char *name) 546 { 547 struct maps_s *mp; 548 549 if ((mp = malloc(sizeof(*mp))) == NULL) 550 return (FALSE); 551 552 mp->p_name = name; 553 mp->p_map = map; 554 mp->p_next = maps; 555 maps = mp; 556 557 return (TRUE); 558 } 559 560 struct maps_s * 561 name_mode(const char *name) 562 { 563 struct maps_s *mp; 564 565 for (mp = maps; mp != NULL; mp = mp->p_next) 566 if (strcmp(mp->p_name, name) == 0) 567 return (mp); 568 return (NULL); 569 } 570 571 KEYMAP * 572 name_map(const char *name) 573 { 574 struct maps_s *mp; 575 576 return ((mp = name_mode(name)) == NULL ? NULL : mp->p_map); 577 } 578