diff --git a/cmd-set-option.c b/cmd-set-option.c index 6658b90b..90b6d611 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -165,6 +165,7 @@ const struct set_option_entry set_window_option_table[] = { { "window-status-current-format", SET_OPTION_STRING, 0, 0, NULL }, { "window-status-fg", SET_OPTION_COLOUR, 0, 0, NULL }, { "window-status-format", SET_OPTION_STRING, 0, 0, NULL }, + { "word-separators", SET_OPTION_STRING, 0, 0, NULL }, { "xterm-keys", SET_OPTION_FLAG, 0, 0, NULL }, { NULL, 0, 0, 0, NULL } }; diff --git a/tmux.1 b/tmux.1 index bbb66dc7..348c2b3a 100644 --- a/tmux.1 +++ b/tmux.1 @@ -649,11 +649,13 @@ The following keys are supported as appropriate for the mode: .Pp The next and previous word keys use space and the .Ql - , -.Ql _ , -.Ql \&" +.Ql _ and .Ql @ -characters as word delimiters. +characters as word delimiters by default, but this can be adjusted by +setting the +.Em word-separators +window option. 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 @@ -2031,6 +2033,13 @@ Like .Ar window-status-format , but is the format used when the window is the current window. .Pp +.It Ic word-separators Ar string +Sets the window's conception of what characters are considered word +separators, for the purposes of the next and previous word commands in +copy mode. +The default is +.Ql \ -_@ . +.Pp .It Xo Ic xterm-keys .Op Ic on | off .Xc diff --git a/tmux.c b/tmux.c index 8671e323..4f0a9090 100644 --- a/tmux.c +++ b/tmux.c @@ -418,6 +418,7 @@ main(int argc, char **argv) options_set_number(wo, "window-status-fg", 8); options_set_string(wo, "window-status-format", "#I:#W#F"); options_set_string(wo, "window-status-current-format", "#I:#W#F"); + options_set_string(wo, "word-separators", " -_@"); options_set_number(wo, "xterm-keys", 0); options_set_number(wo, "remain-on-exit", 0); options_set_number(wo, "synchronize-panes", 0); diff --git a/window-copy.c b/window-copy.c index 0f956bd0..82ae9a2b 100644 --- a/window-copy.c +++ b/window-copy.c @@ -226,7 +226,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 = " -_@"; + const char *word_separators; struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; u_int n; @@ -356,15 +356,21 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) window_copy_cursor_next_word_end(wp, " "); break; case MODEKEYCOPY_NEXTWORD: + word_separators = + options_get_string(&wp->window->options, "word-separators"); window_copy_cursor_next_word(wp, word_separators); break; case MODEKEYCOPY_NEXTWORDEND: + word_separators = + options_get_string(&wp->window->options, "word-separators"); window_copy_cursor_next_word_end(wp, word_separators); break; case MODEKEYCOPY_PREVIOUSSPACE: window_copy_cursor_previous_word(wp, " "); break; case MODEKEYCOPY_PREVIOUSWORD: + word_separators = + options_get_string(&wp->window->options, "word-separators"); window_copy_cursor_previous_word(wp, word_separators); break; case MODEKEYCOPY_SEARCHUP: @@ -1271,30 +1277,36 @@ 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; u_int px, py, xx, yy; + int expected = 0; px = data->cx; py = screen_hsize(base_s) + data->cy - data->oy; xx = window_copy_find_length(wp, py); yy = screen_hsize(base_s) + screen_size_y(base_s) - 1; - /* Are we in a word? Skip it! */ - while (!window_copy_in_set(wp, px, py, separators)) - px++; + /* + * First skip past any nonword characters and then any word characters. + * + * expected is initially set to 0 for the former and then 1 for the + * latter. + */ + do { + while (px > xx || + window_copy_in_set(wp, px, py, separators) == expected) { + /* Move down if we're past the end of the line. */ + if (px > xx) { + if (py == yy) + return; + window_copy_cursor_down(wp, 0); + px = 0; - /* Find the start of a word. */ - 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) - return; - window_copy_cursor_down(wp, 0); - px = 0; - - py = screen_hsize(base_s) + data->cy - data->oy; - xx = window_copy_find_length(wp, py); - } else - px++; - } + py = screen_hsize(base_s) + data->cy - data->oy; + xx = window_copy_find_length(wp, py); + } else + px++; + } + expected = !expected; + } while (expected == 1); window_copy_update_cursor(wp, px, data->cy); if (window_copy_update_selection(wp)) @@ -1307,30 +1319,36 @@ 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; u_int px, py, xx, yy; + int expected = 1; px = data->cx; py = screen_hsize(base_s) + data->cy - data->oy; xx = window_copy_find_length(wp, py); yy = screen_hsize(base_s) + screen_size_y(base_s) - 1; - /* Are we on spaces? Skip 'em! */ - 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) - return; - window_copy_cursor_down(wp, 0); - px = 0; + /* + * First skip past any word characters, then any nonword characters. + * + * expected is initially set to 1 for the former and then 0 for the + * latter. + */ + do { + while (px > xx || + window_copy_in_set(wp, px, py, separators) == expected) { + /* Move down if we're past the end of the line. */ + if (px > xx) { + if (py == yy) + return; + window_copy_cursor_down(wp, 0); + px = 0; - py = screen_hsize(base_s) + data->cy - data->oy; - xx = window_copy_find_length(wp, py); - } else - px++; - } - - /* Find the end of this word. */ - while (!window_copy_in_set(wp, px, py, separators)) - px++; + py = screen_hsize(base_s) + data->cy - data->oy; + xx = window_copy_find_length(wp, py); + } else + px++; + } + expected = !expected; + } while (expected == 0); window_copy_update_cursor(wp, px, data->cy); if (window_copy_update_selection(wp))