From 5e6a7c85ccdbabda01e7c05a10f7bd8dcee47e70 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 4 Feb 2010 20:00:26 +0000 Subject: [PATCH] vi-style B, W and E keys in copy mode to navigate between words treating only spaces as word separators. Also add . to the list of word separators for standard word navigation. From Micah Cowan, tweaked slightly by me. --- mode-key.c | 6 ++++++ tmux.1 | 17 ++++++++++++++++- tmux.h | 3 +++ window-copy.c | 51 ++++++++++++++++++++++++++++----------------------- 4 files changed, 53 insertions(+), 24 deletions(-) diff --git a/mode-key.c b/mode-key.c index a8d9aef7..175a2a04 100644 --- a/mode-key.c +++ b/mode-key.c @@ -91,9 +91,12 @@ struct mode_key_cmdstr mode_key_cmdstr_copy[] = { { MODEKEYCOPY_LEFT, "cursor-left" }, { MODEKEYCOPY_MIDDLELINE, "middle-line" }, { MODEKEYCOPY_NEXTPAGE, "page-down" }, + { MODEKEYCOPY_NEXTSPACE, "next-space" }, + { MODEKEYCOPY_NEXTSPACEEND, "next-space-end" }, { MODEKEYCOPY_NEXTWORD, "next-word" }, { MODEKEYCOPY_NEXTWORDEND, "next-word-end" }, { MODEKEYCOPY_PREVIOUSPAGE, "page-up" }, + { MODEKEYCOPY_PREVIOUSSPACE, "previous-space" }, { MODEKEYCOPY_PREVIOUSWORD, "previous-word" }, { MODEKEYCOPY_RIGHT, "cursor-right" }, { MODEKEYCOPY_SCROLLDOWN, "scroll-down" }, @@ -175,12 +178,15 @@ const struct mode_key_entry mode_key_vi_copy[] = { { '0', 0, MODEKEYCOPY_STARTOFLINE }, { ':', 0, MODEKEYCOPY_GOTOLINE }, { '?', 0, MODEKEYCOPY_SEARCHUP }, + { 'B', 0, MODEKEYCOPY_PREVIOUSSPACE }, + { 'E', 0, MODEKEYCOPY_NEXTSPACEEND }, { 'G', 0, MODEKEYCOPY_HISTORYBOTTOM }, { 'H', 0, MODEKEYCOPY_TOPLINE }, { 'J', 0, MODEKEYCOPY_SCROLLDOWN }, { 'K', 0, MODEKEYCOPY_SCROLLUP }, { 'L', 0, MODEKEYCOPY_BOTTOMLINE }, { 'M', 0, MODEKEYCOPY_MIDDLELINE }, + { 'W', 0, MODEKEYCOPY_NEXTSPACE }, { '\002' /* C-b */, 0, MODEKEYCOPY_PREVIOUSPAGE }, { '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL }, { '\004' /* C-d */, 0, MODEKEYCOPY_HALFPAGEDOWN }, diff --git a/tmux.1 b/tmux.1 index b80e8580..a759c82b 100644 --- a/tmux.1 +++ b/tmux.1 @@ -535,7 +535,7 @@ The keys available depend on whether emacs or vi mode is selected .Ic mode-keys option). The following keys are supported as appropriate for the mode: -.Bl -column "FunctionXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent +.Bl -column "FunctionXXXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent .It Sy "Function" Ta Sy "vi" Ta Sy "emacs" .It Li "Back to indentation" Ta "^" Ta "M-m" .It Li "Bottom of history" Ta "G" Ta "M-<" @@ -555,11 +555,14 @@ The following keys are supported as appropriate for the mode: .It Li "Half page down" Ta "C-d" Ta "M-Down" .It Li "Half page up" Ta "C-u" Ta "M-Up" .It Li "Next page" Ta "C-f" Ta "Page down" +.It Li "Next space" Ta "W" Ta "" +.It Li "Next space, end of word" Ta "E" Ta "" .It Li "Next word" Ta "w" Ta "" .It Li "Next word end" Ta "e" Ta "M-f" .It Li "Paste buffer" Ta "p" Ta "C-y" .It Li "Previous page" Ta "C-b" Ta "Page up" .It Li "Previous word" Ta "b" Ta "M-b" +.It Li "Previous space" Ta "B" Ta "" .It Li "Quit mode" Ta "q" Ta "Escape" .It Li "Scroll down" Ta "C-Down or C-e" Ta "C-Down" .It Li "Scroll up" Ta "C-Up or C-y" Ta "C-Up" @@ -572,6 +575,18 @@ The following keys are supported as appropriate for the mode: .It Li "Transpose chars" Ta "" Ta "C-t" .El .Pp +The next and previous word keys use space and the +.Ql - , +.Ql _ , +.Ql \&" +and +.Ql @ +characters as word delimiters. +Next word moves to the start of the next word, next word end to the end of the +next word and previous word to the start of the previous word. +The three next and previous space keys work similarly but use a space alone as +the word separator. +.Pp These key bindings are defined in a set of named tables: .Em vi-edit and diff --git a/tmux.h b/tmux.h index 7bceb667..c6bb8457 100644 --- a/tmux.h +++ b/tmux.h @@ -462,9 +462,12 @@ enum mode_key_cmd { MODEKEYCOPY_LEFT, MODEKEYCOPY_MIDDLELINE, MODEKEYCOPY_NEXTPAGE, + MODEKEYCOPY_NEXTSPACE, + MODEKEYCOPY_NEXTSPACEEND, MODEKEYCOPY_NEXTWORD, MODEKEYCOPY_NEXTWORDEND, MODEKEYCOPY_PREVIOUSPAGE, + MODEKEYCOPY_PREVIOUSSPACE, MODEKEYCOPY_PREVIOUSWORD, MODEKEYCOPY_RIGHT, MODEKEYCOPY_SCROLLDOWN, diff --git a/window-copy.c b/window-copy.c index fd50339e..e2f15735 100644 --- a/window-copy.c +++ b/window-copy.c @@ -54,7 +54,7 @@ int window_copy_update_selection(struct window_pane *); void window_copy_copy_selection(struct window_pane *, struct client *); void window_copy_copy_line( struct window_pane *, char **, size_t *, u_int, u_int, u_int); -int window_copy_is_space(struct window_pane *, u_int, u_int); +int window_copy_in_set(struct window_pane *, u_int, u_int, const char *); u_int window_copy_find_length(struct window_pane *, u_int); void window_copy_cursor_start_of_line(struct window_pane *); void window_copy_cursor_back_to_indentation(struct window_pane *); @@ -63,9 +63,9 @@ void window_copy_cursor_left(struct window_pane *); void window_copy_cursor_right(struct window_pane *); void window_copy_cursor_up(struct window_pane *, int); void window_copy_cursor_down(struct window_pane *, int); -void window_copy_cursor_next_word(struct window_pane *); -void window_copy_cursor_next_word_end(struct window_pane *); -void window_copy_cursor_previous_word(struct window_pane *); +void window_copy_cursor_next_word(struct window_pane *, const char *); +void window_copy_cursor_next_word_end(struct window_pane *, const char *); +void window_copy_cursor_previous_word(struct window_pane *, const char *); void window_copy_scroll_up(struct window_pane *, u_int); void window_copy_scroll_down(struct window_pane *, u_int); @@ -214,6 +214,7 @@ window_copy_resize(struct window_pane *wp, u_int sx, u_int sy) void window_copy_key(struct window_pane *wp, struct client *c, int key) { + const char *word_separators = " -_@"; struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; u_int n; @@ -334,14 +335,23 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) case MODEKEYCOPY_ENDOFLINE: window_copy_cursor_end_of_line(wp); break; + case MODEKEYCOPY_NEXTSPACE: + window_copy_cursor_next_word(wp, " "); + break; + case MODEKEYCOPY_NEXTSPACEEND: + window_copy_cursor_next_word_end(wp, " "); + break; case MODEKEYCOPY_NEXTWORD: - window_copy_cursor_next_word(wp); + window_copy_cursor_next_word(wp, word_separators); break; case MODEKEYCOPY_NEXTWORDEND: - window_copy_cursor_next_word_end(wp); + window_copy_cursor_next_word_end(wp, word_separators); + break; + case MODEKEYCOPY_PREVIOUSSPACE: + window_copy_cursor_previous_word(wp, " "); break; case MODEKEYCOPY_PREVIOUSWORD: - window_copy_cursor_previous_word(wp); + window_copy_cursor_previous_word(wp, word_separators); break; case MODEKEYCOPY_SEARCHUP: data->inputtype = WINDOW_COPY_SEARCHUP; @@ -965,17 +975,16 @@ window_copy_copy_line(struct window_pane *wp, } int -window_copy_is_space(struct window_pane *wp, u_int px, u_int py) +window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set) { const struct grid_cell *gc; - const char *spaces = " -_@"; gc = grid_peek_cell(wp->base.grid, px, py); if (gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) return (0); if (gc->data == 0x00 || gc->data == 0x7f) return (0); - return (strchr(spaces, gc->data) != NULL); + return (strchr(set, gc->data) != NULL); } u_int @@ -1025,10 +1034,6 @@ window_copy_cursor_back_to_indentation(struct window_pane *wp) py = screen_hsize(&wp->base) + data->cy - data->oy; xx = window_copy_find_length(wp, py); - /* - * Don't use window_copy_is_space because that treats some word - * delimiters as spaces. - */ while (px < xx) { gc = grid_peek_cell(wp->base.grid, px, py); if (gc->flags & GRID_FLAG_UTF8) @@ -1162,7 +1167,7 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only) } void -window_copy_cursor_next_word(struct window_pane *wp) +window_copy_cursor_next_word(struct window_pane *wp, const char *separators) { struct window_copy_mode_data *data = wp->modedata; struct screen *base_s = &wp->base; @@ -1174,11 +1179,11 @@ window_copy_cursor_next_word(struct window_pane *wp) yy = screen_hsize(base_s) + screen_size_y(base_s) - 1; /* Are we in a word? Skip it! */ - while (!window_copy_is_space(wp, px, py)) + while (!window_copy_in_set(wp, px, py, separators)) px++; /* Find the start of a word. */ - while (px > xx || window_copy_is_space(wp, px, py)) { + while (px > xx || window_copy_in_set(wp, px, py, separators)) { /* Past the end of the line? Nothing but spaces. */ if (px > xx) { if (py == yy) @@ -1198,7 +1203,7 @@ window_copy_cursor_next_word(struct window_pane *wp) } void -window_copy_cursor_next_word_end(struct window_pane *wp) +window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators) { struct window_copy_mode_data *data = wp->modedata; struct screen *base_s = &wp->base; @@ -1210,7 +1215,7 @@ window_copy_cursor_next_word_end(struct window_pane *wp) yy = screen_hsize(base_s) + screen_size_y(base_s) - 1; /* Are we on spaces? Skip 'em! */ - while (px > xx || window_copy_is_space(wp, px, py)) { + while (px > xx || window_copy_in_set(wp, px, py, separators)) { /* Nothing but spaces past the end of the line, so move down. */ if (px > xx) { if (py == yy) @@ -1225,7 +1230,7 @@ window_copy_cursor_next_word_end(struct window_pane *wp) } /* Find the end of this word. */ - while (!window_copy_is_space(wp, px, py)) + while (!window_copy_in_set(wp, px, py, separators)) px++; window_copy_update_cursor(wp, px, data->cy); @@ -1235,7 +1240,7 @@ window_copy_cursor_next_word_end(struct window_pane *wp) /* Move to the previous place where a word begins. */ void -window_copy_cursor_previous_word(struct window_pane *wp) +window_copy_cursor_previous_word(struct window_pane *wp, const char *separators) { struct window_copy_mode_data *data = wp->modedata; u_int px, py; @@ -1247,7 +1252,7 @@ window_copy_cursor_previous_word(struct window_pane *wp) for (;;) { if (px > 0) { px--; - if (!window_copy_is_space(wp, px, py)) + if (!window_copy_in_set(wp, px, py, separators)) break; } else { if (data->cy == 0 && @@ -1262,7 +1267,7 @@ window_copy_cursor_previous_word(struct window_pane *wp) } /* Move back to the beginning of this word. */ - while (px > 0 && !window_copy_is_space(wp, px - 1, py)) + while (px > 0 && !window_copy_in_set(wp, px - 1, py, separators)) px--; out: