mirror of
https://github.com/tmux/tmux.git
synced 2024-10-31 22:58:49 +00:00
Copy mode search improvements:
- Add styles for the search marking styles (copy-mode-match-style and copy-mode-current-match-style). - Show the current match (the one with the cursor on it) in a different style. - Copying without a selection will copy the current match if there is one.
This commit is contained in:
parent
80e52545a0
commit
2391fe23ab
@ -656,6 +656,22 @@ const struct options_table_entry options_table[] = {
|
|||||||
.default_num = 1
|
.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",
|
{ .name = "main-pane-height",
|
||||||
.type = OPTIONS_TABLE_STRING,
|
.type = OPTIONS_TABLE_STRING,
|
||||||
.scope = OPTIONS_TABLE_WINDOW,
|
.scope = OPTIONS_TABLE_WINDOW,
|
||||||
|
@ -344,44 +344,9 @@ screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
|
|||||||
free(msg);
|
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
|
* Copy from another screen but without the selection stuff. Assumes the target
|
||||||
* target region is already big enough.
|
* region is already big enough.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src,
|
screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src,
|
||||||
|
16
tmux.1
16
tmux.1
@ -3717,6 +3717,22 @@ If suffixed by
|
|||||||
.Ql % ,
|
.Ql % ,
|
||||||
this is a percentage of the window size.
|
this is a percentage of the window size.
|
||||||
.Pp
|
.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
|
.It Xo Ic mode-keys
|
||||||
.Op Ic vi | emacs
|
.Op Ic vi | emacs
|
||||||
.Xc
|
.Xc
|
||||||
|
2
tmux.h
2
tmux.h
@ -2434,8 +2434,6 @@ void screen_write_vnputs(struct screen_write_ctx *, ssize_t,
|
|||||||
const struct grid_cell *, const char *, va_list);
|
const struct grid_cell *, const char *, va_list);
|
||||||
void screen_write_putc(struct screen_write_ctx *, const struct grid_cell *,
|
void screen_write_putc(struct screen_write_ctx *, const struct grid_cell *,
|
||||||
u_char);
|
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 *,
|
void screen_write_fast_copy(struct screen_write_ctx *, struct screen *,
|
||||||
u_int, u_int, u_int, u_int);
|
u_int, u_int, u_int, u_int);
|
||||||
void screen_write_hline(struct screen_write_ctx *, u_int, int, int);
|
void screen_write_hline(struct screen_write_ctx *, u_int, int, int);
|
||||||
|
148
window-copy.c
148
window-copy.c
@ -257,12 +257,13 @@ struct window_copy_mode_data {
|
|||||||
int searchtype;
|
int searchtype;
|
||||||
int searchregex;
|
int searchregex;
|
||||||
char *searchstr;
|
char *searchstr;
|
||||||
bitstr_t *searchmark;
|
u_char *searchmark;
|
||||||
u_int searchcount;
|
u_int searchcount;
|
||||||
int searchthis;
|
int searchthis;
|
||||||
int searchx;
|
int searchx;
|
||||||
int searchy;
|
int searchy;
|
||||||
int searcho;
|
int searcho;
|
||||||
|
u_char searchgen;
|
||||||
|
|
||||||
int timeout; /* search has timed out */
|
int timeout; /* search has timed out */
|
||||||
#define WINDOW_COPY_SEARCH_TIMEOUT 10
|
#define WINDOW_COPY_SEARCH_TIMEOUT 10
|
||||||
@ -362,10 +363,7 @@ window_copy_common_init(struct window_mode_entry *wme)
|
|||||||
data->searchregex = 0;
|
data->searchregex = 0;
|
||||||
data->searchstr = NULL;
|
data->searchstr = NULL;
|
||||||
}
|
}
|
||||||
data->searchmark = NULL;
|
|
||||||
data->searchx = data->searchy = data->searcho = -1;
|
data->searchx = data->searchy = data->searcho = -1;
|
||||||
data->timeout = 0;
|
|
||||||
data->viewmode = 0;
|
|
||||||
|
|
||||||
data->jumptype = WINDOW_COPY_OFF;
|
data->jumptype = WINDOW_COPY_OFF;
|
||||||
data->jumpchar = '\0';
|
data->jumpchar = '\0';
|
||||||
@ -2860,7 +2858,7 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp,
|
|||||||
const struct grid_line *gl;
|
const struct grid_line *gl;
|
||||||
int found, cis, which = -1;
|
int found, cis, which = -1;
|
||||||
int cflags = REG_EXTENDED;
|
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;
|
u_int ssize = 1;
|
||||||
char *sbuf;
|
char *sbuf;
|
||||||
regex_t reg;
|
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);
|
cis = window_copy_is_lowercase(data->searchstr);
|
||||||
|
|
||||||
free(data->searchmark);
|
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) {
|
if (regex) {
|
||||||
sbuf = xmalloc(ssize);
|
sbuf = xmalloc(ssize);
|
||||||
@ -2921,7 +2920,12 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp,
|
|||||||
which = nfound;
|
which = nfound;
|
||||||
|
|
||||||
b = (py * gd->sx) + px;
|
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++;
|
px++;
|
||||||
}
|
}
|
||||||
@ -2991,6 +2995,114 @@ window_copy_goto_line(struct window_mode_entry *wme, const char *linestr)
|
|||||||
window_copy_redraw_screen(wme);
|
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
|
static void
|
||||||
window_copy_write_line(struct window_mode_entry *wme,
|
window_copy_write_line(struct window_mode_entry *wme,
|
||||||
struct screen_write_ctx *ctx, u_int py)
|
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 window_copy_mode_data *data = wme->data;
|
||||||
struct screen *s = &data->screen;
|
struct screen *s = &data->screen;
|
||||||
struct options *oo = wp->window->options;
|
struct options *oo = wp->window->options;
|
||||||
struct grid_cell gc;
|
struct grid_cell gc, mgc, cgc;
|
||||||
char hdr[512];
|
char hdr[512];
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
u_int hsize = screen_hsize(data->backing);
|
u_int hsize = screen_hsize(data->backing);
|
||||||
|
|
||||||
style_apply(&gc, oo, "mode-style", NULL);
|
style_apply(&gc, oo, "mode-style", NULL);
|
||||||
gc.flags |= GRID_FLAG_NOPALETTE;
|
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 (py == 0 && s->rupper < s->rlower && !data->hide_position) {
|
||||||
if (data->searchmark == NULL) {
|
if (data->searchmark == NULL) {
|
||||||
@ -3035,15 +3151,13 @@ window_copy_write_line(struct window_mode_entry *wme,
|
|||||||
size = 0;
|
size = 0;
|
||||||
|
|
||||||
if (size < screen_size_x(s)) {
|
if (size < screen_size_x(s)) {
|
||||||
screen_write_cursormove(ctx, 0, py, 0);
|
window_copy_write_one(wme, ctx, py, hsize - data->oy + py,
|
||||||
screen_write_copy(ctx, data->backing, 0, hsize - data->oy + py,
|
screen_size_x(s) - size, &mgc, &cgc);
|
||||||
screen_size_x(s) - size, 1, data->searchmark, &gc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (py == data->cy && data->cx == screen_size_x(s)) {
|
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_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;
|
u_int firstsx, lastex, restex, restsx, selx;
|
||||||
int keys;
|
int keys;
|
||||||
|
|
||||||
if (data->screen.sel == NULL && data->lineflag == LINE_SEL_NONE)
|
if (data->screen.sel == NULL && data->lineflag == LINE_SEL_NONE) {
|
||||||
return (NULL);
|
buf = window_copy_match_at_cursor(data);
|
||||||
|
if (buf != NULL)
|
||||||
|
*len = strlen(buf);
|
||||||
|
return (buf);
|
||||||
|
}
|
||||||
|
|
||||||
buf = xmalloc(1);
|
buf = xmalloc(1);
|
||||||
off = 0;
|
off = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user