diff --git a/CHANGES b/CHANGES index 20f08576..f525c14a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,15 @@ +02 July 2008 + +* Split vi and emacs mode keys into two tables and add an option (mode-keys) + to select between them. Default is emacs, use, + + tmux set mode-keys vi + + to change to vi. + + vi mode uses space to start selection, enter to copy selection and escape + to clear selection. + 01 July 2008 * Protocol versioning. Clients which identify as a different version from the @@ -598,4 +610,4 @@ (including mutt, emacs). No status bar yet and no key remapping or other customisation. -$Id: CHANGES,v 1.148 2008-07-01 19:47:02 nicm Exp $ +$Id: CHANGES,v 1.149 2008-07-02 21:22:57 nicm Exp $ diff --git a/Makefile b/Makefile index 60b9dec1..d9f03883 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.70 2008-07-01 05:43:00 nicm Exp $ +# $Id: Makefile,v 1.71 2008-07-02 21:22:57 nicm Exp $ .SUFFIXES: .c .o .y .h .PHONY: clean update-index.html upload-index.html @@ -18,7 +18,7 @@ META?= \002 # C-b SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \ xmalloc.c xmalloc-debug.c input.c input-keys.c screen.c screen-display.c \ window.c session.c log.c client.c client-msg.c client-fn.c cfg.c \ - key-string.c key-bindings.c resize.c arg.c \ + key-string.c key-bindings.c resize.c arg.c mode-key.c \ cmd.c cmd-generic.c cmd-string.c \ cmd-detach-client.c cmd-list-sessions.c cmd-new-window.c cmd-bind-key.c \ cmd-unbind-key.c cmd-previous-window.c cmd-last-window.c cmd-list-keys.c \ diff --git a/TODO b/TODO index cdc9afd0..7e73d292 100644 --- a/TODO +++ b/TODO @@ -67,6 +67,5 @@ - next prev word etc in command prompt - split keys in command prompt/scroll mode/copy mode into vi and emacs and have a "edit-mode" option select which keymap -- zombie windows: don't disappear when the command dies. new command - respawn-window [command] to restart; ommitting commands uses previous - many more info displays for various things +- document mode-keys diff --git a/cmd-set-option.c b/cmd-set-option.c index ed8fb304..fdefe005 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -1,4 +1,4 @@ -/* $Id: cmd-set-option.c,v 1.38 2008-07-01 19:00:50 nicm Exp $ */ +/* $Id: cmd-set-option.c,v 1.39 2008-07-02 21:22:57 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -55,14 +55,19 @@ const struct cmd_entry cmd_set_option_entry = { cmd_set_option_print }; -const char *set_option_bell_action_choices[] = { "none", "any", "current", NULL }; +const char *set_option_bell_action_list[] = { + "none", "any", "current", NULL +}; +const char *set_option_mode_keys_list[] = { + "emacs", "vi", NULL +}; const struct set_option_entry set_option_table[NSETOPTION] = { - { "bell-action", - SET_OPTION_CHOICE, 0, 0, set_option_bell_action_choices }, + { "bell-action", SET_OPTION_CHOICE, 0, 0, set_option_bell_action_list }, { "buffer-limit", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "default-command", SET_OPTION_STRING, 0, 0, NULL }, { "display-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "history-limit", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, + { "mode-keys", SET_OPTION_CHOICE, 0, 0, set_option_mode_keys_list }, { "prefix", SET_OPTION_KEY, 0, 0, NULL }, { "remain-by-default", SET_OPTION_FLAG, 0, 0, NULL }, { "set-titles", SET_OPTION_FLAG, 0, 0, NULL }, diff --git a/mode-key.c b/mode-key.c new file mode 100644 index 00000000..cf5cb107 --- /dev/null +++ b/mode-key.c @@ -0,0 +1,92 @@ +/* $Id: mode-key.c,v 1.1 2008-07-02 21:22:57 nicm Exp $ */ + +/* + * Copyright (c) 2008 Nicholas Marriott + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "tmux.h" + +struct mode_key_entry { + enum mode_key mkey; + int key; +}; + +const struct mode_key_entry mode_key_table_vi[] = { + { MODEKEY_BOL, '0' }, + { MODEKEY_CLEARSEL, '\033' }, + { MODEKEY_COPYSEL, '\r' }, + { MODEKEY_DOWN, 'j' }, + { MODEKEY_DOWN, KEYC_DOWN }, + { MODEKEY_EOL, '$' }, + { MODEKEY_LEFT, 'h' }, + { MODEKEY_LEFT, KEYC_LEFT }, + { MODEKEY_NPAGE, '\006' }, + { MODEKEY_NPAGE, KEYC_NPAGE }, + { MODEKEY_NWORD, 'w' }, + { MODEKEY_PPAGE, '\025' }, + { MODEKEY_PPAGE, KEYC_PPAGE }, + { MODEKEY_PWORD, 'b' }, + { MODEKEY_QUIT, 'q' }, + { MODEKEY_RIGHT, 'l' }, + { MODEKEY_RIGHT, KEYC_RIGHT }, + { MODEKEY_STARTSEL, ' ' }, + { MODEKEY_UP, 'k' }, + { MODEKEY_UP, KEYC_UP }, +}; +#define NKEYVI (sizeof mode_key_table_vi / sizeof mode_key_table_vi[0]) + +const struct mode_key_entry mode_key_table_emacs[] = { + { MODEKEY_BOL, '\001' }, + { MODEKEY_CLEARSEL, '\007' }, + { MODEKEY_COPYSEL, '\027' }, + { MODEKEY_COPYSEL, KEYC_ADDESCAPE('w') }, + { MODEKEY_DOWN, KEYC_DOWN }, + { MODEKEY_EOL, '\005' }, + { MODEKEY_LEFT, KEYC_LEFT }, + { MODEKEY_NPAGE, KEYC_NPAGE }, + { MODEKEY_NWORD, KEYC_ADDESCAPE('f') }, + { MODEKEY_PPAGE, KEYC_PPAGE }, + { MODEKEY_PWORD, KEYC_ADDESCAPE('b') }, + { MODEKEY_QUIT, 'q' }, + { MODEKEY_QUIT, '\033' }, + { MODEKEY_RIGHT, KEYC_RIGHT }, + { MODEKEY_STARTSEL, '\000' }, + { MODEKEY_UP, KEYC_UP }, +}; +#define NKEYEMACS (sizeof mode_key_table_emacs / sizeof mode_key_table_emacs[0]) + +enum mode_key +mode_key_lookup(int table, int key) +{ + const struct mode_key_entry *ptr; + u_int i, n; + + if (table == MODEKEY_EMACS) { + ptr = mode_key_table_emacs; + n = NKEYEMACS; + } else if (table == MODEKEY_VI) { + ptr = mode_key_table_vi; + n = NKEYVI; + } else + return (MODEKEY_NONE); + + for (i = 0; i < n; i++) { + if (ptr[i].key == key) + return (ptr[i].mkey); + } + return (MODEKEY_NONE); +} diff --git a/tmux.c b/tmux.c index f6505c81..71da57c3 100644 --- a/tmux.c +++ b/tmux.c @@ -1,4 +1,4 @@ -/* $Id: tmux.c,v 1.71 2008-06-29 21:03:57 nicm Exp $ */ +/* $Id: tmux.c,v 1.72 2008-07-02 21:22:57 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -223,6 +223,7 @@ main(int argc, char **argv) options_set_number(&global_options, "set-titles", 1); options_set_number(&global_options, "buffer-limit", 9); options_set_number(&global_options, "remain-by-default", 0); + options_set_number(&global_options, "mode-keys", MODEKEY_EMACS); if (cfg_file == NULL) { home = getenv("HOME"); diff --git a/tmux.h b/tmux.h index 58bfe89b..df1069ba 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.174 2008-07-01 20:35:16 nicm Exp $ */ +/* $Id: tmux.h,v 1.175 2008-07-02 21:22:57 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -827,7 +827,28 @@ struct set_option_entry { const char **choices; }; extern const struct set_option_entry set_option_table[]; -#define NSETOPTION 14 +#define NSETOPTION 15 + +/* Edit keys. */ +enum mode_key { + MODEKEY_BOL, + MODEKEY_CLEARSEL, + MODEKEY_COPYSEL, + MODEKEY_DOWN, + MODEKEY_EOL, + MODEKEY_LEFT, + MODEKEY_NONE, + MODEKEY_NPAGE, + MODEKEY_NWORD, + MODEKEY_PPAGE, + MODEKEY_PWORD, + MODEKEY_QUIT, + MODEKEY_RIGHT, + MODEKEY_STARTSEL, + MODEKEY_UP, +}; +#define MODEKEY_EMACS 0 +#define MODEKEY_VI 1 #ifdef NO_STRTONUM /* strtonum.c */ @@ -879,6 +900,9 @@ void sigreset(void); /* cfg.c */ int load_cfg(const char *, char **x); +/* mode-key.c */ +enum mode_key mode_key_lookup(int, int); + /* options.c */ int options_cmp(struct options_entry *, struct options_entry *); SPLAY_PROTOTYPE(options_tree, options_entry, entry, options_cmp); diff --git a/window-copy.c b/window-copy.c index 26f3b2f4..196e49f6 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1,4 +1,4 @@ -/* $Id: window-copy.c,v 1.25 2008-06-27 17:41:48 nicm Exp $ */ +/* $Id: window-copy.c,v 1.26 2008-07-02 21:22:57 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -136,32 +136,26 @@ window_copy_key(struct window *w, struct client *c, int key) { struct window_copy_mode_data *data = w->modedata; struct screen *s = &data->screen; + int table; - switch (key) { - case 'Q': - case 'q': + table = options_get_number(&c->session->options, "mode-keys"); + switch (mode_key_lookup(table, key)) { + case MODEKEY_QUIT: window_reset_mode(w); break; - case 'h': - case KEYC_LEFT: + case MODEKEY_LEFT: window_copy_cursor_left(w); return; - case 'l': - case KEYC_RIGHT: + case MODEKEY_RIGHT: window_copy_cursor_right(w); return; - case 'k': - case 'K': - case KEYC_UP: + case MODEKEY_UP: window_copy_cursor_up(w); return; - case 'j': - case 'J': - case KEYC_DOWN: + case MODEKEY_DOWN: window_copy_cursor_down(w); return; - case '\025': /* C-u */ - case KEYC_PPAGE: + case MODEKEY_PPAGE: if (data->oy + screen_size_y(s) > w->base.hsize) data->oy = w->base.hsize; else @@ -169,8 +163,7 @@ window_copy_key(struct window *w, struct client *c, int key) window_copy_update_selection(w); window_copy_redraw_screen(w); break; - case '\006': /* C-f */ - case KEYC_NPAGE: + case MODEKEY_NPAGE: if (data->oy < screen_size_y(s)) data->oy = 0; else @@ -178,38 +171,33 @@ window_copy_key(struct window *w, struct client *c, int key) window_copy_update_selection(w); window_copy_redraw_screen(w); break; - case '\000': /* C-space */ - case ' ': + case MODEKEY_STARTSEL: window_copy_start_selection(w); break; - case '\033': + case MODEKEY_CLEARSEL: screen_clear_selection(&data->screen); + window_copy_redraw_screen(w); break; - case '\027': /* C-w */ - case '\r': /* enter */ + case MODEKEY_COPYSEL: if (c != NULL && c->session != NULL) { window_copy_copy_selection(w, c); window_reset_mode(w); } break; - case '0': - case '\001': /* C-a */ + case MODEKEY_BOL: window_copy_cursor_start_of_line(w); break; - case '$': - case '\005': /* C-e */ + case MODEKEY_EOL: window_copy_cursor_end_of_line(w); break; - case 'w': - case KEYC_ADDESCAPE('F'): /* M-F */ - case KEYC_ADDESCAPE('f'): /* M-f */ + case MODEKEY_NWORD: window_copy_cursor_next_word(w); break; - case 'b': - case KEYC_ADDESCAPE('B'): /* M-B */ - case KEYC_ADDESCAPE('b'): /* M-b */ + case MODEKEY_PWORD: window_copy_cursor_previous_word(w); break; + default: + break; } } diff --git a/window-more.c b/window-more.c index b5877519..6424c0cd 100644 --- a/window-more.c +++ b/window-more.c @@ -1,4 +1,4 @@ -/* $Id: window-more.c,v 1.14 2008-06-22 16:56:47 nicm Exp $ */ +/* $Id: window-more.c,v 1.15 2008-07-02 21:22:57 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -123,42 +123,39 @@ window_more_resize(struct window *w, u_int sx, u_int sy) } void -window_more_key(struct window *w, unused struct client *c, int key) +window_more_key(struct window *w, struct client *c, int key) { struct window_more_mode_data *data = w->modedata; struct screen *s = &data->screen; + int table; - switch (key) { - case 'Q': - case 'q': + table = options_get_number(&c->session->options, "mode-keys"); + switch (mode_key_lookup(table, key)) { + case MODEKEY_QUIT: window_reset_mode(w); break; - case 'k': - case 'K': - case KEYC_UP: + case MODEKEY_UP: window_more_scroll_up(w); break; - case 'j': - case 'J': - case KEYC_DOWN: + case MODEKEY_DOWN: window_more_scroll_down(w); break; - case '\025': /* C-u */ - case KEYC_PPAGE: + case MODEKEY_PPAGE: if (data->top < screen_size_y(s)) data->top = 0; else data->top -= screen_size_y(s); window_more_redraw_screen(w); break; - case '\006': /* C-f */ - case KEYC_NPAGE: + case MODEKEY_NPAGE: if (data->top + screen_size_y(s) > ARRAY_LENGTH(&data->list)) data->top = ARRAY_LENGTH(&data->list); else data->top += screen_size_y(s); window_more_redraw_screen(w); break; + default: + break; } } diff --git a/window-scroll.c b/window-scroll.c index 639f716d..c0387fd4 100644 --- a/window-scroll.c +++ b/window-scroll.c @@ -1,4 +1,4 @@ -/* $Id: window-scroll.c,v 1.20 2008-06-22 16:56:47 nicm Exp $ */ +/* $Id: window-scroll.c,v 1.21 2008-07-02 21:22:57 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -97,50 +97,45 @@ window_scroll_resize(struct window *w, u_int sx, u_int sy) } void -window_scroll_key(struct window *w, unused struct client *c, int key) +window_scroll_key(struct window *w, struct client *c, int key) { struct window_scroll_mode_data *data = w->modedata; struct screen *s = &data->screen; + int table; - switch (key) { - case 'Q': - case 'q': + table = options_get_number(&c->session->options, "mode-keys"); + switch (mode_key_lookup(table, key)) { + case MODEKEY_QUIT: window_reset_mode(w); break; - case 'h': - case KEYC_LEFT: + case MODEKEY_LEFT: window_scroll_scroll_left(w); break; - case 'l': - case KEYC_RIGHT: + case MODEKEY_RIGHT: window_scroll_scroll_right(w); break; - case 'k': - case 'K': - case KEYC_UP: + case MODEKEY_UP: window_scroll_scroll_up(w); break; - case 'j': - case 'J': - case KEYC_DOWN: + case MODEKEY_DOWN: window_scroll_scroll_down(w); break; - case '\025': /* C-u */ - case KEYC_PPAGE: + case MODEKEY_PPAGE: if (data->oy + screen_size_y(s) > w->base.hsize) data->oy = w->base.hsize; else data->oy += screen_size_y(s); window_scroll_redraw_screen(w); break; - case '\006': /* C-f */ - case KEYC_NPAGE: + case MODEKEY_NPAGE: if (data->oy < screen_size_y(s)) data->oy = 0; else data->oy -= screen_size_y(s); window_scroll_redraw_screen(w); break; + default: + break; } }