help.c revision 1.34
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
16static int	showall(struct buffer *, KEYMAP *, char *);
17static 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 */
24int
25desckey(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		}
67nextmode:
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	}
83found:
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 */
99int
100wallchart(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
123static int
124showall(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
153int
154help_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 */
173int
174apropos_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
207static int
208findbind(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