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