[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.47

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