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.
pull/1702/head
nicm 2019-04-29 06:55:21 +00:00
parent c4b0da5513
commit ec81bd2399
2 changed files with 225 additions and 1 deletions

View File

@ -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",

View File

@ -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;
@ -994,6 +994,218 @@ window_copy_cmd_middle_line(struct window_copy_cmd_state *cs)
return (WINDOW_COPY_CMD_REDRAW);
}
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)
{
@ -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;
}
}