=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/tmux/window-copy.c,v retrieving revision 1.217 retrieving revision 1.218 diff -u -r1.217 -r1.218 --- src/usr.bin/tmux/window-copy.c 2019/04/25 06:34:57 1.217 +++ src/usr.bin/tmux/window-copy.c 2019/04/29 06:55:21 1.218 @@ -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 @@ -223,7 +223,7 @@ int searchtype; char *searchstr; - bitstr_t *searchmark; + bitstr_t *searchmark; u_int searchcount; int searchthis; int searchx; @@ -995,6 +995,218 @@ } 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 @@ 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 @@ 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 @@ 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; } }