mode-key.c 25 KB

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