/* $OpenBSD: help.c,v 1.37 2023/03/08 04:43:11 guenther Exp $ */ /* This file is in the public domain. */ /* * Help functions for Mg 2 */ #include #include #include #include #include "def.h" #include "funmap.h" #include "kbd.h" #include "key.h" #include "macro.h" static int showall(struct buffer *, KEYMAP *, char *); static int findbind(KEYMAP *, PF, char *, size_t); /* * Read a key from the keyboard, and look it up in the keymap. * Display the name of the function currently bound to the key. */ int desckey(int f, int n) { KEYMAP *curmap; PF funct; int c, m, i, num; char *pep; char dprompt[80]; if (inmacro) return (TRUE); /* ignore inside keyboard macro */ num = strlcpy(dprompt, "Describe key briefly: ", sizeof(dprompt)); if (num >= sizeof(dprompt)) num = sizeof(dprompt) - 1; pep = dprompt + num; key.k_count = 0; m = curbp->b_nmodes; curmap = curbp->b_modes[m]->p_map; for (;;) { for (;;) { ewprintf("%s", dprompt); pep[-1] = ' '; pep = getkeyname(pep, sizeof(dprompt) - (pep - dprompt), key.k_chars[key.k_count++] = c = getkey(FALSE)); if ((funct = doscan(curmap, c, &curmap)) != NULL) break; *pep++ = '-'; *pep = '\0'; } if (funct != rescan) break; if (ISUPPER(key.k_chars[key.k_count - 1])) { funct = doscan(curmap, TOLOWER(key.k_chars[key.k_count - 1]), &curmap); if (funct == NULL) { *pep++ = '-'; *pep = '\0'; continue; } if (funct != rescan) break; } nextmode: if (--m < 0) break; curmap = curbp->b_modes[m]->p_map; for (i = 0; i < key.k_count; i++) { funct = doscan(curmap, key.k_chars[i], &curmap); if (funct != NULL) { if (i == key.k_count - 1 && funct != rescan) goto found; funct = rescan; goto nextmode; } } *pep++ = '-'; *pep = '\0'; } found: if (funct == rescan || funct == selfinsert) ewprintf("%k is not bound to any function"); else if ((pep = (char *)function_name(funct)) != NULL) ewprintf("%k runs the command %s", pep); else ewprintf("%k is bound to an unnamed function"); return (TRUE); } /* * This function creates a table, listing all of the command * keys and their current bindings, and stores the table in the * *help* pop-up buffer. This lets Mg produce its own wall chart. */ int wallchart(int f, int n) { int m; struct buffer *bp; bp = bfind("*help*", TRUE); if (bclear(bp) != TRUE) /* clear it out */ return (FALSE); bp->b_flag |= BFREADONLY; for (m = curbp->b_nmodes; m > 0; m--) { if ((addlinef(bp, "Local keybindings for mode %s:", curbp->b_modes[m]->p_name) == FALSE) || (showall(bp, curbp->b_modes[m]->p_map, "") == FALSE) || (addline(bp, "") == FALSE)) return (FALSE); } if ((addline(bp, "Global bindings:") == FALSE) || (showall(bp, fundamental_map, "") == FALSE)) return (FALSE); return (popbuftop(bp, WNONE)); } static int showall(struct buffer *bp, KEYMAP *map, char *prefix) { KEYMAP *newmap; char buf[80], keybuf[16]; PF fun; int c; if (addline(bp, "") == FALSE) return (FALSE); /* XXX - 256 ? */ for (c = 0; c < 256; c++) { fun = doscan(map, c, &newmap); if (fun == rescan || fun == selfinsert) continue; getkeyname(buf, sizeof(buf), c); (void)snprintf(keybuf, sizeof(keybuf), "%s%s ", prefix, buf); if (fun == NULL) { if (showall(bp, newmap, keybuf) == FALSE) return (FALSE); } else { if (addlinef(bp, "%-16s%s", keybuf, function_name(fun)) == FALSE) return (FALSE); } } return (TRUE); } int help_help(int f, int n) { KEYMAP *kp; PF funct; if ((kp = name_map("help")) == NULL) return (FALSE); ewprintf("a b c: "); do { funct = doscan(kp, getkey(FALSE), NULL); } while (funct == NULL || funct == help_help); if (macrodef && macrocount < MAXMACRO) macro[macrocount - 1].m_funct = funct; return ((*funct)(f, n)); } int apropos_command(int f, int n) { struct buffer *bp; struct list *fnames, *el; char string[32]; if (eread("apropos: ", string, sizeof(string), EFNUL | EFNEW) == NULL) return (ABORT); /* FALSE means we got a 0 character string, which is fine */ bp = bfind("*help*", TRUE); if (bclear(bp) == FALSE) return (FALSE); fnames = complete_function_list(""); for (el = fnames; el != NULL; el = el->l_next) { char buf[32]; if (strstr(el->l_name, string) == NULL) continue; buf[0] = '\0'; findbind(fundamental_map, name_function(el->l_name), buf, sizeof(buf)); if (addlinef(bp, "%-32s%s", el->l_name, buf) == FALSE) { free_file_list(fnames); return (FALSE); } } free_file_list(fnames); return (popbuftop(bp, WNONE)); } static int findbind(KEYMAP *map, PF fun, char *buf, size_t len) { KEYMAP *newmap; PF nfun; char buf2[16], keybuf[16]; int c; /* XXX - 256 ? */ for (c = 0; c < 256; c++) { nfun = doscan(map, c, &newmap); if (nfun == fun) { getkeyname(buf, len, c); return (TRUE); } if (nfun == NULL) { if (findbind(newmap, fun, buf2, sizeof(buf2)) == TRUE) { getkeyname(keybuf, sizeof(keybuf), c); (void)snprintf(buf, len, "%s %s", keybuf, buf2); return (TRUE); } } } return (FALSE); }