|
|
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.