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