diff --git a/options-table.c b/options-table.c index 0781da46..e04002ff 100644 --- a/options-table.c +++ b/options-table.c @@ -655,6 +655,22 @@ const struct options_table_entry options_table[] = { .default_num = 1 }, + { .name = "copy-mode-match-style", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_WINDOW, + .default_str = "bg=cyan,fg=black", + .flags = OPTIONS_TABLE_IS_STYLE, + .separator = "," + }, + + { .name = "copy-mode-current-match-style", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_WINDOW, + .default_str = "bg=magenta,fg=black", + .flags = OPTIONS_TABLE_IS_STYLE, + .separator = "," + }, + { .name = "main-pane-height", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_WINDOW, diff --git a/screen-write.c b/screen-write.c index afa1e96a..e3e51020 100644 --- a/screen-write.c +++ b/screen-write.c @@ -344,44 +344,9 @@ screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen, free(msg); } -/* Copy from another screen. Assumes target region is big enough. */ -void -screen_write_copy(struct screen_write_ctx *ctx, struct screen *src, u_int px, - u_int py, u_int nx, u_int ny, bitstr_t *mbs, const struct grid_cell *mgc) -{ - struct screen *s = ctx->s; - struct grid *gd = src->grid; - struct grid_cell gc; - u_int xx, yy, cx, cy, b; - - if (nx == 0 || ny == 0) - return; - - cx = s->cx; - cy = s->cy; - - for (yy = py; yy < py + ny; yy++) { - for (xx = px; xx < px + nx; xx++) { - grid_get_cell(gd, xx, yy, &gc); - if (mbs != NULL) { - b = (yy * screen_size_x(src)) + xx; - if (bit_test(mbs, b)) { - gc.attr = mgc->attr; - gc.fg = mgc->fg; - gc.bg = mgc->bg; - } - } - if (xx + gc.data.width <= px + nx) - screen_write_cell(ctx, &gc); - } - cy++; - screen_write_set_cursor(ctx, cx, cy); - } -} - /* - * Copy from another screen but without the selection stuff. Also assumes the - * target region is already big enough. + * Copy from another screen but without the selection stuff. Assumes the target + * region is already big enough. */ void screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src, diff --git a/tmux.1 b/tmux.1 index a3a05878..c85e7e39 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3717,6 +3717,22 @@ If suffixed by .Ql % , this is a percentage of the window size. .Pp +.It Ic copy-mode-match-style Ar style +Set the style of search matches 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 +.Ar style , +see the +.Sx STYLES +section. +.Pp .It Xo Ic mode-keys .Op Ic vi | emacs .Xc diff --git a/tmux.h b/tmux.h index d3cc1a53..c9c8637c 100644 --- a/tmux.h +++ b/tmux.h @@ -2436,8 +2436,6 @@ void screen_write_vnputs(struct screen_write_ctx *, ssize_t, const struct grid_cell *, const char *, va_list); void screen_write_putc(struct screen_write_ctx *, const struct grid_cell *, u_char); -void screen_write_copy(struct screen_write_ctx *, struct screen *, u_int, - u_int, u_int, u_int, bitstr_t *, const struct grid_cell *); void screen_write_fast_copy(struct screen_write_ctx *, struct screen *, u_int, u_int, u_int, u_int); void screen_write_hline(struct screen_write_ctx *, u_int, int, int); diff --git a/window-copy.c b/window-copy.c index 2c50a1cd..f5a07a10 100644 --- a/window-copy.c +++ b/window-copy.c @@ -257,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 @@ -362,10 +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->viewmode = 0; data->jumptype = WINDOW_COPY_OFF; data->jumpchar = '\0'; @@ -2860,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; @@ -2880,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); @@ -2921,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++; } @@ -2991,6 +2995,114 @@ window_copy_goto_line(struct window_mode_entry *wme, const char *linestr) window_copy_redraw_screen(wme); } +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) @@ -2999,13 +3111,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", 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) { @@ -3035,15 +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, 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, '$'); } } @@ -3354,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;