1 /* $Id: mode-key.c,v 1.1.1.2 2011/08/17 18:40:05 jmmv Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> 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 * (MODEKEYEDIT_SWITCHMODE and MODEKEYEDIT_SWITCHMODEAPPEND) are special-cased 39 * to do this. 40 */ 41 42 /* Edit keys command strings. */ 43 const struct mode_key_cmdstr mode_key_cmdstr_edit[] = { 44 { MODEKEYEDIT_BACKSPACE, "backspace" }, 45 { MODEKEYEDIT_CANCEL, "cancel" }, 46 { MODEKEYEDIT_COMPLETE, "complete" }, 47 { MODEKEYEDIT_CURSORLEFT, "cursor-left" }, 48 { MODEKEYEDIT_CURSORRIGHT, "cursor-right" }, 49 { MODEKEYEDIT_DELETE, "delete" }, 50 { MODEKEYEDIT_DELETELINE, "delete-line" }, 51 { MODEKEYEDIT_DELETETOENDOFLINE, "delete-end-of-line" }, 52 { MODEKEYEDIT_ENDOFLINE, "end-of-line" }, 53 { MODEKEYEDIT_ENTER, "enter" }, 54 { MODEKEYEDIT_HISTORYDOWN, "history-down" }, 55 { MODEKEYEDIT_HISTORYUP, "history-up" }, 56 { MODEKEYEDIT_PASTE, "paste" }, 57 { MODEKEYEDIT_STARTOFLINE, "start-of-line" }, 58 { MODEKEYEDIT_SWITCHMODE, "switch-mode" }, 59 { MODEKEYEDIT_SWITCHMODEAPPEND, "switch-mode-append" }, 60 { MODEKEYEDIT_TRANSPOSECHARS, "transpose-chars" }, 61 62 { 0, NULL } 63 }; 64 65 /* Choice keys command strings. */ 66 const struct mode_key_cmdstr mode_key_cmdstr_choice[] = { 67 { MODEKEYCHOICE_CANCEL, "cancel" }, 68 { MODEKEYCHOICE_CHOOSE, "choose" }, 69 { MODEKEYCHOICE_DOWN, "down" }, 70 { MODEKEYCHOICE_PAGEDOWN, "page-down" }, 71 { MODEKEYCHOICE_PAGEUP, "page-up" }, 72 { MODEKEYCHOICE_SCROLLDOWN, "scroll-down" }, 73 { MODEKEYCHOICE_SCROLLUP, "scroll-up" }, 74 { MODEKEYCHOICE_UP, "up" }, 75 76 { 0, NULL } 77 }; 78 79 /* Copy keys command strings. */ 80 const struct mode_key_cmdstr mode_key_cmdstr_copy[] = { 81 { MODEKEYCOPY_BACKTOINDENTATION, "back-to-indentation" }, 82 { MODEKEYCOPY_BOTTOMLINE, "bottom-line" }, 83 { MODEKEYCOPY_CANCEL, "cancel" }, 84 { MODEKEYCOPY_CLEARSELECTION, "clear-selection" }, 85 { MODEKEYCOPY_COPYLINE, "copy-line" }, 86 { MODEKEYCOPY_COPYENDOFLINE, "copy-end-of-line" }, 87 { MODEKEYCOPY_COPYSELECTION, "copy-selection" }, 88 { MODEKEYCOPY_DOWN, "cursor-down" }, 89 { MODEKEYCOPY_ENDOFLINE, "end-of-line" }, 90 { MODEKEYCOPY_GOTOLINE, "goto-line" }, 91 { MODEKEYCOPY_HISTORYBOTTOM, "history-bottom" }, 92 { MODEKEYCOPY_HISTORYTOP, "history-top" }, 93 { MODEKEYCOPY_JUMP, "jump-forward" }, 94 { MODEKEYCOPY_JUMPAGAIN, "jump-again" }, 95 { MODEKEYCOPY_JUMPREVERSE, "jump-reverse" }, 96 { MODEKEYCOPY_JUMPBACK, "jump-backward" }, 97 { MODEKEYCOPY_LEFT, "cursor-left" }, 98 { MODEKEYCOPY_RECTANGLETOGGLE, "rectangle-toggle" }, 99 { MODEKEYCOPY_MIDDLELINE, "middle-line" }, 100 { MODEKEYCOPY_NEXTPAGE, "page-down" }, 101 { MODEKEYCOPY_NEXTSPACE, "next-space" }, 102 { MODEKEYCOPY_NEXTSPACEEND, "next-space-end" }, 103 { MODEKEYCOPY_NEXTWORD, "next-word" }, 104 { MODEKEYCOPY_NEXTWORDEND, "next-word-end" }, 105 { MODEKEYCOPY_PREVIOUSPAGE, "page-up" }, 106 { MODEKEYCOPY_PREVIOUSSPACE, "previous-space" }, 107 { MODEKEYCOPY_PREVIOUSWORD, "previous-word" }, 108 { MODEKEYCOPY_RIGHT, "cursor-right" }, 109 { MODEKEYCOPY_SCROLLDOWN, "scroll-down" }, 110 { MODEKEYCOPY_SCROLLUP, "scroll-up" }, 111 { MODEKEYCOPY_SEARCHAGAIN, "search-again" }, 112 { MODEKEYCOPY_SEARCHDOWN, "search-forward" }, 113 { MODEKEYCOPY_SEARCHREVERSE, "search-reverse" }, 114 { MODEKEYCOPY_SEARCHUP, "search-backward" }, 115 { MODEKEYCOPY_SELECTLINE, "select-line" }, 116 { MODEKEYCOPY_STARTNUMBERPREFIX, "start-number-prefix" }, 117 { MODEKEYCOPY_STARTOFLINE, "start-of-line" }, 118 { MODEKEYCOPY_STARTSELECTION, "begin-selection" }, 119 { MODEKEYCOPY_TOPLINE, "top-line" }, 120 { MODEKEYCOPY_UP, "cursor-up" }, 121 122 { 0, NULL } 123 }; 124 125 /* vi editing keys. */ 126 const struct mode_key_entry mode_key_vi_edit[] = { 127 { '\003' /* C-c */, 0, MODEKEYEDIT_CANCEL }, 128 { '\010' /* C-h */, 0, MODEKEYEDIT_BACKSPACE }, 129 { '\025' /* C-u */, 0, MODEKEYEDIT_DELETELINE }, 130 { '\011' /* Tab */, 0, MODEKEYEDIT_COMPLETE }, 131 { '\033' /* Escape */, 0, MODEKEYEDIT_SWITCHMODE }, 132 { '\r', 0, MODEKEYEDIT_ENTER }, 133 { KEYC_BSPACE, 0, MODEKEYEDIT_BACKSPACE }, 134 { KEYC_DC, 0, MODEKEYEDIT_DELETE }, 135 136 { '$', 1, MODEKEYEDIT_ENDOFLINE }, 137 { '0', 1, MODEKEYEDIT_STARTOFLINE }, 138 { 'D', 1, MODEKEYEDIT_DELETETOENDOFLINE }, 139 { '\003' /* C-c */, 1, MODEKEYEDIT_CANCEL }, 140 { '\010' /* C-h */, 1, MODEKEYEDIT_BACKSPACE }, 141 { '\r', 1, MODEKEYEDIT_ENTER }, 142 { '^', 1, MODEKEYEDIT_STARTOFLINE }, 143 { 'a', 1, MODEKEYEDIT_SWITCHMODEAPPEND }, 144 { 'd', 1, MODEKEYEDIT_DELETELINE }, 145 { 'h', 1, MODEKEYEDIT_CURSORLEFT }, 146 { 'i', 1, MODEKEYEDIT_SWITCHMODE }, 147 { 'j', 1, MODEKEYEDIT_HISTORYDOWN }, 148 { 'k', 1, MODEKEYEDIT_HISTORYUP }, 149 { 'l', 1, MODEKEYEDIT_CURSORRIGHT }, 150 { 'p', 1, MODEKEYEDIT_PASTE }, 151 { KEYC_BSPACE, 1, MODEKEYEDIT_BACKSPACE }, 152 { KEYC_DC, 1, MODEKEYEDIT_DELETE }, 153 { KEYC_DOWN, 1, MODEKEYEDIT_HISTORYDOWN }, 154 { KEYC_LEFT, 1, MODEKEYEDIT_CURSORLEFT }, 155 { KEYC_RIGHT, 1, MODEKEYEDIT_CURSORRIGHT }, 156 { KEYC_UP, 1, MODEKEYEDIT_HISTORYUP }, 157 158 { 0, -1, 0 } 159 }; 160 struct mode_key_tree mode_key_tree_vi_edit; 161 162 /* vi choice selection keys. */ 163 const struct mode_key_entry mode_key_vi_choice[] = { 164 { '\002' /* C-b */, 0, MODEKEYCHOICE_PAGEUP }, 165 { '\003' /* C-c */, 0, MODEKEYCHOICE_CANCEL }, 166 { '\005' /* C-e */, 0, MODEKEYCHOICE_SCROLLDOWN }, 167 { '\006' /* C-f */, 0, MODEKEYCHOICE_PAGEDOWN }, 168 { '\031' /* C-y */, 0, MODEKEYCHOICE_SCROLLUP }, 169 { '\r', 0, MODEKEYCHOICE_CHOOSE }, 170 { 'j', 0, MODEKEYCHOICE_DOWN }, 171 { 'k', 0, MODEKEYCHOICE_UP }, 172 { 'q', 0, MODEKEYCHOICE_CANCEL }, 173 { KEYC_DOWN | KEYC_CTRL,0, MODEKEYCHOICE_SCROLLDOWN }, 174 { KEYC_DOWN, 0, MODEKEYCHOICE_DOWN }, 175 { KEYC_NPAGE, 0, MODEKEYCHOICE_PAGEDOWN }, 176 { KEYC_PPAGE, 0, MODEKEYCHOICE_PAGEUP }, 177 { KEYC_UP | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLUP }, 178 { KEYC_UP, 0, MODEKEYCHOICE_UP }, 179 180 { 0, -1, 0 } 181 }; 182 struct mode_key_tree mode_key_tree_vi_choice; 183 184 /* vi copy mode keys. */ 185 const struct mode_key_entry mode_key_vi_copy[] = { 186 { ' ', 0, MODEKEYCOPY_STARTSELECTION }, 187 { '$', 0, MODEKEYCOPY_ENDOFLINE }, 188 { ',', 0, MODEKEYCOPY_JUMPREVERSE }, 189 { ';', 0, MODEKEYCOPY_JUMPAGAIN }, 190 { '/', 0, MODEKEYCOPY_SEARCHDOWN }, 191 { '0', 0, MODEKEYCOPY_STARTOFLINE }, 192 { '1', 0, MODEKEYCOPY_STARTNUMBERPREFIX }, 193 { '2', 0, MODEKEYCOPY_STARTNUMBERPREFIX }, 194 { '3', 0, MODEKEYCOPY_STARTNUMBERPREFIX }, 195 { '4', 0, MODEKEYCOPY_STARTNUMBERPREFIX }, 196 { '5', 0, MODEKEYCOPY_STARTNUMBERPREFIX }, 197 { '6', 0, MODEKEYCOPY_STARTNUMBERPREFIX }, 198 { '7', 0, MODEKEYCOPY_STARTNUMBERPREFIX }, 199 { '8', 0, MODEKEYCOPY_STARTNUMBERPREFIX }, 200 { '9', 0, MODEKEYCOPY_STARTNUMBERPREFIX }, 201 { ':', 0, MODEKEYCOPY_GOTOLINE }, 202 { '?', 0, MODEKEYCOPY_SEARCHUP }, 203 { 'B', 0, MODEKEYCOPY_PREVIOUSSPACE }, 204 { 'D', 0, MODEKEYCOPY_COPYENDOFLINE }, 205 { 'E', 0, MODEKEYCOPY_NEXTSPACEEND }, 206 { 'F', 0, MODEKEYCOPY_JUMPBACK }, 207 { 'G', 0, MODEKEYCOPY_HISTORYBOTTOM }, 208 { 'H', 0, MODEKEYCOPY_TOPLINE }, 209 { 'J', 0, MODEKEYCOPY_SCROLLDOWN }, 210 { 'K', 0, MODEKEYCOPY_SCROLLUP }, 211 { 'L', 0, MODEKEYCOPY_BOTTOMLINE }, 212 { 'M', 0, MODEKEYCOPY_MIDDLELINE }, 213 { 'N', 0, MODEKEYCOPY_SEARCHREVERSE }, 214 { 'W', 0, MODEKEYCOPY_NEXTSPACE }, 215 { '\002' /* C-b */, 0, MODEKEYCOPY_PREVIOUSPAGE }, 216 { '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL }, 217 { '\004' /* C-d */, 0, MODEKEYCOPY_HALFPAGEDOWN }, 218 { '\005' /* C-e */, 0, MODEKEYCOPY_SCROLLDOWN }, 219 { '\006' /* C-f */, 0, MODEKEYCOPY_NEXTPAGE }, 220 { '\010' /* C-h */, 0, MODEKEYCOPY_LEFT }, 221 { '\025' /* C-u */, 0, MODEKEYCOPY_HALFPAGEUP }, 222 { '\031' /* C-y */, 0, MODEKEYCOPY_SCROLLUP }, 223 { '\033' /* Escape */, 0, MODEKEYCOPY_CLEARSELECTION }, 224 { '\r', 0, MODEKEYCOPY_COPYSELECTION }, 225 { '^', 0, MODEKEYCOPY_BACKTOINDENTATION }, 226 { 'b', 0, MODEKEYCOPY_PREVIOUSWORD }, 227 { 'e', 0, MODEKEYCOPY_NEXTWORDEND }, 228 { 'f', 0, MODEKEYCOPY_JUMP }, 229 { 'g', 0, MODEKEYCOPY_HISTORYTOP }, 230 { 'h', 0, MODEKEYCOPY_LEFT }, 231 { 'j', 0, MODEKEYCOPY_DOWN }, 232 { 'k', 0, MODEKEYCOPY_UP }, 233 { 'l', 0, MODEKEYCOPY_RIGHT }, 234 { 'n', 0, MODEKEYCOPY_SEARCHAGAIN }, 235 { 'q', 0, MODEKEYCOPY_CANCEL }, 236 { 'v', 0, MODEKEYCOPY_RECTANGLETOGGLE }, 237 { 'w', 0, MODEKEYCOPY_NEXTWORD }, 238 { KEYC_BSPACE, 0, MODEKEYCOPY_LEFT }, 239 { KEYC_DOWN | KEYC_CTRL,0, MODEKEYCOPY_SCROLLDOWN }, 240 { KEYC_DOWN, 0, MODEKEYCOPY_DOWN }, 241 { KEYC_LEFT, 0, MODEKEYCOPY_LEFT }, 242 { KEYC_NPAGE, 0, MODEKEYCOPY_NEXTPAGE }, 243 { KEYC_PPAGE, 0, MODEKEYCOPY_PREVIOUSPAGE }, 244 { KEYC_RIGHT, 0, MODEKEYCOPY_RIGHT }, 245 { KEYC_UP | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLUP }, 246 { KEYC_UP, 0, MODEKEYCOPY_UP }, 247 248 { 0, -1, 0 } 249 }; 250 struct mode_key_tree mode_key_tree_vi_copy; 251 252 /* emacs editing keys. */ 253 const struct mode_key_entry mode_key_emacs_edit[] = { 254 { '\001' /* C-a */, 0, MODEKEYEDIT_STARTOFLINE }, 255 { '\002' /* C-b */, 0, MODEKEYEDIT_CURSORLEFT }, 256 { '\003' /* C-c */, 0, MODEKEYEDIT_CANCEL }, 257 { '\004' /* C-d */, 0, MODEKEYEDIT_DELETE }, 258 { '\005' /* C-e */, 0, MODEKEYEDIT_ENDOFLINE }, 259 { '\006' /* C-f */, 0, MODEKEYEDIT_CURSORRIGHT }, 260 { '\010' /* C-H */, 0, MODEKEYEDIT_BACKSPACE }, 261 { '\011' /* Tab */, 0, MODEKEYEDIT_COMPLETE }, 262 { '\013' /* C-k */, 0, MODEKEYEDIT_DELETETOENDOFLINE }, 263 { '\016' /* C-n */, 0, MODEKEYEDIT_HISTORYDOWN }, 264 { '\020' /* C-p */, 0, MODEKEYEDIT_HISTORYUP }, 265 { '\024' /* C-t */, 0, MODEKEYEDIT_TRANSPOSECHARS }, 266 { '\025' /* C-u */, 0, MODEKEYEDIT_DELETELINE }, 267 { '\031' /* C-y */, 0, MODEKEYEDIT_PASTE }, 268 { '\033' /* Escape */, 0, MODEKEYEDIT_CANCEL }, 269 { '\r', 0, MODEKEYEDIT_ENTER }, 270 { 'm' | KEYC_ESCAPE, 0, MODEKEYEDIT_STARTOFLINE }, 271 { KEYC_BSPACE, 0, MODEKEYEDIT_BACKSPACE }, 272 { KEYC_DC, 0, MODEKEYEDIT_DELETE }, 273 { KEYC_DOWN, 0, MODEKEYEDIT_HISTORYDOWN }, 274 { KEYC_LEFT, 0, MODEKEYEDIT_CURSORLEFT }, 275 { KEYC_RIGHT, 0, MODEKEYEDIT_CURSORRIGHT }, 276 { KEYC_UP, 0, MODEKEYEDIT_HISTORYUP }, 277 278 { 0, -1, 0 } 279 }; 280 struct mode_key_tree mode_key_tree_emacs_edit; 281 282 /* emacs choice selection keys. */ 283 const struct mode_key_entry mode_key_emacs_choice[] = { 284 { '\003' /* C-c */, 0, MODEKEYCHOICE_CANCEL }, 285 { '\016' /* C-n */, 0, MODEKEYCHOICE_DOWN }, 286 { '\020' /* C-p */, 0, MODEKEYCHOICE_UP }, 287 { '\026' /* C-v */, 0, MODEKEYCHOICE_PAGEDOWN }, 288 { '\033' /* Escape */, 0, MODEKEYCHOICE_CANCEL }, 289 { '\r', 0, MODEKEYCHOICE_CHOOSE }, 290 { 'q', 0, MODEKEYCHOICE_CANCEL }, 291 { 'v' | KEYC_ESCAPE, 0, MODEKEYCHOICE_PAGEUP }, 292 { KEYC_DOWN | KEYC_CTRL,0, MODEKEYCHOICE_SCROLLDOWN }, 293 { KEYC_DOWN, 0, MODEKEYCHOICE_DOWN }, 294 { KEYC_NPAGE, 0, MODEKEYCHOICE_PAGEDOWN }, 295 { KEYC_PPAGE, 0, MODEKEYCHOICE_PAGEUP }, 296 { KEYC_UP | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLUP }, 297 { KEYC_UP, 0, MODEKEYCHOICE_UP }, 298 299 { 0, -1, 0 } 300 }; 301 struct mode_key_tree mode_key_tree_emacs_choice; 302 303 /* emacs copy mode keys. */ 304 const struct mode_key_entry mode_key_emacs_copy[] = { 305 { ' ', 0, MODEKEYCOPY_NEXTPAGE }, 306 { ',', 0, MODEKEYCOPY_JUMPREVERSE }, 307 { ';', 0, MODEKEYCOPY_JUMPAGAIN }, 308 { '1' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, 309 { '2' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, 310 { '3' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, 311 { '4' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, 312 { '5' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, 313 { '6' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, 314 { '7' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, 315 { '8' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, 316 { '9' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, 317 { '<' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYTOP }, 318 { '>' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYBOTTOM }, 319 { 'F', 0, MODEKEYCOPY_JUMPBACK }, 320 { 'N', 0, MODEKEYCOPY_SEARCHREVERSE }, 321 { 'R' | KEYC_ESCAPE, 0, MODEKEYCOPY_TOPLINE }, 322 { 'R', 0, MODEKEYCOPY_RECTANGLETOGGLE }, 323 { '\000' /* C-Space */, 0, MODEKEYCOPY_STARTSELECTION }, 324 { '\001' /* C-a */, 0, MODEKEYCOPY_STARTOFLINE }, 325 { '\002' /* C-b */, 0, MODEKEYCOPY_LEFT }, 326 { '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL }, 327 { '\005' /* C-e */, 0, MODEKEYCOPY_ENDOFLINE }, 328 { '\006' /* C-f */, 0, MODEKEYCOPY_RIGHT }, 329 { '\007' /* C-g */, 0, MODEKEYCOPY_CLEARSELECTION }, 330 { '\013' /* C-k */, 0, MODEKEYCOPY_COPYENDOFLINE }, 331 { '\016' /* C-n */, 0, MODEKEYCOPY_DOWN }, 332 { '\020' /* C-p */, 0, MODEKEYCOPY_UP }, 333 { '\022' /* C-r */, 0, MODEKEYCOPY_SEARCHUP }, 334 { '\023' /* C-s */, 0, MODEKEYCOPY_SEARCHDOWN }, 335 { '\026' /* C-v */, 0, MODEKEYCOPY_NEXTPAGE }, 336 { '\027' /* C-w */, 0, MODEKEYCOPY_COPYSELECTION }, 337 { '\033' /* Escape */, 0, MODEKEYCOPY_CANCEL }, 338 { 'N', 0, MODEKEYCOPY_SEARCHREVERSE }, 339 { 'b' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSWORD }, 340 { 'f', 0, MODEKEYCOPY_JUMP }, 341 { 'f' | KEYC_ESCAPE, 0, MODEKEYCOPY_NEXTWORDEND }, 342 { 'g', 0, MODEKEYCOPY_GOTOLINE }, 343 { 'm' | KEYC_ESCAPE, 0, MODEKEYCOPY_BACKTOINDENTATION }, 344 { 'n', 0, MODEKEYCOPY_SEARCHAGAIN }, 345 { 'q', 0, MODEKEYCOPY_CANCEL }, 346 { 'r' | KEYC_ESCAPE, 0, MODEKEYCOPY_MIDDLELINE }, 347 { 'v' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSPAGE }, 348 { 'w' | KEYC_ESCAPE, 0, MODEKEYCOPY_COPYSELECTION }, 349 { KEYC_DOWN | KEYC_CTRL,0, MODEKEYCOPY_SCROLLDOWN }, 350 { KEYC_DOWN | KEYC_ESCAPE, 0, MODEKEYCOPY_HALFPAGEDOWN }, 351 { KEYC_DOWN, 0, MODEKEYCOPY_DOWN }, 352 { KEYC_LEFT, 0, MODEKEYCOPY_LEFT }, 353 { KEYC_NPAGE, 0, MODEKEYCOPY_NEXTPAGE }, 354 { KEYC_PPAGE, 0, MODEKEYCOPY_PREVIOUSPAGE }, 355 { KEYC_RIGHT, 0, MODEKEYCOPY_RIGHT }, 356 { KEYC_UP | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLUP }, 357 { KEYC_UP | KEYC_ESCAPE, 0, MODEKEYCOPY_HALFPAGEUP }, 358 { KEYC_UP, 0, MODEKEYCOPY_UP }, 359 360 { 0, -1, 0 } 361 }; 362 struct mode_key_tree mode_key_tree_emacs_copy; 363 364 /* Table mapping key table names to default settings and trees. */ 365 const struct mode_key_table mode_key_tables[] = { 366 { "vi-edit", mode_key_cmdstr_edit, 367 &mode_key_tree_vi_edit, mode_key_vi_edit }, 368 { "vi-choice", mode_key_cmdstr_choice, 369 &mode_key_tree_vi_choice, mode_key_vi_choice }, 370 { "vi-copy", mode_key_cmdstr_copy, 371 &mode_key_tree_vi_copy, mode_key_vi_copy }, 372 { "emacs-edit", mode_key_cmdstr_edit, 373 &mode_key_tree_emacs_edit, mode_key_emacs_edit }, 374 { "emacs-choice", mode_key_cmdstr_choice, 375 &mode_key_tree_emacs_choice, mode_key_emacs_choice }, 376 { "emacs-copy", mode_key_cmdstr_copy, 377 &mode_key_tree_emacs_copy, mode_key_emacs_copy }, 378 379 { NULL, NULL, NULL, NULL } 380 }; 381 382 SPLAY_GENERATE(mode_key_tree, mode_key_binding, entry, mode_key_cmp); 383 384 int 385 mode_key_cmp(struct mode_key_binding *mbind1, struct mode_key_binding *mbind2) 386 { 387 if (mbind1->mode != mbind2->mode) 388 return (mbind1->mode - mbind2->mode); 389 return (mbind1->key - mbind2->key); 390 } 391 392 const char * 393 mode_key_tostring(const struct mode_key_cmdstr *cmdstr, enum mode_key_cmd cmd) 394 { 395 for (; cmdstr->name != NULL; cmdstr++) { 396 if (cmdstr->cmd == cmd) 397 return (cmdstr->name); 398 } 399 return (NULL); 400 } 401 402 enum mode_key_cmd 403 mode_key_fromstring(const struct mode_key_cmdstr *cmdstr, const char *name) 404 { 405 for (; cmdstr->name != NULL; cmdstr++) { 406 if (strcasecmp(cmdstr->name, name) == 0) 407 return (cmdstr->cmd); 408 } 409 return (MODEKEY_NONE); 410 } 411 412 const struct mode_key_table * 413 mode_key_findtable(const char *name) 414 { 415 const struct mode_key_table *mtab; 416 417 for (mtab = mode_key_tables; mtab->name != NULL; mtab++) { 418 if (strcasecmp(name, mtab->name) == 0) 419 return (mtab); 420 } 421 return (NULL); 422 } 423 424 void 425 mode_key_init_trees(void) 426 { 427 const struct mode_key_table *mtab; 428 const struct mode_key_entry *ment; 429 struct mode_key_binding *mbind; 430 431 for (mtab = mode_key_tables; mtab->name != NULL; mtab++) { 432 SPLAY_INIT(mtab->tree); 433 for (ment = mtab->table; ment->mode != -1; ment++) { 434 mbind = xmalloc(sizeof *mbind); 435 mbind->key = ment->key; 436 mbind->mode = ment->mode; 437 mbind->cmd = ment->cmd; 438 SPLAY_INSERT(mode_key_tree, mtab->tree, mbind); 439 } 440 } 441 } 442 443 void 444 mode_key_init(struct mode_key_data *mdata, struct mode_key_tree *mtree) 445 { 446 mdata->tree = mtree; 447 mdata->mode = 0; 448 } 449 450 enum mode_key_cmd 451 mode_key_lookup(struct mode_key_data *mdata, int key) 452 { 453 struct mode_key_binding *mbind, mtmp; 454 455 mtmp.key = key; 456 mtmp.mode = mdata->mode; 457 if ((mbind = SPLAY_FIND(mode_key_tree, mdata->tree, &mtmp)) == NULL) { 458 if (mdata->mode != 0) 459 return (MODEKEY_NONE); 460 return (MODEKEY_OTHER); 461 } 462 463 switch (mbind->cmd) { 464 case MODEKEYEDIT_SWITCHMODE: 465 case MODEKEYEDIT_SWITCHMODEAPPEND: 466 mdata->mode = 1 - mdata->mode; 467 /* FALLTHROUGH */ 468 default: 469 return (mbind->cmd); 470 } 471 } 472