summaryrefslogtreecommitdiffstats
path: root/window-copy.c
diff options
context:
space:
mode:
authornicm <nicm>2019-04-29 06:55:21 +0000
committernicm <nicm>2019-04-29 06:55:21 +0000
commitec81bd2399d2b038d03f85177bf0c33c3e530737 (patch)
treecb6eae1666f857aa4de3a80303d1daf9c872cbda /window-copy.c
parentc4b0da5513ee4c9692f0980408b0da2ee7e3a553 (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 'window-copy.c')
-rw-r--r--window-copy.c223
1 files changed, 222 insertions, 1 deletions
diff --git a/window-copy.c b/window-copy.c
index 741e2bfd..82b4765c 100644
--- a/window-copy.c
+++ b/window-copy.c
@@ -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;
}
}