Add a way to mark environment variables as "hidden" so they can be used

by tmux but are not passed into the environment of new panes.
This commit is contained in:
nicm 2020-03-31 17:14:40 +00:00
parent e6cddcf752
commit cc8b41f294
13 changed files with 98 additions and 33 deletions

View File

@ -81,7 +81,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
add = args_first_value(args, 'e', &value);
while (add != NULL) {
environ_put(sc.environ, add);
environ_put(sc.environ, add, 0);
add = args_next_value(&value);
}

View File

@ -99,6 +99,7 @@ static void cmd_parse_print_commands(struct cmd_parse_input *, u_int,
}
%token ERROR
%token HIDDEN
%token IF
%token ELSE
%token ELIF
@ -134,6 +135,11 @@ statements : statement '\n'
}
statement : /* empty */
{
$$ = xmalloc (sizeof *$$);
TAILQ_INIT($$);
}
| hidden_assignment
{
$$ = xmalloc (sizeof *$$);
TAILQ_INIT($$);
@ -204,10 +210,21 @@ assignment : EQUALS
if ((~flags & CMD_PARSE_PARSEONLY) &&
(ps->scope == NULL || ps->scope->flag))
environ_put(global_environ, $1);
environ_put(global_environ, $1, 0);
free($1);
}
hidden_assignment : HIDDEN EQUALS
{
struct cmd_parse_state *ps = &parse_state;
int flags = ps->input->flags;
if ((~flags & CMD_PARSE_PARSEONLY) &&
(ps->scope == NULL || ps->scope->flag))
environ_put(global_environ, $2, ENVIRON_HIDDEN);
free($2);
}
if_open : IF expanded
{
struct cmd_parse_state *ps = &parse_state;
@ -1079,6 +1096,10 @@ yylex(void)
if (*cp == '\0')
return (TOKEN);
ps->condition = 1;
if (strcmp(yylval.token, "%hidden") == 0) {
free(yylval.token);
return (HIDDEN);
}
if (strcmp(yylval.token, "%if") == 0) {
free(yylval.token);
return (IF);

View File

@ -71,7 +71,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
add = args_first_value(args, 'e', &value);
while (add != NULL) {
environ_put(sc.environ, add);
environ_put(sc.environ, add, 0);
add = args_next_value(&value);
}

View File

@ -68,7 +68,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
add = args_first_value(args, 'e', &value);
while (add != NULL) {
environ_put(sc.environ, add);
environ_put(sc.environ, add, 0);
add = args_next_value(&value);
}

View File

@ -34,8 +34,8 @@ const struct cmd_entry cmd_set_environment_entry = {
.name = "set-environment",
.alias = "setenv",
.args = { "grt:u", 1, 2 },
.usage = "[-gru] " CMD_TARGET_SESSION_USAGE " name [value]",
.args = { "hgrt:u", 1, 2 },
.usage = "[-hgru] " CMD_TARGET_SESSION_USAGE " name [value]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
@ -96,7 +96,10 @@ cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no value specified");
return (CMD_RETURN_ERROR);
}
environ_set(env, name, "%s", value);
if (args_has(args, 'h'))
environ_set(env, name, ENVIRON_HIDDEN, "%s", value);
else
environ_set(env, name, 0, "%s", value);
}
return (CMD_RETURN_NORMAL);

View File

@ -38,8 +38,8 @@ const struct cmd_entry cmd_show_environment_entry = {
.name = "show-environment",
.alias = "showenv",
.args = { "gst:", 0, 1 },
.usage = "[-gs] " CMD_TARGET_SESSION_USAGE " [name]",
.args = { "hgst:", 0, 1 },
.usage = "[-hgs] " CMD_TARGET_SESSION_USAGE " [name]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
@ -69,7 +69,13 @@ static void
cmd_show_environment_print(struct cmd *self, struct cmdq_item *item,
struct environ_entry *envent)
{
char *escaped;
struct args *args = self->args;
char *escaped;
if (!args_has(args, 'h') && (envent->flags & ENVIRON_HIDDEN))
return;
if (args_has(args, 'h') && (~envent->flags & ENVIRON_HIDDEN))
return;
if (!args_has(self->args, 's')) {
if (envent->value != NULL)

View File

@ -142,7 +142,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
add = args_first_value(args, 'e', &value);
while (add != NULL) {
environ_put(sc.environ, add);
environ_put(sc.environ, add, 0);
add = args_next_value(&value);
}

View File

@ -86,8 +86,10 @@ environ_copy(struct environ *srcenv, struct environ *dstenv)
RB_FOREACH(envent, environ, srcenv) {
if (envent->value == NULL)
environ_clear(dstenv, envent->name);
else
environ_set(dstenv, envent->name, "%s", envent->value);
else {
environ_set(dstenv, envent->name, envent->flags,
"%s", envent->value);
}
}
}
@ -103,18 +105,21 @@ environ_find(struct environ *env, const char *name)
/* Set an environment variable. */
void
environ_set(struct environ *env, const char *name, const char *fmt, ...)
environ_set(struct environ *env, const char *name, int flags, const char *fmt,
...)
{
struct environ_entry *envent;
va_list ap;
va_start(ap, fmt);
if ((envent = environ_find(env, name)) != NULL) {
envent->flags = flags;
free(envent->value);
xvasprintf(&envent->value, fmt, ap);
} else {
envent = xmalloc(sizeof *envent);
envent->name = xstrdup(name);
envent->flags = flags;
xvasprintf(&envent->value, fmt, ap);
RB_INSERT(environ, env, envent);
}
@ -133,6 +138,7 @@ environ_clear(struct environ *env, const char *name)
} else {
envent = xmalloc(sizeof *envent);
envent->name = xstrdup(name);
envent->flags = 0;
envent->value = NULL;
RB_INSERT(environ, env, envent);
}
@ -140,7 +146,7 @@ environ_clear(struct environ *env, const char *name)
/* Set an environment variable from a NAME=VALUE string. */
void
environ_put(struct environ *env, const char *var)
environ_put(struct environ *env, const char *var, int flags)
{
char *name, *value;
@ -152,7 +158,7 @@ environ_put(struct environ *env, const char *var)
name = xstrdup(var);
name[strcspn(name, "=")] = '\0';
environ_set(env, name, "%s", value);
environ_set(env, name, flags, "%s", value);
free(name);
}
@ -170,7 +176,7 @@ environ_unset(struct environ *env, const char *name)
free(envent);
}
/* Copy variables from a destination into a source * environment. */
/* Copy variables from a destination into a source environment. */
void
environ_update(struct options *oo, struct environ *src, struct environ *dst)
{
@ -188,7 +194,7 @@ environ_update(struct options *oo, struct environ *src, struct environ *dst)
if ((envent = environ_find(src, ov->string)) == NULL)
environ_clear(dst, ov->string);
else
environ_set(dst, envent->name, "%s", envent->value);
environ_set(dst, envent->name, 0, "%s", envent->value);
a = options_array_next(a);
}
}
@ -201,7 +207,9 @@ environ_push(struct environ *env)
environ = xcalloc(1, sizeof *environ);
RB_FOREACH(envent, environ, env) {
if (envent->value != NULL && *envent->name != '\0')
if (envent->value != NULL &&
*envent->name != '\0' &&
(~envent->flags & ENVIRON_HIDDEN))
setenv(envent->name, envent->value, 1);
}
}
@ -243,14 +251,15 @@ environ_for_session(struct session *s, int no_TERM)
if (!no_TERM) {
value = options_get_string(global_options, "default-terminal");
environ_set(env, "TERM", "%s", value);
environ_set(env, "TERM", 0, "%s", value);
}
if (s != NULL)
idx = s->id;
else
idx = -1;
environ_set(env, "TMUX", "%s,%ld,%d", socket_path, (long)getpid(), idx);
environ_set(env, "TMUX", 0, "%s,%ld,%d", socket_path, (long)getpid(),
idx);
return (env);
}

View File

@ -520,6 +520,7 @@ server_client_check_mouse(struct client *c, struct key_event *event)
memcpy(&c->click_event, m, sizeof c->click_event);
c->click_button = m->b;
log_debug("click timer started");
tv.tv_sec = KEYC_CLICK_TIMEOUT / 1000;
tv.tv_usec = (KEYC_CLICK_TIMEOUT % 1000) * 1000L;
evtimer_del(&c->click_timer);
@ -2020,7 +2021,7 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_IDENTIFY_ENVIRON string");
if (strchr(data, '=') != NULL)
environ_put(c->environ, data);
environ_put(c->environ, data, 0);
log_debug("client %p IDENTIFY_ENVIRON %s", c, data);
break;
case MSG_IDENTIFY_CLIENTPID:

View File

@ -303,7 +303,7 @@ spawn_pane(struct spawn_context *sc, char **cause)
child = environ_for_session(s, 0);
if (sc->environ != NULL)
environ_copy(sc->environ, child);
environ_set(child, "TMUX_PANE", "%%%u", new_wp->id);
environ_set(child, "TMUX_PANE", 0, "%%%u", new_wp->id);
/*
* Then the PATH environment variable. The session one is replaced from
@ -313,10 +313,10 @@ spawn_pane(struct spawn_context *sc, char **cause)
if (c != NULL && c->session == NULL) { /* only unattached clients */
ee = environ_find(c->environ, "PATH");
if (ee != NULL)
environ_set(child, "PATH", "%s", ee->value);
environ_set(child, "PATH", 0, "%s", ee->value);
}
if (environ_find(child, "PATH") == NULL)
environ_set(child, "%s", _PATH_DEFPATH);
environ_set(child, "PATH", 0, "%s", _PATH_DEFPATH);
/* Then the shell. If respawning, use the old one. */
if (~sc->flags & SPAWN_RESPAWN) {
@ -326,7 +326,7 @@ spawn_pane(struct spawn_context *sc, char **cause)
free(new_wp->shell);
new_wp->shell = xstrdup(tmp);
}
environ_set(child, "SHELL", "%s", new_wp->shell);
environ_set(child, "SHELL", 0, "%s", new_wp->shell);
/* Log the arguments we are going to use. */
log_debug("%s: shell=%s", __func__, new_wp->shell);

26
tmux.1
View File

@ -565,6 +565,18 @@ Environment variables may be set by using the syntax
for example
.Ql HOME=/home/user .
Variables set during parsing are added to the global environment.
A hidden variable may be set with
.Ql %hidden ,
for example:
.Bd -literal -offset indent
%hidden MYVAR=42
.Ed
.Pp
Hidden variables are not passed to the environment of processes created
by tmux.
See the
.Sx GLOBAL AND SESSION ENVIRONMENT
section.
.Pp
Commands may be parsed conditionally by surrounding them with
.Ql %if ,
@ -4711,10 +4723,16 @@ from inside, and the
variable with the correct terminal setting of
.Ql screen .
.Pp
Variables in both session and global environments may be marked as hidden.
Hidden variables are not passed into the environment of new processes and
instead can only be used by tmux itself (for example in formats, see the
.Sx FORMATS
section).
.Pp
Commands to alter and view the environment are:
.Bl -tag -width Ds
.It Xo Ic set-environment
.Op Fl gru
.Op Fl hgru
.Op Fl t Ar target-session
.Ar name Op Ar value
.Xc
@ -4731,8 +4749,10 @@ flag unsets a variable.
.Fl r
indicates the variable is to be removed from the environment before starting a
new process.
.Fl h
marks the variable as hidden.
.It Xo Ic show-environment
.Op Fl gs
.Op Fl hgs
.Op Fl t Ar target-session
.Op Ar variable
.Xc
@ -4749,6 +4769,8 @@ Variables removed from the environment are prefixed with
If
.Fl s
is used, the output is formatted as a set of Bourne shell commands.
.Fl h
shows hidden variables (omitted by default).
.El
.Sh STATUS LINE
.Nm

4
tmux.c
View File

@ -332,9 +332,9 @@ main(int argc, char **argv)
global_environ = environ_create();
for (var = environ; *var != NULL; var++)
environ_put(global_environ, *var);
environ_put(global_environ, *var, 0);
if ((cwd = find_cwd()) != NULL)
environ_set(global_environ, "PWD", "%s", cwd);
environ_set(global_environ, "PWD", 0, "%s", cwd);
global_options = options_create(NULL);
global_s_options = options_create(NULL);

9
tmux.h
View File

@ -1048,6 +1048,9 @@ struct environ_entry {
char *name;
char *value;
int flags;
#define ENVIRON_HIDDEN 0x1
RB_ENTRY(environ_entry) entry;
};
@ -1957,10 +1960,10 @@ struct environ_entry *environ_first(struct environ *);
struct environ_entry *environ_next(struct environ_entry *);
void environ_copy(struct environ *, struct environ *);
struct environ_entry *environ_find(struct environ *, const char *);
void printflike(3, 4) environ_set(struct environ *, const char *, const char *,
...);
void printflike(4, 5) environ_set(struct environ *, const char *, int,
const char *, ...);
void environ_clear(struct environ *, const char *);
void environ_put(struct environ *, const char *);
void environ_put(struct environ *, const char *, int);
void environ_unset(struct environ *, const char *);
void environ_update(struct options *, struct environ *, struct environ *);
void environ_push(struct environ *);