diff options
Diffstat (limited to 'window-copy.c')
-rw-r--r-- | window-copy.c | 361 |
1 files changed, 275 insertions, 86 deletions
diff --git a/window-copy.c b/window-copy.c index 2a47e9b0..9f84ade9 100644 --- a/window-copy.c +++ b/window-copy.c @@ -22,6 +22,7 @@ #include <regex.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include "tmux.h" @@ -205,6 +206,8 @@ struct window_copy_mode_data { struct screen *backing; int backing_written; /* backing display started */ + int viewmode; /* view mode entered */ + u_int oy; /* number of lines scrolled up */ u_int selx; /* beginning of selection */ @@ -254,12 +257,13 @@ struct window_copy_mode_data { int searchtype; int searchregex; char *searchstr; - bitstr_t *searchmark; + u_char *searchmark; u_int searchcount; int searchthis; int searchx; int searchy; int searcho; + u_char searchgen; int timeout; /* search has timed out */ #define WINDOW_COPY_SEARCH_TIMEOUT 10 @@ -295,6 +299,48 @@ window_copy_scroll_timer(__unused int fd, __unused short events, void *arg) } } +static struct screen * +window_copy_clone_screen(struct screen *src, struct screen *hint, u_int *cx, + u_int *cy, int trim) +{ + struct screen *dst; + u_int sy; + const struct grid_line *gl; + + dst = xcalloc(1, sizeof *dst); + + sy = screen_hsize(src) + screen_size_y(src); + if (trim) { + while (sy > screen_hsize(src)) { + gl = grid_peek_line(src->grid, sy - 1); + if (gl->cellused != 0) + break; + sy--; + } + } + log_debug("%s: target screen is %ux%u, source %ux%u", __func__, + screen_size_x(src), sy, screen_size_x(hint), + screen_hsize(src) + screen_size_y(src)); + screen_init(dst, screen_size_x(src), sy, screen_hlimit(src)); + grid_duplicate_lines(dst->grid, 0, src->grid, 0, sy); + + dst->grid->sy = sy - screen_hsize(src); + dst->grid->hsize = screen_hsize(src); + dst->grid->hscrolled = src->grid->hscrolled; + if (src->cy > dst->grid->sy - 1) { + dst->cx = 0; + dst->cy = dst->grid->sy - 1; + } else { + dst->cx = src->cx; + dst->cy = src->cy; + } + + screen_resize_cursor(dst, screen_size_x(hint), screen_size_y(hint), 1, + 0, cx, cy); + + return (dst); +} + static struct window_copy_mode_data * window_copy_common_init(struct window_mode_entry *wme) { @@ -317,9 +363,7 @@ window_copy_common_init(struct window_mode_entry *wme) data->searchregex = 0; data->searchstr = NULL; } - data->searchmark = NULL; data->searchx = data->searchy = data->searcho = -1; - data->timeout = 0; data->jumptype = WINDOW_COPY_OFF; data->jumpchar = '\0'; @@ -336,19 +380,25 @@ static struct screen * window_copy_init(struct window_mode_entry *wme, __unused struct cmd_find_state *fs, struct args *args) { - struct window_pane *wp = wme->wp; + struct window_pane *wp = wme->swp; struct window_copy_mode_data *data; + struct screen *base = &wp->base; struct screen_write_ctx ctx; - u_int i; + u_int i, cx, cy; data = window_copy_common_init(wme); + data->backing = window_copy_clone_screen(base, &data->screen, &cx, &cy, + wme->swp != wme->wp); - if (wp->fd != -1 && wp->disabled++ == 0) - bufferevent_disable(wp->event, EV_READ|EV_WRITE); - - data->backing = &wp->base; - data->cx = data->backing->cx; - data->cy = data->backing->cy; + if (cy < screen_hsize(data->backing)) { + data->cx = cx; + data->cy = 0; + data->oy = screen_hsize(data->backing) - cy; + } else { + data->cx = data->backing->cx; + data->cy = data->backing->cy; + data->oy = 0; + } data->scroll_exit = args_has(args, 'e'); data->hide_position = args_has(args, 'H'); @@ -356,7 +406,7 @@ window_copy_init(struct window_mode_entry *wme, data->screen.cx = data->cx; data->screen.cy = data->cy; - screen_write_start(&ctx, NULL, &data->screen); + screen_write_start(&ctx, &data->screen); for (i = 0; i < screen_size_y(&data->screen); i++) window_copy_write_line(wme, &ctx, i); screen_write_cursormove(&ctx, data->cx, data->cy, 0); @@ -375,6 +425,7 @@ window_copy_view_init(struct window_mode_entry *wme, struct screen *s; data = window_copy_common_init(wme); + data->viewmode = 1; data->backing = s = xmalloc(sizeof *data->backing); screen_init(s, screen_size_x(base), screen_size_y(base), UINT_MAX); @@ -385,23 +436,17 @@ window_copy_view_init(struct window_mode_entry *wme, static void window_copy_free(struct window_mode_entry *wme) { - struct window_pane *wp = wme->wp; struct window_copy_mode_data *data = wme->data; evtimer_del(&data->dragtimer); - if (wp->fd != -1 && --wp->disabled == 0) - bufferevent_enable(wp->event, EV_READ|EV_WRITE); - free(data->searchmark); free(data->searchstr); - if (data->backing != &wp->base) { - screen_free(data->backing); - free(data->backing); - } - screen_free(&data->screen); + screen_free(data->backing); + free(data->backing); + screen_free(&data->screen); free(data); } @@ -425,13 +470,10 @@ window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap) struct grid_cell gc; u_int old_hsize, old_cy; - if (backing == &wp->base) - return; - memcpy(&gc, &grid_default_cell, sizeof gc); old_hsize = screen_hsize(data->backing); - screen_write_start(&back_ctx, NULL, backing); + screen_write_start(&back_ctx, backing); if (data->backing_written) { /* * On the second or later line, do a CRLF before writing @@ -447,7 +489,7 @@ window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap) data->oy += screen_hsize(data->backing) - old_hsize; - screen_write_start(&ctx, wp, &data->screen); + screen_write_start_pane(&ctx, wp, &data->screen); /* * If the history has changed, draw the top line. @@ -661,31 +703,18 @@ window_copy_formats(struct window_mode_entry *wme, struct format_tree *ft) } static void -window_copy_resize(struct window_mode_entry *wme, u_int sx, u_int sy) +window_copy_size_changed(struct window_mode_entry *wme) { - struct window_pane *wp = wme->wp; struct window_copy_mode_data *data = wme->data; struct screen *s = &data->screen; - struct screen_write_ctx ctx; - int search; - - screen_resize(s, sx, sy, 1); - if (data->backing != &wp->base) - screen_resize(data->backing, sx, sy, 1); - - if (data->cy > sy - 1) - data->cy = sy - 1; - if (data->cx > sx) - data->cx = sx; - if (data->oy > screen_hsize(data->backing)) - data->oy = screen_hsize(data->backing); + struct screen_write_ctx ctx; + int search = (data->searchmark != NULL); - search = (data->searchmark != NULL); window_copy_clear_selection(wme); window_copy_clear_marks(wme); - screen_write_start(&ctx, NULL, s); - window_copy_write_lines(wme, &ctx, 0, screen_size_y(s) - 1); + screen_write_start(&ctx, s); + window_copy_write_lines(wme, &ctx, 0, screen_size_y(s)); screen_write_stop(&ctx); if (search && !data->timeout) @@ -693,7 +722,25 @@ window_copy_resize(struct window_mode_entry *wme, u_int sx, u_int sy) data->searchx = data->cx; data->searchy = data->cy; data->searcho = data->oy; +} + +static void +window_copy_resize(struct window_mode_entry *wme, u_int sx, u_int sy) +{ + struct window_copy_mode_data *data = wme->data; + struct screen *s = &data->screen; + + screen_resize(s, sx, sy, 0); + screen_resize_cursor(data->backing, sx, sy, 1, 0, NULL, NULL); + + if (data->cy > sy - 1) + data->cy = sy - 1; + if (data->cx > sx) + data->cx = sx; + if (data->oy > screen_hsize(data->backing)) + data->oy = screen_hsize(data->backing); + window_copy_size_changed(wme); window_copy_redraw_screen(wme); } @@ -1043,14 +1090,15 @@ window_copy_cmd_history_bottom(struct window_copy_cmd_state *cs) { struct window_mode_entry *wme = cs->wme; struct window_copy_mode_data *data = wme->data; + struct screen *s = data->backing; u_int oy; - oy = screen_hsize(data->backing) + data->cy - data->oy; + oy = screen_hsize(s) + data->cy - data->oy; if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely) window_copy_other_end(wme); data->cy = screen_size_y(&data->screen) - 1; - data->cx = window_copy_find_length(wme, data->cy); + data->cx = window_copy_find_length(wme, screen_hsize(s) + data->cy); data->oy = 0; if (data->searchmark != NULL && !data->timeout) @@ -1690,11 +1738,10 @@ window_copy_cmd_copy_pipe_no_clear(struct window_copy_cmd_state *cs) if (cs->args->argc == 3) prefix = format_single(NULL, cs->args->argv[2], c, s, wl, wp); - if (s != NULL && *cs->args->argv[1] != '\0') { + if (s != NULL && cs->args->argc > 1 && *cs->args->argv[1] != '\0') command = format_single(NULL, cs->args->argv[1], c, s, wl, wp); - window_copy_copy_pipe(wme, s, prefix, command); - free(command); - } + window_copy_copy_pipe(wme, s, prefix, command); + free(command); free(prefix); return (WINDOW_COPY_CMD_NOTHING); @@ -1984,6 +2031,25 @@ window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state *cs) return (action); } +static enum window_copy_cmd_action +window_copy_cmd_refresh_from_pane(struct window_copy_cmd_state *cs) +{ + struct window_mode_entry *wme = cs->wme; + struct window_pane *wp = wme->swp; + struct window_copy_mode_data *data = wme->data; + + if (data->viewmode) + return (WINDOW_COPY_CMD_NOTHING); + + screen_free(data->backing); + free(data->backing); + data->backing = window_copy_clone_screen(&wp->base, &data->screen, NULL, + NULL, wme->swp != wme->wp); + + window_copy_size_changed(wme); + return (WINDOW_COPY_CMD_REDRAW); +} + static const struct { const char *command; int minargs; @@ -2009,11 +2075,11 @@ static const struct { window_copy_cmd_copy_end_of_line }, { "copy-line", 0, 1, 0, window_copy_cmd_copy_line }, - { "copy-pipe-no-clear", 1, 2, 0, + { "copy-pipe-no-clear", 0, 2, 0, window_copy_cmd_copy_pipe_no_clear }, - { "copy-pipe", 1, 2, 0, + { "copy-pipe", 0, 2, 0, window_copy_cmd_copy_pipe }, - { "copy-pipe-and-cancel", 1, 2, 0, + { "copy-pipe-and-cancel", 0, 2, 0, window_copy_cmd_copy_pipe_and_cancel }, { "copy-selection-no-clear", 0, 1, 0, window_copy_cmd_copy_selection_no_clear }, @@ -2089,6 +2155,8 @@ static const struct { window_copy_cmd_previous_word }, { "rectangle-toggle", 0, 0, 0, window_copy_cmd_rectangle_toggle }, + { "refresh-from-pane", 0, 0, 0, + window_copy_cmd_refresh_from_pane }, { "scroll-down", 0, 0, 1, window_copy_cmd_scroll_down }, { "scroll-down-and-cancel", 0, 0, 0, @@ -2754,7 +2822,7 @@ window_copy_search(struct window_mode_entry *wme, int direction, int regex) fy = screen_hsize(data->backing) - data->oy + data->cy; screen_init(&ss, screen_write_strlen("%s", str), 1, 0); - screen_write_start(&ctx, NULL, &ss); + screen_write_start(&ctx, &ss); screen_write_nputs(&ctx, -1, &grid_default_cell, "%s", str); screen_write_stop(&ctx); @@ -2790,7 +2858,7 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp, const struct grid_line *gl; int found, cis, which = -1; int cflags = REG_EXTENDED; - u_int px, py, b, nfound = 0, width; + u_int px, py, i, b, nfound = 0, width; u_int ssize = 1; char *sbuf; regex_t reg; @@ -2799,7 +2867,7 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp, if (ssp == NULL) { width = screen_write_strlen("%s", data->searchstr); screen_init(&ss, width, 1, 0); - screen_write_start(&ctx, NULL, &ss); + screen_write_start(&ctx, &ss); screen_write_nputs(&ctx, -1, &grid_default_cell, "%s", data->searchstr); screen_write_stop(&ctx); @@ -2810,7 +2878,8 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp, cis = window_copy_is_lowercase(data->searchstr); free(data->searchmark); - data->searchmark = bit_alloc((gd->hsize + gd->sy) * gd->sx); + data->searchmark = xcalloc(gd->hsize + gd->sy, gd->sx); + data->searchgen = 1; if (regex) { sbuf = xmalloc(ssize); @@ -2851,7 +2920,12 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp, which = nfound; b = (py * gd->sx) + px; - bit_nset(data->searchmark, b, b + width - 1); + for (i = b; i < b + width; i++) + data->searchmark[i] = data->searchgen; + if (data->searchgen == UCHAR_MAX) + data->searchgen = 1; + else + data->searchgen++; px++; } @@ -2922,6 +2996,114 @@ window_copy_goto_line(struct window_mode_entry *wme, const char *linestr) } static void +window_copy_match_start_end(struct window_copy_mode_data *data, u_int at, + u_int *start, u_int *end) +{ + struct grid *gd = data->backing->grid; + u_int last = (gd->hsize + gd->sy) * gd->sx - 1; + u_char mark = data->searchmark[at]; + + *start = *end = at; + while (*start != 0 && data->searchmark[*start] == mark) + (*start)--; + if (data->searchmark[*start] != mark) + (*start)++; + while (*end != last && data->searchmark[*end] == mark) + (*end)++; + if (data->searchmark[*end] != mark) + (*end)--; +} + +static char * +window_copy_match_at_cursor(struct window_copy_mode_data *data) +{ + struct grid *gd = data->backing->grid; + struct grid_cell gc; + u_int at, start, end, cy, px, py; + u_int sx = screen_size_x(data->backing); + char *buf = NULL; + size_t len = 0; + + if (data->searchmark == NULL) + return (NULL); + + cy = screen_hsize(data->backing) - data->oy + data->cy; + at = (cy * sx) + data->cx; + if (data->searchmark[at] == 0) + return (NULL); + window_copy_match_start_end(data, at, &start, &end); + + /* + * Cells will not be set in the marked array unless they are valid text + * and wrapping will be taken care of, so we can just copy. + */ + for (at = start; at <= end; at++) { + py = at / sx; + px = at % (py * sx); + + grid_get_cell(gd, px, py, &gc); + buf = xrealloc(buf, len + gc.data.size + 1); + memcpy(buf + len, gc.data.data, gc.data.size); + len += gc.data.size; + } + if (len != 0) + buf[len] = '\0'; + return (buf); +} + +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) +{ + struct window_copy_mode_data *data = wme->data; + u_int mark, at, start, end, cy; + u_int sx = screen_size_x(data->backing); + + if (data->searchmark == NULL) + return; + mark = data->searchmark[(fy * sx) + fx]; + if (mark == 0) + return; + + cy = screen_hsize(data->backing) - data->oy + data->cy; + at = (cy * sx) + data->cx; + if (data->searchmark[at] == mark) { + window_copy_match_start_end(data, at, &start, &end); + if (at >= start && at <= end) { + gc->attr = cgc->attr; + gc->fg = cgc->fg; + gc->bg = cgc->bg; + } + return; + } + + gc->attr = mgc->attr; + 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) +{ + struct window_copy_mode_data *data = wme->data; + struct grid *gd = data->backing->grid; + struct grid_cell gc; + u_int fx; + + screen_write_cursormove(ctx, 0, py, 0); + 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); + screen_write_cell(ctx, &gc); + } + } +} + +static void window_copy_write_line(struct window_mode_entry *wme, struct screen_write_ctx *ctx, u_int py) { @@ -2929,34 +3111,36 @@ 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; + struct grid_cell gc, mgc, cgc; char hdr[512]; size_t size = 0; + u_int hsize = screen_hsize(data->backing); - style_apply(&gc, oo, "mode-style"); + style_apply(&gc, oo, "mode-style", NULL); gc.flags |= GRID_FLAG_NOPALETTE; + style_apply(&mgc, oo, "copy-mode-match-style", NULL); + mgc.flags |= GRID_FLAG_NOPALETTE; + style_apply(&cgc, oo, "copy-mode-current-match-style", NULL); + cgc.flags |= GRID_FLAG_NOPALETTE; if (py == 0 && s->rupper < s->rlower && !data->hide_position) { if (data->searchmark == NULL) { if (data->timeout) { size = xsnprintf(hdr, sizeof hdr, - "(timed out) [%u/%u]", data->oy, - screen_hsize(data->backing)); + "(timed out) [%u/%u]", data->oy, hsize); } else { size = xsnprintf(hdr, sizeof hdr, - "[%u/%u]", data->oy, - screen_hsize(data->backing)); + "[%u/%u]", data->oy, hsize); } } else { if (data->searchthis == -1) { size = xsnprintf(hdr, sizeof hdr, "(%u results) [%d/%u]", data->searchcount, - data->oy, screen_hsize(data->backing)); + data->oy, hsize); } else { size = xsnprintf(hdr, sizeof hdr, "(%u/%u results) [%d/%u]", data->searchthis, - data->searchcount, data->oy, - screen_hsize(data->backing)); + data->searchcount, data->oy, hsize); } } if (size > screen_size_x(s)) @@ -2967,16 +3151,13 @@ window_copy_write_line(struct window_mode_entry *wme, size = 0; if (size < screen_size_x(s)) { - screen_write_cursormove(ctx, 0, py, 0); - screen_write_copy(ctx, data->backing, 0, - (screen_hsize(data->backing) - data->oy) + py, - screen_size_x(s) - size, 1, data->searchmark, &gc); + window_copy_write_one(wme, ctx, py, hsize - data->oy + py, + screen_size_x(s) - size, &mgc, &cgc); } if (py == data->cy && data->cx == screen_size_x(s)) { - memcpy(&gc, &grid_default_cell, sizeof gc); screen_write_cursormove(ctx, screen_size_x(s) - 1, py, 0); - screen_write_putc(ctx, &gc, '$'); + screen_write_putc(ctx, &grid_default_cell, '$'); } } @@ -3026,7 +3207,7 @@ window_copy_redraw_lines(struct window_mode_entry *wme, u_int py, u_int ny) struct screen_write_ctx ctx; u_int i; - screen_write_start(&ctx, wp, NULL); + screen_write_start_pane(&ctx, wp, NULL); for (i = py; i < py + ny; i++) window_copy_write_line(wme, &ctx, i); screen_write_cursormove(&ctx, data->cx, data->cy, 0); @@ -3145,7 +3326,7 @@ window_copy_update_cursor(struct window_mode_entry *wme, u_int cx, u_int cy) if (data->cx == screen_size_x(s)) window_copy_redraw_lines(wme, data->cy, 1); else { - screen_write_start(&ctx, wp, NULL); + screen_write_start_pane(&ctx, wp, NULL); screen_write_cursormove(&ctx, data->cx, data->cy, 0); screen_write_stop(&ctx); } @@ -3244,7 +3425,7 @@ window_copy_set_selection(struct window_mode_entry *wme, int may_redraw, } /* Set colours and selection. */ - style_apply(&gc, oo, "mode-style"); + style_apply(&gc, oo, "mode-style", NULL); gc.flags |= GRID_FLAG_NOPALETTE; screen_set_selection(s, sx, sy, endsx, endsy, data->rectflag, data->modekeys, &gc); @@ -3287,8 +3468,12 @@ window_copy_get_selection(struct window_mode_entry *wme, size_t *len) u_int firstsx, lastex, restex, restsx, selx; int keys; - if (data->screen.sel == NULL && data->lineflag == LINE_SEL_NONE) - return (NULL); + if (data->screen.sel == NULL && data->lineflag == LINE_SEL_NONE) { + buf = window_copy_match_at_cursor(data); + if (buf != NULL) + *len = strlen(buf); + return (buf); + } buf = xmalloc(1); off = 0; @@ -3394,7 +3579,7 @@ window_copy_copy_buffer(struct window_mode_entry *wme, const char *prefix, struct screen_write_ctx ctx; if (options_get_number(global_options, "set-clipboard") != 0) { - screen_write_start(&ctx, wp, NULL); + screen_write_start_pane(&ctx, wp, NULL); screen_write_setselection(&ctx, buf, len); screen_write_stop(&ctx); notify_pane("pane-set-clipboard", wp); @@ -3415,8 +3600,13 @@ window_copy_copy_pipe(struct window_mode_entry *wme, struct session *s, if (buf == NULL) return; - job = job_run(cmd, s, NULL, NULL, NULL, NULL, NULL, JOB_NOWAIT); - bufferevent_write(job_get_event(job), buf, len); + if (cmd == NULL || *cmd == '\0') + cmd = options_get_string(global_options, "copy-command"); + if (cmd != NULL && *cmd != '\0') { + job = job_run(cmd, s, NULL, NULL, NULL, NULL, NULL, JOB_NOWAIT, + -1, -1); + bufferevent_write(job_get_event(job), buf, len); + } window_copy_copy_buffer(wme, prefix, buf, len); } @@ -3446,7 +3636,7 @@ window_copy_append_selection(struct window_mode_entry *wme) return; if (options_get_number(global_options, "set-clipboard") != 0) { - screen_write_start(&ctx, wp, NULL); + screen_write_start_pane(&ctx, wp, NULL); screen_write_setselection(&ctx, buf, len); screen_write_stop(&ctx); notify_pane("pane-set-clipboard", wp); @@ -4120,7 +4310,6 @@ window_copy_cursor_previous_word_pos(struct window_mode_entry *wme, data->oy >= screen_hsize(data->backing) - 1)) goto out; - py--; py = screen_hsize(data->backing) + data->cy - data->oy; @@ -4210,7 +4399,7 @@ window_copy_scroll_up(struct window_mode_entry *wme, u_int ny) window_copy_search_marks(wme, NULL, data->searchregex); window_copy_update_selection(wme, 0, 0); - screen_write_start(&ctx, wp, NULL); + screen_write_start_pane(&ctx, wp, NULL); screen_write_cursormove(&ctx, 0, 0, 0); screen_write_deleteline(&ctx, ny, 8); window_copy_write_lines(wme, &ctx, screen_size_y(s) - ny, ny); @@ -4246,7 +4435,7 @@ window_copy_scroll_down(struct window_mode_entry *wme, u_int ny) window_copy_search_marks(wme, NULL, data->searchregex); window_copy_update_selection(wme, 0, 0); - screen_write_start(&ctx, wp, NULL); + screen_write_start_pane(&ctx, wp, NULL); screen_write_cursormove(&ctx, 0, 0, 0); screen_write_insertline(&ctx, ny, 8); window_copy_write_lines(wme, &ctx, 0, ny); @@ -4329,7 +4518,7 @@ window_copy_start_drag(struct client *c, struct mouse_event *m) data->selflag = SEL_CHAR; switch (data->selflag) { case SEL_WORD: - if (data->ws) { + if (data->ws != NULL) { window_copy_update_cursor(wme, x, y); window_copy_cursor_previous_word_pos(wme, data->ws, 0, &x, &y); |