mirror of
https://github.com/openbsd/src.git
synced 2026-06-18 07:13:36 +02:00
Replace refresh-from-pane in copy mode with a way to automatically
update as pane content changes. This is toggled by pressing r. GitHub issue 5165 from Barrett Ruth.
This commit is contained in:
+11
-2
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: grid.c,v 1.148 2026/06/07 20:03:02 nicm Exp $ */
|
||||
/* $OpenBSD: grid.c,v 1.149 2026/06/10 14:29:08 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -292,7 +292,7 @@ grid_free_line(struct grid *gd, u_int py)
|
||||
}
|
||||
|
||||
/* Free several lines. */
|
||||
static void
|
||||
void
|
||||
grid_free_lines(struct grid *gd, u_int py, u_int ny)
|
||||
{
|
||||
u_int yy;
|
||||
@@ -320,6 +320,10 @@ grid_create(u_int sx, u_int sy, u_int hlimit)
|
||||
gd->hsize = 0;
|
||||
gd->hlimit = hlimit;
|
||||
|
||||
gd->scroll_added = 0;
|
||||
gd->scroll_collected = 0;
|
||||
gd->scroll_generation = 0;
|
||||
|
||||
if (gd->sy != 0)
|
||||
gd->linedata = xcalloc(gd->sy, sizeof *gd->linedata);
|
||||
else
|
||||
@@ -405,6 +409,7 @@ grid_collect_history(struct grid *gd, int all)
|
||||
grid_trim_history(gd, ny);
|
||||
|
||||
gd->hsize -= ny;
|
||||
gd->scroll_collected += ny;
|
||||
if (gd->hscrolled > gd->hsize)
|
||||
gd->hscrolled = gd->hsize;
|
||||
}
|
||||
@@ -442,6 +447,7 @@ grid_scroll_history(struct grid *gd, u_int bg)
|
||||
grid_compact_line(&gd->linedata[gd->hsize]);
|
||||
gd->linedata[gd->hsize].time = current_time;
|
||||
gd->hsize++;
|
||||
gd->scroll_added++;
|
||||
}
|
||||
|
||||
/* Clear the history. */
|
||||
@@ -452,6 +458,7 @@ grid_clear_history(struct grid *gd)
|
||||
|
||||
gd->hscrolled = 0;
|
||||
gd->hsize = 0;
|
||||
gd->scroll_generation++;
|
||||
|
||||
gd->linedata = xreallocarray(gd->linedata, gd->sy,
|
||||
sizeof *gd->linedata);
|
||||
@@ -489,6 +496,7 @@ grid_scroll_history_region(struct grid *gd, u_int upper, u_int lower, u_int bg)
|
||||
/* Move the history offset down over the line. */
|
||||
gd->hscrolled++;
|
||||
gd->hsize++;
|
||||
gd->scroll_added++;
|
||||
}
|
||||
|
||||
/* Expand line to fit to cell. */
|
||||
@@ -1510,6 +1518,7 @@ grid_reflow(struct grid *gd, u_int sx)
|
||||
free(gd->linedata);
|
||||
gd->linedata = target->linedata;
|
||||
free(target);
|
||||
gd->scroll_generation++;
|
||||
}
|
||||
|
||||
/* Convert to position based on wrapped lines. */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: key-bindings.c,v 1.171 2026/06/07 08:25:59 nicm Exp $ */
|
||||
/* $OpenBSD: key-bindings.c,v 1.172 2026/06/10 14:29:08 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -530,7 +530,7 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode g { command-prompt -p'(goto line)' { send -X goto-line -- '%%' } }",
|
||||
"bind -Tcopy-mode n { send -X search-again }",
|
||||
"bind -Tcopy-mode q { send -X cancel }",
|
||||
"bind -Tcopy-mode r { send -X refresh-from-pane }",
|
||||
"bind -Tcopy-mode r { send -X refresh-toggle }",
|
||||
"bind -Tcopy-mode t { command-prompt -1p'(jump to forward)' { send -X jump-to-forward -- '%%' } }",
|
||||
"bind -Tcopy-mode Home { send -X start-of-line }",
|
||||
"bind -Tcopy-mode End { send -X end-of-line }",
|
||||
@@ -638,7 +638,7 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode-vi n { send -X search-again }",
|
||||
"bind -Tcopy-mode-vi o { send -X other-end }",
|
||||
"bind -Tcopy-mode-vi q { send -X cancel }",
|
||||
"bind -Tcopy-mode-vi r { send -X refresh-from-pane }",
|
||||
"bind -Tcopy-mode-vi r { send -X refresh-toggle }",
|
||||
"bind -Tcopy-mode-vi t { command-prompt -1p'(jump to forward)' { send -X jump-to-forward -- '%%' } }",
|
||||
"bind -Tcopy-mode-vi v { send -X rectangle-toggle }",
|
||||
"bind -Tcopy-mode-vi w { send -X next-word }",
|
||||
|
||||
+15
-4
@@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: tmux.1,v 1.1077 2026/06/09 12:51:57 nicm Exp $
|
||||
.\" $OpenBSD: tmux.1,v 1.1078 2026/06/10 14:29:08 nicm Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
.\"
|
||||
@@ -14,7 +14,7 @@
|
||||
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd $Mdocdate: June 9 2026 $
|
||||
.Dd $Mdocdate: June 10 2026 $
|
||||
.Dt TMUX 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -2293,11 +2293,22 @@ Toggle rectangle selection mode.
|
||||
.Xc
|
||||
Cycles the current line between centre, top, and bottom.
|
||||
.It Xo
|
||||
.Ic refresh\-from\-pane
|
||||
.Ic refresh\-on
|
||||
.Xc
|
||||
Turn on automatic refresh of the content from the pane, so that new output
|
||||
appears while in copy mode.
|
||||
Automatic refresh is off by default; it will scroll only while the cursor is at
|
||||
the bottom and is paused while a selection is in progress.
|
||||
.It Xo
|
||||
.Ic refresh\-off
|
||||
.Xc
|
||||
Turn off automatic refresh of the content from the pane.
|
||||
.It Xo
|
||||
.Ic refresh\-toggle
|
||||
(vi: r)
|
||||
(emacs: r)
|
||||
.Xc
|
||||
Refresh the content from the pane.
|
||||
Toggle automatic refresh of the content from the pane.
|
||||
.It Xo
|
||||
.Ic scroll\-bottom
|
||||
.Xc
|
||||
|
||||
+6
-1
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: tmux.h,v 1.1341 2026/06/09 21:22:22 nicm Exp $ */
|
||||
/* $OpenBSD: tmux.h,v 1.1342 2026/06/10 14:29:08 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -862,6 +862,10 @@ struct grid {
|
||||
u_int hsize;
|
||||
u_int hlimit;
|
||||
|
||||
u_int scroll_added;
|
||||
u_int scroll_collected;
|
||||
u_int scroll_generation;
|
||||
|
||||
struct grid_line *linedata;
|
||||
};
|
||||
|
||||
@@ -3168,6 +3172,7 @@ int grid_cells_look_equal(const struct grid_cell *,
|
||||
const struct grid_cell *);
|
||||
struct grid *grid_create(u_int, u_int, u_int);
|
||||
void grid_destroy(struct grid *);
|
||||
void grid_free_lines(struct grid *, u_int, u_int);
|
||||
int grid_compare(struct grid *, struct grid *);
|
||||
void grid_collect_history(struct grid *, int);
|
||||
void grid_remove_history(struct grid *, u_int );
|
||||
|
||||
+255
-15
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: window-copy.c,v 1.403 2026/06/09 21:22:22 nicm Exp $ */
|
||||
/* $OpenBSD: window-copy.c,v 1.404 2026/06/10 14:29:08 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -51,6 +51,11 @@ static void window_copy_redraw_selection(struct window_mode_entry *, u_int);
|
||||
static void window_copy_redraw_lines(struct window_mode_entry *, u_int,
|
||||
u_int);
|
||||
static void window_copy_redraw_screen(struct window_mode_entry *);
|
||||
static void window_copy_do_refresh(struct window_mode_entry *, int);
|
||||
static void window_copy_refresh_timer(int, short, void *);
|
||||
static void window_copy_refresh_arm(struct window_mode_entry *);
|
||||
static void window_copy_refresh_start(struct window_mode_entry *);
|
||||
static void window_copy_refresh_stop(struct window_mode_entry *);
|
||||
static void window_copy_style_changed(struct window_mode_entry *);
|
||||
static int window_copy_line_number_mode(struct window_mode_entry *);
|
||||
static int window_copy_line_number_is_absolute(struct window_mode_entry *);
|
||||
@@ -255,6 +260,10 @@ struct window_copy_mode_data {
|
||||
int backing_written; /* backing display started */
|
||||
struct input_ctx *ictx;
|
||||
|
||||
u_int sync_added; /* snapshot of backing grid counters */
|
||||
u_int sync_collected;
|
||||
u_int sync_generation;
|
||||
|
||||
int viewmode; /* view mode entered */
|
||||
|
||||
u_int oy; /* number of lines scrolled up */
|
||||
@@ -338,6 +347,10 @@ struct window_copy_mode_data {
|
||||
|
||||
struct event dragtimer;
|
||||
#define WINDOW_COPY_DRAG_REPEAT_TIME 50000
|
||||
|
||||
struct event refresh_timer;
|
||||
#define WINDOW_COPY_REFRESH_INTERVAL 50000
|
||||
int refresh_active;
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -424,6 +437,116 @@ window_copy_clone_screen(struct screen *src, struct screen *hint, u_int *cx,
|
||||
return (dst);
|
||||
}
|
||||
|
||||
/*
|
||||
* Snapshot the source grid's monotonic scroll counters so the next incremental
|
||||
* sync can tell how much history was added or collected since this point.
|
||||
*/
|
||||
static void
|
||||
window_copy_sync_snapshot(struct window_copy_mode_data *data, struct grid *src)
|
||||
{
|
||||
data->sync_added = src->scroll_added;
|
||||
data->sync_collected = src->scroll_collected;
|
||||
data->sync_generation = src->scroll_generation;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reconcile the backing screen with the live pane grid in place, copying only
|
||||
* the history that scrolled in or was collected since the last snapshot rather
|
||||
* than cloning the whole scrollback. The result is identical to a fresh
|
||||
* window_copy_clone_screen, so the caller repositions and redraws the same way
|
||||
* for both paths. Returns 1 on success, or 0 if the caller must fall back to a
|
||||
* full clone (different source pane, geometry or generation change, or counter
|
||||
* deltas that do not add up).
|
||||
*/
|
||||
static int
|
||||
window_copy_sync_backing(struct window_mode_entry *wme)
|
||||
{
|
||||
struct window_copy_mode_data *data = wme->data;
|
||||
struct window_pane *wp = wme->swp;
|
||||
struct screen *src = &wp->base;
|
||||
struct screen *dst = data->backing;
|
||||
struct grid *sg = src->grid;
|
||||
struct grid *dg = dst->grid;
|
||||
u_int sy = sg->sy;
|
||||
u_int old_hsize = dg->hsize;
|
||||
u_int new_hsize = sg->hsize;
|
||||
u_int added, collected, kept;
|
||||
|
||||
/*
|
||||
* Only a pane's own live grid is tracked incrementally. A different
|
||||
* source pane (copy-mode -s) goes through clone_screen, which also
|
||||
* trims trailing blank lines that this path does not.
|
||||
*/
|
||||
if (data->viewmode || wme->swp != wme->wp)
|
||||
return (0);
|
||||
|
||||
/* Indices only line up at the same size and generation. */
|
||||
if (sg->sx != dg->sx || sg->sy != dg->sy ||
|
||||
sg->scroll_generation != data->sync_generation)
|
||||
return (0);
|
||||
|
||||
added = sg->scroll_added - data->sync_added;
|
||||
collected = sg->scroll_collected - data->sync_collected;
|
||||
|
||||
/*
|
||||
* Reject anything that does not balance: counter wrap, a history-limit
|
||||
* change that collected past the snapshot, or arithmetic that does not
|
||||
* reproduce the new history size.
|
||||
*/
|
||||
if (added > (u_int)INT_MAX || collected > (u_int)INT_MAX ||
|
||||
collected > old_hsize || old_hsize + added < collected ||
|
||||
old_hsize + added - collected != new_hsize)
|
||||
return (0);
|
||||
|
||||
kept = old_hsize - collected;
|
||||
|
||||
if (added == 0 && collected == 0) {
|
||||
/* History is unchanged; only the viewport can have mutated. */
|
||||
grid_duplicate_lines(dg, dg->hsize, sg, sg->hsize, sy);
|
||||
} else {
|
||||
/* Drop the oldest lines and shift the rest down. */
|
||||
if (collected > 0) {
|
||||
grid_free_lines(dg, 0, collected);
|
||||
memmove(&dg->linedata[0], &dg->linedata[collected],
|
||||
(old_hsize + sy - collected) * sizeof *dg->linedata);
|
||||
memset(&dg->linedata[old_hsize + sy - collected], 0,
|
||||
collected * sizeof *dg->linedata);
|
||||
}
|
||||
|
||||
/* Resize linedata to the new history plus viewport. */
|
||||
if (new_hsize + sy != old_hsize + sy - collected) {
|
||||
dg->linedata = xreallocarray(dg->linedata,
|
||||
new_hsize + sy, sizeof *dg->linedata);
|
||||
memset(&dg->linedata[old_hsize + sy - collected], 0,
|
||||
(new_hsize - kept) * sizeof *dg->linedata);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set hsize before copying so grid_duplicate_lines does not
|
||||
* clamp the count to the old, smaller grid size.
|
||||
*/
|
||||
dg->hsize = new_hsize;
|
||||
|
||||
/* Copy the newly scrolled history, then refresh the viewport. */
|
||||
if (added > 0)
|
||||
grid_duplicate_lines(dg, kept, sg, kept, added);
|
||||
grid_duplicate_lines(dg, new_hsize, sg, new_hsize, sy);
|
||||
}
|
||||
|
||||
dg->hscrolled = sg->hscrolled;
|
||||
|
||||
/* Match clone_screen's backing cursor placement. */
|
||||
if (src->cy > dg->sy - 1) {
|
||||
dst->cx = 0;
|
||||
dst->cy = dg->sy - 1;
|
||||
} else {
|
||||
dst->cx = src->cx;
|
||||
dst->cy = src->cy;
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
static struct window_copy_mode_data *
|
||||
window_copy_common_init(struct window_mode_entry *wme)
|
||||
{
|
||||
@@ -458,6 +581,7 @@ window_copy_common_init(struct window_mode_entry *wme)
|
||||
data->modekeys = options_get_number(wp->window->options, "mode-keys");
|
||||
|
||||
evtimer_set(&data->dragtimer, window_copy_scroll_timer, wme);
|
||||
evtimer_set(&data->refresh_timer, window_copy_refresh_timer, wme);
|
||||
|
||||
return (data);
|
||||
}
|
||||
@@ -475,6 +599,7 @@ window_copy_init(struct window_mode_entry *wme,
|
||||
data = window_copy_common_init(wme);
|
||||
data->backing = window_copy_clone_screen(base, &data->screen, &cx, &cy,
|
||||
wme->swp != wme->wp);
|
||||
window_copy_sync_snapshot(data, base->grid);
|
||||
|
||||
data->cx = cx;
|
||||
if (cy < screen_hsize(data->backing)) {
|
||||
@@ -541,6 +666,7 @@ window_copy_free(struct window_mode_entry *wme)
|
||||
struct window_copy_mode_data *data = wme->data;
|
||||
|
||||
evtimer_del(&data->dragtimer);
|
||||
evtimer_del(&data->refresh_timer);
|
||||
|
||||
free(data->searchmark);
|
||||
free(data->searchstr);
|
||||
@@ -2781,34 +2907,136 @@ 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)
|
||||
/*
|
||||
* Reconcile the backing screen with the live pane, incrementally if possible
|
||||
* and otherwise by recloning, then reposition the view. When following, jump
|
||||
* to the bottom so new output stays visible; otherwise keep the same lines on
|
||||
* screen. Driven by the automatic refresh timer.
|
||||
*/
|
||||
static void
|
||||
window_copy_do_refresh(struct window_mode_entry *wme, int follow)
|
||||
{
|
||||
struct window_mode_entry *wme = cs->wme;
|
||||
struct window_pane *wp = wme->swp;
|
||||
struct window_copy_mode_data *data = wme->data;
|
||||
u_int oy_from_top;
|
||||
|
||||
if (data->viewmode)
|
||||
return (WINDOW_COPY_CMD_NOTHING);
|
||||
if (data->oy > screen_hsize(data->backing))
|
||||
data->oy = screen_hsize(data->backing);
|
||||
oy_from_top = screen_hsize(data->backing) - data->oy;
|
||||
|
||||
screen_free(data->backing);
|
||||
free(data->backing);
|
||||
data->backing = window_copy_clone_screen(&wp->base, &data->screen, NULL,
|
||||
NULL, wme->swp != wme->wp);
|
||||
if (!window_copy_sync_backing(wme)) {
|
||||
screen_free(data->backing);
|
||||
free(data->backing);
|
||||
data->backing = window_copy_clone_screen(&wp->base,
|
||||
&data->screen, NULL, NULL, wme->swp != wme->wp);
|
||||
}
|
||||
|
||||
if (oy_from_top <= screen_hsize(data->backing))
|
||||
if (follow) {
|
||||
data->cy = screen_size_y(&data->screen) - 1;
|
||||
data->cx = window_copy_cursor_limit(wme,
|
||||
screen_hsize(data->backing) + data->cy, 0);
|
||||
data->oy = 0;
|
||||
} else if (oy_from_top <= screen_hsize(data->backing))
|
||||
data->oy = screen_hsize(data->backing) - oy_from_top;
|
||||
else {
|
||||
data->cy = 0;
|
||||
data->oy = screen_hsize(data->backing);
|
||||
}
|
||||
|
||||
window_copy_sync_snapshot(data, wp->base.grid);
|
||||
window_copy_size_changed(wme);
|
||||
return (WINDOW_COPY_CMD_REDRAW);
|
||||
}
|
||||
|
||||
static void
|
||||
window_copy_refresh_arm(struct window_mode_entry *wme)
|
||||
{
|
||||
struct window_copy_mode_data *data = wme->data;
|
||||
struct timeval tv = {
|
||||
.tv_sec = WINDOW_COPY_REFRESH_INTERVAL / 1000000,
|
||||
.tv_usec = WINDOW_COPY_REFRESH_INTERVAL % 1000000
|
||||
};
|
||||
|
||||
if (data->refresh_active)
|
||||
evtimer_add(&data->refresh_timer, &tv);
|
||||
}
|
||||
|
||||
static void
|
||||
window_copy_refresh_timer(__unused int fd, __unused short events, void *arg)
|
||||
{
|
||||
struct window_mode_entry *wme = arg;
|
||||
struct window_pane *wp = wme->wp;
|
||||
struct window_copy_mode_data *data = wme->data;
|
||||
int follow;
|
||||
|
||||
if (TAILQ_FIRST(&wp->modes) != wme || !data->refresh_active)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Skip the refresh while a selection is being made, otherwise it would
|
||||
* move; only follow new output if the cursor is still at the bottom.
|
||||
*/
|
||||
if ((wp->flags & PANE_UNSEENCHANGES) && data->screen.sel == NULL &&
|
||||
data->cursordrag == CURSORDRAG_NONE) {
|
||||
follow = (data->oy == 0 &&
|
||||
data->cy == screen_size_y(&data->screen) - 1);
|
||||
window_copy_do_refresh(wme, follow);
|
||||
window_copy_redraw_screen(wme);
|
||||
/* The timer runs outside key handling, so force a repaint. */
|
||||
wp->flags |= PANE_REDRAW;
|
||||
wp->flags &= ~PANE_UNSEENCHANGES;
|
||||
}
|
||||
|
||||
window_copy_refresh_arm(wme);
|
||||
}
|
||||
|
||||
static void
|
||||
window_copy_refresh_start(struct window_mode_entry *wme)
|
||||
{
|
||||
struct window_copy_mode_data *data = wme->data;
|
||||
|
||||
/*
|
||||
* Do not refresh a view of another pane (copy-mode -s): the source may
|
||||
* disappear and changes are not tracked on this pane.
|
||||
*/
|
||||
if (data->viewmode || wme->swp != wme->wp || data->refresh_active)
|
||||
return;
|
||||
data->refresh_active = 1;
|
||||
window_copy_refresh_arm(wme);
|
||||
}
|
||||
|
||||
static void
|
||||
window_copy_refresh_stop(struct window_mode_entry *wme)
|
||||
{
|
||||
struct window_copy_mode_data *data = wme->data;
|
||||
|
||||
data->refresh_active = 0;
|
||||
evtimer_del(&data->refresh_timer);
|
||||
}
|
||||
|
||||
static enum window_copy_cmd_action
|
||||
window_copy_cmd_refresh_on(struct window_copy_cmd_state *cs)
|
||||
{
|
||||
window_copy_refresh_start(cs->wme);
|
||||
return (WINDOW_COPY_CMD_NOTHING);
|
||||
}
|
||||
|
||||
static enum window_copy_cmd_action
|
||||
window_copy_cmd_refresh_off(struct window_copy_cmd_state *cs)
|
||||
{
|
||||
window_copy_refresh_stop(cs->wme);
|
||||
return (WINDOW_COPY_CMD_NOTHING);
|
||||
}
|
||||
|
||||
static enum window_copy_cmd_action
|
||||
window_copy_cmd_refresh_toggle(struct window_copy_cmd_state *cs)
|
||||
{
|
||||
struct window_copy_mode_data *data = cs->wme->data;
|
||||
|
||||
if (data->refresh_active)
|
||||
window_copy_refresh_stop(cs->wme);
|
||||
else
|
||||
window_copy_refresh_start(cs->wme);
|
||||
return (WINDOW_COPY_CMD_NOTHING);
|
||||
}
|
||||
|
||||
static enum window_copy_cmd_action
|
||||
@@ -3275,11 +3503,23 @@ static const struct {
|
||||
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
|
||||
.f = window_copy_cmd_rectangle_toggle
|
||||
},
|
||||
{ .command = "refresh-from-pane",
|
||||
{ .command = "refresh-on",
|
||||
.args = { "", 0, 0, NULL },
|
||||
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
|
||||
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
|
||||
.f = window_copy_cmd_refresh_from_pane
|
||||
.clear = WINDOW_COPY_CMD_CLEAR_NEVER,
|
||||
.f = window_copy_cmd_refresh_on
|
||||
},
|
||||
{ .command = "refresh-off",
|
||||
.args = { "", 0, 0, NULL },
|
||||
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
|
||||
.clear = WINDOW_COPY_CMD_CLEAR_NEVER,
|
||||
.f = window_copy_cmd_refresh_off
|
||||
},
|
||||
{ .command = "refresh-toggle",
|
||||
.args = { "", 0, 0, NULL },
|
||||
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
|
||||
.clear = WINDOW_COPY_CMD_CLEAR_NEVER,
|
||||
.f = window_copy_cmd_refresh_toggle
|
||||
},
|
||||
{ .command = "scroll-bottom",
|
||||
.args = { "", 0, 0, NULL },
|
||||
|
||||
Reference in New Issue
Block a user