xref: /openbsd-src/usr.bin/tmux/cmd-list-keys.c (revision d4741794dd2f512d997014f8bd85fbb24d935059)
1 /* $OpenBSD: cmd-list-keys.c,v 1.40 2016/10/16 19:04:05 nicm Exp $ */
2 
3 /*
4  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include "tmux.h"
25 
26 /*
27  * List key bindings.
28  */
29 
30 static enum cmd_retval	cmd_list_keys_exec(struct cmd *, struct cmdq_item *);
31 
32 static enum cmd_retval	cmd_list_keys_table(struct cmd *, struct cmdq_item *);
33 static enum cmd_retval	cmd_list_keys_commands(struct cmd *,
34 			    struct cmdq_item *);
35 
36 const struct cmd_entry cmd_list_keys_entry = {
37 	.name = "list-keys",
38 	.alias = "lsk",
39 
40 	.args = { "t:T:", 0, 0 },
41 	.usage = "[-t mode-table] [-T key-table]",
42 
43 	.flags = CMD_STARTSERVER|CMD_AFTERHOOK,
44 	.exec = cmd_list_keys_exec
45 };
46 
47 const struct cmd_entry cmd_list_commands_entry = {
48 	.name = "list-commands",
49 	.alias = "lscm",
50 
51 	.args = { "F:", 0, 0 },
52 	.usage = "[-F format]",
53 
54 	.flags = CMD_STARTSERVER|CMD_AFTERHOOK,
55 	.exec = cmd_list_keys_exec
56 };
57 
58 static enum cmd_retval
59 cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
60 {
61 	struct args		*args = self->args;
62 	struct key_table	*table;
63 	struct key_binding	*bd;
64 	const char		*key, *tablename, *r;
65 	char			*cp, tmp[BUFSIZ];
66 	int			 repeat, width, tablewidth, keywidth;
67 
68 	if (self->entry == &cmd_list_commands_entry)
69 		return (cmd_list_keys_commands(self, item));
70 
71 	if (args_has(args, 't'))
72 		return (cmd_list_keys_table(self, item));
73 
74 	tablename = args_get(args, 'T');
75 	if (tablename != NULL && key_bindings_get_table(tablename, 0) == NULL) {
76 		cmdq_error(item, "table %s doesn't exist", tablename);
77 		return (CMD_RETURN_ERROR);
78 	}
79 
80 	repeat = 0;
81 	tablewidth = keywidth = 0;
82 	RB_FOREACH(table, key_tables, &key_tables) {
83 		if (tablename != NULL && strcmp(table->name, tablename) != 0)
84 			continue;
85 		RB_FOREACH(bd, key_bindings, &table->key_bindings) {
86 			key = key_string_lookup_key(bd->key);
87 
88 			if (bd->can_repeat)
89 				repeat = 1;
90 
91 			width = utf8_cstrwidth(table->name);
92 			if (width > tablewidth)
93 				tablewidth = width;
94 			width = utf8_cstrwidth(key);
95 			if (width > keywidth)
96 				keywidth = width;
97 		}
98 	}
99 
100 	RB_FOREACH(table, key_tables, &key_tables) {
101 		if (tablename != NULL && strcmp(table->name, tablename) != 0)
102 			continue;
103 		RB_FOREACH(bd, key_bindings, &table->key_bindings) {
104 			key = key_string_lookup_key(bd->key);
105 
106 			if (!repeat)
107 				r = "";
108 			else if (bd->can_repeat)
109 				r = "-r ";
110 			else
111 				r = "   ";
112 			xsnprintf(tmp, sizeof tmp, "%s-T ", r);
113 
114 			cp = utf8_padcstr(table->name, tablewidth);
115 			strlcat(tmp, cp, sizeof tmp);
116 			strlcat(tmp, " ", sizeof tmp);
117 			free(cp);
118 
119 			cp = utf8_padcstr(key, keywidth);
120 			strlcat(tmp, cp, sizeof tmp);
121 			strlcat(tmp, " ", sizeof tmp);
122 			free(cp);
123 
124 			cp = cmd_list_print(bd->cmdlist);
125 			strlcat(tmp, cp, sizeof tmp);
126 			free(cp);
127 
128 			cmdq_print(item, "bind-key %s", tmp);
129 		}
130 	}
131 
132 	return (CMD_RETURN_NORMAL);
133 }
134 
135 static enum cmd_retval
136 cmd_list_keys_table(struct cmd *self, struct cmdq_item *item)
137 {
138 	struct args			*args = self->args;
139 	const char			*tablename, *cmdstr;
140 	const struct mode_key_table	*mtab;
141 	struct mode_key_binding		*mbind;
142 	int			 	 width, keywidth;
143 
144 	tablename = args_get(args, 't');
145 	if ((mtab = mode_key_findtable(tablename)) == NULL) {
146 		cmdq_error(item, "unknown key table: %s", tablename);
147 		return (CMD_RETURN_ERROR);
148 	}
149 
150 	keywidth = 0;
151 	RB_FOREACH(mbind, mode_key_tree, mtab->tree) {
152 		width = strlen(key_string_lookup_key(mbind->key));
153 		if (width > keywidth)
154 			keywidth = width;
155 	}
156 
157 	RB_FOREACH(mbind, mode_key_tree, mtab->tree) {
158 		cmdstr = mode_key_tostring(mtab->cmdstr, mbind->cmd);
159 		if (cmdstr != NULL) {
160 			cmdq_print(item, "bind-key -t %s %*s %s",
161 			    mtab->name, (int)keywidth,
162 			    key_string_lookup_key(mbind->key), cmdstr);
163 		}
164 	}
165 
166 	return (CMD_RETURN_NORMAL);
167 }
168 
169 static enum cmd_retval
170 cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
171 {
172 	struct args		*args = self->args;
173 	const struct cmd_entry	**entryp;
174 	const struct cmd_entry	 *entry;
175 	struct format_tree	 *ft;
176 	const char		 *template, *s;
177 	char			 *line;
178 
179 	if ((template = args_get(args, 'F')) == NULL) {
180 		template = "#{command_list_name}"
181 		    "#{?command_list_alias, (#{command_list_alias}),} "
182 		    "#{command_list_usage}";
183 	}
184 
185 	ft = format_create(item, 0);
186 	format_defaults(ft, NULL, NULL, NULL, NULL);
187 
188 	for (entryp = cmd_table; *entryp != NULL; entryp++) {
189 		entry = *entryp;
190 
191 		format_add(ft, "command_list_name", "%s", entry->name);
192 		if (entry->alias != NULL)
193 			s = entry->alias;
194 		else
195 			s = "";
196 		format_add(ft, "command_list_alias", "%s", s);
197 		if (entry->usage != NULL)
198 			s = entry->usage;
199 		else
200 			s = "";
201 		format_add(ft, "command_list_usage", "%s", s);
202 
203 		line = format_expand(ft, template);
204 		if (*line != '\0')
205 			cmdq_print(item, "%s", line);
206 		free(line);
207 	}
208 
209 	format_free(ft);
210 	return (CMD_RETURN_NORMAL);
211 }
212