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
desckey(int f,int n)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
wallchart(int f,int n)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
showall(struct buffer * bp,KEYMAP * map,char * prefix)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
help_help(int f,int n)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
apropos_command(int f,int n)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
findbind(KEYMAP * map,PF fun,char * buf,size_t len)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