From 6214cd07264b393fd751271791870f1e8f251371 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 13 May 2020 06:29:57 +0100 Subject: [PATCH] Add a mark in copy mode. Set with set-mark command (bound to 'X') by default and the mark and cursor position are swapped with 'jump-to-mark' (bound to M-x). The line containing the mark is shown in copy-mode-mark-style with the horizontal position in reverse. From Anindya Mukherjee in GitHub issue 2209. --- key-bindings.c | 4 ++ options-table.c | 9 ++++ tmux.1 | 10 +++++ window-copy.c | 107 ++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 121 insertions(+), 9 deletions(-) diff --git a/key-bindings.c b/key-bindings.c index fc083db4..fe4c8fe3 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -426,6 +426,7 @@ key_bindings_init(void) "bind -Tcopy-mode N send -X search-reverse", "bind -Tcopy-mode R send -X rectangle-toggle", "bind -Tcopy-mode T command-prompt -1p'(jump to backward)' 'send -X jump-to-backward \"%%%\"'", + "bind -Tcopy-mode X send -X set-mark", "bind -Tcopy-mode f command-prompt -1p'(jump forward)' 'send -X jump-forward \"%%%\"'", "bind -Tcopy-mode g command-prompt -p'(goto line)' 'send -X goto-line \"%%%\"'", "bind -Tcopy-mode n send -X search-again", @@ -467,6 +468,7 @@ key_bindings_init(void) "bind -Tcopy-mode M-r send -X middle-line", "bind -Tcopy-mode M-v send -X page-up", "bind -Tcopy-mode M-w send -X copy-pipe-and-cancel", + "bind -Tcopy-mode M-x send -X jump-to-mark", "bind -Tcopy-mode 'M-{' send -X previous-paragraph", "bind -Tcopy-mode 'M-}' send -X next-paragraph", "bind -Tcopy-mode M-Up send -X halfpage-up", @@ -521,6 +523,7 @@ key_bindings_init(void) "bind -Tcopy-mode-vi T command-prompt -1p'(jump to backward)' 'send -X jump-to-backward \"%%%\"'", "bind -Tcopy-mode-vi V send -X select-line", "bind -Tcopy-mode-vi W send -X next-space", + "bind -Tcopy-mode-vi X send -X set-mark", "bind -Tcopy-mode-vi ^ send -X back-to-indentation", "bind -Tcopy-mode-vi b send -X previous-word", "bind -Tcopy-mode-vi e send -X next-word-end", @@ -554,6 +557,7 @@ key_bindings_init(void) "bind -Tcopy-mode-vi Down send -X cursor-down", "bind -Tcopy-mode-vi Left send -X cursor-left", "bind -Tcopy-mode-vi Right send -X cursor-right", + "bind -Tcopy-mode-vi M-x send -X jump-to-mark", "bind -Tcopy-mode-vi C-Up send -X scroll-up", "bind -Tcopy-mode-vi C-Down send -X scroll-down", }; diff --git a/options-table.c b/options-table.c index c3a9f23b..39bb7d25 100644 --- a/options-table.c +++ b/options-table.c @@ -794,6 +794,15 @@ const struct options_table_entry options_table[] = { .text = "Style of the current search match in copy mode." }, + { .name = "copy-mode-mark-style", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_WINDOW, + .default_str = "bg=red,fg=black", + .flags = OPTIONS_TABLE_IS_STYLE, + .separator = ",", + .text = "Style of the marked line in copy mode." + }, + { .name = "main-pane-height", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_WINDOW, diff --git a/tmux.1 b/tmux.1 index b6ac248f..66922285 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1555,6 +1555,7 @@ The following commands are supported in copy mode: .It Li "jump-reverse" Ta "," Ta "," .It Li "jump-to-backward " Ta "T" Ta "" .It Li "jump-to-forward " Ta "t" Ta "" +.It Li "jump-to-mark" Ta "M-x" Ta "M-x" .It Li "middle-line" Ta "M" Ta "M-r" .It Li "next-matching-bracket" Ta "%" Ta "M-C-f" .It Li "next-paragraph" Ta "}" Ta "M-}" @@ -1585,6 +1586,7 @@ The following commands are supported in copy mode: .It Li "search-reverse" Ta "N" Ta "N" .It Li "select-line" Ta "V" Ta "" .It Li "select-word" Ta "" Ta "" +.It Li "set-mark" Ta "X" Ta "X" .It Li "start-of-line" Ta "0" Ta "C-a" .It Li "stop-selection" Ta "" Ta "" .It Li "top-line" Ta "H" Ta "M-R" @@ -3817,6 +3819,14 @@ see the .Sx STYLES section. .Pp +.It Ic copy-mode-mark-style Ar style +Set the style of the line containing the mark in copy mode. +For how to specify +.Ar style , +see the +.Sx STYLES +section. +.Pp .It Ic copy-mode-current-match-style Ar style Set the style of the current search match in copy mode. For how to specify diff --git a/window-copy.c b/window-copy.c index 95b4cc6e..e572eaa8 100644 --- a/window-copy.c +++ b/window-copy.c @@ -131,6 +131,7 @@ static void window_copy_rectangle_toggle(struct window_mode_entry *); static void window_copy_move_mouse(struct mouse_event *); static void window_copy_drag_update(struct client *, struct mouse_event *); static void window_copy_drag_release(struct client *, struct mouse_event *); +static void window_copy_jump_to_mark(struct window_mode_entry *); const struct window_mode window_copy_mode = { .name = "copy-mode", @@ -254,6 +255,10 @@ struct window_copy_mode_data { u_int lastcx; /* position in last line w/ content */ u_int lastsx; /* size of last line w/ content */ + u_int mx; /* mark position */ + u_int my; + int showmark; + int searchtype; int searchregex; char *searchstr; @@ -424,6 +429,9 @@ window_copy_init(struct window_mode_entry *wme, data->screen.cx = data->cx; data->screen.cy = data->cy; + data->mx = data->cx; + data->my = screen_hsize(data->backing) + data->cy - data->oy; + data->showmark = 0; screen_write_start(&ctx, &data->screen); for (i = 0; i < screen_size_y(&data->screen); i++) @@ -448,6 +456,9 @@ window_copy_view_init(struct window_mode_entry *wme, data->backing = s = xmalloc(sizeof *data->backing); screen_init(s, screen_size_x(base), screen_size_y(base), UINT_MAX); + data->mx = data->cx; + data->my = screen_hsize(data->backing) + data->cy - data->oy; + data->showmark = 0; return (&data->screen); } @@ -1733,6 +1744,17 @@ window_copy_cmd_select_word(struct window_copy_cmd_state *cs) return (WINDOW_COPY_CMD_REDRAW); } +static enum window_copy_cmd_action +window_copy_cmd_set_mark(struct window_copy_cmd_state *cs) +{ + struct window_copy_mode_data *data = cs->wme->data; + + data->mx = data->cx; + data->my = screen_hsize(data->backing) + data->cy - data->oy; + data->showmark = 1; + return (WINDOW_COPY_CMD_REDRAW); +} + static enum window_copy_cmd_action window_copy_cmd_start_of_line(struct window_copy_cmd_state *cs) { @@ -1877,6 +1899,15 @@ window_copy_cmd_jump_to_forward(struct window_copy_cmd_state *cs) return (WINDOW_COPY_CMD_NOTHING); } +static enum window_copy_cmd_action +window_copy_cmd_jump_to_mark(struct window_copy_cmd_state *cs) +{ + struct window_mode_entry *wme = cs->wme; + + window_copy_jump_to_mark(wme); + return (WINDOW_COPY_CMD_NOTHING); +} + static enum window_copy_cmd_action window_copy_cmd_search_backward(struct window_copy_cmd_state *cs) { @@ -2154,6 +2185,8 @@ static const struct { window_copy_cmd_jump_to_backward }, { "jump-to-forward", 1, 1, 1, window_copy_cmd_jump_to_forward }, + { "jump-to-mark", 0, 0, 0, + window_copy_cmd_jump_to_mark }, { "middle-line", 0, 0, 1, window_copy_cmd_middle_line }, { "next-matching-bracket", 0, 0, 0, @@ -2214,6 +2247,8 @@ static const struct { window_copy_cmd_select_line }, { "select-word", 0, 0, 0, window_copy_cmd_select_word }, + { "set-mark", 0, 0, 0, + window_copy_cmd_set_mark }, { "start-of-line", 0, 0, 1, window_copy_cmd_start_of_line }, { "stop-selection", 0, 0, 0, @@ -3129,11 +3164,26 @@ window_copy_match_at_cursor(struct window_copy_mode_data *data) static void window_copy_update_style(struct window_mode_entry *wme, u_int fx, u_int fy, struct grid_cell *gc, const struct grid_cell *mgc, - const struct grid_cell *cgc) + const struct grid_cell *cgc, const struct grid_cell *mkgc) { struct window_copy_mode_data *data = wme->data; u_int mark, start, end, cy, cursor, current; u_int sx = screen_size_x(data->backing); + int inv = 0; + + if (data->showmark && fy == data->my) { + gc->attr = mkgc->attr; + if (fx == data->mx) + inv = 1; + if (inv) { + gc->fg = mkgc->bg; + gc->bg = mkgc->fg; + } + else { + gc->fg = mkgc->fg; + gc->bg = mkgc->bg; + } + } if (data->searchmark == NULL) return; @@ -3150,21 +3200,34 @@ window_copy_update_style(struct window_mode_entry *wme, u_int fx, u_int fy, window_copy_match_start_end(data, cursor, &start, &end); if (current >= start && current <= end) { gc->attr = cgc->attr; - gc->fg = cgc->fg; - gc->bg = cgc->bg; + if (inv) { + gc->fg = cgc->bg; + gc->bg = cgc->fg; + } + else { + gc->fg = cgc->fg; + gc->bg = cgc->bg; + } return; } } gc->attr = mgc->attr; - gc->fg = mgc->fg; - gc->bg = mgc->bg; + if (inv) { + gc->fg = mgc->bg; + gc->bg = mgc->fg; + } + else { + gc->fg = mgc->fg; + gc->bg = mgc->bg; + } } static void window_copy_write_one(struct window_mode_entry *wme, struct screen_write_ctx *ctx, u_int py, u_int fy, u_int nx, - const struct grid_cell *mgc, const struct grid_cell *cgc) + const struct grid_cell *mgc, const struct grid_cell *cgc, + const struct grid_cell *mkgc) { struct window_copy_mode_data *data = wme->data; struct grid *gd = data->backing->grid; @@ -3175,7 +3238,8 @@ window_copy_write_one(struct window_mode_entry *wme, for (fx = 0; fx < nx; fx++) { grid_get_cell(gd, fx, fy, &gc); if (fx + gc.data.width <= nx) { - window_copy_update_style(wme, fx, fy, &gc, mgc, cgc); + window_copy_update_style(wme, fx, fy, &gc, mgc, cgc, + mkgc); screen_write_cell(ctx, &gc); } } @@ -3189,7 +3253,7 @@ window_copy_write_line(struct window_mode_entry *wme, struct window_copy_mode_data *data = wme->data; struct screen *s = &data->screen; struct options *oo = wp->window->options; - struct grid_cell gc, mgc, cgc; + struct grid_cell gc, mgc, cgc, mkgc; char hdr[512]; size_t size = 0; u_int hsize = screen_hsize(data->backing); @@ -3200,6 +3264,8 @@ window_copy_write_line(struct window_mode_entry *wme, mgc.flags |= GRID_FLAG_NOPALETTE; style_apply(&cgc, oo, "copy-mode-current-match-style", NULL); cgc.flags |= GRID_FLAG_NOPALETTE; + style_apply(&mkgc, oo, "copy-mode-mark-style", NULL); + mkgc.flags |= GRID_FLAG_NOPALETTE; if (py == 0 && s->rupper < s->rlower && !data->hide_position) { if (data->searchmark == NULL) { @@ -3233,7 +3299,7 @@ window_copy_write_line(struct window_mode_entry *wme, if (size < screen_size_x(s)) { window_copy_write_one(wme, ctx, py, hsize - data->oy + py, - screen_size_x(s) - size, &mgc, &cgc); + screen_size_x(s) - size, &mgc, &cgc, &mkgc); } if (py == data->cy && data->cx == screen_size_x(s)) { @@ -4687,3 +4753,26 @@ window_copy_drag_release(struct client *c, struct mouse_event *m) data = wme->data; evtimer_del(&data->dragtimer); } + +static void +window_copy_jump_to_mark(struct window_mode_entry *wme) +{ + struct window_copy_mode_data *data = wme->data; + u_int tmx, tmy; + + tmx = data->cx; + tmy = screen_hsize(data->backing) + data->cy - data->oy; + data->cx = data->mx; + if (data->my < screen_hsize(data->backing)) { + data->cy = 0; + data->oy = screen_hsize(data->backing) - data->my; + } else { + data->cy = data->my - screen_hsize(data->backing); + data->oy = 0; + } + data->mx = tmx; + data->my = tmy; + data->showmark = 1; + window_copy_update_selection(wme, 0, 0); + window_copy_redraw_screen(wme); +}