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