diff options
Diffstat (limited to 'window-copy.c')
-rw-r--r-- | window-copy.c | 348 |
1 files changed, 274 insertions, 74 deletions
diff --git a/window-copy.c b/window-copy.c index 2bda5d56..95b4cc6e 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" @@ -256,15 +257,18 @@ struct window_copy_mode_data { int searchtype; int searchregex; char *searchstr; - bitstr_t *searchmark; - u_int searchcount; + u_char *searchmark; + int searchcount; + int searchmore; int searchthis; int searchx; int searchy; int searcho; + u_char searchgen; int timeout; /* search has timed out */ -#define WINDOW_COPY_SEARCH_TIMEOUT 10 +#define WINDOW_COPY_SEARCH_TIMEOUT 10000 +#define WINDOW_COPY_SEARCH_ALL_TIMEOUT 200 int jumptype; char jumpchar; @@ -302,8 +306,9 @@ 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; + u_int sy, wx, wy; + int reflow; dst = xcalloc(1, sizeof *dst); @@ -320,6 +325,12 @@ window_copy_clone_screen(struct screen *src, struct screen *hint, u_int *cx, 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)); + + /* + * Ensure history is on for the backing grid so lines are not deleted + * during resizing. + */ + dst->grid->flags |= GRID_HISTORY; grid_duplicate_lines(dst->grid, 0, src->grid, 0, sy); dst->grid->sy = sy - screen_hsize(src); @@ -333,8 +344,19 @@ window_copy_clone_screen(struct screen *src, struct screen *hint, u_int *cx, dst->cy = src->cy; } + if (cx != NULL && cy != NULL) { + *cx = dst->cx; + *cy = screen_hsize(dst) + dst->cy; + reflow = (screen_size_x(hint) != screen_size_x(dst)); + } + else + reflow = 0; + if (reflow) + grid_wrap_position(dst->grid, *cx, *cy, &wx, &wy); screen_resize_cursor(dst, screen_size_x(hint), screen_size_y(hint), 1, - 0, cx, cy); + 0, 0); + if (reflow) + grid_unwrap_position(dst->grid, cx, cy, wx, wy); return (dst); } @@ -361,10 +383,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->viewmode = 0; data->jumptype = WINDOW_COPY_OFF; data->jumpchar = '\0'; @@ -391,13 +410,12 @@ window_copy_init(struct window_mode_entry *wme, data->backing = window_copy_clone_screen(base, &data->screen, &cx, &cy, wme->swp != wme->wp); + data->cx = cx; 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->cy = cy - screen_hsize(data->backing); data->oy = 0; } @@ -407,7 +425,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); @@ -474,7 +492,7 @@ window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap) 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 @@ -490,7 +508,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. @@ -714,7 +732,7 @@ window_copy_size_changed(struct window_mode_entry *wme) window_copy_clear_selection(wme); window_copy_clear_marks(wme); - screen_write_start(&ctx, NULL, s); + screen_write_start(&ctx, s); window_copy_write_lines(wme, &ctx, 0, screen_size_y(s)); screen_write_stop(&ctx); @@ -730,16 +748,28 @@ 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; + struct grid *gd = data->backing->grid; + u_int cx, cy, wx, wy; + int reflow; 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); + cx = data->cx; + cy = gd->hsize + data->cy - data->oy; + reflow = (gd->sx != sx); + if (reflow) + grid_wrap_position(gd, cx, cy, &wx, &wy); + screen_resize_cursor(data->backing, sx, sy, 1, 0, 0); + if (reflow) + grid_unwrap_position(gd, &cx, &cy, wx, wy); + + data->cx = cx; + if (cy < gd->hsize) { + data->cy = 0; + data->oy = gd->hsize - cy; + } else { + data->cy = cy - gd->hsize; + data->oy = 0; + } window_copy_size_changed(wme); window_copy_redraw_screen(wme); @@ -1335,9 +1365,9 @@ window_copy_cmd_next_matching_bracket(struct window_copy_cmd_state *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) + if (gc.data.size == 1 && + (~gc.flags & GRID_FLAG_PADDING) && + strchr(close, *gc.data.data) != NULL) window_copy_scroll_to(wme, sx, sy); break; } @@ -2415,7 +2445,8 @@ window_copy_search_lr_regex(struct grid *gd, u_int *ppx, u_int *psx, u_int py, len += gd->sx; } - if (regexec(reg, buf, 1, ®match, eflags) == 0) { + if (regexec(reg, buf, 1, ®match, eflags) == 0 && + regmatch.rm_so != regmatch.rm_eo) { foundx = first; foundy = py; window_copy_cstrtocellpos(gd, len, &foundx, &foundy, @@ -2517,6 +2548,8 @@ window_copy_last_regex(struct grid *gd, u_int py, u_int first, u_int last, foundy = py; oldx = first; while (regexec(preg, buf + px, 1, ®match, eflags) == 0) { + if (regmatch.rm_so == regmatch.rm_eo) + break; window_copy_cstrtocellpos(gd, len, &foundx, &foundy, buf + px + regmatch.rm_so); if (foundy > py || foundx >= last) @@ -2823,7 +2856,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); @@ -2848,6 +2881,15 @@ window_copy_search(struct window_mode_entry *wme, int direction, int regex) return (found); } +static uint64_t +window_copy_get_time(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + return ((tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000ULL)); +} + static int window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp, int regex) @@ -2857,18 +2899,18 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp, struct screen_write_ctx ctx; struct grid *gd = s->grid; const struct grid_line *gl; - int found, cis, which = -1; + int found, cis, which = -1, stopped = 0; int cflags = REG_EXTENDED; - u_int px, py, b, nfound = 0, width; - u_int ssize = 1; + u_int px, py, i, b, nfound = 0, width; + u_int ssize = 1, start, end; char *sbuf; regex_t reg; - time_t tstart, t; + uint64_t stop = 0, tstart, t; 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); @@ -2878,9 +2920,6 @@ 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); - if (regex) { sbuf = xmalloc(ssize); sbuf[0] = '\0'; @@ -2893,13 +2932,18 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp, return (0); } } - time(&tstart); - for (py = gd->hsize - data->oy; py > 0; py--) { - gl = grid_peek_line(gd, py - 1); - if (~gl->flags & GRID_LINE_WRAPPED) - break; - } - for (; py < gd->hsize - data->oy + gd->sy; py++) { + tstart = window_copy_get_time(); + + start = 0; + end = gd->hsize + gd->sy; + stop = window_copy_get_time() + WINDOW_COPY_SEARCH_ALL_TIMEOUT; + +again: + free(data->searchmark); + data->searchmark = xcalloc(gd->hsize + gd->sy, gd->sx); + data->searchgen = 1; + + for (py = start; py < end; py++) { px = 0; for (;;) { if (regex) { @@ -2920,34 +2964,70 @@ 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++; } - time(&t); + t = window_copy_get_time(); if (t - tstart > WINDOW_COPY_SEARCH_TIMEOUT) { data->timeout = 1; break; } - } - if (regex) { - free(sbuf); - regfree(®); + if (stop != 0 && t > stop) { + stopped = 1; + break; + } } if (data->timeout) { window_copy_clear_marks(wme); - return (1); + goto out; } - if (which != -1) - data->searchthis = 1 + nfound - which; - else + if (stopped && stop != 0) { + /* Try again but just the visible context. */ + for (start = gd->hsize - data->oy; start > 0; start--) { + gl = grid_peek_line(gd, start - 1); + if (~gl->flags & GRID_LINE_WRAPPED) + break; + } + end = gd->hsize - data->oy + gd->sy; + stop = 0; + goto again; + } + + if (stopped) { data->searchthis = -1; - data->searchcount = nfound; + if (nfound > 1000) + data->searchcount = 1000; + else if (nfound > 100) + data->searchcount = 100; + else if (nfound > 10) + data->searchcount = 10; + else + data->searchcount = -1; + data->searchmore = 1; + } else { + if (which != -1) + data->searchthis = 1 + nfound - which; + else + data->searchthis = -1; + data->searchcount = nfound; + data->searchmore = 0; + } +out: if (ssp == &ss) screen_free(&ss); + if (regex) { + free(sbuf); + regfree(®); + } return (1); } @@ -2991,6 +3071,117 @@ 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, start, end, cy, cursor, current; + u_int sx = screen_size_x(data->backing); + + if (data->searchmark == NULL) + return; + + current = (fy * sx) + fx; + + mark = data->searchmark[current]; + if (mark == 0) + return; + + cy = screen_hsize(data->backing) - data->oy + data->cy; + cursor = (cy * sx) + data->cx; + if (data->searchmark[cursor] == mark) { + 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; + 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) { @@ -2998,13 +3189,17 @@ 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) { @@ -3016,13 +3211,16 @@ window_copy_write_line(struct window_mode_entry *wme, "[%u/%u]", data->oy, hsize); } } else { - if (data->searchthis == -1) { + if (data->searchcount == -1) { + size = xsnprintf(hdr, sizeof hdr, + "[%u/%u]", data->oy, hsize); + } else if (data->searchthis == -1) { size = xsnprintf(hdr, sizeof hdr, - "(%u results) [%d/%u]", data->searchcount, - data->oy, hsize); + "(%d%s results) [%u/%u]", data->searchcount, + data->searchmore ? "+" : "", data->oy, hsize); } else { size = xsnprintf(hdr, sizeof hdr, - "(%u/%u results) [%d/%u]", data->searchthis, + "(%d/%d results) [%u/%u]", data->searchthis, data->searchcount, data->oy, hsize); } } @@ -3034,15 +3232,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, hsize - 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, '$'); } } @@ -3092,7 +3288,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); @@ -3211,7 +3407,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); } @@ -3310,7 +3506,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); @@ -3353,8 +3549,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; @@ -3460,7 +3660,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); @@ -3517,7 +3717,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); @@ -4280,7 +4480,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); @@ -4316,7 +4516,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); |