diff options
author | Nicholas Marriott <nicm@cvs.openbsd.org> | 2019-04-29 06:55:22 +0000 |
---|---|---|
committer | Nicholas Marriott <nicm@cvs.openbsd.org> | 2019-04-29 06:55:22 +0000 |
commit | bc5c4604d2df4c9814723976129f2111d5729ded (patch) | |
tree | ad076a27f9b0f9bd62d6c58dab645673b23c4851 /usr.bin/tmux | |
parent | 22e732bac62cc27aeba5033d7a63d1f747a3c6b3 (diff) |
Add support for keys to jump between matching brackets - C-M-f and C-M-b
in emacs, % in vi. Suggested by and help from Chris Barber in GitHub
issue 1666.
Diffstat (limited to 'usr.bin/tmux')
-rw-r--r-- | usr.bin/tmux/key-bindings.c | 5 | ||||
-rw-r--r-- | usr.bin/tmux/window-copy.c | 225 |
2 files changed, 227 insertions, 3 deletions
diff --git a/usr.bin/tmux/key-bindings.c b/usr.bin/tmux/key-bindings.c index e06596ed0fe..79db69a2e3f 100644 --- a/usr.bin/tmux/key-bindings.c +++ b/usr.bin/tmux/key-bindings.c @@ -1,4 +1,4 @@ -/* $OpenBSD: key-bindings.c,v 1.88 2018/10/18 08:38:01 nicm Exp $ */ +/* $OpenBSD: key-bindings.c,v 1.89 2019/04/29 06:55:21 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -335,7 +335,9 @@ key_bindings_init(void) "bind -Tcopy-mode M-> send -X history-bottom", "bind -Tcopy-mode M-R send -X top-line", "bind -Tcopy-mode M-b send -X previous-word", + "bind -Tcopy-mode C-M-b send -X previous-matching-bracket", "bind -Tcopy-mode M-f send -X next-word-end", + "bind -Tcopy-mode C-M-f send -X next-matching-bracket", "bind -Tcopy-mode M-m send -X back-to-indentation", "bind -Tcopy-mode M-r send -X middle-line", "bind -Tcopy-mode M-v send -X page-up", @@ -408,6 +410,7 @@ key_bindings_init(void) "bind -Tcopy-mode-vi w send -X next-word", "bind -Tcopy-mode-vi { send -X previous-paragraph", "bind -Tcopy-mode-vi } send -X next-paragraph", + "bind -Tcopy-mode-vi % send -X next-matching-bracket", "bind -Tcopy-mode-vi MouseDown1Pane select-pane", "bind -Tcopy-mode-vi MouseDrag1Pane select-pane\\; send -X begin-selection", "bind -Tcopy-mode-vi MouseDragEnd1Pane send -X copy-selection-and-cancel", diff --git a/usr.bin/tmux/window-copy.c b/usr.bin/tmux/window-copy.c index 59b94405ed1..27033de6d26 100644 --- a/usr.bin/tmux/window-copy.c +++ b/usr.bin/tmux/window-copy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: window-copy.c,v 1.217 2019/04/25 06:34:57 nicm Exp $ */ +/* $OpenBSD: window-copy.c,v 1.218 2019/04/29 06:55:21 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -223,7 +223,7 @@ struct window_copy_mode_data { int searchtype; char *searchstr; - bitstr_t *searchmark; + bitstr_t *searchmark; u_int searchcount; int searchthis; int searchx; @@ -995,6 +995,218 @@ window_copy_cmd_middle_line(struct window_copy_cmd_state *cs) } static enum window_copy_cmd_action +window_copy_cmd_previous_matching_bracket(struct window_copy_cmd_state *cs) +{ + struct window_mode_entry *wme = cs->wme; + u_int np = wme->prefix; + struct window_copy_mode_data *data = wme->data; + struct screen *s = data->backing; + char open[] = "{[(", close[] = "}])"; + char tried, found, start, *cp; + u_int px, py, xx, yy, n; + struct grid_cell gc; + int failed; + + for (; np != 0; np--) { + /* Get cursor position and line length. */ + px = data->cx; + py = screen_hsize(s) + data->cy - data->oy; + xx = window_copy_find_length(wme, py); + yy = screen_hsize(s) + screen_size_y(s) - 1; + if (xx == 0) + break; + + /* + * Get the current character. If not on a bracket, try the + * previous. If still not, then behave like previous-word. + */ + tried = 0; + retry: + grid_get_cell(s->grid, px, py, &gc); + if (gc.data.size != 1 || (gc.flags & GRID_FLAG_PADDING)) + cp = NULL; + else { + found = *gc.data.data; + cp = strchr(close, found); + } + if (cp == NULL) { + if (data->modekeys == MODEKEY_EMACS) { + if (!tried && px > 0) { + px--; + tried = 1; + goto retry; + } + window_copy_cursor_previous_word(wme, "}]) "); + px = data->cx; + continue; + } + continue; + } + start = open[cp - close]; + + /* Walk backward until the matching bracket is reached. */ + n = 1; + failed = 0; + do { + if (px == 0) { + if (py == 0) { + failed = 1; + break; + } + do { + py--; + xx = window_copy_find_length(wme, py); + } while (xx == 0 && py > 0); + if (xx == 0 && py == 0) { + failed = 1; + break; + } + px = xx - 1; + } else + px--; + + grid_get_cell(s->grid, px, py, &gc); + if (gc.data.size == 1 && + (~gc.flags & GRID_FLAG_PADDING)) { + if (*gc.data.data == found) + n++; + else if (*gc.data.data == start) + n--; + } + } while (n != 0); + + /* Move the cursor to the found location if any. */ + if (!failed) + window_copy_scroll_to(wme, px, py); + } + + return (WINDOW_COPY_CMD_NOTHING); +} + + +static enum window_copy_cmd_action +window_copy_cmd_next_matching_bracket(struct window_copy_cmd_state *cs) +{ + struct window_mode_entry *wme = cs->wme; + u_int np = wme->prefix; + struct window_copy_mode_data *data = wme->data; + struct screen *s = data->backing; + char open[] = "{[(", close[] = "}])"; + char tried, found, end, *cp; + u_int px, py, xx, yy, sx, sy, n; + struct grid_cell gc; + int failed; + struct grid_line *gl; + + for (; np != 0; np--) { + /* Get cursor position and line length. */ + px = data->cx; + py = screen_hsize(s) + data->cy - data->oy; + xx = window_copy_find_length(wme, py); + yy = screen_hsize(s) + screen_size_y(s) - 1; + if (xx == 0) + break; + + /* + * Get the current character. If not on a bracket, try the + * next. If still not, then behave like next-word. + */ + tried = 0; + retry: + grid_get_cell(s->grid, px, py, &gc); + if (gc.data.size != 1 || (gc.flags & GRID_FLAG_PADDING)) + cp = NULL; + else { + found = *gc.data.data; + + /* + * In vi mode, attempt to move to previous bracket if a + * closing bracket is found first. If this fails, + * return to the original cursor position. + */ + cp = strchr(close, found); + if (cp != NULL && data->modekeys == MODEKEY_VI) { + sx = data->cx; + sy = screen_hsize(s) + data->cy - data->oy; + + window_copy_scroll_to(wme, px, py); + window_copy_cmd_previous_matching_bracket(cs); + + px = data->cx; + py = screen_hsize(s) + data->cy - data->oy; + grid_get_cell(s->grid, px, py, &gc); + if (gc.data.size != 1 || + (gc.flags & GRID_FLAG_PADDING) || + strchr(close, *gc.data.data) == NULL) + window_copy_scroll_to(wme, sx, sy); + break; + } + + cp = strchr(open, found); + } + if (cp == NULL) { + if (data->modekeys == MODEKEY_EMACS) { + if (!tried && px <= xx) { + px++; + tried = 1; + goto retry; + } + window_copy_cursor_next_word_end(wme, "{[( "); + px = data->cx; + continue; + } + /* For vi, continue searching for bracket until EOL. */ + if (px > xx) { + if (py == yy) + continue; + gl = grid_get_line(s->grid, py); + if (~gl->flags & GRID_LINE_WRAPPED) + continue; + if (gl->cellsize > s->grid->sx) + continue; + px = 0; + py++; + xx = window_copy_find_length(wme, py); + } else + px++; + goto retry; + } + end = close[cp - open]; + + /* Walk forward until the matching bracket is reached. */ + n = 1; + failed = 0; + do { + if (px > xx) { + if (py == yy) { + failed = 1; + break; + } + px = 0; + py++; + xx = window_copy_find_length(wme, py); + } else + px++; + + grid_get_cell(s->grid, px, py, &gc); + if (gc.data.size == 1 && + (~gc.flags & GRID_FLAG_PADDING)) { + if (*gc.data.data == found) + n++; + else if (*gc.data.data == end) + n--; + } + } while (n != 0); + + /* Move the cursor to the found location if any. */ + if (!failed) + window_copy_scroll_to(wme, px, py); + } + + return (WINDOW_COPY_CMD_NOTHING); +} + +static enum window_copy_cmd_action window_copy_cmd_next_paragraph(struct window_copy_cmd_state *cs) { struct window_mode_entry *wme = cs->wme; @@ -1613,6 +1825,8 @@ static const struct { window_copy_cmd_jump_to_forward }, { "middle-line", 0, 0, window_copy_cmd_middle_line }, + { "next-matching-bracket", 0, 0, + window_copy_cmd_next_matching_bracket }, { "next-paragraph", 0, 0, window_copy_cmd_next_paragraph }, { "next-space", 0, 0, @@ -1631,6 +1845,8 @@ static const struct { window_copy_cmd_page_down_and_cancel }, { "page-up", 0, 0, window_copy_cmd_page_up }, + { "previous-matching-bracket", 0, 0, + window_copy_cmd_previous_matching_bracket }, { "previous-paragraph", 0, 0, window_copy_cmd_previous_paragraph }, { "previous-space", 0, 0, @@ -3147,6 +3363,11 @@ window_copy_cursor_previous_word(struct window_mode_entry *wme, py = screen_hsize(data->backing) + data->cy - data->oy; px = window_copy_find_length(wme, py); + + /* Stop if separator at EOL. */ + if (px > 0 && + window_copy_in_set(wme, px - 1, py, separators)) + break; } } |