help.c revision 1.7
1/*	$OpenBSD: help.c,v 1.7 2001/05/23 21:01:16 art Exp $	*/
2
3/*
4 * Help functions for Mg 2
5 */
6
7#include "def.h"
8
9#ifndef NO_HELP
10#include "kbd.h"
11#include "key.h"
12#ifndef NO_MACRO
13#include "macro.h"
14#endif /* !NO_MACRO */
15
16static int	showall		__P((char *ind, KEYMAP *map));
17static VOID	findbind	__P((PF, char *, KEYMAP *));
18static VOID	bindfound	__P((void));
19
20static BUFFER  *bp;
21static char     buf[80];	/* used by showall and findbind */
22static char     buf2[128];
23static char    *buf2p;
24
25/*
26 * Read a key from the keyboard, and look it up in the keymap.
27 * Display the name of the function currently bound to the key.
28 */
29/* ARGSUSED */
30int
31desckey(f, n)
32	int f, n;
33{
34	KEYMAP	*curmap;
35	PF	 funct;
36	int	 c, m, i;
37	char	*pep;
38	char	 prompt[80];
39
40#ifndef NO_MACRO
41	if (inmacro)
42		return TRUE;	/* ignore inside keyboard macro */
43#endif /* !NO_MACRO */
44	(VOID)strcpy(prompt, "Describe key briefly: ");
45	pep = prompt + strlen(prompt);
46	key.k_count = 0;
47	m = curbp->b_nmodes;
48	curmap = curbp->b_modes[m]->p_map;
49	for (;;) {
50		for (;;) {
51			ewprintf("%s", prompt);
52			pep[-1] = ' ';
53			pep = keyname(pep, key.k_chars[key.k_count++] =
54			    c = getkey(FALSE));
55			if ((funct = doscan(curmap, c, &curmap)) != NULL)
56				break;
57			*pep++ = '-';
58			*pep = '\0';
59		}
60		if (funct != rescan)
61			break;
62		if (ISUPPER(key.k_chars[key.k_count - 1])) {
63			funct = doscan(curmap,
64			    TOLOWER(key.k_chars[key.k_count - 1]), &curmap);
65			if (funct == NULL) {
66				*pep++ = '-';
67				*pep = '\0';
68				continue;
69			}
70			if (funct != rescan)
71				break;
72		}
73nextmode:
74		if (--m < 0)
75			break;
76		curmap = curbp->b_modes[m]->p_map;
77		for (i = 0; i < key.k_count; i++) {
78			funct = doscan(curmap, key.k_chars[i], &curmap);
79			if (funct != NULL) {
80				if (i == key.k_count - 1 && funct != rescan)
81					goto found;
82				funct = rescan;
83				goto nextmode;
84			}
85		}
86		*pep++ = '-';
87		*pep = '\0';
88	}
89found:
90	if (funct == rescan || funct == selfinsert)
91		ewprintf("%k is not bound to any function");
92	else if ((pep = function_name(funct)) != NULL)
93		ewprintf("%k runs the command %s", pep);
94	else
95		ewprintf("%k is bound to an unnamed function");
96	return TRUE;
97}
98
99/*
100 * This function creates a table, listing all of the command
101 * keys and their current bindings, and stores the table in the
102 * *help* pop-up buffer.  This lets Mg produce it's own wall chart.
103 */
104/* ARGSUSED */
105int
106wallchart(f, n)
107	int f, n;
108{
109	int		 m;
110	static char	 locbind[80] = "Local keybindings for mode ";
111
112	bp = bfind("*help*", TRUE);
113	if (bclear(bp) != TRUE)
114		/* clear it out */
115		return FALSE;
116	for (m = curbp->b_nmodes; m > 0; m--) {
117		(VOID)strcpy(&locbind[27], curbp->b_modes[m]->p_name);
118		(VOID)strcat(&locbind[27], ":");
119		if ((addline(bp, locbind) == FALSE) ||
120		    (showall(buf, curbp->b_modes[m]->p_map) == FALSE) ||
121		    (addline(bp, "") == FALSE))
122			return FALSE;
123	}
124	if ((addline(bp, "Global bindings:") == FALSE) ||
125	    (showall(buf, map_table[0].p_map) == FALSE))
126		return FALSE;
127	return popbuftop(bp);
128}
129
130static int
131showall(ind, map)
132	char   *ind;
133	KEYMAP *map;
134{
135	MAP_ELEMENT	*ele;
136	PF		 functp;
137	int		 i, last;
138	char		*cp, *cp2;
139
140	if (addline(bp, "") == FALSE)
141		return FALSE;
142	last = -1;
143	for (ele = &map->map_element[0];
144	    ele < &map->map_element[map->map_num]; ele++) {
145		if (map->map_default != rescan && ++last < ele->k_base) {
146			cp = keyname(ind, last);
147			if (last < ele->k_base - 1) {
148				(VOID)strcpy(cp, " .. ");
149				cp = keyname(cp + 4, ele->k_base - 1);
150			}
151			do {
152				*cp++ = ' ';
153			} while (cp < &buf[16]);
154			(VOID)strcpy(cp, function_name(map->map_default));
155			if (addline(bp, buf) == FALSE)
156				return FALSE;
157		}
158		last = ele->k_num;
159		for (i = ele->k_base; i <= last; i++) {
160			functp = ele->k_funcp[i - ele->k_base];
161			if (functp != rescan) {
162				if (functp != NULL)
163					cp2 = function_name(functp);
164				else
165					cp2 = map_name(ele->k_prefmap);
166				if (cp2 != NULL) {
167					cp = keyname(ind, i);
168					do {
169						*cp++ = ' ';
170					} while (cp < &buf[16]);
171					(VOID)strcpy(cp, cp2);
172					if (addline(bp, buf) == FALSE)
173						return FALSE;
174				}
175			}
176		}
177	}
178	for (ele = &map->map_element[0];
179	    ele < &map->map_element[map->map_num]; ele++) {
180		if (ele->k_prefmap != NULL) {
181			for (i = ele->k_base;
182			    ele->k_funcp[i - ele->k_base] != NULL; i++) {
183				if (i >= ele->k_num)
184					/* damaged map */
185					return FALSE;
186			}
187			cp = keyname(ind, i);
188			*cp++ = ' ';
189			if (showall(cp, ele->k_prefmap) == FALSE)
190				return FALSE;
191		}
192	}
193	return TRUE;
194}
195
196int
197help_help(f, n)
198	int f, n;
199{
200	KEYMAP	*kp;
201	PF	 funct;
202
203	if ((kp = name_map("help")) == NULL)
204		return FALSE;
205	ewprintf("a b c: ");
206	do {
207		funct = doscan(kp, getkey(FALSE), NULL);
208	} while (funct == NULL || funct == help_help);
209#ifndef NO_MACRO
210	if (macrodef && macrocount < MAXMACRO)
211		macro[macrocount - 1].m_funct = funct;
212#endif /* !NO_MACRO */
213	return (*funct)(f, n);
214}
215
216/* ARGSUSED */
217int
218apropos_command(f, n)
219	int f, n;
220{
221	BUFFER		*bp;
222	FUNCTNAMES	*fnp;
223	char		*cp1, *cp2;
224	char		 string[32];
225
226	if (eread("apropos: ", string, sizeof(string), EFNEW) == ABORT)
227		return ABORT;
228	/* FALSE means we got a 0 character string, which is fine */
229	bp = bfind("*help*", TRUE);
230	if (bclear(bp) == FALSE)
231		return FALSE;
232	for (fnp = &functnames[0]; fnp < &functnames[nfunct]; fnp++) {
233		for (cp1 = fnp->n_name; *cp1; cp1++) {
234			cp2 = string;
235			while (*cp2 && *cp1 == *cp2)
236				cp1++, cp2++;
237			if (!*cp2) {
238				(VOID)strcpy(buf2, fnp->n_name);
239				buf2p = &buf2[strlen(buf2)];
240				findbind(fnp->n_funct, buf, map_table[0].p_map);
241				if (addline(bp, buf2) == FALSE)
242					return FALSE;
243				break;
244			} else
245				cp1 -= cp2 - string;
246		}
247	}
248	return popbuftop(bp);
249}
250
251static VOID
252findbind(funct, ind, map)
253	KEYMAP *map;
254	PF      funct;
255	char   *ind;
256{
257	MAP_ELEMENT	*ele;
258	int		 i, last;
259	char		*cp;
260
261	last = -1;
262	for (ele = &map->map_element[0];
263	    ele < &map->map_element[map->map_num]; ele++) {
264		if (map->map_default == funct && ++last < ele->k_base) {
265			cp = keyname(ind, last);
266			if (last < ele->k_base - 1) {
267				(VOID)strcpy(cp, " .. ");
268				(VOID)keyname(cp + 4, ele->k_base - 1);
269			}
270			bindfound();
271		}
272		last = ele->k_num;
273		for (i = ele->k_base; i <= last; i++) {
274			if (funct == ele->k_funcp[i - ele->k_base]) {
275				if (funct == NULL) {
276					cp = map_name(ele->k_prefmap);
277					if (!cp ||
278					    strncmp(cp, buf2, strlen(cp)) != 0)
279						continue;
280				}
281				(VOID)keyname(ind, i);
282				bindfound();
283			}
284		}
285	}
286	for (ele = &map->map_element[0];
287	    ele < &map->map_element[map->map_num]; ele++) {
288		if (ele->k_prefmap != NULL) {
289			for (i = ele->k_base;
290			    ele->k_funcp[i - ele->k_base] != NULL; i++) {
291				if (i >= ele->k_num)
292					/* damaged */
293					return;
294			}
295			cp = keyname(ind, i);
296			*cp++ = ' ';
297			findbind(funct, cp, ele->k_prefmap);
298		}
299	}
300}
301
302static VOID
303bindfound()
304{
305	if (buf2p < &buf2[32]) {
306		do {
307			*buf2p++ = ' ';
308		} while (buf2p < &buf2[32]);
309	} else {
310		*buf2p++ = ',';
311		*buf2p++ = ' ';
312	}
313	(VOID)strcpy(buf2p, buf);
314	buf2p += strlen(buf);
315}
316#endif /* !NO_HELP */
317