mirror of
https://github.com/tmux/tmux.git
synced 2026-10-07 01:55:49 +00:00
Merge remote-tracking branch 'refs/remotes/tmux-openbsd/master'
* refs/remotes/tmux-openbsd/master: Add A modifier to cycle through a series of values, GitHub issue 5412 from Fernando Daciuk.
This commit is contained in:
101
format.c
101
format.c
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: format.c,v 1.407 2026/07/20 07:42:13 nicm Exp $ */
|
/* $OpenBSD: format.c,v 1.408 2026/07/22 08:19:14 nicm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
|
* Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -128,6 +128,7 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
|
|||||||
#define FORMAT_OPTIONS 0x40000000
|
#define FORMAT_OPTIONS 0x40000000
|
||||||
#define FORMAT_ENVIRON 0x80000000ULL
|
#define FORMAT_ENVIRON 0x80000000ULL
|
||||||
#define FORMAT_DIFFERENCE 0x100000000ULL
|
#define FORMAT_DIFFERENCE 0x100000000ULL
|
||||||
|
#define FORMAT_CYCLE 0x200000000ULL
|
||||||
|
|
||||||
/* Limit on recursion. */
|
/* Limit on recursion. */
|
||||||
#define FORMAT_LOOP_LIMIT 100
|
#define FORMAT_LOOP_LIMIT 100
|
||||||
@@ -138,9 +139,13 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
|
|||||||
/* How often to check the time in long loops. */
|
/* How often to check the time in long loops. */
|
||||||
#define FORMAT_TIME_LOOP_CHECK 10000
|
#define FORMAT_TIME_LOOP_CHECK 10000
|
||||||
|
|
||||||
|
/* Fixed animation period (ms): redraw interval and shortest frame step. */
|
||||||
|
#define FORMAT_CYCLE_PERIOD 100
|
||||||
|
|
||||||
/* Format expand flags. */
|
/* Format expand flags. */
|
||||||
#define FORMAT_EXPAND_TIME 0x1
|
#define FORMAT_EXPAND_TIME 0x1
|
||||||
#define FORMAT_EXPAND_NOJOBS 0x2
|
#define FORMAT_EXPAND_NOJOBS 0x2
|
||||||
|
#define FORMAT_EXPAND_NOCYCLE 0x4
|
||||||
|
|
||||||
/* Entry in format tree. */
|
/* Entry in format tree. */
|
||||||
struct format_entry {
|
struct format_entry {
|
||||||
@@ -413,7 +418,8 @@ format_job_get(struct format_expand_state *es, const char *cmd)
|
|||||||
RB_INSERT(format_job_tree, jobs, fj);
|
RB_INSERT(format_job_tree, jobs, fj);
|
||||||
}
|
}
|
||||||
|
|
||||||
format_copy_state(&next, es, FORMAT_EXPAND_NOJOBS);
|
format_copy_state(&next, es, FORMAT_EXPAND_NOJOBS|
|
||||||
|
FORMAT_EXPAND_NOCYCLE);
|
||||||
next.flags &= ~FORMAT_EXPAND_TIME;
|
next.flags &= ~FORMAT_EXPAND_TIME;
|
||||||
|
|
||||||
expanded = format_expand1(&next, cmd);
|
expanded = format_expand1(&next, cmd);
|
||||||
@@ -4797,7 +4803,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Modifiers are a ; separated list of the forms:
|
* Modifiers are a ; separated list of the forms:
|
||||||
* l,m,C,a,b,c,d,I,n,t,w,q,E,T,S,W,P,O,V,R,<,>
|
* l,m,C,a,b,c,d,I,n,t,w,q,E,T,S,W,P,O,V,R,A,<,>
|
||||||
* =a
|
* =a
|
||||||
* =/a
|
* =/a
|
||||||
* =/a/
|
* =/a/
|
||||||
@@ -4816,7 +4822,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* Check single character modifiers with no arguments. */
|
/* Check single character modifiers with no arguments. */
|
||||||
if (strchr("labdnwETSWPOVL!<>", cp[0]) != NULL &&
|
if (strchr("labdnwETSWPOVL!<>A", cp[0]) != NULL &&
|
||||||
format_is_end(cp[1])) {
|
format_is_end(cp[1])) {
|
||||||
format_add_modifier(&list, count, cp, 1, NULL, 0);
|
format_add_modifier(&list, count, cp, 1, NULL, 0);
|
||||||
cp++;
|
cp++;
|
||||||
@@ -4838,7 +4844,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Now try single character with arguments. */
|
/* Now try single character with arguments. */
|
||||||
if (strchr("ImCLNPSOVst=pReqWc", cp[0]) == NULL)
|
if (strchr("ImCLNPSOVst=pReqWcA", cp[0]) == NULL)
|
||||||
break;
|
break;
|
||||||
c = cp[0];
|
c = cp[0];
|
||||||
|
|
||||||
@@ -5797,6 +5803,74 @@ fail:
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Callback for the cycle timer; redraw the status line. */
|
||||||
|
static void
|
||||||
|
format_cycle_callback(__unused int fd, __unused short events, void *arg)
|
||||||
|
{
|
||||||
|
struct client *c = arg;
|
||||||
|
|
||||||
|
if (c->message_string == NULL && c->prompt == NULL)
|
||||||
|
c->flags |= CLIENT_REDRAWSTATUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Arm the cycle timer to redraw the status line if it is not already. */
|
||||||
|
static void
|
||||||
|
format_cycle_start_timer(struct client *c)
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
tv.tv_sec = FORMAT_CYCLE_PERIOD / 1000;
|
||||||
|
tv.tv_usec = (FORMAT_CYCLE_PERIOD % 1000) * 1000L;
|
||||||
|
|
||||||
|
if (!event_initialized(&c->cycle_timer))
|
||||||
|
evtimer_set(&c->cycle_timer, format_cycle_callback, c);
|
||||||
|
if (!evtimer_pending(&c->cycle_timer, NULL))
|
||||||
|
evtimer_add(&c->cycle_timer, &tv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Expand the "A" animation modifier; see the manual for the syntax. */
|
||||||
|
static char *
|
||||||
|
format_cycle(struct format_expand_state *es, const char *frames, u_int count)
|
||||||
|
{
|
||||||
|
struct format_tree *ft = es->ft;
|
||||||
|
const char *start, *end, *cp;
|
||||||
|
u_int n, index, i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A cycle is only expanded in a status format, and never in the
|
||||||
|
* command or output of #() where it would change on every frame and
|
||||||
|
* make the job run again.
|
||||||
|
*/
|
||||||
|
if (!(ft->flags & FORMAT_STATUS) || (es->flags & FORMAT_EXPAND_NOCYCLE))
|
||||||
|
return (xstrdup(""));
|
||||||
|
if (*frames == '\0')
|
||||||
|
return (xstrdup(""));
|
||||||
|
|
||||||
|
/* Count the comma-separated frames (there is at least one). */
|
||||||
|
n = 1;
|
||||||
|
for (cp = frames; *cp != '\0'; cp++) {
|
||||||
|
if (*cp == ',')
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
index = (es->start_time / (count * FORMAT_CYCLE_PERIOD)) % n;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Redraw the status line so the frames advance on their own; a
|
||||||
|
* single frame never changes so there is nothing to redraw for.
|
||||||
|
*/
|
||||||
|
if (n > 1 && ft->client != NULL)
|
||||||
|
format_cycle_start_timer(ft->client);
|
||||||
|
|
||||||
|
/* Walk to the chosen frame and return a copy of it. */
|
||||||
|
start = frames;
|
||||||
|
for (i = 0; i < index; i++)
|
||||||
|
start = strchr(start, ',') + 1;
|
||||||
|
end = strchr(start, ',');
|
||||||
|
if (end == NULL)
|
||||||
|
end = start + strlen(start);
|
||||||
|
return (xstrndup(start, end - start));
|
||||||
|
}
|
||||||
|
|
||||||
/* Replace a key. */
|
/* Replace a key. */
|
||||||
static int
|
static int
|
||||||
format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
||||||
@@ -5817,6 +5891,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
struct format_modifier *list, *cmp = NULL, *search = NULL;
|
struct format_modifier *list, *cmp = NULL, *search = NULL;
|
||||||
struct format_modifier **sub = NULL, *mexp = NULL, *fm;
|
struct format_modifier **sub = NULL, *mexp = NULL, *fm;
|
||||||
struct format_modifier *bool_op_n = NULL;
|
struct format_modifier *bool_op_n = NULL;
|
||||||
|
u_int cycle_count = 1;
|
||||||
u_int i, count, nsub = 0, nrep, check = 0;
|
u_int i, count, nsub = 0, nrep, check = 0;
|
||||||
const char *loop_flags = "";
|
const char *loop_flags = "";
|
||||||
struct format_expand_state next;
|
struct format_expand_state next;
|
||||||
@@ -5877,6 +5952,15 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
if (errstr != NULL)
|
if (errstr != NULL)
|
||||||
width = 0;
|
width = 0;
|
||||||
break;
|
break;
|
||||||
|
case 'A':
|
||||||
|
modifiers |= FORMAT_CYCLE;
|
||||||
|
if (fm->argc < 1)
|
||||||
|
break;
|
||||||
|
cycle_count = strtonum(fm->argv[0], 1, 100,
|
||||||
|
&errstr);
|
||||||
|
if (errstr != NULL)
|
||||||
|
cycle_count = 1;
|
||||||
|
break;
|
||||||
case 'w':
|
case 'w':
|
||||||
modifiers |= FORMAT_WIDTH;
|
modifiers |= FORMAT_WIDTH;
|
||||||
break;
|
break;
|
||||||
@@ -6098,6 +6182,13 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Is this an animation cycle? */
|
||||||
|
if (modifiers & FORMAT_CYCLE) {
|
||||||
|
value = format_cycle(es, copy, cycle_count);
|
||||||
|
format_log(es, "cycle '%s' is: %s", copy, value);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
/* Is this a literal string? */
|
/* Is this a literal string? */
|
||||||
if (modifiers & FORMAT_LITERAL) {
|
if (modifiers & FORMAT_LITERAL) {
|
||||||
format_log(es, "literal string is '%s'", copy);
|
format_log(es, "literal string is '%s'", copy);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: server-client.c,v 1.498 2026/07/21 12:28:43 nicm Exp $ */
|
/* $OpenBSD: server-client.c,v 1.499 2026/07/22 08:19:14 nicm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -525,6 +525,8 @@ server_client_lost(struct client *c)
|
|||||||
|
|
||||||
evtimer_del(&c->repeat_timer);
|
evtimer_del(&c->repeat_timer);
|
||||||
evtimer_del(&c->click_timer);
|
evtimer_del(&c->click_timer);
|
||||||
|
if (event_initialized(&c->cycle_timer))
|
||||||
|
evtimer_del(&c->cycle_timer);
|
||||||
|
|
||||||
key_bindings_unref_table(c->keytable);
|
key_bindings_unref_table(c->keytable);
|
||||||
|
|
||||||
|
|||||||
24
tmux.1
24
tmux.1
@@ -1,4 +1,4 @@
|
|||||||
.\" $OpenBSD: tmux.1,v 1.1146 2026/07/21 12:28:43 nicm Exp $
|
.\" $OpenBSD: tmux.1,v 1.1147 2026/07/22 08:19:14 nicm Exp $
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
.\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
.\"
|
.\"
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||||
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
.\"
|
.\"
|
||||||
.Dd $Mdocdate: July 21 2026 $
|
.Dd $Mdocdate: July 22 2026 $
|
||||||
.Dt TMUX 1
|
.Dt TMUX 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -7185,6 +7185,26 @@ For example
|
|||||||
will be replaced by
|
will be replaced by
|
||||||
.Ql #{?pane_in_mode,yes,no} .
|
.Ql #{?pane_in_mode,yes,no} .
|
||||||
.Pp
|
.Pp
|
||||||
|
The
|
||||||
|
.Ql A
|
||||||
|
modifier shows one of a list of frames in turn:
|
||||||
|
.Ql #{A/count:frame,frame,...}
|
||||||
|
or
|
||||||
|
.Ql #{A:frame,frame,...} .
|
||||||
|
Each frame is shown for
|
||||||
|
.Ar count
|
||||||
|
periods of 100 milliseconds before the next, wrapping back to the first after
|
||||||
|
the last.
|
||||||
|
If no count is given, one is used.
|
||||||
|
The
|
||||||
|
.Ql A
|
||||||
|
modifier is expanded only in the status line and
|
||||||
|
.Ic pane\-border\-format ;
|
||||||
|
if present, the status line or pane borders are redrawn every 100 milliseconds.
|
||||||
|
For example,
|
||||||
|
.Ql #{A/2:|,/,\-,\e}
|
||||||
|
shows the four frames in turn, changing every 200 milliseconds.
|
||||||
|
.Pp
|
||||||
The following variables are available, where appropriate:
|
The following variables are available, where appropriate:
|
||||||
.Bl -column "XXXXXXXXXXXXXXXXXXX" "XXXXX"
|
.Bl -column "XXXXXXXXXXXXXXXXXXX" "XXXXX"
|
||||||
.It Sy "Variable name" Ta Sy "Alias" Ta Sy "Replaced with"
|
.It Sy "Variable name" Ta Sy "Alias" Ta Sy "Replaced with"
|
||||||
|
|||||||
3
tmux.h
3
tmux.h
@@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: tmux.h,v 1.1412 2026/07/21 12:28:43 nicm Exp $ */
|
/* $OpenBSD: tmux.h,v 1.1413 2026/07/22 08:19:14 nicm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
@@ -2244,6 +2244,7 @@ struct client {
|
|||||||
struct mouse_event click_event;
|
struct mouse_event click_event;
|
||||||
|
|
||||||
struct status_line status;
|
struct status_line status;
|
||||||
|
struct event cycle_timer;
|
||||||
enum client_theme theme;
|
enum client_theme theme;
|
||||||
|
|
||||||
struct input_requests input_requests;
|
struct input_requests input_requests;
|
||||||
|
|||||||
Reference in New Issue
Block a user