1/* $OpenBSD: help.c,v 1.37 2023/03/08 04:43:11 guenther Exp $ */ 2 3/* This file is in the public domain. */ 4 5/* 6 * Help functions for Mg 2 7 */ 8 9#include <sys/queue.h> 10#include <signal.h> 11#include <stdio.h> 12#include <string.h> 13 14#include "def.h" 15#include "funmap.h" 16#include "kbd.h" 17#include "key.h" 18#include "macro.h" 19 20static int showall(struct buffer *, KEYMAP *, char *); 21static int findbind(KEYMAP *, PF, char *, size_t); 22 23/* 24 * Read a key from the keyboard, and look it up in the keymap. 25 * Display the name of the function currently bound to the key. 26 */ 27int 28desckey(int f, int n) 29{ 30 KEYMAP *curmap; 31 PF funct; 32 int c, m, i, num; 33 char *pep; 34 char dprompt[80]; 35 36 if (inmacro) 37 return (TRUE); /* ignore inside keyboard macro */ 38 39 num = strlcpy(dprompt, "Describe key briefly: ", sizeof(dprompt)); 40 if (num >= sizeof(dprompt)) 41 num = sizeof(dprompt) - 1; 42 pep = dprompt + num; 43 key.k_count = 0; 44 m = curbp->b_nmodes; 45 curmap = curbp->b_modes[m]->p_map; 46 for (;;) { 47 for (;;) { 48 ewprintf("%s", dprompt); 49 pep[-1] = ' '; 50 pep = getkeyname(pep, sizeof(dprompt) - (pep - dprompt), 51 key.k_chars[key.k_count++] = c = getkey(FALSE)); 52 if ((funct = doscan(curmap, c, &curmap)) != NULL) 53 break; 54 *pep++ = '-'; 55 *pep = '\0'; 56 } 57 if (funct != rescan) 58 break; 59 if (ISUPPER(key.k_chars[key.k_count - 1])) { 60 funct = doscan(curmap, 61 TOLOWER(key.k_chars[key.k_count - 1]), &curmap); 62 if (funct == NULL) { 63 *pep++ = '-'; 64 *pep = '\0'; 65 continue; 66 } 67 if (funct != rescan) 68 break; 69 } 70nextmode: 71 if (--m < 0) 72 break; 73 curmap = curbp->b_modes[m]->p_map; 74 for (i = 0; i < key.k_count; i++) { 75 funct = doscan(curmap, key.k_chars[i], &curmap); 76 if (funct != NULL) { 77 if (i == key.k_count - 1 && funct != rescan) 78 goto found; 79 funct = rescan; 80 goto nextmode; 81 } 82 } 83 *pep++ = '-'; 84 *pep = '\0'; 85 } 86found: 87 if (funct == rescan || funct == selfinsert) 88 ewprintf("%k is not bound to any function"); 89 else if ((pep = (char *)function_name(funct)) != NULL) 90 ewprintf("%k runs the command %s", pep); 91 else 92 ewprintf("%k is bound to an unnamed function"); 93 return (TRUE); 94} 95 96/* 97 * This function creates a table, listing all of the command 98 * keys and their current bindings, and stores the table in the 99 * *help* pop-up buffer. This lets Mg produce its own wall chart. 100 */ 101int 102wallchart(int f, int n) 103{ 104 int m; 105 struct buffer *bp; 106 107 bp = bfind("*help*", TRUE); 108 if (bclear(bp) != TRUE) 109 /* clear it out */ 110 return (FALSE); 111 bp->b_flag |= BFREADONLY; 112 for (m = curbp->b_nmodes; m > 0; m--) { 113 if ((addlinef(bp, "Local keybindings for mode %s:", 114 curbp->b_modes[m]->p_name) == FALSE) || 115 (showall(bp, curbp->b_modes[m]->p_map, "") == FALSE) || 116 (addline(bp, "") == FALSE)) 117 return (FALSE); 118 } 119 if ((addline(bp, "Global bindings:") == FALSE) || 120 (showall(bp, fundamental_map, "") == FALSE)) 121 return (FALSE); 122 return (popbuftop(bp, WNONE)); 123} 124 125static int 126showall(struct buffer *bp, KEYMAP *map, char *prefix) 127{ 128 KEYMAP *newmap; 129 char buf[80], keybuf[16]; 130 PF fun; 131 int c; 132 133 if (addline(bp, "") == FALSE) 134 return (FALSE); 135 136 /* XXX - 256 ? */ 137 for (c = 0; c < 256; c++) { 138 fun = doscan(map, c, &newmap); 139 if (fun == rescan || fun == selfinsert) 140 continue; 141 getkeyname(buf, sizeof(buf), c); 142 (void)snprintf(keybuf, sizeof(keybuf), "%s%s ", prefix, buf); 143 if (fun == NULL) { 144 if (showall(bp, newmap, keybuf) == FALSE) 145 return (FALSE); 146 } else { 147 if (addlinef(bp, "%-16s%s", keybuf, 148 function_name(fun)) == FALSE) 149 return (FALSE); 150 } 151 } 152 return (TRUE); 153} 154 155int 156help_help(int f, int n) 157{ 158 KEYMAP *kp; 159 PF funct; 160 161 if ((kp = name_map("help")) == NULL) 162 return (FALSE); 163 ewprintf("a b c: "); 164 do { 165 funct = doscan(kp, getkey(FALSE), NULL); 166 } while (funct == NULL || funct == help_help); 167 168 if (macrodef && macrocount < MAXMACRO) 169 macro[macrocount - 1].m_funct = funct; 170 171 return ((*funct)(f, n)); 172} 173 174int 175apropos_command(int f, int n) 176{ 177 struct buffer *bp; 178 struct list *fnames, *el; 179 char string[32]; 180 181 if (eread("apropos: ", string, sizeof(string), EFNUL | EFNEW) == NULL) 182 return (ABORT); 183 /* FALSE means we got a 0 character string, which is fine */ 184 bp = bfind("*help*", TRUE); 185 if (bclear(bp) == FALSE) 186 return (FALSE); 187 188 fnames = complete_function_list(""); 189 for (el = fnames; el != NULL; el = el->l_next) { 190 char buf[32]; 191 192 if (strstr(el->l_name, string) == NULL) 193 continue; 194 195 buf[0] = '\0'; 196 findbind(fundamental_map, name_function(el->l_name), 197 buf, sizeof(buf)); 198 199 if (addlinef(bp, "%-32s%s", el->l_name, buf) == FALSE) { 200 free_file_list(fnames); 201 return (FALSE); 202 } 203 } 204 free_file_list(fnames); 205 return (popbuftop(bp, WNONE)); 206} 207 208static int 209findbind(KEYMAP *map, PF fun, char *buf, size_t len) 210{ 211 KEYMAP *newmap; 212 PF nfun; 213 char buf2[16], keybuf[16]; 214 int c; 215 216 /* XXX - 256 ? */ 217 for (c = 0; c < 256; c++) { 218 nfun = doscan(map, c, &newmap); 219 if (nfun == fun) { 220 getkeyname(buf, len, c); 221 return (TRUE); 222 } 223 if (nfun == NULL) { 224 if (findbind(newmap, fun, buf2, sizeof(buf2)) == TRUE) { 225 getkeyname(keybuf, sizeof(keybuf), c); 226 (void)snprintf(buf, len, "%s %s", keybuf, buf2); 227 return (TRUE); 228 } 229 } 230 } 231 return (FALSE); 232} 233