Annotation of src/usr.bin/tmux/mode-key.c, Revision 1.73
1.73 ! nicm 1: /* $OpenBSD: mode-key.c,v 1.72 2016/10/11 13:45:47 nicm Exp $ */
1.1 nicm 2:
3: /*
1.65 nicm 4: * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
1.1 nicm 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:
1.11 nicm 21: #include <string.h>
22:
1.1 nicm 23: #include "tmux.h"
24:
1.10 nicm 25: /*
26: * Mode keys. These are the key bindings used when editing (status prompt), and
27: * in the modes. They are split into two sets of three tables, one set of three
28: * for vi and the other for emacs key bindings. The three tables are for
29: * editing, for menu-like modes (choice, more), and for copy modes (copy,
30: * scroll).
31: *
32: * The fixed tables of struct mode_key_entry below are the defaults: they are
33: * built into a tree of struct mode_key_binding by mode_key_init_trees, which
34: * can then be modified.
35: *
36: * vi command mode is handled by having a mode flag in the struct which allows
37: * two sets of bindings to be swapped between. A couple of editing commands
1.53 nicm 38: * (any matching MODEKEYEDIT_SWITCHMODE*) are special-cased to do this.
1.10 nicm 39: */
1.63 nicm 40:
1.72 nicm 41: /* Command to string mapping. */
42: struct mode_key_cmdstr {
43: enum mode_key_cmd cmd;
44: const char *name;
45: };
46:
1.63 nicm 47: /* Entry in the default mode key tables. */
48: struct mode_key_entry {
1.64 nicm 49: key_code key;
1.63 nicm 50: enum mode_key_cmd cmd;
51: };
1.10 nicm 52:
53: /* Choice keys command strings. */
1.70 nicm 54: static const struct mode_key_cmdstr mode_key_cmdstr_choice[] = {
1.46 nicm 55: { MODEKEYCHOICE_BACKSPACE, "backspace" },
1.57 nicm 56: { MODEKEYCHOICE_BOTTOMLINE, "bottom-line"},
1.10 nicm 57: { MODEKEYCHOICE_CANCEL, "cancel" },
58: { MODEKEYCHOICE_CHOOSE, "choose" },
59: { MODEKEYCHOICE_DOWN, "down" },
1.57 nicm 60: { MODEKEYCHOICE_ENDOFLIST, "end-of-list"},
1.10 nicm 61: { MODEKEYCHOICE_PAGEDOWN, "page-down" },
62: { MODEKEYCHOICE_PAGEUP, "page-up" },
1.30 nicm 63: { MODEKEYCHOICE_SCROLLDOWN, "scroll-down" },
64: { MODEKEYCHOICE_SCROLLUP, "scroll-up" },
1.46 nicm 65: { MODEKEYCHOICE_STARTNUMBERPREFIX, "start-number-prefix" },
1.57 nicm 66: { MODEKEYCHOICE_STARTOFLIST, "start-of-list"},
67: { MODEKEYCHOICE_TOPLINE, "top-line"},
1.49 nicm 68: { MODEKEYCHOICE_TREE_COLLAPSE, "tree-collapse" },
1.48 nicm 69: { MODEKEYCHOICE_TREE_COLLAPSE_ALL, "tree-collapse-all" },
1.49 nicm 70: { MODEKEYCHOICE_TREE_EXPAND, "tree-expand" },
1.48 nicm 71: { MODEKEYCHOICE_TREE_EXPAND_ALL, "tree-expand-all" },
72: { MODEKEYCHOICE_TREE_TOGGLE, "tree-toggle" },
1.10 nicm 73: { MODEKEYCHOICE_UP, "up" },
1.11 nicm 74:
75: { 0, NULL }
1.10 nicm 76: };
77:
1.8 nicm 78: /* vi choice selection keys. */
1.70 nicm 79: static const struct mode_key_entry mode_key_vi_choice[] = {
1.73 ! nicm 80: { '0' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
! 81: { '1' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
! 82: { '2' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
! 83: { '3' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
! 84: { '4' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
! 85: { '5' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
! 86: { '6' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
! 87: { '7' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
! 88: { '8' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
! 89: { '9' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
! 90: { '\002' /* C-b */, MODEKEYCHOICE_PAGEUP },
! 91: { '\003' /* C-c */, MODEKEYCHOICE_CANCEL },
! 92: { '\005' /* C-e */, MODEKEYCHOICE_SCROLLDOWN },
! 93: { '\006' /* C-f */, MODEKEYCHOICE_PAGEDOWN },
! 94: { '\031' /* C-y */, MODEKEYCHOICE_SCROLLUP },
! 95: { '\n', MODEKEYCHOICE_CHOOSE },
! 96: { '\r', MODEKEYCHOICE_CHOOSE },
! 97: { 'j', MODEKEYCHOICE_DOWN },
! 98: { 'k', MODEKEYCHOICE_UP },
! 99: { 'q', MODEKEYCHOICE_CANCEL },
! 100: { KEYC_HOME, MODEKEYCHOICE_STARTOFLIST },
! 101: { 'g', MODEKEYCHOICE_STARTOFLIST },
! 102: { 'H', MODEKEYCHOICE_TOPLINE },
! 103: { 'L', MODEKEYCHOICE_BOTTOMLINE },
! 104: { 'G', MODEKEYCHOICE_ENDOFLIST },
! 105: { KEYC_END, MODEKEYCHOICE_ENDOFLIST },
! 106: { KEYC_BSPACE, MODEKEYCHOICE_BACKSPACE },
! 107: { KEYC_DOWN | KEYC_CTRL, MODEKEYCHOICE_SCROLLDOWN },
! 108: { KEYC_DOWN, MODEKEYCHOICE_DOWN },
! 109: { KEYC_NPAGE, MODEKEYCHOICE_PAGEDOWN },
! 110: { KEYC_PPAGE, MODEKEYCHOICE_PAGEUP },
! 111: { KEYC_UP | KEYC_CTRL, MODEKEYCHOICE_SCROLLUP },
! 112: { KEYC_UP, MODEKEYCHOICE_UP },
! 113: { ' ', MODEKEYCHOICE_TREE_TOGGLE },
! 114: { KEYC_LEFT, MODEKEYCHOICE_TREE_COLLAPSE },
! 115: { KEYC_RIGHT, MODEKEYCHOICE_TREE_EXPAND },
! 116: { KEYC_LEFT | KEYC_CTRL, MODEKEYCHOICE_TREE_COLLAPSE_ALL },
! 117: { KEYC_RIGHT | KEYC_CTRL, MODEKEYCHOICE_TREE_EXPAND_ALL },
! 118: { KEYC_MOUSEDOWN1_PANE, MODEKEYCHOICE_CHOOSE },
! 119: { KEYC_MOUSEDOWN3_PANE, MODEKEYCHOICE_TREE_TOGGLE },
! 120: { KEYC_WHEELUP_PANE, MODEKEYCHOICE_UP },
! 121: { KEYC_WHEELDOWN_PANE, MODEKEYCHOICE_DOWN },
1.8 nicm 122:
1.73 ! nicm 123: { KEYC_NONE, -1 }
1.8 nicm 124: };
1.10 nicm 125: struct mode_key_tree mode_key_tree_vi_choice;
1.8 nicm 126:
127: /* emacs choice selection keys. */
1.70 nicm 128: static const struct mode_key_entry mode_key_emacs_choice[] = {
1.73 ! nicm 129: { '0' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
! 130: { '1' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
! 131: { '2' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
! 132: { '3' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
! 133: { '4' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
! 134: { '5' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
! 135: { '6' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
! 136: { '7' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
! 137: { '8' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
! 138: { '9' | KEYC_ESCAPE, MODEKEYCHOICE_STARTNUMBERPREFIX },
! 139: { '\003' /* C-c */, MODEKEYCHOICE_CANCEL },
! 140: { '\016' /* C-n */, MODEKEYCHOICE_DOWN },
! 141: { '\020' /* C-p */, MODEKEYCHOICE_UP },
! 142: { '\026' /* C-v */, MODEKEYCHOICE_PAGEDOWN },
! 143: { '\033' /* Escape */, MODEKEYCHOICE_CANCEL },
! 144: { '\n', MODEKEYCHOICE_CHOOSE },
! 145: { '\r', MODEKEYCHOICE_CHOOSE },
! 146: { 'q', MODEKEYCHOICE_CANCEL },
! 147: { 'v' | KEYC_ESCAPE, MODEKEYCHOICE_PAGEUP },
! 148: { KEYC_HOME, MODEKEYCHOICE_STARTOFLIST },
! 149: { '<' | KEYC_ESCAPE, MODEKEYCHOICE_STARTOFLIST },
! 150: { 'R' | KEYC_ESCAPE, MODEKEYCHOICE_TOPLINE },
! 151: { '>' | KEYC_ESCAPE, MODEKEYCHOICE_ENDOFLIST },
! 152: { KEYC_END, MODEKEYCHOICE_ENDOFLIST },
! 153: { KEYC_BSPACE, MODEKEYCHOICE_BACKSPACE },
! 154: { KEYC_DOWN | KEYC_CTRL, MODEKEYCHOICE_SCROLLDOWN },
! 155: { KEYC_DOWN, MODEKEYCHOICE_DOWN },
! 156: { KEYC_NPAGE, MODEKEYCHOICE_PAGEDOWN },
! 157: { KEYC_PPAGE, MODEKEYCHOICE_PAGEUP },
! 158: { KEYC_UP | KEYC_CTRL, MODEKEYCHOICE_SCROLLUP },
! 159: { KEYC_UP, MODEKEYCHOICE_UP },
! 160: { ' ', MODEKEYCHOICE_TREE_TOGGLE },
! 161: { KEYC_LEFT, MODEKEYCHOICE_TREE_COLLAPSE },
! 162: { KEYC_RIGHT, MODEKEYCHOICE_TREE_EXPAND },
! 163: { KEYC_LEFT | KEYC_CTRL, MODEKEYCHOICE_TREE_COLLAPSE_ALL },
! 164: { KEYC_RIGHT | KEYC_CTRL, MODEKEYCHOICE_TREE_EXPAND_ALL },
! 165: { KEYC_MOUSEDOWN1_PANE, MODEKEYCHOICE_CHOOSE },
! 166: { KEYC_MOUSEDOWN3_PANE, MODEKEYCHOICE_TREE_TOGGLE },
! 167: { KEYC_WHEELUP_PANE, MODEKEYCHOICE_UP },
! 168: { KEYC_WHEELDOWN_PANE, MODEKEYCHOICE_DOWN },
1.8 nicm 169:
1.73 ! nicm 170: { KEYC_NONE, -1 }
1.8 nicm 171: };
1.10 nicm 172: struct mode_key_tree mode_key_tree_emacs_choice;
1.8 nicm 173:
1.10 nicm 174: /* Table mapping key table names to default settings and trees. */
1.72 nicm 175: static const struct mode_key_table mode_key_tables[] = {
1.10 nicm 176: { "vi-choice", mode_key_cmdstr_choice,
177: &mode_key_tree_vi_choice, mode_key_vi_choice },
178: { "emacs-choice", mode_key_cmdstr_choice,
179: &mode_key_tree_emacs_choice, mode_key_emacs_choice },
180:
181: { NULL, NULL, NULL, NULL }
182: };
183:
1.44 nicm 184: RB_GENERATE(mode_key_tree, mode_key_binding, entry, mode_key_cmp);
1.10 nicm 185:
186: int
187: mode_key_cmp(struct mode_key_binding *mbind1, struct mode_key_binding *mbind2)
188: {
1.64 nicm 189: if (mbind1->key < mbind2->key)
190: return (-1);
191: if (mbind1->key > mbind2->key)
192: return (1);
193: return (0);
1.10 nicm 194: }
195:
196: const char *
1.36 nicm 197: mode_key_tostring(const struct mode_key_cmdstr *cmdstr, enum mode_key_cmd cmd)
1.10 nicm 198: {
199: for (; cmdstr->name != NULL; cmdstr++) {
200: if (cmdstr->cmd == cmd)
201: return (cmdstr->name);
1.11 nicm 202: }
203: return (NULL);
204: }
205:
206: enum mode_key_cmd
1.36 nicm 207: mode_key_fromstring(const struct mode_key_cmdstr *cmdstr, const char *name)
1.11 nicm 208: {
209: for (; cmdstr->name != NULL; cmdstr++) {
210: if (strcasecmp(cmdstr->name, name) == 0)
211: return (cmdstr->cmd);
212: }
213: return (MODEKEY_NONE);
214: }
215:
216: const struct mode_key_table *
217: mode_key_findtable(const char *name)
218: {
219: const struct mode_key_table *mtab;
1.25 nicm 220:
1.11 nicm 221: for (mtab = mode_key_tables; mtab->name != NULL; mtab++) {
222: if (strcasecmp(name, mtab->name) == 0)
223: return (mtab);
1.10 nicm 224: }
225: return (NULL);
226: }
1.1 nicm 227:
228: void
1.10 nicm 229: mode_key_init_trees(void)
1.1 nicm 230: {
1.10 nicm 231: const struct mode_key_table *mtab;
232: const struct mode_key_entry *ment;
233: struct mode_key_binding *mbind;
234:
235: for (mtab = mode_key_tables; mtab->name != NULL; mtab++) {
1.44 nicm 236: RB_INIT(mtab->tree);
1.73 ! nicm 237: for (ment = mtab->table; ment->key != KEYC_NONE; ment++) {
1.10 nicm 238: mbind = xmalloc(sizeof *mbind);
239: mbind->key = ment->key;
240: mbind->cmd = ment->cmd;
1.44 nicm 241: RB_INSERT(mode_key_tree, mtab->tree, mbind);
1.10 nicm 242: }
243: }
244: }
245:
246: void
247: mode_key_init(struct mode_key_data *mdata, struct mode_key_tree *mtree)
248: {
249: mdata->tree = mtree;
1.1 nicm 250: }
251:
252: enum mode_key_cmd
1.71 nicm 253: mode_key_lookup(struct mode_key_data *mdata, key_code key)
1.1 nicm 254: {
1.10 nicm 255: struct mode_key_binding *mbind, mtmp;
256:
257: mtmp.key = key;
1.73 ! nicm 258: if ((mbind = RB_FIND(mode_key_tree, mdata->tree, &mtmp)) == NULL)
1.10 nicm 259: return (MODEKEY_OTHER);
1.73 ! nicm 260: return (mbind->cmd);
1.1 nicm 261: }