Change the existing client flags for control mode to apply for any client, use

the same mechanism for the read-only flag and add an ignore-size flag.

refresh-client -F has become -f (-F stays for backwards compatibility) and
attach-session and switch-client now have -f flags also. A new format
"client_flags" lists the flags and is shown by list-clients by default.

This separates the read-only flag from "ignore size" behaviour (new
ignore-size) flag - both behaviours are useful in different circumstances.

attach -r and switchc -r remain and set or toggle both flags together.
This commit is contained in:
Nicholas Marriott 2020-05-05 15:42:20 +01:00
parent deacfedc65
commit 2f89d2e7d8
10 changed files with 136 additions and 50 deletions

View File

@ -37,8 +37,9 @@ const struct cmd_entry cmd_attach_session_entry = {
.name = "attach-session",
.alias = "attach",
.args = { "c:dErt:x", 0, 0 },
.usage = "[-dErx] [-c working-directory] " CMD_TARGET_SESSION_USAGE,
.args = { "c:dEf:rt:x", 0, 0 },
.usage = "[-dErx] [-c working-directory] [-f flags] "
CMD_TARGET_SESSION_USAGE,
/* -t is special */
@ -48,7 +49,7 @@ const struct cmd_entry cmd_attach_session_entry = {
enum cmd_retval
cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
int xflag, int rflag, const char *cflag, int Eflag)
int xflag, int rflag, const char *cflag, int Eflag, const char *fflag)
{
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state target;
@ -101,6 +102,10 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
free((void *)s->cwd);
s->cwd = format_single(item, cflag, c, s, wl, wp);
}
if (fflag)
server_client_set_flags(c, fflag);
if (rflag)
c->flags |= (CLIENT_READONLY|CLIENT_IGNORESIZE);
c->last_session = c->session;
if (c->session != NULL) {
@ -135,8 +140,6 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
free(cause);
return (CMD_RETURN_ERROR);
}
if (rflag)
c->flags |= CLIENT_READONLY;
if (dflag || xflag) {
if (xflag)
@ -182,5 +185,5 @@ cmd_attach_session_exec(struct cmd *self, struct cmdq_item *item)
return (cmd_attach_session(item, args_get(args, 't'),
args_has(args, 'd'), args_has(args, 'x'), args_has(args, 'r'),
args_get(args, 'c'), args_has(args, 'E')));
args_get(args, 'c'), args_has(args, 'E'), args_get(args, 'f')));
}

View File

@ -31,7 +31,7 @@
#define LIST_CLIENTS_TEMPLATE \
"#{client_name}: #{session_name} " \
"[#{client_width}x#{client_height} #{client_termname}] " \
"#{?client_utf8, (utf8),}#{?client_readonly, (ro),}"
"#{?client_flags,(,}#{client_flags}#{?client_flags,),}"
static enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmdq_item *);

View File

@ -39,9 +39,9 @@ const struct cmd_entry cmd_new_session_entry = {
.name = "new-session",
.alias = "new",
.args = { "Ac:dDe:EF:n:Ps:t:x:Xy:", 0, -1 },
.args = { "Ac:dDe:EF:f:n:Ps:t:x:Xy:", 0, -1 },
.usage = "[-AdDEPX] [-c start-directory] [-e environment] [-F format] "
"[-n window-name] [-s session-name] "
"[-f flags] [-n window-name] [-s session-name] "
CMD_TARGET_SESSION_USAGE " [-x width] [-y height] [command]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
@ -112,7 +112,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
if (as != NULL) {
retval = cmd_attach_session(item, as->name,
args_has(args, 'D'), args_has(args, 'X'), 0, NULL,
args_has(args, 'E'));
args_has(args, 'E'), args_get(args, 'f'));
free(newname);
return (retval);
}
@ -306,6 +306,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
* taking this session and needs to get MSG_READY and stay around.
*/
if (!detached) {
if (args_has(args, 'f'))
server_client_set_flags(c, args_get(args, 'f'));
if (!already_attached) {
if (~c->flags & CLIENT_CONTROL)
proc_send(c->peer, MSG_READY, -1, NULL, 0);

View File

@ -34,8 +34,8 @@ const struct cmd_entry cmd_refresh_client_entry = {
.name = "refresh-client",
.alias = "refresh",
.args = { "cC:DF:lLRSt:U", 0, 1 },
.usage = "[-cDlLRSU] [-C XxY] [-F flags] " CMD_TARGET_CLIENT_USAGE
.args = { "cC:Df:F:lLRSt:U", 0, 1 },
.usage = "[-cDlLRSU] [-C XxY] [-f flags] " CMD_TARGET_CLIENT_USAGE
" [adjustment]",
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
@ -50,7 +50,6 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
struct tty *tty = &tc->tty;
struct window *w;
const char *size, *errstr;
char *copy, *next, *s;
u_int x, y, adjust;
if (args_has(args, 'c') ||
@ -108,7 +107,12 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'C') || args_has(args, 'F')) {
if (args_has(args, 'F')) /* -F is an alias for -f */
server_client_set_flags(tc, args_get(args, 'F'));
if (args_has(args, 'f'))
server_client_set_flags(tc, args_get(args, 'f'));
if (args_has(args, 'C')) {
if (args_has(args, 'C')) {
if (!(tc->flags & CLIENT_CONTROL)) {
cmdq_error(item, "not a control client");
@ -129,19 +133,6 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
tc->flags |= CLIENT_SIZECHANGED;
recalculate_sizes();
}
if (args_has(args, 'F')) {
if (!(tc->flags & CLIENT_CONTROL)) {
cmdq_error(item, "not a control client");
return (CMD_RETURN_ERROR);
}
s = copy = xstrdup(args_get(args, 'F'));
while ((next = strsep(&s, ",")) != NULL) {
/* Unknown flags are ignored. */
if (strcmp(next, "no-output") == 0)
tc->flags |= CLIENT_CONTROL_NOOUTPUT;
}
free(copy);
}
return (CMD_RETURN_NORMAL);
}

View File

@ -34,7 +34,7 @@ const struct cmd_entry cmd_switch_client_entry = {
.name = "switch-client",
.alias = "switchc",
.args = { "lc:Enpt:rT:Z", 0, 0 },
.args = { "lc:EFnpt:rT:Z", 0, 0 },
.usage = "[-ElnprZ] [-c target-client] [-t target-session] "
"[-T key-table]",
@ -74,8 +74,12 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
wl = target.wl;
wp = target.wp;
if (args_has(args, 'r'))
tc->flags ^= CLIENT_READONLY;
if (args_has(args, 'r')) {
if (tc->flags & CLIENT_READONLY)
tc->flags &= ~(CLIENT_READONLY|CLIENT_IGNORESIZE);
else
tc->flags |= (CLIENT_READONLY|CLIENT_IGNORESIZE);
}
tablename = args_get(args, 'T');
if (tablename != NULL) {

View File

@ -2671,11 +2671,11 @@ format_defaults_client(struct format_tree *ft, struct client *c)
format_add(ft, "client_utf8", "%d", 1);
else
format_add(ft, "client_utf8", "%d", 0);
if (c->flags & CLIENT_READONLY)
format_add(ft, "client_readonly", "%d", 1);
else
format_add(ft, "client_readonly", "%d", 0);
format_add(ft, "client_flags", "%s", server_client_get_flags(c));
s = c->session;
if (s != NULL)

View File

@ -72,17 +72,17 @@ ignore_client_size(struct client *c)
return (1);
if (c->flags & CLIENT_NOSIZEFLAGS)
return (1);
if (c->flags & CLIENT_READONLY) {
if (c->flags & CLIENT_IGNORESIZE) {
/*
* Ignore readonly clients if there are any attached clients
* that aren't readonly.
* Ignore flagged clients if there are any attached clients
* that aren't flagged.
*/
TAILQ_FOREACH (loop, &clients, entry) {
if (loop->session == NULL)
continue;
if (loop->flags & CLIENT_NOSIZEFLAGS)
continue;
if (~loop->flags & CLIENT_READONLY)
if (~loop->flags & CLIENT_IGNORESIZE)
return (1);
}
}

View File

@ -2255,3 +2255,61 @@ server_client_get_cwd(struct client *c, struct session *s)
return (home);
return ("/");
}
/* Set client flags. */
void
server_client_set_flags(struct client *c, const char *flags)
{
char *s, *copy, *next;
int flag, not;
s = copy = xstrdup (flags);
while ((next = strsep(&s, ",")) != NULL) {
not = (*next == '!');
if (not)
next++;
if (strcmp(next, "no-output") == 0)
flag = CLIENT_CONTROL_NOOUTPUT;
else if (strcmp(next, "read-only") == 0)
flag = CLIENT_READONLY;
else if (strcmp(next, "ignore-size") == 0)
flag = CLIENT_IGNORESIZE;
else
continue;
log_debug("client %s set flag %s", c->name, next);
if (not)
c->flags &= ~flag;
else
c->flags |= flag;
}
free(copy);
}
/*Get client flags. This is only flags useful to show to users. */
const char *
server_client_get_flags(struct client *c)
{
static char s[256];
*s = '\0';
if (c->flags & CLIENT_ATTACHED)
strlcat(s, "attached,", sizeof s);
if (c->flags & CLIENT_CONTROL)
strlcat(s, "control-mode,", sizeof s);
if (c->flags & CLIENT_IGNORESIZE)
strlcat(s, "ignore-size,", sizeof s);
if (c->flags & CLIENT_CONTROL_NOOUTPUT)
strlcat(s, "no-output,", sizeof s);
if (c->flags & CLIENT_READONLY)
strlcat(s, "read-only,", sizeof s);
if (c->flags & CLIENT_SUSPENDED)
strlcat(s, "suspended,", sizeof s);
if (c->flags & CLIENT_UTF8)
strlcat(s, "UTF-8,", sizeof s);
if (*s != '\0')
s[strlen(s) - 1] = '\0';
return (s);
}

46
tmux.1
View File

@ -947,6 +947,7 @@ The following commands are available to manage clients and sessions:
.It Xo Ic attach-session
.Op Fl dErx
.Op Fl c Ar working-directory
.Op Fl f Ar flags
.Op Fl t Ar target-session
.Xc
.D1 (alias: Ic attach )
@ -964,12 +965,30 @@ is given, send
.Dv SIGHUP
to the parent process of the client as well as
detaching the client, typically causing it to exit.
.Fl f
sets a comma-separated list of client flags.
The flags are:
.Bl -tag -width Ds
.It read-only
the client is read-only
.It ignore-size
the client does not affect the size of other clients
.It no-output
the client does not receive pane output in control mode
.El
.Pp
A leading
.Ql !
turns a flag off if the client is already attached.
.Fl r
signifies the client is read-only (only keys bound to the
is an alias for
.Fl f
.Ar read-only,ignore-size .
When a client is read-only, only keys bound to the
.Ic detach-client
or
.Ic switch-client
commands have any effect)
commands have any effect.
.Pp
If no server is started,
.Ic attach-session
@ -1095,6 +1114,7 @@ Lock all clients attached to
.Op Fl AdDEPX
.Op Fl c Ar start-directory
.Op Fl e Ar environment
.Op Fl f Ar flags
.Op Fl F Ar format
.Op Fl n Ar window-name
.Op Fl s Ar session-name
@ -1132,6 +1152,9 @@ or
is given, the
.Ic default-size
option is set for the session.
.Fl f
sets a comma-separated list of client flags (see
.Ic attach-session ) .
.Pp
If run from a terminal, any
.Xr termios 4
@ -1209,7 +1232,7 @@ specified multiple times.
.It Xo Ic refresh-client
.Op Fl cDlLRSU
.Op Fl C Ar XxY
.Op Fl F Ar flags
.Op Fl f Ar flags
.Op Fl t Ar target-client
.Op Ar adjustment
.Xc
@ -1252,12 +1275,10 @@ window, changing the current window in the attached session will reset
it.
.Pp
.Fl C
sets the width and height of a control client and
.Fl F
sets a comma-separated list of flags.
Currently the only flag available is
.Ql no-output
to disable receiving pane output.
sets the width and height of a control client.
.Fl f
sets a comma-separated list of client flags, see
.Ic attach-session .
.Pp
.Fl l
requests the clipboard from the client using the
@ -1377,7 +1398,11 @@ or
is used, the client is moved to the last, next or previous session
respectively.
.Fl r
toggles whether a client is read-only (see the
toggles the client
.Ic read-only
and
.Ic ignore-size
flags (see the
.Ic attach-session
command).
.Pp
@ -4480,6 +4505,7 @@ The following variables are available, where appropriate:
.It Li "client_control_mode" Ta "" Ta "1 if client is in control mode"
.It Li "client_created" Ta "" Ta "Time client created"
.It Li "client_discarded" Ta "" Ta "Bytes discarded when client behind"
.It Li "client_flags" Ta "" Ta "List of client flags"
.It Li "client_height" Ta "" Ta "Height of client"
.It Li "client_key_table" Ta "" Ta "Current key table"
.It Li "client_last_session" Ta "" Ta "Name of the client's last session"

6
tmux.h
View File

@ -1570,7 +1570,7 @@ struct client {
#define CLIENT_CONTROLCONTROL 0x4000
#define CLIENT_FOCUSED 0x8000
#define CLIENT_UTF8 0x10000
/* 0x20000 unused */
#define CLIENT_IGNORESIZE 0x20000
#define CLIENT_IDENTIFIED 0x40000
#define CLIENT_STATUSFORCE 0x80000
#define CLIENT_DOUBLECLICK 0x100000
@ -2165,7 +2165,7 @@ char *cmd_template_replace(const char *, const char *, int);
/* cmd-attach-session.c */
enum cmd_retval cmd_attach_session(struct cmdq_item *, const char *, int, int,
int, const char *, int);
int, const char *, int, const char *);
/* cmd-parse.c */
void cmd_parse_empty(struct cmd_parse_input *);
@ -2304,6 +2304,8 @@ void server_client_push_stderr(struct client *);
void printflike(2, 3) server_client_add_message(struct client *, const char *,
...);
const char *server_client_get_cwd(struct client *, struct session *);
void server_client_set_flags(struct client *, const char *);
const char *server_client_get_flags(struct client *);
/* server-fn.c */
void server_redraw_client(struct client *);