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