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

1.71    ! nicm        1: /* $OpenBSD: mode-key.c,v 1.70 2016/10/10 21:29:23 nicm Exp $ */
1.1       nicm        2:
                      3: /*
1.65      nicm        4:  * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
1.1       nicm        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.53      nicm       38:  * (any matching MODEKEYEDIT_SWITCHMODE*) are special-cased to do this.
1.10      nicm       39:  */
1.63      nicm       40:
                     41: /* Entry in the default mode key tables. */
                     42: struct mode_key_entry {
1.64      nicm       43:        key_code                key;
1.63      nicm       44:
                     45:        /*
                     46:         * Editing mode for vi: 0 is edit mode, keys not in the table are
                     47:         * returned as MODEKEY_OTHER; 1 is command mode, keys not in the table
                     48:         * are returned as MODEKEY_NONE. This is also matched on, allowing some
                     49:         * keys to be bound in edit mode.
                     50:         */
                     51:        int                     mode;
                     52:        enum mode_key_cmd       cmd;
                     53: };
1.10      nicm       54:
                     55: /* Edit keys command strings. */
1.70      nicm       56: static const struct mode_key_cmdstr mode_key_cmdstr_edit[] = {
1.10      nicm       57:        { MODEKEYEDIT_BACKSPACE, "backspace" },
1.25      nicm       58:        { MODEKEYEDIT_CANCEL, "cancel" },
1.10      nicm       59:        { MODEKEYEDIT_COMPLETE, "complete" },
                     60:        { MODEKEYEDIT_CURSORLEFT, "cursor-left" },
                     61:        { MODEKEYEDIT_CURSORRIGHT, "cursor-right" },
                     62:        { MODEKEYEDIT_DELETE, "delete" },
1.16      nicm       63:        { MODEKEYEDIT_DELETELINE, "delete-line" },
1.10      nicm       64:        { MODEKEYEDIT_DELETETOENDOFLINE, "delete-end-of-line" },
1.40      nicm       65:        { MODEKEYEDIT_DELETEWORD, "delete-word" },
1.10      nicm       66:        { MODEKEYEDIT_ENDOFLINE, "end-of-line" },
                     67:        { MODEKEYEDIT_ENTER, "enter" },
                     68:        { MODEKEYEDIT_HISTORYDOWN, "history-down" },
                     69:        { MODEKEYEDIT_HISTORYUP, "history-up" },
1.43      nicm       70:        { MODEKEYEDIT_NEXTSPACE, "next-space" },
                     71:        { MODEKEYEDIT_NEXTSPACEEND, "next-space-end" },
1.40      nicm       72:        { MODEKEYEDIT_NEXTWORD, "next-word" },
                     73:        { MODEKEYEDIT_NEXTWORDEND, "next-word-end" },
1.10      nicm       74:        { MODEKEYEDIT_PASTE, "paste" },
1.43      nicm       75:        { MODEKEYEDIT_PREVIOUSSPACE, "previous-space" },
1.40      nicm       76:        { MODEKEYEDIT_PREVIOUSWORD, "previous-word" },
1.10      nicm       77:        { MODEKEYEDIT_STARTOFLINE, "start-of-line" },
                     78:        { MODEKEYEDIT_SWITCHMODE, "switch-mode" },
                     79:        { MODEKEYEDIT_SWITCHMODEAPPEND, "switch-mode-append" },
1.45      nicm       80:        { MODEKEYEDIT_SWITCHMODEAPPENDLINE, "switch-mode-append-line" },
                     81:        { MODEKEYEDIT_SWITCHMODEBEGINLINE, "switch-mode-begin-line" },
1.53      nicm       82:        { MODEKEYEDIT_SWITCHMODECHANGELINE, "switch-mode-change-line" },
                     83:        { MODEKEYEDIT_SWITCHMODESUBSTITUTE, "switch-mode-substitute" },
                     84:        { MODEKEYEDIT_SWITCHMODESUBSTITUTELINE, "switch-mode-substitute-line" },
1.17      nicm       85:        { MODEKEYEDIT_TRANSPOSECHARS, "transpose-chars" },
1.11      nicm       86:
                     87:        { 0, NULL }
1.10      nicm       88: };
1.25      nicm       89:
1.10      nicm       90: /* Choice keys command strings. */
1.70      nicm       91: static const struct mode_key_cmdstr mode_key_cmdstr_choice[] = {
1.46      nicm       92:        { MODEKEYCHOICE_BACKSPACE, "backspace" },
1.57      nicm       93:        { MODEKEYCHOICE_BOTTOMLINE, "bottom-line"},
1.10      nicm       94:        { MODEKEYCHOICE_CANCEL, "cancel" },
                     95:        { MODEKEYCHOICE_CHOOSE, "choose" },
                     96:        { MODEKEYCHOICE_DOWN, "down" },
1.57      nicm       97:        { MODEKEYCHOICE_ENDOFLIST, "end-of-list"},
1.10      nicm       98:        { MODEKEYCHOICE_PAGEDOWN, "page-down" },
                     99:        { MODEKEYCHOICE_PAGEUP, "page-up" },
1.30      nicm      100:        { MODEKEYCHOICE_SCROLLDOWN, "scroll-down" },
                    101:        { MODEKEYCHOICE_SCROLLUP, "scroll-up" },
1.46      nicm      102:        { MODEKEYCHOICE_STARTNUMBERPREFIX, "start-number-prefix" },
1.57      nicm      103:        { MODEKEYCHOICE_STARTOFLIST, "start-of-list"},
                    104:        { MODEKEYCHOICE_TOPLINE, "top-line"},
1.49      nicm      105:        { MODEKEYCHOICE_TREE_COLLAPSE, "tree-collapse" },
1.48      nicm      106:        { MODEKEYCHOICE_TREE_COLLAPSE_ALL, "tree-collapse-all" },
1.49      nicm      107:        { MODEKEYCHOICE_TREE_EXPAND, "tree-expand" },
1.48      nicm      108:        { MODEKEYCHOICE_TREE_EXPAND_ALL, "tree-expand-all" },
                    109:        { MODEKEYCHOICE_TREE_TOGGLE, "tree-toggle" },
1.10      nicm      110:        { MODEKEYCHOICE_UP, "up" },
1.11      nicm      111:
                    112:        { 0, NULL }
1.10      nicm      113: };
                    114:
1.8       nicm      115: /* vi editing keys. */
1.70      nicm      116: static const struct mode_key_entry mode_key_vi_edit[] = {
1.71    ! nicm      117:        { '\003' /* C-c */,         0, MODEKEYEDIT_CANCEL },
        !           118:        { '\010' /* C-h */,         0, MODEKEYEDIT_BACKSPACE },
        !           119:        { '\011' /* Tab */,         0, MODEKEYEDIT_COMPLETE },
        !           120:        { '\025' /* C-u */,         0, MODEKEYEDIT_DELETELINE },
        !           121:        { '\027' /* C-w */,         0, MODEKEYEDIT_DELETEWORD },
        !           122:        { '\033' /* Escape */,      0, MODEKEYEDIT_SWITCHMODE },
        !           123:        { '\n',                     0, MODEKEYEDIT_ENTER },
        !           124:        { '\r',                     0, MODEKEYEDIT_ENTER },
        !           125:        { KEYC_BSPACE,              0, MODEKEYEDIT_BACKSPACE },
        !           126:        { KEYC_DC,                  0, MODEKEYEDIT_DELETE },
        !           127:        { KEYC_DOWN,                0, MODEKEYEDIT_HISTORYDOWN },
        !           128:        { KEYC_LEFT,                0, MODEKEYEDIT_CURSORLEFT },
        !           129:        { KEYC_RIGHT,               0, MODEKEYEDIT_CURSORRIGHT },
        !           130:        { KEYC_UP,                  0, MODEKEYEDIT_HISTORYUP },
        !           131:        { KEYC_HOME,                0, MODEKEYEDIT_STARTOFLINE },
        !           132:        { KEYC_END,                 0, MODEKEYEDIT_ENDOFLINE },
        !           133:
        !           134:        { '$',                      1, MODEKEYEDIT_ENDOFLINE },
        !           135:        { '0',                      1, MODEKEYEDIT_STARTOFLINE },
        !           136:        { 'A',                      1, MODEKEYEDIT_SWITCHMODEAPPENDLINE },
        !           137:        { 'B',                      1, MODEKEYEDIT_PREVIOUSSPACE },
        !           138:        { 'C',                      1, MODEKEYEDIT_SWITCHMODECHANGELINE },
        !           139:        { 'D',                      1, MODEKEYEDIT_DELETETOENDOFLINE },
        !           140:        { 'E',                      1, MODEKEYEDIT_NEXTSPACEEND },
        !           141:        { 'I',                      1, MODEKEYEDIT_SWITCHMODEBEGINLINE },
        !           142:        { 'S',                      1, MODEKEYEDIT_SWITCHMODESUBSTITUTELINE },
        !           143:        { 'W',                      1, MODEKEYEDIT_NEXTSPACE },
        !           144:        { 'X',                      1, MODEKEYEDIT_BACKSPACE },
        !           145:        { '\003' /* C-c */,         1, MODEKEYEDIT_CANCEL },
        !           146:        { '\010' /* C-h */,         1, MODEKEYEDIT_BACKSPACE },
        !           147:        { '\n',                     1, MODEKEYEDIT_ENTER },
        !           148:        { '\r',                     1, MODEKEYEDIT_ENTER },
        !           149:        { '^',                      1, MODEKEYEDIT_STARTOFLINE },
        !           150:        { 'a',                      1, MODEKEYEDIT_SWITCHMODEAPPEND },
        !           151:        { 'b',                      1, MODEKEYEDIT_PREVIOUSWORD },
        !           152:        { 'd',                      1, MODEKEYEDIT_DELETELINE },
        !           153:        { 'e',                      1, MODEKEYEDIT_NEXTWORDEND },
        !           154:        { 'h',                      1, MODEKEYEDIT_CURSORLEFT },
        !           155:        { 'i',                      1, MODEKEYEDIT_SWITCHMODE },
        !           156:        { 'j',                      1, MODEKEYEDIT_HISTORYDOWN },
        !           157:        { 'k',                      1, MODEKEYEDIT_HISTORYUP },
        !           158:        { 'l',                      1, MODEKEYEDIT_CURSORRIGHT },
        !           159:        { 'p',                      1, MODEKEYEDIT_PASTE },
        !           160:        { 's',                      1, MODEKEYEDIT_SWITCHMODESUBSTITUTE },
        !           161:        { 'w',                      1, MODEKEYEDIT_NEXTWORD },
        !           162:        { 'x',                      1, MODEKEYEDIT_DELETE },
        !           163:        { KEYC_BSPACE,              1, MODEKEYEDIT_BACKSPACE },
        !           164:        { KEYC_DC,                  1, MODEKEYEDIT_DELETE },
        !           165:        { KEYC_DOWN,                1, MODEKEYEDIT_HISTORYDOWN },
        !           166:        { KEYC_LEFT,                1, MODEKEYEDIT_CURSORLEFT },
        !           167:        { KEYC_RIGHT,               1, MODEKEYEDIT_CURSORRIGHT },
        !           168:        { KEYC_UP,                  1, MODEKEYEDIT_HISTORYUP },
1.8       nicm      169:
1.71    ! nicm      170:        { 0,                       -1, 0 }
1.8       nicm      171: };
1.10      nicm      172: struct mode_key_tree mode_key_tree_vi_edit;
1.8       nicm      173:
                    174: /* vi choice selection keys. */
1.70      nicm      175: static const struct mode_key_entry mode_key_vi_choice[] = {
1.71    ! nicm      176:        { '0' | KEYC_ESCAPE,        0, MODEKEYCHOICE_STARTNUMBERPREFIX },
        !           177:        { '1' | KEYC_ESCAPE,        0, MODEKEYCHOICE_STARTNUMBERPREFIX },
        !           178:        { '2' | KEYC_ESCAPE,        0, MODEKEYCHOICE_STARTNUMBERPREFIX },
        !           179:        { '3' | KEYC_ESCAPE,        0, MODEKEYCHOICE_STARTNUMBERPREFIX },
        !           180:        { '4' | KEYC_ESCAPE,        0, MODEKEYCHOICE_STARTNUMBERPREFIX },
        !           181:        { '5' | KEYC_ESCAPE,        0, MODEKEYCHOICE_STARTNUMBERPREFIX },
        !           182:        { '6' | KEYC_ESCAPE,        0, MODEKEYCHOICE_STARTNUMBERPREFIX },
        !           183:        { '7' | KEYC_ESCAPE,        0, MODEKEYCHOICE_STARTNUMBERPREFIX },
        !           184:        { '8' | KEYC_ESCAPE,        0, MODEKEYCHOICE_STARTNUMBERPREFIX },
        !           185:        { '9' | KEYC_ESCAPE,        0, MODEKEYCHOICE_STARTNUMBERPREFIX },
        !           186:        { '\002' /* C-b */,         0, MODEKEYCHOICE_PAGEUP },
        !           187:        { '\003' /* C-c */,         0, MODEKEYCHOICE_CANCEL },
        !           188:        { '\005' /* C-e */,         0, MODEKEYCHOICE_SCROLLDOWN },
        !           189:        { '\006' /* C-f */,         0, MODEKEYCHOICE_PAGEDOWN },
        !           190:        { '\031' /* C-y */,         0, MODEKEYCHOICE_SCROLLUP },
        !           191:        { '\n',                     0, MODEKEYCHOICE_CHOOSE },
        !           192:        { '\r',                     0, MODEKEYCHOICE_CHOOSE },
        !           193:        { 'j',                      0, MODEKEYCHOICE_DOWN },
        !           194:        { 'k',                      0, MODEKEYCHOICE_UP },
        !           195:        { 'q',                      0, MODEKEYCHOICE_CANCEL },
        !           196:        { KEYC_HOME,                0, MODEKEYCHOICE_STARTOFLIST },
        !           197:        { 'g',                      0, MODEKEYCHOICE_STARTOFLIST },
        !           198:        { 'H',                      0, MODEKEYCHOICE_TOPLINE },
        !           199:        { 'L',                      0, MODEKEYCHOICE_BOTTOMLINE },
        !           200:        { 'G',                      0, MODEKEYCHOICE_ENDOFLIST },
        !           201:        { KEYC_END,                 0, MODEKEYCHOICE_ENDOFLIST },
        !           202:        { KEYC_BSPACE,              0, MODEKEYCHOICE_BACKSPACE },
        !           203:        { KEYC_DOWN | KEYC_CTRL,    0, MODEKEYCHOICE_SCROLLDOWN },
        !           204:        { KEYC_DOWN,                0, MODEKEYCHOICE_DOWN },
        !           205:        { KEYC_NPAGE,               0, MODEKEYCHOICE_PAGEDOWN },
        !           206:        { KEYC_PPAGE,               0, MODEKEYCHOICE_PAGEUP },
        !           207:        { KEYC_UP | KEYC_CTRL,      0, MODEKEYCHOICE_SCROLLUP },
        !           208:        { KEYC_UP,                  0, MODEKEYCHOICE_UP },
        !           209:        { ' ',                      0, MODEKEYCHOICE_TREE_TOGGLE },
        !           210:        { KEYC_LEFT,                0, MODEKEYCHOICE_TREE_COLLAPSE },
        !           211:        { KEYC_RIGHT,               0, MODEKEYCHOICE_TREE_EXPAND },
        !           212:        { KEYC_LEFT | KEYC_CTRL,    0, MODEKEYCHOICE_TREE_COLLAPSE_ALL },
        !           213:        { KEYC_RIGHT | KEYC_CTRL,   0, MODEKEYCHOICE_TREE_EXPAND_ALL },
        !           214:        { KEYC_MOUSEDOWN1_PANE,     0, MODEKEYCHOICE_CHOOSE },
        !           215:        { KEYC_MOUSEDOWN3_PANE,     0, MODEKEYCHOICE_TREE_TOGGLE },
        !           216:        { KEYC_WHEELUP_PANE,        0, MODEKEYCHOICE_UP },
        !           217:        { KEYC_WHEELDOWN_PANE,      0, MODEKEYCHOICE_DOWN },
1.8       nicm      218:
1.71    ! nicm      219:        { 0,                       -1, 0 }
1.8       nicm      220: };
1.10      nicm      221: struct mode_key_tree mode_key_tree_vi_choice;
1.8       nicm      222:
                    223: /* emacs editing keys. */
1.70      nicm      224: static const struct mode_key_entry mode_key_emacs_edit[] = {
1.71    ! nicm      225:        { '\001' /* C-a */,         0, MODEKEYEDIT_STARTOFLINE },
        !           226:        { '\002' /* C-b */,         0, MODEKEYEDIT_CURSORLEFT },
        !           227:        { '\003' /* C-c */,         0, MODEKEYEDIT_CANCEL },
        !           228:        { '\004' /* C-d */,         0, MODEKEYEDIT_DELETE },
        !           229:        { '\005' /* C-e */,         0, MODEKEYEDIT_ENDOFLINE },
        !           230:        { '\006' /* C-f */,         0, MODEKEYEDIT_CURSORRIGHT },
        !           231:        { '\010' /* C-H */,         0, MODEKEYEDIT_BACKSPACE },
        !           232:        { '\011' /* Tab */,         0, MODEKEYEDIT_COMPLETE },
        !           233:        { '\013' /* C-k */,         0, MODEKEYEDIT_DELETETOENDOFLINE },
        !           234:        { '\016' /* C-n */,         0, MODEKEYEDIT_HISTORYDOWN },
        !           235:        { '\020' /* C-p */,         0, MODEKEYEDIT_HISTORYUP },
        !           236:        { '\024' /* C-t */,         0, MODEKEYEDIT_TRANSPOSECHARS },
        !           237:        { '\025' /* C-u */,         0, MODEKEYEDIT_DELETELINE },
        !           238:        { '\027' /* C-w */,         0, MODEKEYEDIT_DELETEWORD },
        !           239:        { '\031' /* C-y */,         0, MODEKEYEDIT_PASTE },
        !           240:        { '\033' /* Escape */,      0, MODEKEYEDIT_CANCEL },
        !           241:        { '\n',                     0, MODEKEYEDIT_ENTER },
        !           242:        { '\r',                     0, MODEKEYEDIT_ENTER },
        !           243:        { 'b' | KEYC_ESCAPE,        0, MODEKEYEDIT_PREVIOUSWORD },
        !           244:        { 'f' | KEYC_ESCAPE,        0, MODEKEYEDIT_NEXTWORDEND },
        !           245:        { 'm' | KEYC_ESCAPE,        0, MODEKEYEDIT_STARTOFLINE },
        !           246:        { KEYC_BSPACE,              0, MODEKEYEDIT_BACKSPACE },
        !           247:        { KEYC_DC,                  0, MODEKEYEDIT_DELETE },
        !           248:        { KEYC_DOWN,                0, MODEKEYEDIT_HISTORYDOWN },
        !           249:        { KEYC_LEFT,                0, MODEKEYEDIT_CURSORLEFT },
        !           250:        { KEYC_RIGHT,               0, MODEKEYEDIT_CURSORRIGHT },
        !           251:        { KEYC_UP,                  0, MODEKEYEDIT_HISTORYUP },
        !           252:        { KEYC_HOME,                0, MODEKEYEDIT_STARTOFLINE },
        !           253:        { KEYC_END,                 0, MODEKEYEDIT_ENDOFLINE },
1.8       nicm      254:
1.71    ! nicm      255:        { 0,                       -1, 0 }
1.8       nicm      256: };
1.10      nicm      257: struct mode_key_tree mode_key_tree_emacs_edit;
1.8       nicm      258:
                    259: /* emacs choice selection keys. */
1.70      nicm      260: static const struct mode_key_entry mode_key_emacs_choice[] = {
1.71    ! nicm      261:        { '0' | KEYC_ESCAPE,        0, MODEKEYCHOICE_STARTNUMBERPREFIX },
        !           262:        { '1' | KEYC_ESCAPE,        0, MODEKEYCHOICE_STARTNUMBERPREFIX },
        !           263:        { '2' | KEYC_ESCAPE,        0, MODEKEYCHOICE_STARTNUMBERPREFIX },
        !           264:        { '3' | KEYC_ESCAPE,        0, MODEKEYCHOICE_STARTNUMBERPREFIX },
        !           265:        { '4' | KEYC_ESCAPE,        0, MODEKEYCHOICE_STARTNUMBERPREFIX },
        !           266:        { '5' | KEYC_ESCAPE,        0, MODEKEYCHOICE_STARTNUMBERPREFIX },
        !           267:        { '6' | KEYC_ESCAPE,        0, MODEKEYCHOICE_STARTNUMBERPREFIX },
        !           268:        { '7' | KEYC_ESCAPE,        0, MODEKEYCHOICE_STARTNUMBERPREFIX },
        !           269:        { '8' | KEYC_ESCAPE,        0, MODEKEYCHOICE_STARTNUMBERPREFIX },
        !           270:        { '9' | KEYC_ESCAPE,        0, MODEKEYCHOICE_STARTNUMBERPREFIX },
        !           271:        { '\003' /* C-c */,         0, MODEKEYCHOICE_CANCEL },
        !           272:        { '\016' /* C-n */,         0, MODEKEYCHOICE_DOWN },
        !           273:        { '\020' /* C-p */,         0, MODEKEYCHOICE_UP },
        !           274:        { '\026' /* C-v */,         0, MODEKEYCHOICE_PAGEDOWN },
        !           275:        { '\033' /* Escape */,      0, MODEKEYCHOICE_CANCEL },
        !           276:        { '\n',                     0, MODEKEYCHOICE_CHOOSE },
        !           277:        { '\r',                     0, MODEKEYCHOICE_CHOOSE },
        !           278:        { 'q',                      0, MODEKEYCHOICE_CANCEL },
        !           279:        { 'v' | KEYC_ESCAPE,        0, MODEKEYCHOICE_PAGEUP },
        !           280:        { KEYC_HOME,                0, MODEKEYCHOICE_STARTOFLIST },
        !           281:        { '<' | KEYC_ESCAPE,        0, MODEKEYCHOICE_STARTOFLIST },
        !           282:        { 'R' | KEYC_ESCAPE,        0, MODEKEYCHOICE_TOPLINE },
        !           283:        { '>' | KEYC_ESCAPE,        0, MODEKEYCHOICE_ENDOFLIST },
        !           284:        { KEYC_END,                 0, MODEKEYCHOICE_ENDOFLIST },
        !           285:        { KEYC_BSPACE,              0, MODEKEYCHOICE_BACKSPACE },
        !           286:        { KEYC_DOWN | KEYC_CTRL,    0, MODEKEYCHOICE_SCROLLDOWN },
        !           287:        { KEYC_DOWN,                0, MODEKEYCHOICE_DOWN },
        !           288:        { KEYC_NPAGE,               0, MODEKEYCHOICE_PAGEDOWN },
        !           289:        { KEYC_PPAGE,               0, MODEKEYCHOICE_PAGEUP },
        !           290:        { KEYC_UP | KEYC_CTRL,      0, MODEKEYCHOICE_SCROLLUP },
        !           291:        { KEYC_UP,                  0, MODEKEYCHOICE_UP },
        !           292:        { ' ',                      0, MODEKEYCHOICE_TREE_TOGGLE },
        !           293:        { KEYC_LEFT,                0, MODEKEYCHOICE_TREE_COLLAPSE },
        !           294:        { KEYC_RIGHT,               0, MODEKEYCHOICE_TREE_EXPAND },
        !           295:        { KEYC_LEFT | KEYC_CTRL,    0, MODEKEYCHOICE_TREE_COLLAPSE_ALL },
        !           296:        { KEYC_RIGHT | KEYC_CTRL,   0, MODEKEYCHOICE_TREE_EXPAND_ALL },
        !           297:        { KEYC_MOUSEDOWN1_PANE,     0, MODEKEYCHOICE_CHOOSE },
        !           298:        { KEYC_MOUSEDOWN3_PANE,     0, MODEKEYCHOICE_TREE_TOGGLE },
        !           299:        { KEYC_WHEELUP_PANE,        0, MODEKEYCHOICE_UP },
        !           300:        { KEYC_WHEELDOWN_PANE,      0, MODEKEYCHOICE_DOWN },
1.8       nicm      301:
1.71    ! nicm      302:        { 0,                       -1, 0 }
1.8       nicm      303: };
1.10      nicm      304: struct mode_key_tree mode_key_tree_emacs_choice;
1.8       nicm      305:
1.10      nicm      306: /* Table mapping key table names to default settings and trees. */
                    307: const struct mode_key_table mode_key_tables[] = {
                    308:        { "vi-edit", mode_key_cmdstr_edit,
                    309:          &mode_key_tree_vi_edit, mode_key_vi_edit },
                    310:        { "vi-choice", mode_key_cmdstr_choice,
                    311:          &mode_key_tree_vi_choice, mode_key_vi_choice },
                    312:        { "emacs-edit", mode_key_cmdstr_edit,
                    313:          &mode_key_tree_emacs_edit, mode_key_emacs_edit },
                    314:        { "emacs-choice", mode_key_cmdstr_choice,
                    315:          &mode_key_tree_emacs_choice, mode_key_emacs_choice },
                    316:
                    317:        { NULL, NULL, NULL, NULL }
                    318: };
                    319:
1.44      nicm      320: RB_GENERATE(mode_key_tree, mode_key_binding, entry, mode_key_cmp);
1.10      nicm      321:
                    322: int
                    323: mode_key_cmp(struct mode_key_binding *mbind1, struct mode_key_binding *mbind2)
                    324: {
1.64      nicm      325:        if (mbind1->mode < mbind2->mode)
                    326:                return (-1);
                    327:        if (mbind1->mode > mbind2->mode)
                    328:                return (1);
                    329:        if (mbind1->key < mbind2->key)
                    330:                return (-1);
                    331:        if (mbind1->key > mbind2->key)
                    332:                return (1);
                    333:        return (0);
1.10      nicm      334: }
                    335:
                    336: const char *
1.36      nicm      337: mode_key_tostring(const struct mode_key_cmdstr *cmdstr, enum mode_key_cmd cmd)
1.10      nicm      338: {
                    339:        for (; cmdstr->name != NULL; cmdstr++) {
                    340:                if (cmdstr->cmd == cmd)
                    341:                        return (cmdstr->name);
1.11      nicm      342:        }
                    343:        return (NULL);
                    344: }
                    345:
                    346: enum mode_key_cmd
1.36      nicm      347: mode_key_fromstring(const struct mode_key_cmdstr *cmdstr, const char *name)
1.11      nicm      348: {
                    349:        for (; cmdstr->name != NULL; cmdstr++) {
                    350:                if (strcasecmp(cmdstr->name, name) == 0)
                    351:                        return (cmdstr->cmd);
                    352:        }
                    353:        return (MODEKEY_NONE);
                    354: }
                    355:
                    356: const struct mode_key_table *
                    357: mode_key_findtable(const char *name)
                    358: {
                    359:        const struct mode_key_table     *mtab;
1.25      nicm      360:
1.11      nicm      361:        for (mtab = mode_key_tables; mtab->name != NULL; mtab++) {
                    362:                if (strcasecmp(name, mtab->name) == 0)
                    363:                        return (mtab);
1.10      nicm      364:        }
                    365:        return (NULL);
                    366: }
1.1       nicm      367:
                    368: void
1.10      nicm      369: mode_key_init_trees(void)
1.1       nicm      370: {
1.10      nicm      371:        const struct mode_key_table     *mtab;
                    372:        const struct mode_key_entry     *ment;
                    373:        struct mode_key_binding         *mbind;
                    374:
                    375:        for (mtab = mode_key_tables; mtab->name != NULL; mtab++) {
1.44      nicm      376:                RB_INIT(mtab->tree);
1.10      nicm      377:                for (ment = mtab->table; ment->mode != -1; ment++) {
                    378:                        mbind = xmalloc(sizeof *mbind);
                    379:                        mbind->key = ment->key;
                    380:                        mbind->mode = ment->mode;
                    381:                        mbind->cmd = ment->cmd;
1.44      nicm      382:                        RB_INSERT(mode_key_tree, mtab->tree, mbind);
1.10      nicm      383:                }
                    384:        }
                    385: }
                    386:
                    387: void
                    388: mode_key_init(struct mode_key_data *mdata, struct mode_key_tree *mtree)
                    389: {
                    390:        mdata->tree = mtree;
1.8       nicm      391:        mdata->mode = 0;
1.1       nicm      392: }
                    393:
                    394: enum mode_key_cmd
1.71    ! nicm      395: mode_key_lookup(struct mode_key_data *mdata, key_code key)
1.1       nicm      396: {
1.10      nicm      397:        struct mode_key_binding *mbind, mtmp;
                    398:
                    399:        mtmp.key = key;
                    400:        mtmp.mode = mdata->mode;
1.44      nicm      401:        if ((mbind = RB_FIND(mode_key_tree, mdata->tree, &mtmp)) == NULL) {
1.10      nicm      402:                if (mdata->mode != 0)
                    403:                        return (MODEKEY_NONE);
                    404:                return (MODEKEY_OTHER);
                    405:        }
1.1       nicm      406:
1.10      nicm      407:        switch (mbind->cmd) {
                    408:        case MODEKEYEDIT_SWITCHMODE:
                    409:        case MODEKEYEDIT_SWITCHMODEAPPEND:
1.45      nicm      410:        case MODEKEYEDIT_SWITCHMODEAPPENDLINE:
                    411:        case MODEKEYEDIT_SWITCHMODEBEGINLINE:
1.53      nicm      412:        case MODEKEYEDIT_SWITCHMODECHANGELINE:
                    413:        case MODEKEYEDIT_SWITCHMODESUBSTITUTE:
                    414:        case MODEKEYEDIT_SWITCHMODESUBSTITUTELINE:
1.10      nicm      415:                mdata->mode = 1 - mdata->mode;
                    416:                /* FALLTHROUGH */
                    417:        default:
                    418:                return (mbind->cmd);
1.1       nicm      419:        }
                    420: }