|
|
1.1 ! root 1: /*************************************************************************** ! 2: * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE * ! 3: * is provided to you without charge, and with no warranty. You may give * ! 4: * away copies of JOVE, including sources, provided that this notice is * ! 5: * included in all the files. * ! 6: ***************************************************************************/ ! 7: ! 8: #include "jove.h" ! 9: #include "list.h" ! 10: #include "fp.h" ! 11: #include "termcap.h" ! 12: #include "chars.h" ! 13: #include "disp.h" ! 14: #include "re.h" ! 15: ! 16: /* Up until now a keymap was an array of pointers to ! 17: data_obj's. A data_obj was either a pointer to a built-in ! 18: command or a keyboard macro. Now a data_obj can be a ! 19: pointer to a keymap as well, which is how prefix keys will ! 20: be handled. ! 21: ! 22: There will be a way to build keymaps and give them names, ! 23: and to look those keymaps up by name, attach them to keys. ! 24: There will be a way to specify a string of key strokes and ! 25: have a series of keymaps built automatically for those ! 26: sequences. */ ! 27: ! 28: private void ! 29: fb_aux proto((data_obj *, struct keymap *, char *, char *)), ! 30: find_binds proto((data_obj *, char *)); ! 31: ! 32: private List *keymaps; /* list of all keymaps */ ! 33: private struct keymap *mainmap; ! 34: #if defined(IPROCS) ! 35: private struct keymap *procsmap; ! 36: #endif ! 37: ! 38: /* make a new keymap, give it name NAME, initialize the keys array ! 39: to keys, if nonzero, or make an empty one, otherwise */ ! 40: ! 41: private struct keymap * ! 42: km_new(name, keys) ! 43: char *name; ! 44: data_obj **keys; ! 45: { ! 46: struct keymap *km; ! 47: ! 48: km = (struct keymap *) emalloc(sizeof *km); ! 49: (void) list_push(&keymaps, (Element *) km); ! 50: km->Type = KEYMAP; ! 51: km->Name = name; ! 52: if (keys != 0) { ! 53: km->k_keys = keys; ! 54: km->k_alloc_p = NO; ! 55: } else { ! 56: km->k_keys = (data_obj **) emalloc(NCHARS * sizeof (data_obj *)); ! 57: byte_zero((char *) km->k_keys, NCHARS * sizeof (data_obj *)); ! 58: km->k_alloc_p = YES; ! 59: } ! 60: return km; ! 61: } ! 62: ! 63: #ifdef NEVER_USED ! 64: ! 65: /* free up a keymap */ ! 66: ! 67: private void ! 68: km_destroy(km) ! 69: struct keymap *km; ! 70: { ! 71: if (km->k_alloc_p == YES) ! 72: free((char *) km->k_keys); ! 73: km->k_keys = 0; ! 74: free((char *) km); ! 75: } ! 76: ! 77: /* lookup a keymap by name */ ! 78: ! 79: private struct keymap * ! 80: km_lookup(name) ! 81: char *name; ! 82: { ! 83: List *lp; ! 84: ! 85: for (lp = keymaps; lp != 0; lp = list_next(lp)) ! 86: if (strcmp(name, ((struct keymap *) list_data(lp))->Name) == 0) ! 87: break; ! 88: if (lp == 0) ! 89: return 0; ! 90: return (struct keymap *) list_data(lp); ! 91: } ! 92: ! 93: #endif ! 94: ! 95: /* given a map and a key, return the object bound to that key */ ! 96: ! 97: #define km_getkey(m, c) ((m)->k_keys[(c) & CHARMASK]) ! 98: ! 99: #ifndef km_getkey ! 100: data_obj * ! 101: km_getkey(m, c) ! 102: struct keymap *m; ! 103: int c; ! 104: { ! 105: return (m->k_keys[c & CHARMASK]); ! 106: } ! 107: #endif ! 108: ! 109: private void ! 110: km_setkey(m, c, d) ! 111: struct keymap *m; ! 112: int c; ! 113: data_obj *d; ! 114: { ! 115: m->k_keys[c & CHARMASK] = d; ! 116: } ! 117: ! 118: /* get the currently active keymaps into km_buf */ ! 119: ! 120: private int ! 121: get_keymaps(km_buf) ! 122: struct keymap **km_buf; ! 123: { ! 124: int nmaps = 0; ! 125: ! 126: #ifdef IPROCS ! 127: if (curbuf->b_process != 0) ! 128: km_buf[nmaps++] = procsmap; ! 129: #endif ! 130: if (curbuf->b_map != 0) ! 131: km_buf[nmaps++] = curbuf->b_map; ! 132: km_buf[nmaps++] = mainmap; ! 133: ! 134: return nmaps; ! 135: } ! 136: ! 137: private struct keymap * ! 138: IsPrefix(cp) ! 139: data_obj *cp; ! 140: { ! 141: if (cp == 0 || (cp->Type & TYPEMASK) != KEYMAP) ! 142: return 0; ! 143: return (struct keymap *) cp; ! 144: } ! 145: ! 146: /* Is `c' a prefix character */ ! 147: ! 148: int ! 149: PrefChar(c) ! 150: int c; ! 151: { ! 152: return (int) IsPrefix(km_getkey(mainmap, c)); ! 153: } ! 154: ! 155: void ! 156: UnbindC() ! 157: { ! 158: char *keys; ! 159: struct keymap *map = mainmap; ! 160: ! 161: keys = ask((char *) 0, ProcFmt); ! 162: for (;;) { ! 163: if (keys[1] == '\0') ! 164: break; ! 165: if ((map = IsPrefix(km_getkey(map, *keys))) == 0) ! 166: break; ! 167: keys += 1; ! 168: } ! 169: if (keys[1] != 0) ! 170: complain("That's not a legitimate key sequence."); ! 171: km_setkey(map, keys[0], (data_obj *) 0); ! 172: } ! 173: ! 174: void ! 175: BindWMap(map, lastkey, cmd) ! 176: struct keymap *map; ! 177: int lastkey; ! 178: data_obj *cmd; ! 179: { ! 180: struct keymap *nextmap; ! 181: int c; ! 182: ! 183: c = addgetc(); ! 184: if (c == EOF) { ! 185: if (lastkey == EOF) ! 186: complain("[Empty key sequence]"); ! 187: complain("[Premature end of key sequence]"); ! 188: } else { ! 189: if ((nextmap = IsPrefix(km_getkey(map, c))) != NULL) ! 190: BindWMap(nextmap, c, cmd); ! 191: else { ! 192: km_setkey(map, c, cmd); ! 193: #ifdef MAC ! 194: ((struct cmd *) cmd)->c_key = c; /* see about_j() in mac.c */ ! 195: if (map->k_keys == MainKeys) ! 196: ((struct cmd *) cmd)->c_map = F_MAINMAP; ! 197: else if (map->k_keys == EscKeys) ! 198: ((struct cmd *) cmd)->c_map = F_PREF1MAP; ! 199: else if (map == (struct keymap *) CtlxKeys) ! 200: ((struct cmd *) cmd)->c_map = F_PREF2MAP; ! 201: #endif ! 202: } ! 203: } ! 204: } ! 205: ! 206: void ! 207: BindSomething(proc, map) ! 208: #if defined(MAC) || defined(IBMPC) ! 209: data_obj *(*proc)(); ! 210: #else ! 211: data_obj *(*proc) proto((char *)); ! 212: #endif ! 213: struct keymap *map; ! 214: { ! 215: data_obj *d; ! 216: ! 217: if ((d = (*proc)(ProcFmt)) == 0) ! 218: return; ! 219: s_mess(": %f %s ", d->Name); ! 220: BindWMap(map, EOF, d); ! 221: } ! 222: ! 223: void ! 224: BindAKey() ! 225: { ! 226: BindSomething(findcom, mainmap); ! 227: } ! 228: ! 229: void ! 230: BindMac() ! 231: { ! 232: BindSomething(findmac, mainmap); ! 233: } ! 234: ! 235: void ! 236: DescWMap(map, key) ! 237: struct keymap *map; ! 238: int key; ! 239: { ! 240: data_obj *cp = km_getkey(map, key); ! 241: struct keymap *prefp; ! 242: ! 243: if (cp == 0) ! 244: add_mess("is unbound."); ! 245: else if ((prefp = IsPrefix(cp)) != NULL) ! 246: DescWMap(prefp, addgetc()); ! 247: else ! 248: add_mess("is bound to %s.", cp->Name); ! 249: } ! 250: ! 251: void ! 252: KeyDesc() ! 253: { ! 254: s_mess(ProcFmt); ! 255: DescWMap(mainmap, addgetc()); ! 256: } ! 257: ! 258: void ! 259: DescBindings() ! 260: { ! 261: TOstart("Key Bindings", TRUE); ! 262: DescMap(mainmap, NullStr); ! 263: TOstop(); ! 264: } ! 265: ! 266: void ! 267: DescMap(map, pref) ! 268: struct keymap *map; ! 269: char *pref; ! 270: { ! 271: int c1, ! 272: c2 = 0, ! 273: numbetween; ! 274: char keydescbuf[40]; ! 275: struct keymap *prefp; ! 276: ! 277: for (c1 = 0; c1 < NCHARS && c2 < NCHARS; c1 = c2 + 1) { ! 278: c2 = c1; ! 279: if (km_getkey(map, c1) == 0) ! 280: continue; ! 281: while (++c2 < NCHARS && km_getkey(map, c1) == km_getkey(map, c2)) ! 282: ; ! 283: c2 -= 1; ! 284: numbetween = c2 - c1; ! 285: if (numbetween == 1) ! 286: swritef(keydescbuf, "%s {%p,%p}", pref, c1, c2); ! 287: else if (numbetween == 0) ! 288: swritef(keydescbuf, "%s %p", pref, c1); ! 289: else ! 290: swritef(keydescbuf, "%s [%p-%p]", pref, c1, c2); ! 291: if ((prefp = IsPrefix(km_getkey(map, c1)))!=NULL && (prefp != map)) { ! 292: Typeout("%-18s KEYMAP %s", keydescbuf, km_getkey(map, c1)->Name); ! 293: DescMap(prefp, keydescbuf); ! 294: } ! 295: else ! 296: Typeout("%-18s %s", keydescbuf, km_getkey(map, c1)->Name); ! 297: } ! 298: } ! 299: ! 300: private void ! 301: find_binds(dp, buf) ! 302: data_obj *dp; ! 303: char *buf; ! 304: { ! 305: char *endp; ! 306: ! 307: buf[0] = '\0'; ! 308: fb_aux(dp, mainmap, (char *) 0, buf); ! 309: endp = buf + strlen(buf) - 2; ! 310: if ((endp > buf) && (strcmp(endp, ", ") == 0)) ! 311: *endp = '\0'; ! 312: } ! 313: ! 314: private void ! 315: fb_aux(cp, map, prefix, buf) ! 316: register data_obj *cp; ! 317: struct keymap *map; ! 318: char *buf, ! 319: *prefix; ! 320: { ! 321: int c1, ! 322: c2; ! 323: char *bufp = buf + strlen(buf), ! 324: prefbuf[20]; ! 325: struct keymap *prefp; ! 326: ! 327: for (c1 = c2 = 0; c1 < NCHARS && c2 < NCHARS; c1 = c2 + 1) { ! 328: c2 = c1; ! 329: if (km_getkey(map, c1) == cp) { ! 330: while (++c2 < NCHARS && km_getkey(map, c1) == km_getkey(map, c2)) ! 331: ; ! 332: c2 -= 1; ! 333: if (prefix) ! 334: swritef(bufp, "%s ", prefix); ! 335: bufp += strlen(bufp); ! 336: switch (c2 - c1) { ! 337: case 0: ! 338: swritef(bufp, "%p, ", c1); ! 339: break; ! 340: ! 341: case 1: ! 342: swritef(bufp, "{%p,%p}, ", c1, c2); ! 343: break; ! 344: ! 345: default: ! 346: swritef(bufp, "[%p-%p], ", c1, c2); ! 347: break; ! 348: } ! 349: } ! 350: if ((prefp = IsPrefix(km_getkey(map, c1)))!=NULL && (prefp != map)) { ! 351: swritef(prefbuf, "%p", c1); ! 352: fb_aux(cp, prefp, prefbuf, bufp); ! 353: } ! 354: bufp += strlen(bufp); ! 355: } ! 356: } ! 357: ! 358: void ! 359: DescCom() ! 360: { ! 361: data_obj *dp; ! 362: char pattern[100], ! 363: *doc_type, ! 364: *file = CmdDb; ! 365: static char var_type[] = "Variable"; ! 366: static char cmd_type[] = "Command"; ! 367: File *fp; ! 368: ! 369: if (!strcmp(LastCmd->Name, "describe-variable")) { ! 370: doc_type = var_type; ! 371: dp = (data_obj *) findvar(ProcFmt); ! 372: } else { ! 373: doc_type = cmd_type; ! 374: dp = (data_obj *) findcom(ProcFmt); ! 375: } ! 376: if (dp == 0) ! 377: return; ! 378: fp = open_file(file, iobuff, F_READ, YES, YES); ! 379: Placur(ILI, 0); ! 380: flusho(); ! 381: swritef(pattern, "^:entry \"%s\" \"%s\"$", dp->Name, doc_type); ! 382: TOstart("Help", TRUE); ! 383: for (;;) { ! 384: if (f_gets(fp, genbuf, (size_t)LBSIZE) == EOF) { ! 385: Typeout("There is no documentation for \"%s\".", dp->Name); ! 386: break; ! 387: } ! 388: if (genbuf[0] == ':' && LookingAt(pattern, genbuf, 0)) { ! 389: /* found it ... let's print it */ ! 390: if (doc_type == var_type) ! 391: Typeout(dp->Name); ! 392: else if (doc_type == cmd_type) { ! 393: char binding[128]; ! 394: ! 395: find_binds(dp, binding); ! 396: if (blnkp(binding)) ! 397: Typeout("To invoke %s, type \"ESC X %s<cr>\".", ! 398: dp->Name, dp->Name); ! 399: else ! 400: Typeout("Type \"%s\" to invoke %s.", ! 401: binding, dp->Name); ! 402: } ! 403: Typeout(""); ! 404: while (f_gets(fp, genbuf, (size_t)LBSIZE) != EOF ! 405: && strncmp(genbuf, ":entry", (size_t)6) != 0) { ! 406: Typeout("%s", genbuf); ! 407: } ! 408: break; ! 409: } ! 410: } ! 411: f_close(fp); ! 412: TOstop(); ! 413: } ! 414: ! 415: ! 416: void ! 417: Apropos() ! 418: { ! 419: register const struct cmd *cp; ! 420: register struct macro *m; ! 421: register const struct variable *v; ! 422: register List *klp; ! 423: char *ans; ! 424: int anyfs = NO, ! 425: anyvs = NO, ! 426: anyms = NO, ! 427: anykms = NO; ! 428: char buf[256]; ! 429: ! 430: ans = ask((char *) 0, ": %f (keyword) "); ! 431: TOstart("Help", TRUE); ! 432: for (cp = commands; cp->Name != 0; cp++) ! 433: if (sindex(ans, cp->Name)) { ! 434: if (anyfs == NO) { ! 435: Typeout("Commands"); ! 436: Typeout("--------"); ! 437: anyfs = YES; ! 438: } ! 439: find_binds((data_obj *) cp, buf); ! 440: if (buf[0]) ! 441: Typeout(": %-35s (%s)", cp->Name, buf); ! 442: else ! 443: Typeout(": %s", cp->Name); ! 444: } ! 445: if (anyfs == YES) ! 446: Typeout(NullStr); ! 447: for (v = variables; v->Name != 0; v++) ! 448: if (sindex(ans, v->Name)) { ! 449: if (anyvs == NO) { ! 450: Typeout("Variables"); ! 451: Typeout("---------"); ! 452: anyvs = YES; ! 453: } ! 454: vpr_aux(v, buf); ! 455: Typeout(": set %-26s %s", v->Name, buf); ! 456: } ! 457: if (anyvs == YES) ! 458: Typeout(NullStr); ! 459: for (m = macros; m != 0; m = m->m_nextm) ! 460: if (sindex(ans, m->Name)) { ! 461: if (anyms == NO) { ! 462: Typeout("Macros"); ! 463: Typeout("------"); ! 464: anyms = YES; ! 465: } ! 466: find_binds((data_obj *) m, buf); ! 467: if (buf[0]) ! 468: Typeout(": %-35s (%s)", m->Name, buf); ! 469: else ! 470: Typeout(": %-35s %s", "execute-macro", m->Name); ! 471: } ! 472: if (anyms == YES) ! 473: Typeout(NullStr); ! 474: for (klp = keymaps; klp; klp = list_next(klp)) { ! 475: register struct keymap *km = (struct keymap *)list_data(klp); ! 476: ! 477: if (sindex(ans, km->Name)) { ! 478: if (anykms == NO) { ! 479: Typeout("Keymaps"); ! 480: Typeout("-------"); ! 481: anykms = YES; ! 482: } ! 483: find_binds((data_obj *) km, buf); ! 484: if (buf[0]) ! 485: Typeout(": %-35s (%s)", km->Name, buf); ! 486: else ! 487: Typeout(": %s", km->Name); ! 488: } ! 489: } ! 490: TOstop(); ! 491: } ! 492: ! 493: #ifdef NEVER_USED ! 494: private char * ! 495: km_newname() ! 496: { ! 497: char buffer[128]; ! 498: static int km_count = 1; ! 499: ! 500: swritef(buffer, "keymap-%d", km_count++); ! 501: return copystr(buffer); ! 502: } ! 503: #endif ! 504: ! 505: void ! 506: InitKeymaps() ! 507: { ! 508: struct keymap *km; ! 509: ! 510: mainmap = km_new(copystr("mainmap"), MainKeys); ! 511: ! 512: /* setup ESC map */ ! 513: km = km_new(copystr("ESC-map"), EscKeys); ! 514: km_setkey(mainmap, ESC, (data_obj *) km); ! 515: ! 516: /* setup Ctlx map */ ! 517: km = km_new(copystr("CTLX-map"), CtlxKeys); ! 518: km_setkey(mainmap, CTL('X'), (data_obj *) km); ! 519: } ! 520: ! 521: void ! 522: MakeKMap() ! 523: { ! 524: char *name; ! 525: ! 526: name = ask((char *) 0, ProcFmt); ! 527: (void) km_new(copystr(name), (data_obj **) 0); ! 528: } ! 529: ! 530: private data_obj * ! 531: findmap(fmt) ! 532: char *fmt; ! 533: { ! 534: List *lp; ! 535: char *strings[128]; ! 536: int i; ! 537: ! 538: for (lp = keymaps, i = 0; lp != 0; lp = list_next(lp)) ! 539: strings[i++] = ((struct keymap *) list_data(lp))->Name; ! 540: strings[i] = 0; ! 541: ! 542: i = complete(strings, fmt, 0); ! 543: if (i < 0) ! 544: return 0; ! 545: lp = keymaps; ! 546: while (--i >= 0) ! 547: lp = list_next(lp); ! 548: return (data_obj *) list_data(lp); ! 549: } ! 550: ! 551: #ifdef IPROCS ! 552: private void ! 553: mk_proc_km() ! 554: { ! 555: procsmap = km_new("process-keymap", (data_obj **) 0); ! 556: } ! 557: ! 558: void ! 559: ProcBind() ! 560: { ! 561: data_obj *d; ! 562: ! 563: if (procsmap == 0) ! 564: mk_proc_km(); ! 565: ! 566: if ((d = findcom(ProcFmt)) == 0) ! 567: return; ! 568: s_mess(": %f %s ", d->Name); ! 569: BindWMap(procsmap, EOF, d); ! 570: } ! 571: ! 572: void ! 573: ProcKmBind() ! 574: { ! 575: data_obj *d; ! 576: ! 577: if (procsmap == 0) ! 578: mk_proc_km(); ! 579: if ((d = findmap(ProcFmt)) == 0) ! 580: return; ! 581: s_mess(": %f %s ", d->Name); ! 582: BindWMap(procsmap, EOF, d); ! 583: } ! 584: ! 585: #endif ! 586: ! 587: void ! 588: KmBind() ! 589: { ! 590: BindSomething(findmap, mainmap); ! 591: } ! 592: ! 593: void ! 594: dispatch(c) ! 595: register int c; ! 596: { ! 597: data_obj *cp; ! 598: struct keymap *maps[10]; /* never more than 10 active ! 599: maps at a time, I promise */ ! 600: int nmaps; ! 601: ! 602: this_cmd = 0; ! 603: nmaps = get_keymaps(maps); ! 604: ! 605: for (;;) { ! 606: int i, ! 607: nvalid, ! 608: slow = NO; ! 609: ! 610: for (i = 0, nvalid = 0; i < nmaps; i++) { ! 611: if (maps[i] == 0) ! 612: continue; ! 613: cp = km_getkey(maps[i], c); ! 614: if (cp != 0) { ! 615: if (obj_type(cp) != KEYMAP) { ! 616: ExecCmd(cp); ! 617: return; ! 618: } ! 619: nvalid += 1; ! 620: } ! 621: maps[i] = (struct keymap *) cp; ! 622: } ! 623: if (nvalid == 0) { ! 624: char strokes[128]; ! 625: ! 626: pp_key_strokes(strokes, sizeof (strokes)); ! 627: s_mess("[%sunbound]", strokes); ! 628: rbell(); ! 629: clr_arg_value(); ! 630: errormsg = NO; ! 631: return; ! 632: } ! 633: ! 634: c = waitchar(&slow); ! 635: if (c == AbortChar) { ! 636: message("[Aborted]"); ! 637: rbell(); ! 638: return; ! 639: } ! 640: } ! 641: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.