1 /* Copyright (c) 2006-2014 Jonas Fonseca <jonas.fonseca@gmail.com>
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.
15 #include "tig/types.h"
27 static struct keymap keymaps
[] = {
29 #define VIEW_KEYMAP(id, name) { #name }
30 VIEW_INFO(VIEW_KEYMAP
)
33 static struct keymap
*generic_keymap
= keymaps
;
34 #define is_generic_keymap(keymap) ((keymap) == generic_keymap)
37 get_keymap_by_index(int i
)
39 return 0 <= i
&& i
< ARRAY_SIZE(keymaps
) ? &keymaps
[i
] : NULL
;
43 get_keymap(const char *name
, size_t namelen
)
47 for (i
= 0; i
< ARRAY_SIZE(keymaps
); i
++)
48 if (!strncasecmp(keymaps
[i
].name
, name
, namelen
))
55 keybinding_equals(struct keybinding
*keybinding
, struct key key
[],
56 size_t keys
, bool *conflict_ptr
)
58 bool conflict
= FALSE
;
61 if (keybinding
->keys
!= keys
)
64 for (i
= 0; i
< keys
; i
++) {
65 struct key
*key1
= &keybinding
->key
[i
];
66 struct key
*key2
= &key
[i
];
68 if (key1
->modifiers
.control
&&
69 key1
->modifiers
.multibytes
&&
70 !memcmp(&key1
->modifiers
, &key2
->modifiers
, sizeof(key1
->modifiers
)) &&
71 strlen(key1
->data
.bytes
) == 1 &&
72 strlen(key2
->data
.bytes
) == 1) {
73 int c1
= key1
->data
.bytes
[0];
74 int c2
= key2
->data
.bytes
[0];
76 if (ascii_toupper(c1
) != ascii_toupper(c2
))
81 if (memcmp(key1
, key2
, sizeof(*key1
)))
87 *conflict_ptr
= conflict
;
92 add_keybinding(struct keymap
*table
, enum request request
,
93 struct key key
[], size_t keys
)
95 struct keybinding
*keybinding
;
97 bool conflict
= FALSE
;
100 for (i
= 0; i
< table
->size
; i
++) {
101 if (keybinding_equals(table
->data
[i
], key
, keys
, &conflict
)) {
102 enum request old_request
= table
->data
[i
]->request
;
103 const char *old_name
;
105 table
->data
[i
]->request
= request
;
109 old_name
= get_request_name(old_request
);
110 string_ncopy(buf
, old_name
, strlen(old_name
));
111 return error("Key binding for %s and %s conflict; "
112 "keys using Ctrl are case insensitive",
113 buf
, get_request_name(request
));
117 table
->data
= realloc(table
->data
, (table
->size
+ 1) * sizeof(*table
->data
));
118 keybinding
= calloc(1, sizeof(*keybinding
) + (sizeof(*key
) * (keys
- 1)));
119 if (!table
->data
|| !keybinding
)
120 die("Failed to allocate keybinding");
122 memcpy(keybinding
->key
, key
, sizeof(*key
) * keys
);
123 keybinding
->keys
= keys
;
124 keybinding
->request
= request
;
125 table
->data
[table
->size
++] = keybinding
;
129 /* Looks for a key binding first in the given map, then in the generic map, and
130 * lastly in the default keybindings. */
132 get_keybinding(struct keymap
*keymap
, struct key key
[], size_t keys
)
136 for (i
= 0; i
< keymap
->size
; i
++)
137 if (keybinding_equals(keymap
->data
[i
], key
, keys
, NULL
))
138 return keymap
->data
[i
]->request
;
140 for (i
= 0; i
< generic_keymap
->size
; i
++)
141 if (keybinding_equals(generic_keymap
->data
[i
], key
, keys
, NULL
))
142 return generic_keymap
->data
[i
]->request
;
153 static const struct key_table key_table
[] = {
154 { "Enter", KEY_RETURN
},
156 { "Backspace", KEY_BACKSPACE
},
158 { "Escape", KEY_ESC
},
159 { "Left", KEY_LEFT
},
160 { "Right", KEY_RIGHT
},
162 { "Down", KEY_DOWN
},
163 { "Insert", KEY_IC
},
164 { "Delete", KEY_DC
},
166 { "Home", KEY_HOME
},
168 { "PageUp", KEY_PPAGE
},
169 { "PgUp", KEY_PPAGE
},
170 { "PageDown", KEY_NPAGE
},
171 { "PgDown", KEY_NPAGE
},
181 { "F10", KEY_F(10) },
182 { "F11", KEY_F(11) },
183 { "F12", KEY_F(12) },
187 get_key_value(const char **name_ptr
, struct key
*key
)
189 const char *name
= *name_ptr
;
193 memset(key
, 0, sizeof(*key
));
195 for (i
= 0; i
< ARRAY_SIZE(key_table
); i
++)
196 if (!strcasecmp(key_table
[i
].name
, name
)) {
197 namelen
= strlen(key_table
[i
].name
);
198 if (key_table
[i
].value
== ' ') {
202 if (key_table
[i
].value
== '#') {
206 *name_ptr
= name
+ namelen
;
207 key
->data
.value
= key_table
[i
].value
;
211 if (name
[0] == '^' && name
[1] == '[') {
212 key
->modifiers
.escape
= 1;
214 } else if (name
[0] == '^') {
215 key
->modifiers
.control
= 1;
219 i
= utf8_char_length(name
);
220 if (strlen(name
) >= i
&& utf8_to_unicode(name
, i
) != 0) {
221 strncpy(key
->data
.bytes
, name
, i
);
222 key
->modifiers
.multibytes
= 1;
224 namelen
+= i
+ (name
- *name_ptr
);
225 *name_ptr
+= namelen
;
233 get_key_name(const struct key key
[], size_t keys
)
235 static char buf
[SIZEOF_STR
];
236 const char *modifier
= "";
240 if (keys
== 1 && !key
->modifiers
.multibytes
) {
241 for (i
= 0; i
< ARRAY_SIZE(key_table
); i
++)
242 if (key_table
[i
].value
== key
->data
.value
)
243 return key_table
[i
].name
;
246 for (i
= 0; i
< keys
; i
++) {
247 const char *start
= pos
? "" : "'";
248 const char *end
= i
+ 1 == keys
? "'" : "";
250 if (key
[i
].modifiers
.escape
)
252 else if (key
[i
].modifiers
.control
)
255 if (!string_format_from(buf
, &pos
, "%s%s%s%s",
256 start
, modifier
, key
[i
].data
.bytes
, end
))
264 append_key(char *buf
, size_t *pos
, const struct keybinding
*keybinding
)
266 const char *sep
= *pos
> 0 ? ", " : "";
267 const char *keyname
= get_key_name(keybinding
->key
, keybinding
->keys
);
269 return string_nformat(buf
, BUFSIZ
, pos
, "%s%s", sep
, keyname
);
273 append_keymap_request_keys(char *buf
, size_t *pos
, enum request request
,
274 struct keymap
*keymap
, bool all
)
278 for (i
= 0; i
< keymap
->size
; i
++) {
279 if (keymap
->data
[i
]->request
== request
) {
280 if (!append_key(buf
, pos
, keymap
->data
[i
]))
291 get_keys(struct keymap
*keymap
, enum request request
, bool all
)
293 static char buf
[BUFSIZ
];
298 if (!append_keymap_request_keys(buf
, &pos
, request
, keymap
, all
))
299 return "Too many keybindings!";
303 if (!is_generic_keymap(keymap
)) {
304 /* Only the generic keymap includes the default keybindings when
305 * listing all keys. */
309 if (!append_keymap_request_keys(buf
, &pos
, request
, generic_keymap
, all
))
310 return "Too many keybindings!";
318 static struct run_request
*run_request
;
319 static size_t run_requests
;
321 DEFINE_ALLOCATOR(realloc_run_requests
, struct run_request
, 8)
324 add_run_request(struct keymap
*keymap
, struct key key
[],
325 size_t keys
, const char **argv
)
327 struct run_request
*req
;
328 struct run_request_flags flags
= {};
330 if (!strchr(":!?@<", *argv
[0]))
331 return error("Unknown request name: %s", argv
[0]);
334 if (*argv
[0] == ':') {
338 } else if (*argv
[0] == '@') {
340 } else if (*argv
[0] == '?') {
342 } else if (*argv
[0] == '<') {
344 } else if (*argv
[0] != '!') {
350 if (!realloc_run_requests(&run_request
, run_requests
, 1))
351 return ERROR_OUT_OF_MEMORY
;
353 if (!argv_copy(&run_request
[run_requests
].argv
, argv
))
354 return ERROR_OUT_OF_MEMORY
;
356 req
= &run_request
[run_requests
++];
358 req
->keymap
= keymap
;
360 return add_keybinding(keymap
, REQ_RUN_REQUESTS
+ run_requests
, key
, keys
);
364 get_run_request(enum request request
)
366 if (request
<= REQ_RUN_REQUESTS
|| request
> REQ_RUN_REQUESTS
+ run_requests
)
368 return &run_request
[request
- REQ_RUN_REQUESTS
- 1];
371 /* vim: set ts=8 sw=8 noexpandtab: */