4 * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
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.
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.
19 #include <sys/types.h>
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,
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.
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
38 * (any matching MODEKEYEDIT_SWITCHMODE*) are special-cased to do this.
41 /* Command to string mapping. */
42 struct mode_key_cmdstr
{
43 enum mode_key_cmd cmd
;
47 /* Entry in the default mode key tables. */
48 struct mode_key_entry
{
50 enum mode_key_cmd cmd
;
53 /* Choice keys command strings. */
54 static const struct mode_key_cmdstr mode_key_cmdstr_choice
[] = {
55 { MODEKEYCHOICE_BACKSPACE
, "backspace" },
56 { MODEKEYCHOICE_BOTTOMLINE
, "bottom-line"},
57 { MODEKEYCHOICE_CANCEL
, "cancel" },
58 { MODEKEYCHOICE_CHOOSE
, "choose" },
59 { MODEKEYCHOICE_DOWN
, "down" },
60 { MODEKEYCHOICE_ENDOFLIST
, "end-of-list"},
61 { MODEKEYCHOICE_PAGEDOWN
, "page-down" },
62 { MODEKEYCHOICE_PAGEUP
, "page-up" },
63 { MODEKEYCHOICE_SCROLLDOWN
, "scroll-down" },
64 { MODEKEYCHOICE_SCROLLUP
, "scroll-up" },
65 { MODEKEYCHOICE_STARTNUMBERPREFIX
, "start-number-prefix" },
66 { MODEKEYCHOICE_STARTOFLIST
, "start-of-list"},
67 { MODEKEYCHOICE_TOPLINE
, "top-line"},
68 { MODEKEYCHOICE_TREE_COLLAPSE
, "tree-collapse" },
69 { MODEKEYCHOICE_TREE_COLLAPSE_ALL
, "tree-collapse-all" },
70 { MODEKEYCHOICE_TREE_EXPAND
, "tree-expand" },
71 { MODEKEYCHOICE_TREE_EXPAND_ALL
, "tree-expand-all" },
72 { MODEKEYCHOICE_TREE_TOGGLE
, "tree-toggle" },
73 { MODEKEYCHOICE_UP
, "up" },
78 /* vi choice selection keys. */
79 static const struct mode_key_entry mode_key_vi_choice
[] = {
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
},
125 struct mode_key_tree mode_key_tree_vi_choice
;
127 /* emacs choice selection keys. */
128 static const struct mode_key_entry mode_key_emacs_choice
[] = {
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
},
172 struct mode_key_tree mode_key_tree_emacs_choice
;
174 /* Table mapping key table names to default settings and trees. */
175 static const struct mode_key_table mode_key_tables
[] = {
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
},
181 { NULL
, NULL
, NULL
, NULL
}
184 RB_GENERATE(mode_key_tree
, mode_key_binding
, entry
, mode_key_cmp
);
187 mode_key_cmp(struct mode_key_binding
*mbind1
, struct mode_key_binding
*mbind2
)
189 if (mbind1
->key
< mbind2
->key
)
191 if (mbind1
->key
> mbind2
->key
)
197 mode_key_tostring(const struct mode_key_cmdstr
*cmdstr
, enum mode_key_cmd cmd
)
199 for (; cmdstr
->name
!= NULL
; cmdstr
++) {
200 if (cmdstr
->cmd
== cmd
)
201 return (cmdstr
->name
);
207 mode_key_fromstring(const struct mode_key_cmdstr
*cmdstr
, const char *name
)
209 for (; cmdstr
->name
!= NULL
; cmdstr
++) {
210 if (strcasecmp(cmdstr
->name
, name
) == 0)
211 return (cmdstr
->cmd
);
213 return (MODEKEY_NONE
);
216 const struct mode_key_table
*
217 mode_key_findtable(const char *name
)
219 const struct mode_key_table
*mtab
;
221 for (mtab
= mode_key_tables
; mtab
->name
!= NULL
; mtab
++) {
222 if (strcasecmp(name
, mtab
->name
) == 0)
229 mode_key_init_trees(void)
231 const struct mode_key_table
*mtab
;
232 const struct mode_key_entry
*ment
;
233 struct mode_key_binding
*mbind
;
235 for (mtab
= mode_key_tables
; mtab
->name
!= NULL
; mtab
++) {
237 for (ment
= mtab
->table
; ment
->key
!= KEYC_NONE
; ment
++) {
238 mbind
= xmalloc(sizeof *mbind
);
239 mbind
->key
= ment
->key
;
240 mbind
->cmd
= ment
->cmd
;
241 RB_INSERT(mode_key_tree
, mtab
->tree
, mbind
);
247 mode_key_init(struct mode_key_data
*mdata
, struct mode_key_tree
*mtree
)
253 mode_key_lookup(struct mode_key_data
*mdata
, key_code key
)
255 struct mode_key_binding
*mbind
, mtmp
;
258 if ((mbind
= RB_FIND(mode_key_tree
, mdata
->tree
, &mtmp
)) == NULL
)
259 return (MODEKEY_OTHER
);