Move refs helpers to refs module
[tig.git] / src / keys.c
blob79cac0a7fc65f698b1d87832410c21bd4c94fc23
1 /* Copyright (c) 2006-2014 Jonas Fonseca <fonseca@diku.dk>
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License as
5 * published by the Free Software Foundation; either version 2 of
6 * the License, or (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #include "tig.h"
15 #include "types.h"
16 #include "keys.h"
17 #include "util.h"
18 #include "io.h"
20 struct keybinding {
21 int alias;
22 enum request request;
25 static struct keymap generic_keymap = { "generic" };
26 #define is_generic_keymap(keymap) ((keymap) == &generic_keymap)
28 static struct keymap *keymaps = &generic_keymap;
30 struct keymap *
31 get_keymaps(void)
33 return keymaps;
36 void
37 add_keymap(struct keymap *keymap)
39 keymap->next = keymaps;
40 keymaps = keymap;
43 struct keymap *
44 get_keymap(const char *name)
46 struct keymap *keymap = keymaps;
48 while (keymap) {
49 if (!strcasecmp(keymap->name, name))
50 return keymap;
51 keymap = keymap->next;
54 return NULL;
58 void
59 add_keybinding(struct keymap *table, enum request request, int key)
61 size_t i;
63 for (i = 0; i < table->size; i++) {
64 if (table->data[i].alias == key) {
65 table->data[i].request = request;
66 return;
70 table->data = realloc(table->data, (table->size + 1) * sizeof(*table->data));
71 if (!table->data)
72 die("Failed to allocate keybinding");
73 table->data[table->size].alias = key;
74 table->data[table->size++].request = request;
77 /* Looks for a key binding first in the given map, then in the generic map, and
78 * lastly in the default keybindings. */
79 enum request
80 get_keybinding(struct keymap *keymap, int key)
82 size_t i;
84 for (i = 0; i < keymap->size; i++)
85 if (keymap->data[i].alias == key)
86 return keymap->data[i].request;
88 for (i = 0; i < generic_keymap.size; i++)
89 if (generic_keymap.data[i].alias == key)
90 return generic_keymap.data[i].request;
92 return (enum request) key;
96 struct key {
97 const char *name;
98 int value;
101 static const struct key key_table[] = {
102 { "Enter", KEY_RETURN },
103 { "Space", ' ' },
104 { "Backspace", KEY_BACKSPACE },
105 { "Tab", KEY_TAB },
106 { "Escape", KEY_ESC },
107 { "Left", KEY_LEFT },
108 { "Right", KEY_RIGHT },
109 { "Up", KEY_UP },
110 { "Down", KEY_DOWN },
111 { "Insert", KEY_IC },
112 { "Delete", KEY_DC },
113 { "Hash", '#' },
114 { "Home", KEY_HOME },
115 { "End", KEY_END },
116 { "PageUp", KEY_PPAGE },
117 { "PgUp", KEY_PPAGE },
118 { "PageDown", KEY_NPAGE },
119 { "PgDown", KEY_NPAGE },
120 { "F1", KEY_F(1) },
121 { "F2", KEY_F(2) },
122 { "F3", KEY_F(3) },
123 { "F4", KEY_F(4) },
124 { "F5", KEY_F(5) },
125 { "F6", KEY_F(6) },
126 { "F7", KEY_F(7) },
127 { "F8", KEY_F(8) },
128 { "F9", KEY_F(9) },
129 { "F10", KEY_F(10) },
130 { "F11", KEY_F(11) },
131 { "F12", KEY_F(12) },
135 get_key_value(const char *name)
137 int i;
139 for (i = 0; i < ARRAY_SIZE(key_table); i++)
140 if (!strcasecmp(key_table[i].name, name))
141 return key_table[i].value;
143 if (strlen(name) == 3 && name[0] == '^' && name[1] == '[' && isprint(*name))
144 return (int)name[2] + 0x80;
145 if (strlen(name) == 2 && name[0] == '^' && isprint(*name))
146 return (int)name[1] & 0x1f;
147 if (strlen(name) == 1 && isprint(*name))
148 return (int) *name;
149 return ERR;
152 const char *
153 get_key_name(int key_value)
155 static char key_char[] = "'X'\0";
156 const char *seq = NULL;
157 int key;
159 for (key = 0; key < ARRAY_SIZE(key_table); key++)
160 if (key_table[key].value == key_value)
161 seq = key_table[key].name;
163 if (seq == NULL && key_value < 0x7f) {
164 char *s = key_char + 1;
166 if (key_value >= 0x20) {
167 *s++ = key_value;
168 } else {
169 *s++ = '^';
170 *s++ = 0x40 | (key_value & 0x1f);
172 *s++ = '\'';
173 *s++ = '\0';
174 seq = key_char;
177 return seq ? seq : "(no key)";
180 static bool
181 append_key(char *buf, size_t *pos, const struct keybinding *keybinding)
183 const char *sep = *pos > 0 ? ", " : "";
184 const char *keyname = get_key_name(keybinding->alias);
186 return string_nformat(buf, BUFSIZ, pos, "%s%s", sep, keyname);
189 static bool
190 append_keymap_request_keys(char *buf, size_t *pos, enum request request,
191 struct keymap *keymap, bool all)
193 int i;
195 for (i = 0; i < keymap->size; i++) {
196 if (keymap->data[i].request == request) {
197 if (!append_key(buf, pos, &keymap->data[i]))
198 return FALSE;
199 if (!all)
200 break;
204 return TRUE;
207 #define get_view_key(view, request) get_keys(&(view)->ops->keymap, request, FALSE)
209 const char *
210 get_keys(struct keymap *keymap, enum request request, bool all)
212 static char buf[BUFSIZ];
213 size_t pos = 0;
215 buf[pos] = 0;
217 if (!append_keymap_request_keys(buf, &pos, request, keymap, all))
218 return "Too many keybindings!";
219 if (pos > 0 && !all)
220 return buf;
222 if (!is_generic_keymap(keymap)) {
223 /* Only the generic keymap includes the default keybindings when
224 * listing all keys. */
225 if (all)
226 return buf;
228 if (!append_keymap_request_keys(buf, &pos, request, &generic_keymap, all))
229 return "Too many keybindings!";
230 if (pos)
231 return buf;
234 return buf;
237 static struct run_request *run_request;
238 static size_t run_requests;
240 DEFINE_ALLOCATOR(realloc_run_requests, struct run_request, 8)
242 bool
243 add_run_request(struct keymap *keymap, int key, const char **argv, enum run_request_flag flags)
245 bool force = flags & RUN_REQUEST_FORCE;
246 struct run_request *req;
248 if (!force && get_keybinding(keymap, key) != key)
249 return TRUE;
251 if (!realloc_run_requests(&run_request, run_requests, 1))
252 return FALSE;
254 if (!argv_copy(&run_request[run_requests].argv, argv))
255 return FALSE;
257 req = &run_request[run_requests++];
258 req->silent = flags & RUN_REQUEST_SILENT;
259 req->confirm = flags & RUN_REQUEST_CONFIRM;
260 req->exit = flags & RUN_REQUEST_EXIT;
261 req->internal = flags & RUN_REQUEST_INTERNAL;
262 req->keymap = keymap;
263 req->key = key;
265 add_keybinding(keymap, REQ_RUN_REQUESTS + run_requests, key);
266 return TRUE;
269 struct run_request *
270 get_run_request(enum request request)
272 if (request <= REQ_RUN_REQUESTS || request > REQ_RUN_REQUESTS + run_requests)
273 return NULL;
274 return &run_request[request - REQ_RUN_REQUESTS - 1];
277 /* vim: set ts=8 sw=8 noexpandtab: */