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