help.c revision 1.36
1/*	$OpenBSD: help.c,v 1.36 2022/01/28 06:18:41 guenther 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
20static int	showall(struct buffer *, KEYMAP *, char *);
21static 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 */
28int
29desckey(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		}
71nextmode:
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	}
87found:
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 its own wall chart.
101 */
102/* ARGSUSED */
103int
104wallchart(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
127static int
128showall(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
157int
158help_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 */
177int
178apropos_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
211static int
212findbind(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