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

1.9       nicm        1: /* $OpenBSD: mode-key.c,v 1.8 2009/07/27 19:29:35 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:
                     21: #include "tmux.h"
                     22:
1.10    ! nicm       23: /*
        !            24:  * Mode keys. These are the key bindings used when editing (status prompt), and
        !            25:  * in the modes. They are split into two sets of three tables, one set of three
        !            26:  * for vi and the other for emacs key bindings. The three tables are for
        !            27:  * editing, for menu-like modes (choice, more), and for copy modes (copy,
        !            28:  * scroll).
        !            29:  *
        !            30:  * The fixed tables of struct mode_key_entry below are the defaults: they are
        !            31:  * built into a tree of struct mode_key_binding by mode_key_init_trees, which
        !            32:  * can then be modified.
        !            33:  *
        !            34:  * vi command mode is handled by having a mode flag in the struct which allows
        !            35:  * two sets of bindings to be swapped between. A couple of editing commands
        !            36:  * (MODEKEYEDIT_SWITCHMODE and MODEKEYEDIT_SWITCHMODEAPPEND) are special-cased
        !            37:  * to do this.
        !            38:  */
        !            39:
        !            40: /* Edit keys command strings. */
        !            41: struct mode_key_cmdstr mode_key_cmdstr_edit[] = {
        !            42:        { MODEKEYEDIT_BACKSPACE, "backspace" },
        !            43:        { MODEKEYEDIT_CANCEL, "cancel" },
        !            44:        { MODEKEYEDIT_COMPLETE, "complete" },
        !            45:        { MODEKEYEDIT_CURSORLEFT, "cursor-left" },
        !            46:        { MODEKEYEDIT_CURSORRIGHT, "cursor-right" },
        !            47:        { MODEKEYEDIT_DELETE, "delete" },
        !            48:        { MODEKEYEDIT_DELETETOENDOFLINE, "delete-end-of-line" },
        !            49:        { MODEKEYEDIT_ENDOFLINE, "end-of-line" },
        !            50:        { MODEKEYEDIT_ENTER, "enter" },
        !            51:        { MODEKEYEDIT_HISTORYDOWN, "history-down" },
        !            52:        { MODEKEYEDIT_HISTORYUP, "history-up" },
        !            53:        { MODEKEYEDIT_PASTE, "paste" },
        !            54:        { MODEKEYEDIT_STARTOFLINE, "start-of-line" },
        !            55:        { MODEKEYEDIT_SWITCHMODE, "switch-mode" },
        !            56:        { MODEKEYEDIT_SWITCHMODEAPPEND, "switch-mode-append" },
        !            57: };
        !            58:
        !            59: /* Choice keys command strings. */
        !            60: struct mode_key_cmdstr mode_key_cmdstr_choice[] = {
        !            61:        { MODEKEYCHOICE_CANCEL, "cancel" },
        !            62:        { MODEKEYCHOICE_CHOOSE, "choose" },
        !            63:        { MODEKEYCHOICE_DOWN, "down" },
        !            64:        { MODEKEYCHOICE_PAGEDOWN, "page-down" },
        !            65:        { MODEKEYCHOICE_PAGEUP, "page-up" },
        !            66:        { MODEKEYCHOICE_UP, "up" },
        !            67: };
        !            68:
        !            69: /* Copy keys command strings. */
        !            70: struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
        !            71:        { MODEKEYCOPY_CANCEL, "cancel" },
        !            72:        { MODEKEYCOPY_BACKTOINDENTATION, "back-to-indentation" },
        !            73:        { MODEKEYCOPY_CLEARSELECTION, "clear-selection" },
        !            74:        { MODEKEYCOPY_COPYSELECTION, "copy-selection" },
        !            75:        { MODEKEYCOPY_DOWN, "cursor-down" },
        !            76:        { MODEKEYCOPY_ENDOFLINE, "end-of-line" },
        !            77:        { MODEKEYCOPY_LEFT, "cursor-left" },
        !            78:        { MODEKEYCOPY_NEXTPAGE, "page-down" },
        !            79:        { MODEKEYCOPY_NEXTWORD, "next-word" },
        !            80:        { MODEKEYCOPY_PREVIOUSPAGE, "page-up" },
        !            81:        { MODEKEYCOPY_PREVIOUSWORD, "previous-word" },
        !            82:        { MODEKEYCOPY_RIGHT, "cursor-right" },
        !            83:        { MODEKEYCOPY_STARTOFLINE, "start-of-line" },
        !            84:        { MODEKEYCOPY_STARTSELECTION, "begin-selection" },
        !            85:        { MODEKEYCOPY_UP, "cursor-up" },
        !            86: };
        !            87:
1.8       nicm       88: /* vi editing keys. */
                     89: const struct mode_key_entry mode_key_vi_edit[] = {
                     90:        { '\003' /* C-c */,     0, MODEKEYEDIT_CANCEL },
                     91:        { '\010' /* C-h */,     0, MODEKEYEDIT_BACKSPACE },
                     92:        { '\011' /* Tab */,     0, MODEKEYEDIT_COMPLETE },
                     93:        { '\033' /* Escape */,  0, MODEKEYEDIT_SWITCHMODE },
                     94:        { '\r',                 0, MODEKEYEDIT_ENTER },
                     95:        { KEYC_BSPACE,          0, MODEKEYEDIT_BACKSPACE },
                     96:        { KEYC_DC,              0, MODEKEYEDIT_DELETE },
                     97:
                     98:        { '$',                  1, MODEKEYEDIT_ENDOFLINE },
                     99:        { '0',                  1, MODEKEYEDIT_STARTOFLINE },
                    100:        { 'D',                  1, MODEKEYEDIT_DELETETOENDOFLINE },
                    101:        { '\003' /* C-c */,     1, MODEKEYEDIT_CANCEL },
                    102:        { '\010' /* C-h */,     1, MODEKEYEDIT_BACKSPACE },
                    103:        { '\r',                 1, MODEKEYEDIT_ENTER },
                    104:        { '^',                  1, MODEKEYEDIT_STARTOFLINE },
                    105:        { 'a',                  1, MODEKEYEDIT_SWITCHMODEAPPEND },
                    106:        { 'h',                  1, MODEKEYEDIT_CURSORLEFT },
                    107:        { 'i',                  1, MODEKEYEDIT_SWITCHMODE },
                    108:        { 'j',                  1, MODEKEYEDIT_HISTORYDOWN },
                    109:        { 'k',                  1, MODEKEYEDIT_HISTORYUP },
                    110:        { 'l',                  1, MODEKEYEDIT_CURSORRIGHT },
                    111:        { 'p',                  1, MODEKEYEDIT_PASTE },
                    112:        { KEYC_BSPACE,          1, MODEKEYEDIT_BACKSPACE },
                    113:        { KEYC_DC,              1, MODEKEYEDIT_DELETE },
                    114:        { KEYC_DOWN,            1, MODEKEYEDIT_HISTORYDOWN },
                    115:        { KEYC_LEFT,            1, MODEKEYEDIT_CURSORLEFT },
                    116:        { KEYC_RIGHT,           1, MODEKEYEDIT_CURSORRIGHT },
                    117:        { KEYC_UP,              1, MODEKEYEDIT_HISTORYUP },
                    118:
                    119:        { 0,                   -1, 0 }
                    120: };
1.10    ! nicm      121: struct mode_key_tree mode_key_tree_vi_edit;
1.8       nicm      122:
                    123: /* vi choice selection keys. */
                    124: const struct mode_key_entry mode_key_vi_choice[] = {
                    125:        { '\003' /* C-c */,     0, MODEKEYCHOICE_CANCEL },
                    126:        { '\r',                 0, MODEKEYCHOICE_CHOOSE },
                    127:        { 'j',                  0, MODEKEYCHOICE_DOWN },
                    128:        { 'k',                  0, MODEKEYCHOICE_UP },
                    129:        { 'q',                  0, MODEKEYCHOICE_CANCEL },
                    130:        { KEYC_DOWN,            0, MODEKEYCHOICE_DOWN },
                    131:        { KEYC_NPAGE,           0, MODEKEYCHOICE_PAGEDOWN },
                    132:        { KEYC_PPAGE,           0, MODEKEYCHOICE_PAGEUP },
                    133:        { KEYC_UP,              0, MODEKEYCHOICE_UP },
                    134:
                    135:        { 0,                    -1, 0 }
                    136: };
1.10    ! nicm      137: struct mode_key_tree mode_key_tree_vi_choice;
1.8       nicm      138:
                    139: /* vi copy mode keys. */
                    140: const struct mode_key_entry mode_key_vi_copy[] = {
                    141:        { ' ',                  0, MODEKEYCOPY_STARTSELECTION },
                    142:        { '$',                  0, MODEKEYCOPY_ENDOFLINE },
                    143:        { '0',                  0, MODEKEYCOPY_STARTOFLINE },
1.9       nicm      144:        { '\003' /* C-c */,     0, MODEKEYCOPY_CANCEL },
1.8       nicm      145:        { '\006' /* C-f */,     0, MODEKEYCOPY_NEXTPAGE },
                    146:        { '\010' /* C-h */,     0, MODEKEYCOPY_LEFT },
                    147:        { '\025' /* C-u */,     0, MODEKEYCOPY_PREVIOUSPAGE },
                    148:        { '\033' /* Escape */,  0, MODEKEYCOPY_CLEARSELECTION },
                    149:        { '\r',                 0, MODEKEYCOPY_COPYSELECTION },
                    150:        { '^',                  0, MODEKEYCOPY_BACKTOINDENTATION },
                    151:        { 'b',                  0, MODEKEYCOPY_PREVIOUSWORD },
                    152:        { 'h',                  0, MODEKEYCOPY_LEFT },
                    153:        { 'j',                  0, MODEKEYCOPY_DOWN },
                    154:        { 'k',                  0, MODEKEYCOPY_UP },
                    155:        { 'l',                  0, MODEKEYCOPY_RIGHT },
1.9       nicm      156:        { 'q',                  0, MODEKEYCOPY_CANCEL },
1.8       nicm      157:        { 'w',                  0, MODEKEYCOPY_NEXTWORD },
                    158:        { KEYC_BSPACE,          0, MODEKEYCOPY_LEFT },
                    159:        { KEYC_DOWN,            0, MODEKEYCOPY_DOWN },
                    160:        { KEYC_LEFT,            0, MODEKEYCOPY_LEFT },
                    161:        { KEYC_NPAGE,           0, MODEKEYCOPY_NEXTPAGE },
                    162:        { KEYC_PPAGE,           0, MODEKEYCOPY_PREVIOUSPAGE },
                    163:        { KEYC_RIGHT,           0, MODEKEYCOPY_RIGHT },
                    164:        { KEYC_UP,              0, MODEKEYCOPY_UP },
                    165:
                    166:        { 0,                    -1, 0 }
                    167: };
1.10    ! nicm      168: struct mode_key_tree mode_key_tree_vi_copy;
1.8       nicm      169:
                    170: /* emacs editing keys. */
                    171: const struct mode_key_entry mode_key_emacs_edit[] = {
                    172:        { '\001' /* C-a */,     0, MODEKEYEDIT_STARTOFLINE },
                    173:        { '\002' /* C-p */,     0, MODEKEYEDIT_CURSORLEFT },
                    174:        { '\004' /* C-d */,     0, MODEKEYEDIT_DELETE },
                    175:        { '\005' /* C-e */,     0, MODEKEYEDIT_ENDOFLINE },
                    176:        { '\006' /* C-f */,     0, MODEKEYEDIT_CURSORRIGHT },
                    177:        { '\010' /* C-H */,     0, MODEKEYEDIT_BACKSPACE },
                    178:        { '\011' /* Tab */,     0, MODEKEYEDIT_COMPLETE },
                    179:        { '\013' /* C-k */,     0, MODEKEYEDIT_DELETETOENDOFLINE },
                    180:        { '\016' /* C-n */,     0, MODEKEYEDIT_HISTORYDOWN },
                    181:        { '\020' /* C-p */,     0, MODEKEYEDIT_HISTORYUP },
                    182:        { '\031' /* C-y */,     0, MODEKEYEDIT_PASTE },
                    183:        { '\r',                 0, MODEKEYEDIT_ENTER },
                    184:        { 'm' | KEYC_ESCAPE,    0, MODEKEYEDIT_STARTOFLINE },
                    185:        { KEYC_BSPACE,          0, MODEKEYEDIT_BACKSPACE },
                    186:        { KEYC_DC,              0, MODEKEYEDIT_DELETE },
                    187:        { KEYC_DOWN,            0, MODEKEYEDIT_HISTORYDOWN },
                    188:        { KEYC_LEFT,            0, MODEKEYEDIT_CURSORLEFT },
                    189:        { KEYC_RIGHT,           0, MODEKEYEDIT_CURSORRIGHT },
                    190:        { KEYC_UP,              0, MODEKEYEDIT_HISTORYUP },
                    191:
                    192:        { 0,                   -1, 0 }
                    193: };
1.10    ! nicm      194: struct mode_key_tree mode_key_tree_emacs_edit;
1.8       nicm      195:
                    196: /* emacs choice selection keys. */
                    197: const struct mode_key_entry mode_key_emacs_choice[] = {
                    198:        { '\003' /* C-c */,     0, MODEKEYCHOICE_CANCEL },
                    199:        { '\033' /* Escape */,  0, MODEKEYCHOICE_CANCEL },
                    200:        { '\r',                 0, MODEKEYCHOICE_CHOOSE },
                    201:        { 'q',                  0, MODEKEYCHOICE_CANCEL },
                    202:        { KEYC_DOWN,            0, MODEKEYCHOICE_DOWN },
                    203:        { KEYC_NPAGE,           0, MODEKEYCHOICE_PAGEDOWN },
                    204:        { KEYC_PPAGE,           0, MODEKEYCHOICE_PAGEUP },
                    205:        { KEYC_UP,              0, MODEKEYCHOICE_UP },
                    206:
                    207:        { 0,                    -1, 0 }
                    208: };
1.10    ! nicm      209: struct mode_key_tree mode_key_tree_emacs_choice;
1.8       nicm      210:
                    211: /* emacs copy mode keys. */
                    212: const struct mode_key_entry mode_key_emacs_copy[] = {
                    213:        { ' ',                  0, MODEKEYCOPY_NEXTPAGE },
                    214:        { '\000' /* C-Space */, 0, MODEKEYCOPY_STARTSELECTION },
                    215:        { '\001' /* C-a */,     0, MODEKEYCOPY_STARTOFLINE },
                    216:        { '\002' /* C-b */,     0, MODEKEYCOPY_LEFT },
1.9       nicm      217:        { '\003' /* C-c */,     0, MODEKEYCOPY_CANCEL },
1.8       nicm      218:        { '\005' /* C-e */,     0, MODEKEYCOPY_ENDOFLINE },
                    219:        { '\006' /* C-f */,     0, MODEKEYCOPY_RIGHT },
                    220:        { '\007' /* C-g */,     0, MODEKEYCOPY_CLEARSELECTION },
                    221:        { '\016' /* C-n */,     0, MODEKEYCOPY_DOWN },
                    222:        { '\020' /* C-p */,     0, MODEKEYCOPY_UP },
                    223:        { '\026' /* C-v */,     0, MODEKEYCOPY_NEXTPAGE },
                    224:        { '\027' /* C-w */,     0, MODEKEYCOPY_COPYSELECTION },
1.9       nicm      225:        { '\033' /* Escape */,  0, MODEKEYCOPY_CANCEL },
1.8       nicm      226:        { 'b' | KEYC_ESCAPE,    0, MODEKEYCOPY_PREVIOUSWORD },
                    227:        { 'f' | KEYC_ESCAPE,    0, MODEKEYCOPY_NEXTWORD },
                    228:        { 'm' | KEYC_ESCAPE,    0, MODEKEYCOPY_BACKTOINDENTATION },
1.9       nicm      229:        { 'q',                  0, MODEKEYCOPY_CANCEL },
1.8       nicm      230:        { 'v' | KEYC_ESCAPE,    0, MODEKEYCOPY_PREVIOUSPAGE },
                    231:        { 'w' | KEYC_ESCAPE,    0, MODEKEYCOPY_COPYSELECTION },
                    232:        { KEYC_DOWN,            0, MODEKEYCOPY_DOWN },
                    233:        { KEYC_LEFT,            0, MODEKEYCOPY_LEFT },
                    234:        { KEYC_NPAGE,           0, MODEKEYCOPY_NEXTPAGE },
                    235:        { KEYC_PPAGE,           0, MODEKEYCOPY_PREVIOUSPAGE },
                    236:        { KEYC_RIGHT,           0, MODEKEYCOPY_RIGHT },
                    237:        { KEYC_UP,              0, MODEKEYCOPY_UP },
                    238:
                    239:        { 0,                    -1, 0 }
                    240: };
1.10    ! nicm      241: struct mode_key_tree mode_key_tree_emacs_copy;
        !           242:
        !           243: /* Table mapping key table names to default settings and trees. */
        !           244: const struct mode_key_table mode_key_tables[] = {
        !           245:        { "vi-edit", mode_key_cmdstr_edit,
        !           246:          &mode_key_tree_vi_edit, mode_key_vi_edit },
        !           247:        { "vi-choice", mode_key_cmdstr_choice,
        !           248:          &mode_key_tree_vi_choice, mode_key_vi_choice },
        !           249:        { "vi-copy", mode_key_cmdstr_copy,
        !           250:          &mode_key_tree_vi_copy, mode_key_vi_copy },
        !           251:        { "emacs-edit", mode_key_cmdstr_edit,
        !           252:          &mode_key_tree_emacs_edit, mode_key_emacs_edit },
        !           253:        { "emacs-choice", mode_key_cmdstr_choice,
        !           254:          &mode_key_tree_emacs_choice, mode_key_emacs_choice },
        !           255:        { "emacs-copy", mode_key_cmdstr_copy,
        !           256:          &mode_key_tree_emacs_copy, mode_key_emacs_copy },
        !           257:
        !           258:        { NULL, NULL, NULL, NULL }
        !           259: };
        !           260:
        !           261: SPLAY_GENERATE(mode_key_tree, mode_key_binding, entry, mode_key_cmp);
        !           262:
        !           263: int
        !           264: mode_key_cmp(struct mode_key_binding *mbind1, struct mode_key_binding *mbind2)
        !           265: {
        !           266:        if (mbind1->mode != mbind2->mode)
        !           267:                return (mbind1->mode - mbind2->mode);
        !           268:        return (mbind1->key - mbind2->key);
        !           269: }
        !           270:
        !           271: const char *
        !           272: mode_key_tostring(struct mode_key_cmdstr *cmdstr, enum mode_key_cmd cmd)
        !           273: {
        !           274:        for (; cmdstr->name != NULL; cmdstr++) {
        !           275:                if (cmdstr->cmd == cmd)
        !           276:                        return (cmdstr->name);
        !           277:        }
        !           278:        return (NULL);
        !           279: }
1.1       nicm      280:
                    281: void
1.10    ! nicm      282: mode_key_init_trees(void)
1.1       nicm      283: {
1.10    ! nicm      284:        const struct mode_key_table     *mtab;
        !           285:        const struct mode_key_entry     *ment;
        !           286:        struct mode_key_binding         *mbind;
        !           287:
        !           288:        for (mtab = mode_key_tables; mtab->name != NULL; mtab++) {
        !           289:                SPLAY_INIT(mtab->tree);
        !           290:                for (ment = mtab->table; ment->mode != -1; ment++) {
        !           291:                        mbind = xmalloc(sizeof *mbind);
        !           292:                        mbind->key = ment->key;
        !           293:                        mbind->mode = ment->mode;
        !           294:                        mbind->cmd = ment->cmd;
        !           295:                        SPLAY_INSERT(mode_key_tree, mtab->tree, mbind);
        !           296:                }
        !           297:        }
        !           298: }
        !           299:
        !           300: void
        !           301: mode_key_free_trees(void)
        !           302: {
        !           303:        const struct mode_key_table     *mtab;
        !           304:        struct mode_key_binding         *mbind;
        !           305:
        !           306:        for (mtab = mode_key_tables; mtab->name != NULL; mtab++) {
        !           307:                while (!SPLAY_EMPTY(mtab->tree)) {
        !           308:                        mbind = SPLAY_ROOT(mtab->tree);
        !           309:                        SPLAY_REMOVE(mode_key_tree, mtab->tree, mbind);
        !           310:                }
        !           311:        }
        !           312: }
        !           313:
        !           314: void
        !           315: mode_key_init(struct mode_key_data *mdata, struct mode_key_tree *mtree)
        !           316: {
        !           317:        mdata->tree = mtree;
1.8       nicm      318:        mdata->mode = 0;
1.1       nicm      319: }
                    320:
                    321: enum mode_key_cmd
                    322: mode_key_lookup(struct mode_key_data *mdata, int key)
                    323: {
1.10    ! nicm      324:        struct mode_key_binding *mbind, mtmp;
        !           325:
        !           326:        mtmp.key = key;
        !           327:        mtmp.mode = mdata->mode;
        !           328:        if ((mbind = SPLAY_FIND(mode_key_tree, mdata->tree, &mtmp)) == NULL) {
        !           329:                if (mdata->mode != 0)
        !           330:                        return (MODEKEY_NONE);
        !           331:                return (MODEKEY_OTHER);
        !           332:        }
1.1       nicm      333:
1.10    ! nicm      334:        switch (mbind->cmd) {
        !           335:        case MODEKEYEDIT_SWITCHMODE:
        !           336:        case MODEKEYEDIT_SWITCHMODEAPPEND:
        !           337:                mdata->mode = 1 - mdata->mode;
        !           338:                /* FALLTHROUGH */
        !           339:        default:
        !           340:                return (mbind->cmd);
1.1       nicm      341:        }
                    342: }