[BACK]Return to mode-key.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tmux

Annotation of src/usr.bin/tmux/mode-key.c, Revision 1.48

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