1 /* Key bindings and extended commands
2
3 Copyright (c) 1997-2012 Free Software Foundation, Inc.
4
5 This file is part of GNU Zile.
6
7 GNU Zile is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GNU Zile is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Zile; see the file COPYING. If not, write to the
19 Free Software Foundation, Fifth Floor, 51 Franklin Street, Boston,
20 MA 02111-1301, USA. */
21
22 #include <config.h>
23
24 #include <assert.h>
25 #include <ctype.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include "gl_array_list.h"
30 #include "gl_linked_list.h"
31
32 #include "main.h"
33 #include "extern.h"
34
35 /*--------------------------------------------------------------------------
36 * Key binding.
37 *--------------------------------------------------------------------------*/
38
39 struct Binding
40 {
41 size_t key; /* The key code (for every level except the root). */
42 Function func; /* The function for this key (if a leaf node). */
43
44 /* Branch vector, number of items, max number of items. */
45 Binding *vec;
46 size_t vecnum, vecmax;
47 };
48
49 static Binding root_bindings;
50
51 static Binding
node_new(int vecmax)52 node_new (int vecmax)
53 {
54 Binding p = (Binding) XZALLOC (struct Binding);
55
56 p->vecmax = vecmax;
57 p->vec = (Binding *) XCALLOC (vecmax, struct Binding);
58
59 return p;
60 }
61
62 static Binding
search_node(Binding tree,size_t key)63 search_node (Binding tree, size_t key)
64 {
65 for (size_t i = 0; i < tree->vecnum; ++i)
66 if (tree->vec[i]->key == key)
67 return tree->vec[i];
68
69 return NULL;
70 }
71
72 static void
add_node(Binding tree,Binding p)73 add_node (Binding tree, Binding p)
74 {
75 /* Erase any previous binding the current key might have had in case
76 it was non-prefix and is now being made prefix, as we don't want
77 to accidentally create a default for the prefix map. */
78 if (tree->vecnum == 0)
79 tree->func = NULL;
80
81 /* Reallocate vector if there is not enough space. */
82 if (tree->vecnum + 1 >= tree->vecmax)
83 {
84 tree->vecmax += 5;
85 tree->vec = xrealloc (tree->vec, sizeof (*p) * tree->vecmax);
86 }
87
88 /* Insert the node. */
89 tree->vec[tree->vecnum++] = p;
90 }
91
92 static void
bind_key_vec(Binding tree,gl_list_t keys,size_t from,Function func)93 bind_key_vec (Binding tree, gl_list_t keys, size_t from, Function func)
94 {
95 Binding p, s = search_node (tree, (size_t) gl_list_get_at (keys, from));
96 size_t n = gl_list_size (keys) - from;
97
98 if (s == NULL)
99 {
100 p = node_new (n == 1 ? 1 : 5);
101 p->key = (size_t) gl_list_get_at (keys, from);
102 add_node (tree, p);
103 if (n == 1)
104 p->func = func;
105 else if (n > 0)
106 bind_key_vec (p, keys, from + 1, func);
107 }
108 else if (n > 1)
109 bind_key_vec (s, keys, from + 1, func);
110 else
111 s->func = func;
112 }
113
114 static Binding
search_key(Binding tree,gl_list_t keys,size_t from)115 search_key (Binding tree, gl_list_t keys, size_t from)
116 {
117 Binding p = search_node (tree, (size_t) gl_list_get_at (keys, from));
118
119 if (p != NULL)
120 {
121 if (gl_list_size (keys) - from == 1)
122 return p;
123 else
124 return search_key (p, keys, from + 1);
125 }
126
127 return NULL;
128 }
129
130 size_t
do_binding_completion(astr as)131 do_binding_completion (astr as)
132 {
133 astr bs = astr_new ();
134
135 if (lastflag & FLAG_SET_UNIARG)
136 {
137 unsigned arg = abs (last_uniarg);
138 do
139 {
140 bs = astr_fmt ("%c %s", arg % 10 + '0', astr_cstr (bs));
141 arg /= 10;
142 }
143 while (arg != 0);
144
145 if (last_uniarg < 0)
146 bs = astr_fmt ("- %s", astr_cstr (bs));
147 }
148
149 minibuf_write ("%s%s%s-",
150 lastflag & (FLAG_SET_UNIARG | FLAG_UNIARG_EMPTY) ? "C-u " : "",
151 astr_cstr (bs),
152 astr_cstr (as));
153 size_t key = getkey (GETKEY_DEFAULT);
154 minibuf_clear ();
155
156 return key;
157 }
158
159 /* Get a key sequence from the keyboard; the sequence returned
160 has at most the last stroke unbound. */
161 gl_list_t
get_key_sequence(void)162 get_key_sequence (void)
163 {
164 gl_list_t keys = gl_list_create_empty (GL_ARRAY_LIST,
165 NULL, NULL, NULL, true);
166 size_t key;
167
168 do
169 key = getkey (GETKEY_DEFAULT);
170 while (key == KBD_NOKEY);
171 gl_list_add_last (keys, (void *) key);
172 for (;;)
173 {
174 astr as;
175 Binding p = search_key (root_bindings, keys, 0);
176 if (p == NULL || p->func != NULL)
177 break;
178 as = keyvectodesc (keys);
179 gl_list_add_last (keys, (void *) do_binding_completion (as));
180 }
181
182 return keys;
183 }
184
185 Function
get_function_by_keys(gl_list_t keys)186 get_function_by_keys (gl_list_t keys)
187 {
188 Binding p;
189
190 /* Detect Meta-digit */
191 if (gl_list_size (keys) == 1)
192 {
193 size_t key = (size_t) gl_list_get_at (keys, 0);
194 if (key & KBD_META &&
195 (isdigit ((int) (key & 0xff)) || (int) (key & 0xff) == '-'))
196 return F_universal_argument;
197 }
198
199 /* See if we've got a valid key sequence */
200 p = search_key (root_bindings, keys, 0);
201
202 return p ? p->func : NULL;
203 }
204
205 static bool
self_insert_command(void)206 self_insert_command (void)
207 {
208 int ret = true;
209 /* Mask out ~KBD_CTRL to allow control sequences to be themselves. */
210 int key = (int) (lastkey () & ~KBD_CTRL);
211 deactivate_mark ();
212 if (key <= 0xff)
213 {
214 if (isspace (key) && get_buffer_autofill (cur_bp))
215 ret = fill_break_line () != -1;
216 insert_char (key);
217 }
218 else
219 {
220 ding ();
221 ret = false;
222 }
223
224 return ret;
225 }
226
227 DEFUN ("self-insert-command", self_insert_command)
228 /*+
229 Insert the character you type.
230 Whichever character you type to run this command is inserted.
231 +*/
232 {
233 ok = execute_with_uniarg (uniarg, self_insert_command, NULL);
234 }
235 END_DEFUN
236
237 static Function _last_command;
238 static Function _this_command;
239
240 Function
last_command(void)241 last_command (void)
242 {
243 return _last_command;
244 }
245
246 void
set_this_command(Function cmd)247 set_this_command (Function cmd)
248 {
249 _this_command = cmd;
250 }
251
252 le *
call_command(Function f,int uniarg,bool uniflag,le * branch)253 call_command (Function f, int uniarg, bool uniflag, le *branch)
254 {
255 thisflag = lastflag & FLAG_DEFINING_MACRO;
256 undo_start_sequence ();
257
258 /* Reset last_uniarg before function call, so recursion (e.g. in
259 macros) works. */
260 if (!(thisflag & FLAG_SET_UNIARG))
261 last_uniarg = 1;
262
263 /* Execute the command. */
264 _this_command = f;
265 le *ok = f (uniarg, uniflag, branch);
266 _last_command = _this_command;
267
268 /* Only add keystrokes if we were already in macro defining mode
269 before the function call, to cope with start-kbd-macro. */
270 if (lastflag & FLAG_DEFINING_MACRO && thisflag & FLAG_DEFINING_MACRO)
271 add_cmd_to_macro ();
272
273 undo_end_sequence ();
274 lastflag = thisflag;
275
276 return ok;
277 }
278
279 void
get_and_run_command(void)280 get_and_run_command (void)
281 {
282 gl_list_t keys = get_key_sequence ();
283 Function f = get_function_by_keys (keys);
284
285 minibuf_clear ();
286
287 if (f != NULL)
288 call_command (f, last_uniarg, (lastflag & FLAG_SET_UNIARG) != 0, NULL);
289 else
290 minibuf_error ("%s is undefined", astr_cstr (keyvectodesc (keys)));
291 }
292
293 static Binding
init_bindings(void)294 init_bindings (void)
295 {
296 return node_new (10);
297 }
298
299 void
init_default_bindings(void)300 init_default_bindings (void)
301 {
302 root_bindings = init_bindings ();
303
304 /* Bind all printing keys to self_insert_command */
305 gl_list_t keys = gl_list_create_empty (GL_ARRAY_LIST,
306 NULL, NULL, NULL, true);
307 gl_list_add_last (keys, NULL);
308 for (size_t i = 0; i <= 0xff; i++)
309 {
310 if (isprint (i))
311 {
312 gl_list_set_at (keys, 0, (void *) i);
313 bind_key_vec (root_bindings, keys, 0, F_self_insert_command);
314 }
315 }
316
317 astr as = astr_new_cstr ("\
318 (global-set-key \"\\M-m\" 'back-to-indentation)\
319 (global-set-key \"\\LEFT\" 'backward-char)\
320 (global-set-key \"\\C-b\" 'backward-char)\
321 (global-set-key \"\\BACKSPACE\" 'backward-delete-char)\
322 (global-set-key \"\\M-\\BACKSPACE\" 'backward-kill-word)\
323 (global-set-key \"\\M-{\" 'backward-paragraph)\
324 (global-set-key \"\\C-\\M-b\" 'backward-sexp)\
325 (global-set-key \"\\M-b\" 'backward-word)\
326 (global-set-key \"\\M-<\" 'beginning-of-buffer)\
327 (global-set-key \"\\HOME\" 'beginning-of-line)\
328 (global-set-key \"\\C-a\" 'beginning-of-line)\
329 (global-set-key \"\\C-xe\" 'call-last-kbd-macro)\
330 (global-set-key \"\\M-c\" 'capitalize-word)\
331 (global-set-key \"\\M-w\" 'copy-region-as-kill)\
332 (global-set-key \"\\C-xrs\" 'copy-to-register)\
333 (global-set-key \"\\C-xrx\" 'copy-to-register)\
334 (global-set-key \"\\C-x\\C-o\" 'delete-blank-lines)\
335 (global-set-key \"\\DELETE\" 'delete-char)\
336 (global-set-key \"\\C-d\" 'delete-char)\
337 (global-set-key \"\\M-\\\\\" 'delete-horizontal-space)\
338 (global-set-key \"\\C-x1\" 'delete-other-windows)\
339 (global-set-key \"\\C-x0\" 'delete-window)\
340 (global-set-key \"\\C-hb\" 'describe-bindings)\
341 (global-set-key \"\\F1b\" 'describe-bindings)\
342 (global-set-key \"\\C-hf\" 'describe-function)\
343 (global-set-key \"\\F1f\" 'describe-function)\
344 (global-set-key \"\\C-hk\" 'describe-key)\
345 (global-set-key \"\\F1k\" 'describe-key)\
346 (global-set-key \"\\C-hv\" 'describe-variable)\
347 (global-set-key \"\\F1v\" 'describe-variable)\
348 (global-set-key \"\\C-x\\C-l\" 'downcase-region)\
349 (global-set-key \"\\M-l\" 'downcase-word)\
350 (global-set-key \"\\C-x)\" 'end-kbd-macro)\
351 (global-set-key \"\\M->\" 'end-of-buffer)\
352 (global-set-key \"\\END\" 'end-of-line)\
353 (global-set-key \"\\C-e\" 'end-of-line)\
354 (global-set-key \"\\C-x^\" 'enlarge-window)\
355 (global-set-key \"\\C-x\\C-x\" 'exchange-point-and-mark)\
356 (global-set-key \"\\M-x\" 'execute-extended-command)\
357 (global-set-key \"\\M-q\" 'fill-paragraph)\
358 (global-set-key \"\\C-x\\C-v\" 'find-alternate-file)\
359 (global-set-key \"\\C-x\\C-f\" 'find-file)\
360 (global-set-key \"\\C-x\\C-r\" 'find-file-read-only)\
361 (global-set-key \"\\RIGHT\" 'forward-char)\
362 (global-set-key \"\\C-f\" 'forward-char)\
363 (global-set-key \"\\M-}\" 'forward-paragraph)\
364 (global-set-key \"\\C-\\M-f\" 'forward-sexp)\
365 (global-set-key \"\\M-f\" 'forward-word)\
366 (global-set-key \"\\M-gg\" 'goto-line)\
367 (global-set-key \"\\M-g\\M-g\" 'goto-line)\
368 (global-set-key \"\\TAB\" 'indent-for-tab-command)\
369 (global-set-key \"\\C-xi\" 'insert-file)\
370 (global-set-key \"\\C-xri\" 'insert-register)\
371 (global-set-key \"\\C-xrg\" 'insert-register)\
372 (global-set-key \"\\C-r\" 'isearch-backward)\
373 (global-set-key \"\\C-\\M-r\" 'isearch-backward-regexp)\
374 (global-set-key \"\\C-s\" 'isearch-forward)\
375 (global-set-key \"\\C-\\M-s\" 'isearch-forward-regexp)\
376 (global-set-key \"\\M-\\SPC\" 'just-one-space)\
377 (global-set-key \"\\C-g\" 'keyboard-quit)\
378 (global-set-key \"\\C-xk\" 'kill-buffer)\
379 (global-set-key \"\\C-k\" 'kill-line)\
380 (global-set-key \"\\C-w\" 'kill-region)\
381 (global-set-key \"\\C-\\M-k\" 'kill-sexp)\
382 (global-set-key \"\\M-d\" 'kill-word)\
383 (global-set-key \"\\C-x\\C-b\" 'list-buffers)\
384 (global-set-key \"\\M-h\" 'mark-paragraph)\
385 (global-set-key \"\\C-\\M-@\" 'mark-sexp)\
386 (global-set-key \"\\C-xh\" 'mark-whole-buffer)\
387 (global-set-key \"\\M-@\" 'mark-word)\
388 (global-set-key \"\\RET\" 'newline)\
389 (global-set-key \"\\C-j\" 'newline-and-indent)\
390 (global-set-key \"\\DOWN\" 'next-line)\
391 (global-set-key \"\\C-n\" 'next-line)\
392 (global-set-key \"\\C-o\" 'open-line)\
393 (global-set-key \"\\C-xo\" 'other-window)\
394 (global-set-key \"\\UP\" 'previous-line)\
395 (global-set-key \"\\C-p\" 'previous-line)\
396 (global-set-key \"\\M-%\" 'query-replace)\
397 (global-set-key \"\\C-q\" 'quoted-insert)\
398 (global-set-key \"\\C-l\" 'recenter)\
399 (global-set-key \"\\C-x\\C-s\" 'save-buffer)\
400 (global-set-key \"\\C-x\\C-c\" 'save-buffers-kill-emacs)\
401 (global-set-key \"\\C-xs\" 'save-some-buffers)\
402 (global-set-key \"\\PRIOR\" 'scroll-down)\
403 (global-set-key \"\\M-v\" 'scroll-down)\
404 (global-set-key \"\\NEXT\" 'scroll-up)\
405 (global-set-key \"\\C-v\" 'scroll-up)\
406 (global-set-key \"\\C-xf\" 'set-fill-column)\
407 (global-set-key \"\\C-@\" 'set-mark-command)\
408 (global-set-key \"\\M-!\" 'shell-command)\
409 (global-set-key \"\\M-|\" 'shell-command-on-region)\
410 (global-set-key \"\\C-x2\" 'split-window)\
411 (global-set-key \"\\C-x(\" 'start-kbd-macro)\
412 (global-set-key \"\\C-x\\C-z\" 'suspend-emacs)\
413 (global-set-key \"\\C-z\" 'suspend-emacs)\
414 (global-set-key \"\\C-xb\" 'switch-to-buffer)\
415 (global-set-key \"\\M-i\" 'tab-to-tab-stop)\
416 (global-set-key \"\\C-x\\C-q\" 'toggle-read-only)\
417 (global-set-key \"\\C-t\" 'transpose-chars)\
418 (global-set-key \"\\C-x\\C-t\" 'transpose-lines)\
419 (global-set-key \"\\C-\\M-t\" 'transpose-sexps)\
420 (global-set-key \"\\M-t\" 'transpose-words)\
421 (global-set-key \"\\C-xu\" 'undo)\
422 (global-set-key \"\\C-_\" 'undo)\
423 (global-set-key \"\\C-u\" 'universal-argument)\
424 (global-set-key \"\\C-x\\C-u\" 'upcase-region)\
425 (global-set-key \"\\M-u\" 'upcase-word)\
426 (global-set-key \"\\C-hw\" 'where-is)\
427 (global-set-key \"\\F1w\" 'where-is)\
428 (global-set-key \"\\C-x\\C-w\" 'write-file)\
429 (global-set-key \"\\C-y\" 'yank)\
430 ");
431 lisp_loadstring (as);
432 }
433
434 DEFUN_ARGS ("global-set-key", global_set_key,
435 STR_ARG (keystr)
436 STR_ARG (name))
437 /*+
438 Bind a command to a key sequence.
439 Read key sequence and function name, and bind the function to the key
440 sequence.
441 +*/
442 {
443 gl_list_t keys;
444 Function func;
445
446 STR_INIT (keystr);
447 if (keystr != NULL)
448 {
449 keys = keystrtovec (astr_cstr (keystr));
450 if (keys == NULL)
451 {
452 minibuf_error ("Key sequence %s is invalid", astr_cstr (keystr));
453 return leNIL;
454 }
455 }
456 else
457 {
458 minibuf_write ("Set key globally: ");
459 keys = get_key_sequence ();
460 keystr = keyvectodesc (keys);
461 }
462
463 STR_INIT (name)
464 else
465 name = minibuf_read_function_name ("Set key %s to command: ",
466 astr_cstr (keystr));
467 if (name == NULL)
468 return leNIL;
469
470 func = get_function (astr_cstr (name));
471 if (func == NULL) /* Possible if called non-interactively */
472 {
473 minibuf_error ("No such function `%s'", astr_cstr (name));
474 return leNIL;
475 }
476 bind_key_vec (root_bindings, keys, 0, func);
477 }
478 END_DEFUN
479
480 static void
walk_bindings_tree(Binding tree,gl_list_t keys,void (* process)(astr key,Binding p,void * st),void * st)481 walk_bindings_tree (Binding tree, gl_list_t keys,
482 void (*process) (astr key, Binding p, void *st), void *st)
483 {
484 for (size_t i = 0; i < tree->vecnum; ++i)
485 {
486 Binding p = tree->vec[i];
487 if (p->func != NULL)
488 {
489 astr key = astr_new ();
490 for (size_t j = 0; j < gl_list_size (keys); j++)
491 {
492 astr_cat (key, (const_astr) gl_list_get_at (keys, j));
493 astr_cat_char (key, ' ');
494 }
495 astr_cat (key, chordtodesc (p->key));
496 process (key, p, st);
497 }
498 else
499 {
500 gl_list_add_last (keys, chordtodesc (p->key));
501 walk_bindings_tree (p, keys, process, st);
502 assert (gl_list_remove_at (keys, gl_list_size (keys) - 1));
503 }
504 }
505 }
506
507 static void
walk_bindings(Binding tree,void (* process)(astr key,Binding p,void * st),void * st)508 walk_bindings (Binding tree, void (*process) (astr key, Binding p, void *st),
509 void *st)
510 {
511 walk_bindings_tree (tree, gl_list_create_empty (GL_LINKED_LIST,
512 NULL, NULL, NULL, true), process, st);
513 }
514
515 typedef struct
516 {
517 Function f;
518 astr bindings;
519 } gather_bindings_state;
520
521 static void
gather_bindings(astr key,Binding p,void * st)522 gather_bindings (astr key, Binding p, void *st)
523 {
524 gather_bindings_state *g = (gather_bindings_state *) st;
525
526 if (p->func == g->f)
527 {
528 if (astr_len (g->bindings) > 0)
529 astr_cat_cstr (g->bindings, ", ");
530 astr_cat (g->bindings, key);
531 }
532 }
533
534 DEFUN ("where-is", where_is)
535 /*+
536 Print message listing key sequences that invoke the command DEFINITION.
537 Argument is a command name.
538 +*/
539 {
540 const_astr name = minibuf_read_function_name ("Where is command: ");
541 gather_bindings_state g;
542
543 ok = leNIL;
544
545 if (name)
546 {
547 g.f = get_function (astr_cstr (name));
548 if (g.f)
549 {
550 g.bindings = astr_new ();
551 walk_bindings (root_bindings, gather_bindings, &g);
552
553 if (astr_len (g.bindings) == 0)
554 minibuf_write ("%s is not on any key", astr_cstr (name));
555 else
556 minibuf_write ("%s is on %s", astr_cstr (name), astr_cstr (g.bindings));
557 ok = leT;
558 }
559 }
560 }
561 END_DEFUN
562
563 static void
print_binding(astr key,Binding p,void * st _GL_UNUSED_PARAMETER)564 print_binding (astr key, Binding p, void *st _GL_UNUSED_PARAMETER)
565 {
566 bprintf ("%-15s %s\n", astr_cstr (key), get_function_name (p->func));
567 }
568
569 static void
write_bindings_list(va_list ap _GL_UNUSED_PARAMETER)570 write_bindings_list (va_list ap _GL_UNUSED_PARAMETER)
571 {
572 bprintf ("Key translations:\n");
573 bprintf ("%-15s %s\n", "key", "binding");
574 bprintf ("%-15s %s\n", "---", "-------");
575
576 walk_bindings (root_bindings, print_binding, NULL);
577 }
578
579 DEFUN ("describe-bindings", describe_bindings)
580 /*+
581 Show a list of all defined keys, and their definitions.
582 +*/
583 {
584 write_temp_buffer ("*Help*", true, write_bindings_list);
585 }
586 END_DEFUN
587