GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/tmux/mode-key.c Lines: 0 44 0.0 %
Date: 2016-12-06 Branches: 0 238 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: mode-key.c,v 1.68 2016/04/27 09:39:09 nicm Exp $ */
2
3
/*
4
 * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
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
21
#include <string.h>
22
23
#include "tmux.h"
24
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
38
 * (any matching MODEKEYEDIT_SWITCHMODE*) are special-cased to do this.
39
 */
40
41
/* Entry in the default mode key tables. */
42
struct mode_key_entry {
43
	key_code		key;
44
45
	/*
46
	 * Editing mode for vi: 0 is edit mode, keys not in the table are
47
	 * returned as MODEKEY_OTHER; 1 is command mode, keys not in the table
48
	 * are returned as MODEKEY_NONE. This is also matched on, allowing some
49
	 * keys to be bound in edit mode.
50
	 */
51
	int			mode;
52
	enum mode_key_cmd	cmd;
53
};
54
55
/* Edit keys command strings. */
56
const struct mode_key_cmdstr mode_key_cmdstr_edit[] = {
57
	{ MODEKEYEDIT_BACKSPACE, "backspace" },
58
	{ MODEKEYEDIT_CANCEL, "cancel" },
59
	{ MODEKEYEDIT_COMPLETE, "complete" },
60
	{ MODEKEYEDIT_CURSORLEFT, "cursor-left" },
61
	{ MODEKEYEDIT_CURSORRIGHT, "cursor-right" },
62
	{ MODEKEYEDIT_DELETE, "delete" },
63
	{ MODEKEYEDIT_DELETELINE, "delete-line" },
64
	{ MODEKEYEDIT_DELETETOENDOFLINE, "delete-end-of-line" },
65
	{ MODEKEYEDIT_DELETEWORD, "delete-word" },
66
	{ MODEKEYEDIT_ENDOFLINE, "end-of-line" },
67
	{ MODEKEYEDIT_ENTER, "enter" },
68
	{ MODEKEYEDIT_HISTORYDOWN, "history-down" },
69
	{ MODEKEYEDIT_HISTORYUP, "history-up" },
70
	{ MODEKEYEDIT_NEXTSPACE, "next-space" },
71
	{ MODEKEYEDIT_NEXTSPACEEND, "next-space-end" },
72
	{ MODEKEYEDIT_NEXTWORD, "next-word" },
73
	{ MODEKEYEDIT_NEXTWORDEND, "next-word-end" },
74
	{ MODEKEYEDIT_PASTE, "paste" },
75
	{ MODEKEYEDIT_PREVIOUSSPACE, "previous-space" },
76
	{ MODEKEYEDIT_PREVIOUSWORD, "previous-word" },
77
	{ MODEKEYEDIT_STARTOFLINE, "start-of-line" },
78
	{ MODEKEYEDIT_SWITCHMODE, "switch-mode" },
79
	{ MODEKEYEDIT_SWITCHMODEAPPEND, "switch-mode-append" },
80
	{ MODEKEYEDIT_SWITCHMODEAPPENDLINE, "switch-mode-append-line" },
81
	{ MODEKEYEDIT_SWITCHMODEBEGINLINE, "switch-mode-begin-line" },
82
	{ MODEKEYEDIT_SWITCHMODECHANGELINE, "switch-mode-change-line" },
83
	{ MODEKEYEDIT_SWITCHMODESUBSTITUTE, "switch-mode-substitute" },
84
	{ MODEKEYEDIT_SWITCHMODESUBSTITUTELINE, "switch-mode-substitute-line" },
85
	{ MODEKEYEDIT_TRANSPOSECHARS, "transpose-chars" },
86
87
	{ 0, NULL }
88
};
89
90
/* Choice keys command strings. */
91
const struct mode_key_cmdstr mode_key_cmdstr_choice[] = {
92
	{ MODEKEYCHOICE_BACKSPACE, "backspace" },
93
	{ MODEKEYCHOICE_BOTTOMLINE, "bottom-line"},
94
	{ MODEKEYCHOICE_CANCEL, "cancel" },
95
	{ MODEKEYCHOICE_CHOOSE, "choose" },
96
	{ MODEKEYCHOICE_DOWN, "down" },
97
	{ MODEKEYCHOICE_ENDOFLIST, "end-of-list"},
98
	{ MODEKEYCHOICE_PAGEDOWN, "page-down" },
99
	{ MODEKEYCHOICE_PAGEUP, "page-up" },
100
	{ MODEKEYCHOICE_SCROLLDOWN, "scroll-down" },
101
	{ MODEKEYCHOICE_SCROLLUP, "scroll-up" },
102
	{ MODEKEYCHOICE_STARTNUMBERPREFIX, "start-number-prefix" },
103
	{ MODEKEYCHOICE_STARTOFLIST, "start-of-list"},
104
	{ MODEKEYCHOICE_TOPLINE, "top-line"},
105
	{ MODEKEYCHOICE_TREE_COLLAPSE, "tree-collapse" },
106
	{ MODEKEYCHOICE_TREE_COLLAPSE_ALL, "tree-collapse-all" },
107
	{ MODEKEYCHOICE_TREE_EXPAND, "tree-expand" },
108
	{ MODEKEYCHOICE_TREE_EXPAND_ALL, "tree-expand-all" },
109
	{ MODEKEYCHOICE_TREE_TOGGLE, "tree-toggle" },
110
	{ MODEKEYCHOICE_UP, "up" },
111
112
	{ 0, NULL }
113
};
114
115
/* Copy keys command strings. */
116
const struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
117
	{ MODEKEYCOPY_APPENDSELECTION, "append-selection" },
118
	{ MODEKEYCOPY_BACKTOINDENTATION, "back-to-indentation" },
119
	{ MODEKEYCOPY_BOTTOMLINE, "bottom-line" },
120
	{ MODEKEYCOPY_CANCEL, "cancel" },
121
	{ MODEKEYCOPY_CLEARSELECTION, "clear-selection" },
122
	{ MODEKEYCOPY_COPYPIPE, "copy-pipe" },
123
	{ MODEKEYCOPY_COPYLINE, "copy-line" },
124
	{ MODEKEYCOPY_COPYENDOFLINE, "copy-end-of-line" },
125
	{ MODEKEYCOPY_COPYSELECTION, "copy-selection" },
126
	{ MODEKEYCOPY_DOWN, "cursor-down" },
127
	{ MODEKEYCOPY_ENDOFLINE, "end-of-line" },
128
	{ MODEKEYCOPY_GOTOLINE, "goto-line" },
129
	{ MODEKEYCOPY_HALFPAGEDOWN, "halfpage-down" },
130
	{ MODEKEYCOPY_HALFPAGEUP, "halfpage-up" },
131
	{ MODEKEYCOPY_HISTORYBOTTOM, "history-bottom" },
132
	{ MODEKEYCOPY_HISTORYTOP, "history-top" },
133
	{ MODEKEYCOPY_JUMP, "jump-forward" },
134
	{ MODEKEYCOPY_JUMPAGAIN, "jump-again" },
135
	{ MODEKEYCOPY_JUMPREVERSE, "jump-reverse" },
136
	{ MODEKEYCOPY_JUMPBACK, "jump-backward" },
137
	{ MODEKEYCOPY_JUMPTO, "jump-to-forward" },
138
	{ MODEKEYCOPY_JUMPTOBACK, "jump-to-backward" },
139
	{ MODEKEYCOPY_LEFT, "cursor-left" },
140
	{ MODEKEYCOPY_RECTANGLETOGGLE, "rectangle-toggle" },
141
	{ MODEKEYCOPY_MIDDLELINE, "middle-line" },
142
	{ MODEKEYCOPY_NEXTPAGE, "page-down" },
143
	{ MODEKEYCOPY_NEXTPARAGRAPH, "next-paragraph" },
144
	{ MODEKEYCOPY_NEXTSPACE, "next-space" },
145
	{ MODEKEYCOPY_NEXTSPACEEND, "next-space-end" },
146
	{ MODEKEYCOPY_NEXTWORD, "next-word" },
147
	{ MODEKEYCOPY_NEXTWORDEND, "next-word-end" },
148
	{ MODEKEYCOPY_OTHEREND, "other-end" },
149
	{ MODEKEYCOPY_PREVIOUSPAGE, "page-up" },
150
	{ MODEKEYCOPY_PREVIOUSPARAGRAPH, "previous-paragraph" },
151
	{ MODEKEYCOPY_PREVIOUSSPACE, "previous-space" },
152
	{ MODEKEYCOPY_PREVIOUSWORD, "previous-word" },
153
	{ MODEKEYCOPY_RIGHT, "cursor-right" },
154
	{ MODEKEYCOPY_SCROLLDOWN, "scroll-down" },
155
	{ MODEKEYCOPY_SCROLLUP, "scroll-up" },
156
	{ MODEKEYCOPY_SEARCHAGAIN, "search-again" },
157
	{ MODEKEYCOPY_SEARCHDOWN, "search-forward" },
158
	{ MODEKEYCOPY_SEARCHREVERSE, "search-reverse" },
159
	{ MODEKEYCOPY_SEARCHUP, "search-backward" },
160
	{ MODEKEYCOPY_SELECTLINE, "select-line" },
161
	{ MODEKEYCOPY_STARTNAMEDBUFFER, "start-named-buffer" },
162
	{ MODEKEYCOPY_STARTNUMBERPREFIX, "start-number-prefix" },
163
	{ MODEKEYCOPY_STARTOFLINE, "start-of-line" },
164
	{ MODEKEYCOPY_STARTSELECTION, "begin-selection" },
165
	{ MODEKEYCOPY_TOPLINE, "top-line" },
166
	{ MODEKEYCOPY_UP, "cursor-up" },
167
168
	{ 0, NULL }
169
};
170
171
/* vi editing keys. */
172
const struct mode_key_entry mode_key_vi_edit[] = {
173
	{ '\003' /* C-c */,	    0, MODEKEYEDIT_CANCEL },
174
	{ '\010' /* C-h */,	    0, MODEKEYEDIT_BACKSPACE },
175
	{ '\011' /* Tab */,	    0, MODEKEYEDIT_COMPLETE },
176
	{ '\025' /* C-u */,	    0, MODEKEYEDIT_DELETELINE },
177
	{ '\027' /* C-w */,	    0, MODEKEYEDIT_DELETEWORD },
178
	{ '\033' /* Escape */,	    0, MODEKEYEDIT_SWITCHMODE },
179
	{ '\n',			    0, MODEKEYEDIT_ENTER },
180
	{ '\r',			    0, MODEKEYEDIT_ENTER },
181
	{ KEYC_BSPACE,		    0, MODEKEYEDIT_BACKSPACE },
182
	{ KEYC_DC,		    0, MODEKEYEDIT_DELETE },
183
	{ KEYC_DOWN,		    0, MODEKEYEDIT_HISTORYDOWN },
184
	{ KEYC_LEFT,		    0, MODEKEYEDIT_CURSORLEFT },
185
	{ KEYC_RIGHT,		    0, MODEKEYEDIT_CURSORRIGHT },
186
	{ KEYC_UP,		    0, MODEKEYEDIT_HISTORYUP },
187
	{ KEYC_HOME,		    0, MODEKEYEDIT_STARTOFLINE },
188
	{ KEYC_END,		    0, MODEKEYEDIT_ENDOFLINE },
189
190
	{ '$',			    1, MODEKEYEDIT_ENDOFLINE },
191
	{ '0',			    1, MODEKEYEDIT_STARTOFLINE },
192
	{ 'A',			    1, MODEKEYEDIT_SWITCHMODEAPPENDLINE },
193
	{ 'B',			    1, MODEKEYEDIT_PREVIOUSSPACE },
194
	{ 'C',			    1, MODEKEYEDIT_SWITCHMODECHANGELINE },
195
	{ 'D',			    1, MODEKEYEDIT_DELETETOENDOFLINE },
196
	{ 'E',			    1, MODEKEYEDIT_NEXTSPACEEND },
197
	{ 'I',			    1, MODEKEYEDIT_SWITCHMODEBEGINLINE },
198
	{ 'S',			    1, MODEKEYEDIT_SWITCHMODESUBSTITUTELINE },
199
	{ 'W',			    1, MODEKEYEDIT_NEXTSPACE },
200
	{ 'X',			    1, MODEKEYEDIT_BACKSPACE },
201
	{ '\003' /* C-c */,	    1, MODEKEYEDIT_CANCEL },
202
	{ '\010' /* C-h */,	    1, MODEKEYEDIT_BACKSPACE },
203
	{ '\n',			    1, MODEKEYEDIT_ENTER },
204
	{ '\r',			    1, MODEKEYEDIT_ENTER },
205
	{ '^',			    1, MODEKEYEDIT_STARTOFLINE },
206
	{ 'a',			    1, MODEKEYEDIT_SWITCHMODEAPPEND },
207
	{ 'b',			    1, MODEKEYEDIT_PREVIOUSWORD },
208
	{ 'd',			    1, MODEKEYEDIT_DELETELINE },
209
	{ 'e',			    1, MODEKEYEDIT_NEXTWORDEND },
210
	{ 'h',			    1, MODEKEYEDIT_CURSORLEFT },
211
	{ 'i',			    1, MODEKEYEDIT_SWITCHMODE },
212
	{ 'j',			    1, MODEKEYEDIT_HISTORYDOWN },
213
	{ 'k',			    1, MODEKEYEDIT_HISTORYUP },
214
	{ 'l',			    1, MODEKEYEDIT_CURSORRIGHT },
215
	{ 'p',			    1, MODEKEYEDIT_PASTE },
216
	{ 's',			    1, MODEKEYEDIT_SWITCHMODESUBSTITUTE },
217
	{ 'w',			    1, MODEKEYEDIT_NEXTWORD },
218
	{ 'x',			    1, MODEKEYEDIT_DELETE },
219
	{ KEYC_BSPACE,		    1, MODEKEYEDIT_BACKSPACE },
220
	{ KEYC_DC,		    1, MODEKEYEDIT_DELETE },
221
	{ KEYC_DOWN,		    1, MODEKEYEDIT_HISTORYDOWN },
222
	{ KEYC_LEFT,		    1, MODEKEYEDIT_CURSORLEFT },
223
	{ KEYC_RIGHT,		    1, MODEKEYEDIT_CURSORRIGHT },
224
	{ KEYC_UP,		    1, MODEKEYEDIT_HISTORYUP },
225
226
	{ 0,			   -1, 0 }
227
};
228
struct mode_key_tree mode_key_tree_vi_edit;
229
230
/* vi choice selection keys. */
231
const struct mode_key_entry mode_key_vi_choice[] = {
232
	{ '0' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTNUMBERPREFIX },
233
	{ '1' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTNUMBERPREFIX },
234
	{ '2' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTNUMBERPREFIX },
235
	{ '3' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTNUMBERPREFIX },
236
	{ '4' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTNUMBERPREFIX },
237
	{ '5' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTNUMBERPREFIX },
238
	{ '6' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTNUMBERPREFIX },
239
	{ '7' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTNUMBERPREFIX },
240
	{ '8' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTNUMBERPREFIX },
241
	{ '9' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTNUMBERPREFIX },
242
	{ '\002' /* C-b */,	    0, MODEKEYCHOICE_PAGEUP },
243
	{ '\003' /* C-c */,	    0, MODEKEYCHOICE_CANCEL },
244
	{ '\005' /* C-e */,	    0, MODEKEYCHOICE_SCROLLDOWN },
245
	{ '\006' /* C-f */,	    0, MODEKEYCHOICE_PAGEDOWN },
246
	{ '\031' /* C-y */,	    0, MODEKEYCHOICE_SCROLLUP },
247
	{ '\n',			    0, MODEKEYCHOICE_CHOOSE },
248
	{ '\r',			    0, MODEKEYCHOICE_CHOOSE },
249
	{ 'j',			    0, MODEKEYCHOICE_DOWN },
250
	{ 'k',			    0, MODEKEYCHOICE_UP },
251
	{ 'q',			    0, MODEKEYCHOICE_CANCEL },
252
	{ KEYC_HOME,                0, MODEKEYCHOICE_STARTOFLIST },
253
	{ 'g',                      0, MODEKEYCHOICE_STARTOFLIST },
254
	{ 'H',                      0, MODEKEYCHOICE_TOPLINE },
255
	{ 'L',                      0, MODEKEYCHOICE_BOTTOMLINE },
256
	{ 'G',                      0, MODEKEYCHOICE_ENDOFLIST },
257
	{ KEYC_END,                 0, MODEKEYCHOICE_ENDOFLIST },
258
	{ KEYC_BSPACE,		    0, MODEKEYCHOICE_BACKSPACE },
259
	{ KEYC_DOWN | KEYC_CTRL,    0, MODEKEYCHOICE_SCROLLDOWN },
260
	{ KEYC_DOWN,		    0, MODEKEYCHOICE_DOWN },
261
	{ KEYC_NPAGE,		    0, MODEKEYCHOICE_PAGEDOWN },
262
	{ KEYC_PPAGE,		    0, MODEKEYCHOICE_PAGEUP },
263
	{ KEYC_UP | KEYC_CTRL,	    0, MODEKEYCHOICE_SCROLLUP },
264
	{ KEYC_UP,		    0, MODEKEYCHOICE_UP },
265
	{ ' ',			    0, MODEKEYCHOICE_TREE_TOGGLE },
266
	{ KEYC_LEFT,		    0, MODEKEYCHOICE_TREE_COLLAPSE },
267
	{ KEYC_RIGHT,		    0, MODEKEYCHOICE_TREE_EXPAND },
268
	{ KEYC_LEFT | KEYC_CTRL,    0, MODEKEYCHOICE_TREE_COLLAPSE_ALL },
269
	{ KEYC_RIGHT | KEYC_CTRL,   0, MODEKEYCHOICE_TREE_EXPAND_ALL },
270
	{ KEYC_MOUSEDOWN1_PANE,     0, MODEKEYCHOICE_CHOOSE },
271
	{ KEYC_MOUSEDOWN3_PANE,     0, MODEKEYCHOICE_TREE_TOGGLE },
272
	{ KEYC_WHEELUP_PANE,        0, MODEKEYCHOICE_UP },
273
	{ KEYC_WHEELDOWN_PANE,      0, MODEKEYCHOICE_DOWN },
274
275
	{ 0,			   -1, 0 }
276
};
277
struct mode_key_tree mode_key_tree_vi_choice;
278
279
/* vi copy mode keys. */
280
const struct mode_key_entry mode_key_vi_copy[] = {
281
	{ ' ',			    0, MODEKEYCOPY_STARTSELECTION },
282
	{ '"',			    0, MODEKEYCOPY_STARTNAMEDBUFFER },
283
	{ '$',			    0, MODEKEYCOPY_ENDOFLINE },
284
	{ ',',			    0, MODEKEYCOPY_JUMPREVERSE },
285
	{ ';',			    0, MODEKEYCOPY_JUMPAGAIN },
286
	{ '/',			    0, MODEKEYCOPY_SEARCHDOWN },
287
	{ '0',			    0, MODEKEYCOPY_STARTOFLINE },
288
	{ '1',			    0, MODEKEYCOPY_STARTNUMBERPREFIX },
289
	{ '2',			    0, MODEKEYCOPY_STARTNUMBERPREFIX },
290
	{ '3',			    0, MODEKEYCOPY_STARTNUMBERPREFIX },
291
	{ '4',			    0, MODEKEYCOPY_STARTNUMBERPREFIX },
292
	{ '5',			    0, MODEKEYCOPY_STARTNUMBERPREFIX },
293
	{ '6',			    0, MODEKEYCOPY_STARTNUMBERPREFIX },
294
	{ '7',			    0, MODEKEYCOPY_STARTNUMBERPREFIX },
295
	{ '8',			    0, MODEKEYCOPY_STARTNUMBERPREFIX },
296
	{ '9',			    0, MODEKEYCOPY_STARTNUMBERPREFIX },
297
	{ ':',			    0, MODEKEYCOPY_GOTOLINE },
298
	{ '?',			    0, MODEKEYCOPY_SEARCHUP },
299
	{ 'A',			    0, MODEKEYCOPY_APPENDSELECTION },
300
	{ 'B',			    0, MODEKEYCOPY_PREVIOUSSPACE },
301
	{ 'D',			    0, MODEKEYCOPY_COPYENDOFLINE },
302
	{ 'E',			    0, MODEKEYCOPY_NEXTSPACEEND },
303
	{ 'F',			    0, MODEKEYCOPY_JUMPBACK },
304
	{ 'G',			    0, MODEKEYCOPY_HISTORYBOTTOM },
305
	{ 'H',			    0, MODEKEYCOPY_TOPLINE },
306
	{ 'J',			    0, MODEKEYCOPY_SCROLLDOWN },
307
	{ 'K',			    0, MODEKEYCOPY_SCROLLUP },
308
	{ 'L',			    0, MODEKEYCOPY_BOTTOMLINE },
309
	{ 'M',			    0, MODEKEYCOPY_MIDDLELINE },
310
	{ 'N',			    0, MODEKEYCOPY_SEARCHREVERSE },
311
	{ 'T',			    0, MODEKEYCOPY_JUMPTOBACK },
312
	{ 'V',			    0, MODEKEYCOPY_SELECTLINE },
313
	{ 'W',			    0, MODEKEYCOPY_NEXTSPACE },
314
	{ '\002' /* C-b */,	    0, MODEKEYCOPY_PREVIOUSPAGE },
315
	{ '\003' /* C-c */,	    0, MODEKEYCOPY_CANCEL },
316
	{ '\004' /* C-d */,	    0, MODEKEYCOPY_HALFPAGEDOWN },
317
	{ '\005' /* C-e */,	    0, MODEKEYCOPY_SCROLLDOWN },
318
	{ '\006' /* C-f */,	    0, MODEKEYCOPY_NEXTPAGE },
319
	{ '\010' /* C-h */,	    0, MODEKEYCOPY_LEFT },
320
	{ '\025' /* C-u */,	    0, MODEKEYCOPY_HALFPAGEUP },
321
	{ '\031' /* C-y */,	    0, MODEKEYCOPY_SCROLLUP },
322
	{ '\033' /* Escape */,	    0, MODEKEYCOPY_CLEARSELECTION },
323
	{ '\n',			    0, MODEKEYCOPY_COPYSELECTION },
324
	{ '\r',			    0, MODEKEYCOPY_COPYSELECTION },
325
	{ '^',			    0, MODEKEYCOPY_BACKTOINDENTATION },
326
	{ 'b',			    0, MODEKEYCOPY_PREVIOUSWORD },
327
	{ 'e',			    0, MODEKEYCOPY_NEXTWORDEND },
328
	{ 'f',			    0, MODEKEYCOPY_JUMP },
329
	{ 'g',			    0, MODEKEYCOPY_HISTORYTOP },
330
	{ 'h',			    0, MODEKEYCOPY_LEFT },
331
	{ 'j',			    0, MODEKEYCOPY_DOWN },
332
	{ 'k',			    0, MODEKEYCOPY_UP },
333
	{ 'l',			    0, MODEKEYCOPY_RIGHT },
334
	{ 'n',			    0, MODEKEYCOPY_SEARCHAGAIN },
335
	{ 'o',			    0, MODEKEYCOPY_OTHEREND },
336
	{ 't',			    0, MODEKEYCOPY_JUMPTO },
337
	{ 'q',			    0, MODEKEYCOPY_CANCEL },
338
	{ 'v',			    0, MODEKEYCOPY_RECTANGLETOGGLE },
339
	{ 'w',			    0, MODEKEYCOPY_NEXTWORD },
340
	{ '{',			    0, MODEKEYCOPY_PREVIOUSPARAGRAPH },
341
	{ '}',			    0, MODEKEYCOPY_NEXTPARAGRAPH },
342
	{ KEYC_BSPACE,		    0, MODEKEYCOPY_LEFT },
343
	{ KEYC_DOWN | KEYC_CTRL,    0, MODEKEYCOPY_SCROLLDOWN },
344
	{ KEYC_DOWN,		    0, MODEKEYCOPY_DOWN },
345
	{ KEYC_LEFT,		    0, MODEKEYCOPY_LEFT },
346
	{ KEYC_NPAGE,		    0, MODEKEYCOPY_NEXTPAGE },
347
	{ KEYC_PPAGE,		    0, MODEKEYCOPY_PREVIOUSPAGE },
348
	{ KEYC_RIGHT,		    0, MODEKEYCOPY_RIGHT },
349
	{ KEYC_UP | KEYC_CTRL,	    0, MODEKEYCOPY_SCROLLUP },
350
	{ KEYC_UP,		    0, MODEKEYCOPY_UP },
351
	{ KEYC_WHEELUP_PANE,        0, MODEKEYCOPY_SCROLLUP },
352
	{ KEYC_WHEELDOWN_PANE,      0, MODEKEYCOPY_SCROLLDOWN },
353
	{ KEYC_MOUSEDRAG1_PANE,     0, MODEKEYCOPY_STARTSELECTION },
354
	{ KEYC_MOUSEDRAGEND1_PANE,  0, MODEKEYCOPY_COPYSELECTION },
355
356
	{ 0,			   -1, 0 }
357
};
358
struct mode_key_tree mode_key_tree_vi_copy;
359
360
/* emacs editing keys. */
361
const struct mode_key_entry mode_key_emacs_edit[] = {
362
	{ '\001' /* C-a */,	    0, MODEKEYEDIT_STARTOFLINE },
363
	{ '\002' /* C-b */,	    0, MODEKEYEDIT_CURSORLEFT },
364
	{ '\003' /* C-c */,	    0, MODEKEYEDIT_CANCEL },
365
	{ '\004' /* C-d */,	    0, MODEKEYEDIT_DELETE },
366
	{ '\005' /* C-e */,	    0, MODEKEYEDIT_ENDOFLINE },
367
	{ '\006' /* C-f */,	    0, MODEKEYEDIT_CURSORRIGHT },
368
	{ '\010' /* C-H */,	    0, MODEKEYEDIT_BACKSPACE },
369
	{ '\011' /* Tab */,	    0, MODEKEYEDIT_COMPLETE },
370
	{ '\013' /* C-k */,	    0, MODEKEYEDIT_DELETETOENDOFLINE },
371
	{ '\016' /* C-n */,	    0, MODEKEYEDIT_HISTORYDOWN },
372
	{ '\020' /* C-p */,	    0, MODEKEYEDIT_HISTORYUP },
373
	{ '\024' /* C-t */,	    0, MODEKEYEDIT_TRANSPOSECHARS },
374
	{ '\025' /* C-u */,	    0, MODEKEYEDIT_DELETELINE },
375
	{ '\027' /* C-w */,	    0, MODEKEYEDIT_DELETEWORD },
376
	{ '\031' /* C-y */,	    0, MODEKEYEDIT_PASTE },
377
	{ '\033' /* Escape */,	    0, MODEKEYEDIT_CANCEL },
378
	{ '\n',			    0, MODEKEYEDIT_ENTER },
379
	{ '\r',			    0, MODEKEYEDIT_ENTER },
380
	{ 'b' | KEYC_ESCAPE,	    0, MODEKEYEDIT_PREVIOUSWORD },
381
	{ 'f' | KEYC_ESCAPE,	    0, MODEKEYEDIT_NEXTWORDEND },
382
	{ 'm' | KEYC_ESCAPE,	    0, MODEKEYEDIT_STARTOFLINE },
383
	{ KEYC_BSPACE,		    0, MODEKEYEDIT_BACKSPACE },
384
	{ KEYC_DC,		    0, MODEKEYEDIT_DELETE },
385
	{ KEYC_DOWN,		    0, MODEKEYEDIT_HISTORYDOWN },
386
	{ KEYC_LEFT,		    0, MODEKEYEDIT_CURSORLEFT },
387
	{ KEYC_RIGHT,		    0, MODEKEYEDIT_CURSORRIGHT },
388
	{ KEYC_UP,		    0, MODEKEYEDIT_HISTORYUP },
389
	{ KEYC_HOME,		    0, MODEKEYEDIT_STARTOFLINE },
390
	{ KEYC_END,		    0, MODEKEYEDIT_ENDOFLINE },
391
392
	{ 0,			   -1, 0 }
393
};
394
struct mode_key_tree mode_key_tree_emacs_edit;
395
396
/* emacs choice selection keys. */
397
const struct mode_key_entry mode_key_emacs_choice[] = {
398
	{ '0' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTNUMBERPREFIX },
399
	{ '1' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTNUMBERPREFIX },
400
	{ '2' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTNUMBERPREFIX },
401
	{ '3' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTNUMBERPREFIX },
402
	{ '4' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTNUMBERPREFIX },
403
	{ '5' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTNUMBERPREFIX },
404
	{ '6' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTNUMBERPREFIX },
405
	{ '7' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTNUMBERPREFIX },
406
	{ '8' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTNUMBERPREFIX },
407
	{ '9' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTNUMBERPREFIX },
408
	{ '\003' /* C-c */,	    0, MODEKEYCHOICE_CANCEL },
409
	{ '\016' /* C-n */,	    0, MODEKEYCHOICE_DOWN },
410
	{ '\020' /* C-p */,	    0, MODEKEYCHOICE_UP },
411
	{ '\026' /* C-v */,	    0, MODEKEYCHOICE_PAGEDOWN },
412
	{ '\033' /* Escape */,	    0, MODEKEYCHOICE_CANCEL },
413
	{ '\n',			    0, MODEKEYCHOICE_CHOOSE },
414
	{ '\r',			    0, MODEKEYCHOICE_CHOOSE },
415
	{ 'q',			    0, MODEKEYCHOICE_CANCEL },
416
	{ 'v' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_PAGEUP },
417
	{ KEYC_HOME,                0, MODEKEYCHOICE_STARTOFLIST },
418
	{ '<' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_STARTOFLIST },
419
	{ 'R' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_TOPLINE },
420
	{ '>' | KEYC_ESCAPE,	    0, MODEKEYCHOICE_ENDOFLIST },
421
	{ KEYC_END,                 0, MODEKEYCHOICE_ENDOFLIST },
422
	{ KEYC_BSPACE,		    0, MODEKEYCHOICE_BACKSPACE },
423
	{ KEYC_DOWN | KEYC_CTRL,    0, MODEKEYCHOICE_SCROLLDOWN },
424
	{ KEYC_DOWN,		    0, MODEKEYCHOICE_DOWN },
425
	{ KEYC_NPAGE,		    0, MODEKEYCHOICE_PAGEDOWN },
426
	{ KEYC_PPAGE,		    0, MODEKEYCHOICE_PAGEUP },
427
	{ KEYC_UP | KEYC_CTRL,	    0, MODEKEYCHOICE_SCROLLUP },
428
	{ KEYC_UP,		    0, MODEKEYCHOICE_UP },
429
	{ ' ',			    0, MODEKEYCHOICE_TREE_TOGGLE },
430
	{ KEYC_LEFT,		    0, MODEKEYCHOICE_TREE_COLLAPSE },
431
	{ KEYC_RIGHT,		    0, MODEKEYCHOICE_TREE_EXPAND },
432
	{ KEYC_LEFT | KEYC_CTRL,    0, MODEKEYCHOICE_TREE_COLLAPSE_ALL },
433
	{ KEYC_RIGHT | KEYC_CTRL,   0, MODEKEYCHOICE_TREE_EXPAND_ALL },
434
	{ KEYC_MOUSEDOWN1_PANE,     0, MODEKEYCHOICE_CHOOSE },
435
	{ KEYC_MOUSEDOWN3_PANE,     0, MODEKEYCHOICE_TREE_TOGGLE },
436
	{ KEYC_WHEELUP_PANE,        0, MODEKEYCHOICE_UP },
437
	{ KEYC_WHEELDOWN_PANE,      0, MODEKEYCHOICE_DOWN },
438
439
	{ 0,			   -1, 0 }
440
};
441
struct mode_key_tree mode_key_tree_emacs_choice;
442
443
/* emacs copy mode keys. */
444
const struct mode_key_entry mode_key_emacs_copy[] = {
445
	{ ' ',			    0, MODEKEYCOPY_NEXTPAGE },
446
	{ ',',			    0, MODEKEYCOPY_JUMPREVERSE },
447
	{ ';',			    0, MODEKEYCOPY_JUMPAGAIN },
448
	{ '1' | KEYC_ESCAPE,	    0, MODEKEYCOPY_STARTNUMBERPREFIX },
449
	{ '2' | KEYC_ESCAPE,	    0, MODEKEYCOPY_STARTNUMBERPREFIX },
450
	{ '3' | KEYC_ESCAPE,	    0, MODEKEYCOPY_STARTNUMBERPREFIX },
451
	{ '4' | KEYC_ESCAPE,	    0, MODEKEYCOPY_STARTNUMBERPREFIX },
452
	{ '5' | KEYC_ESCAPE,	    0, MODEKEYCOPY_STARTNUMBERPREFIX },
453
	{ '6' | KEYC_ESCAPE,	    0, MODEKEYCOPY_STARTNUMBERPREFIX },
454
	{ '7' | KEYC_ESCAPE,	    0, MODEKEYCOPY_STARTNUMBERPREFIX },
455
	{ '8' | KEYC_ESCAPE,	    0, MODEKEYCOPY_STARTNUMBERPREFIX },
456
	{ '9' | KEYC_ESCAPE,	    0, MODEKEYCOPY_STARTNUMBERPREFIX },
457
	{ '<' | KEYC_ESCAPE,	    0, MODEKEYCOPY_HISTORYTOP },
458
	{ '>' | KEYC_ESCAPE,	    0, MODEKEYCOPY_HISTORYBOTTOM },
459
	{ 'F',			    0, MODEKEYCOPY_JUMPBACK },
460
	{ 'N',			    0, MODEKEYCOPY_SEARCHREVERSE },
461
	{ 'R' | KEYC_ESCAPE,	    0, MODEKEYCOPY_TOPLINE },
462
	{ 'R',			    0, MODEKEYCOPY_RECTANGLETOGGLE },
463
	{ 'T',			    0, MODEKEYCOPY_JUMPTOBACK },
464
	{ '\000' /* C-Space */,	    0, MODEKEYCOPY_STARTSELECTION },
465
	{ '\001' /* C-a */,	    0, MODEKEYCOPY_STARTOFLINE },
466
	{ '\002' /* C-b */,	    0, MODEKEYCOPY_LEFT },
467
	{ '\003' /* C-c */,	    0, MODEKEYCOPY_CANCEL },
468
	{ '\005' /* C-e */,	    0, MODEKEYCOPY_ENDOFLINE },
469
	{ '\006' /* C-f */,	    0, MODEKEYCOPY_RIGHT },
470
	{ '\007' /* C-g */,	    0, MODEKEYCOPY_CLEARSELECTION },
471
	{ '\013' /* C-k */,	    0, MODEKEYCOPY_COPYENDOFLINE },
472
	{ '\016' /* C-n */,	    0, MODEKEYCOPY_DOWN },
473
	{ '\020' /* C-p */,	    0, MODEKEYCOPY_UP },
474
	{ '\022' /* C-r */,	    0, MODEKEYCOPY_SEARCHUP },
475
	{ '\023' /* C-s */,	    0, MODEKEYCOPY_SEARCHDOWN },
476
	{ '\026' /* C-v */,	    0, MODEKEYCOPY_NEXTPAGE },
477
	{ '\027' /* C-w */,	    0, MODEKEYCOPY_COPYSELECTION },
478
	{ '\033' /* Escape */,	    0, MODEKEYCOPY_CANCEL },
479
	{ 'b' | KEYC_ESCAPE,	    0, MODEKEYCOPY_PREVIOUSWORD },
480
	{ 'f',			    0, MODEKEYCOPY_JUMP },
481
	{ 'f' | KEYC_ESCAPE,	    0, MODEKEYCOPY_NEXTWORDEND },
482
	{ 'g',			    0, MODEKEYCOPY_GOTOLINE },
483
	{ 'm' | KEYC_ESCAPE,	    0, MODEKEYCOPY_BACKTOINDENTATION },
484
	{ 'n',			    0, MODEKEYCOPY_SEARCHAGAIN },
485
	{ 'q',			    0, MODEKEYCOPY_CANCEL },
486
	{ 'r' | KEYC_ESCAPE,	    0, MODEKEYCOPY_MIDDLELINE },
487
	{ 't',			    0, MODEKEYCOPY_JUMPTO },
488
	{ 'v' | KEYC_ESCAPE,	    0, MODEKEYCOPY_PREVIOUSPAGE },
489
	{ 'w' | KEYC_ESCAPE,	    0, MODEKEYCOPY_COPYSELECTION },
490
	{ '{' | KEYC_ESCAPE,	    0, MODEKEYCOPY_PREVIOUSPARAGRAPH },
491
	{ '}' | KEYC_ESCAPE,	    0, MODEKEYCOPY_NEXTPARAGRAPH },
492
	{ KEYC_DOWN | KEYC_CTRL,    0, MODEKEYCOPY_SCROLLDOWN },
493
	{ KEYC_DOWN | KEYC_ESCAPE,  0, MODEKEYCOPY_HALFPAGEDOWN },
494
	{ KEYC_DOWN,		    0, MODEKEYCOPY_DOWN },
495
	{ KEYC_LEFT,		    0, MODEKEYCOPY_LEFT },
496
	{ KEYC_NPAGE,		    0, MODEKEYCOPY_NEXTPAGE },
497
	{ KEYC_PPAGE,		    0, MODEKEYCOPY_PREVIOUSPAGE },
498
	{ KEYC_RIGHT,		    0, MODEKEYCOPY_RIGHT },
499
	{ KEYC_UP | KEYC_CTRL,	    0, MODEKEYCOPY_SCROLLUP },
500
	{ KEYC_UP | KEYC_ESCAPE,    0, MODEKEYCOPY_HALFPAGEUP },
501
	{ KEYC_UP,		    0, MODEKEYCOPY_UP },
502
	{ KEYC_WHEELUP_PANE,        0, MODEKEYCOPY_SCROLLUP },
503
	{ KEYC_WHEELDOWN_PANE,      0, MODEKEYCOPY_SCROLLDOWN },
504
	{ KEYC_MOUSEDRAG1_PANE,     0, MODEKEYCOPY_STARTSELECTION },
505
	{ KEYC_MOUSEDRAGEND1_PANE,  0, MODEKEYCOPY_COPYSELECTION },
506
507
	{ 0,			   -1, 0 }
508
};
509
struct mode_key_tree mode_key_tree_emacs_copy;
510
511
/* Table mapping key table names to default settings and trees. */
512
const struct mode_key_table mode_key_tables[] = {
513
	{ "vi-edit", mode_key_cmdstr_edit,
514
	  &mode_key_tree_vi_edit, mode_key_vi_edit },
515
	{ "vi-choice", mode_key_cmdstr_choice,
516
	  &mode_key_tree_vi_choice, mode_key_vi_choice },
517
	{ "vi-copy", mode_key_cmdstr_copy,
518
	  &mode_key_tree_vi_copy, mode_key_vi_copy },
519
	{ "emacs-edit", mode_key_cmdstr_edit,
520
	  &mode_key_tree_emacs_edit, mode_key_emacs_edit },
521
	{ "emacs-choice", mode_key_cmdstr_choice,
522
	  &mode_key_tree_emacs_choice, mode_key_emacs_choice },
523
	{ "emacs-copy", mode_key_cmdstr_copy,
524
	  &mode_key_tree_emacs_copy, mode_key_emacs_copy },
525
526
	{ NULL, NULL, NULL, NULL }
527
};
528
529
RB_GENERATE(mode_key_tree, mode_key_binding, entry, mode_key_cmp);
530
531
int
532
mode_key_cmp(struct mode_key_binding *mbind1, struct mode_key_binding *mbind2)
533
{
534
	if (mbind1->mode < mbind2->mode)
535
		return (-1);
536
	if (mbind1->mode > mbind2->mode)
537
		return (1);
538
	if (mbind1->key < mbind2->key)
539
		return (-1);
540
	if (mbind1->key > mbind2->key)
541
		return (1);
542
	return (0);
543
}
544
545
const char *
546
mode_key_tostring(const struct mode_key_cmdstr *cmdstr, enum mode_key_cmd cmd)
547
{
548
	for (; cmdstr->name != NULL; cmdstr++) {
549
		if (cmdstr->cmd == cmd)
550
			return (cmdstr->name);
551
	}
552
	return (NULL);
553
}
554
555
enum mode_key_cmd
556
mode_key_fromstring(const struct mode_key_cmdstr *cmdstr, const char *name)
557
{
558
	for (; cmdstr->name != NULL; cmdstr++) {
559
		if (strcasecmp(cmdstr->name, name) == 0)
560
			return (cmdstr->cmd);
561
	}
562
	return (MODEKEY_NONE);
563
}
564
565
const struct mode_key_table *
566
mode_key_findtable(const char *name)
567
{
568
	const struct mode_key_table	*mtab;
569
570
	for (mtab = mode_key_tables; mtab->name != NULL; mtab++) {
571
		if (strcasecmp(name, mtab->name) == 0)
572
			return (mtab);
573
	}
574
	return (NULL);
575
}
576
577
void
578
mode_key_init_trees(void)
579
{
580
	const struct mode_key_table	*mtab;
581
	const struct mode_key_entry	*ment;
582
	struct mode_key_binding		*mbind;
583
584
	for (mtab = mode_key_tables; mtab->name != NULL; mtab++) {
585
		RB_INIT(mtab->tree);
586
		for (ment = mtab->table; ment->mode != -1; ment++) {
587
			mbind = xmalloc(sizeof *mbind);
588
			mbind->key = ment->key;
589
			mbind->mode = ment->mode;
590
			mbind->cmd = ment->cmd;
591
			mbind->arg = NULL;
592
			RB_INSERT(mode_key_tree, mtab->tree, mbind);
593
		}
594
	}
595
}
596
597
void
598
mode_key_init(struct mode_key_data *mdata, struct mode_key_tree *mtree)
599
{
600
	mdata->tree = mtree;
601
	mdata->mode = 0;
602
}
603
604
enum mode_key_cmd
605
mode_key_lookup(struct mode_key_data *mdata, key_code key, const char **arg)
606
{
607
	struct mode_key_binding	*mbind, mtmp;
608
609
	mtmp.key = key;
610
	mtmp.mode = mdata->mode;
611
	if ((mbind = RB_FIND(mode_key_tree, mdata->tree, &mtmp)) == NULL) {
612
		if (mdata->mode != 0)
613
			return (MODEKEY_NONE);
614
		return (MODEKEY_OTHER);
615
	}
616
617
	switch (mbind->cmd) {
618
	case MODEKEYEDIT_SWITCHMODE:
619
	case MODEKEYEDIT_SWITCHMODEAPPEND:
620
	case MODEKEYEDIT_SWITCHMODEAPPENDLINE:
621
	case MODEKEYEDIT_SWITCHMODEBEGINLINE:
622
	case MODEKEYEDIT_SWITCHMODECHANGELINE:
623
	case MODEKEYEDIT_SWITCHMODESUBSTITUTE:
624
	case MODEKEYEDIT_SWITCHMODESUBSTITUTELINE:
625
		mdata->mode = 1 - mdata->mode;
626
		/* FALLTHROUGH */
627
	default:
628
		if (arg != NULL)
629
			*arg = mbind->arg;
630
		return (mbind->cmd);
631
	}
632
}