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