summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornicm <nicm>2019-04-28 20:05:50 +0000
committernicm <nicm>2019-04-28 20:05:50 +0000
commitc4b0da5513ee4c9692f0980408b0da2ee7e3a553 (patch)
tree3bef007901ae51d68f18454f1bbf8a9c2027e11e
parentdfb7bb683057d08303955c49073f4b475bd0e2d6 (diff)
Support multiple occurances of the same argument. Use this for a new
flag -e to new-window, split-window, respawn-window, respawn-pane to pass environment variables into the newly created process. From Steffen Christgau in GitHub issue 1697.
-rw-r--r--arguments.c157
-rw-r--r--cmd-new-window.c17
-rw-r--r--cmd-respawn-pane.c16
-rw-r--r--cmd-respawn-window.c16
-rw-r--r--cmd-split-window.c15
-rw-r--r--spawn.c2
-rw-r--r--tmux.128
-rw-r--r--tmux.h4
8 files changed, 192 insertions, 63 deletions
diff --git a/arguments.c b/arguments.c
index c0a09729..f7288e81 100644
--- a/arguments.c
+++ b/arguments.c
@@ -29,9 +29,15 @@
* Manipulate command arguments.
*/
+struct args_value {
+ char *value;
+ TAILQ_ENTRY(args_value) entry;
+};
+TAILQ_HEAD(args_values, args_value);
+
struct args_entry {
u_char flag;
- char *value;
+ struct args_values values;
RB_ENTRY(args_entry) entry;
};
@@ -93,12 +99,18 @@ args_free(struct args *args)
{
struct args_entry *entry;
struct args_entry *entry1;
+ struct args_value *value;
+ struct args_value *value1;
cmd_free_argv(args->argc, args->argv);
RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) {
RB_REMOVE(args_tree, &args->tree, entry);
- free(entry->value);
+ TAILQ_FOREACH_SAFE(value, &entry->values, entry, value1) {
+ TAILQ_REMOVE(&entry->values, value, entry);
+ free(value->value);
+ free(value);
+ }
free(entry);
}
@@ -124,22 +136,69 @@ args_print_add(char **buf, size_t *len, const char *fmt, ...)
free(s);
}
+/* Add value to string. */
+static void
+args_print_add_value(char **buf, size_t *len, struct args_entry *entry,
+ struct args_value *value)
+{
+ static const char quoted[] = " #\"';$";
+ char *escaped;
+ int flags;
+
+ if (**buf != '\0')
+ args_print_add(buf, len, " -%c ", entry->flag);
+ else
+ args_print_add(buf, len, "-%c ", entry->flag);
+
+ flags = VIS_OCTAL|VIS_TAB|VIS_NL;
+ if (value->value[strcspn(value->value, quoted)] != '\0')
+ flags |= VIS_DQ;
+ utf8_stravis(&escaped, value->value, flags);
+ if (flags & VIS_DQ)
+ args_print_add(buf, len, "\"%s\"", escaped);
+ else
+ args_print_add(buf, len, "%s", escaped);
+ free(escaped);
+}
+
+/* Add argument to string. */
+static void
+args_print_add_argument(char **buf, size_t *len, const char *argument)
+{
+ static const char quoted[] = " #\"';$";
+ char *escaped;
+ int flags;
+
+ if (**buf != '\0')
+ args_print_add(buf, len, " ");
+
+ flags = VIS_OCTAL|VIS_TAB|VIS_NL;
+ if (argument[strcspn(argument, quoted)] != '\0')
+ flags |= VIS_DQ;
+ utf8_stravis(&escaped, argument, flags);
+ if (flags & VIS_DQ)
+ args_print_add(buf, len, "\"%s\"", escaped);
+ else
+ args_print_add(buf, len, "%s", escaped);
+ free(escaped);
+}
+
/* Print a set of arguments. */
char *
args_print(struct args *args)
{
size_t len;
- char *buf, *escaped;
- int i, flags;
+ char *buf;
+ int i;
struct args_entry *entry;
- static const char quoted[] = " #\"';$";
+ struct args_value *value;
len = 1;
buf = xcalloc(1, len);
/* Process the flags first. */
RB_FOREACH(entry, args_tree, &args->tree) {
- if (entry->value != NULL)
+ if (!TAILQ_EMPTY(&entry->values))
continue;
if (*buf == '\0')
@@ -149,40 +208,13 @@ args_print(struct args *args)
/* Then the flags with arguments. */
RB_FOREACH(entry, args_tree, &args->tree) {
- if (entry->value == NULL)
- continue;
-
- if (*buf != '\0')
- args_print_add(&buf, &len, " -%c ", entry->flag);
- else
- args_print_add(&buf, &len, "-%c ", entry->flag);
-
- flags = VIS_OCTAL|VIS_TAB|VIS_NL;
- if (entry->value[strcspn(entry->value, quoted)] != '\0')
- flags |= VIS_DQ;
- utf8_stravis(&escaped, entry->value, flags);
- if (flags & VIS_DQ)
- args_print_add(&buf, &len, "\"%s\"", escaped);
- else
- args_print_add(&buf, &len, "%s", escaped);
- free(escaped);
+ TAILQ_FOREACH(value, &entry->values, entry)
+ args_print_add_value(&buf, &len, entry, value);
}
/* And finally the argument vector. */
- for (i = 0; i < args->argc; i++) {
- if (*buf != '\0')
- args_print_add(&buf, &len, " ");
-
- flags = VIS_OCTAL|VIS_TAB|VIS_NL;
- if (args->argv[i][strcspn(args->argv[i], quoted)] != '\0')
- flags |= VIS_DQ;
- utf8_stravis(&escaped, args->argv[i], flags);
- if (flags & VIS_DQ)
- args_print_add(&buf, &len, "\"%s\"", escaped);
- else
- args_print_add(&buf, &len, "%s", escaped);
- free(escaped);
- }
+ for (i = 0; i < args->argc; i++)
+ args_print_add_argument(&buf, &len, args->argv[i]);
return (buf);
}
@@ -196,22 +228,24 @@ args_has(struct args *args, u_char ch)
/* Set argument value in the arguments tree. */
void
-args_set(struct args *args, u_char ch, const char *value)
+args_set(struct args *args, u_char ch, const char *s)
{
struct args_entry *entry;
+ struct args_value *value;
- /* Replace existing argument. */
- if ((entry = args_find(args, ch)) != NULL) {
- free(entry->value);
- entry->value = NULL;
- } else {
+ entry = args_find(args, ch);
+ if (entry == NULL) {
entry = xcalloc(1, sizeof *entry);
entry->flag = ch;
+ TAILQ_INIT(&entry->values);
RB_INSERT(args_tree, &args->tree, entry);
}
- if (value != NULL)
- entry->value = xstrdup(value);
+ if (s != NULL) {
+ value = xcalloc(1, sizeof *value);
+ value->value = xstrdup(s);
+ TAILQ_INSERT_TAIL(&entry->values, value, entry);
+ }
}
/* Get argument value. Will be NULL if it isn't present. */
@@ -222,7 +256,34 @@ args_get(struct args *args, u_char ch)
if ((entry = args_find(args, ch)) == NULL)
return (NULL);
- return (entry->value);
+ return (TAILQ_LAST(&entry->values, args_values)->value);
+}
+
+/* Get first value in argument. */
+const char *
+args_first_value(struct args *args, u_char ch, struct args_value **value)
+{
+ struct args_entry *entry;
+
+ if ((entry = args_find(args, ch)) == NULL)
+ return (NULL);
+
+ *value = TAILQ_FIRST(&entry->values);
+ if (*value == NULL)
+ return (NULL);
+ return ((*value)->value);
+}
+
+/* Get next value in argument. */
+const char *
+args_next_value(struct args_value **value)
+{
+ if (*value == NULL)
+ return (NULL);
+ *value = TAILQ_NEXT(*value, entry);
+ if (*value == NULL)
+ return (NULL);
+ return ((*value)->value);
}
/* Convert an argument value to a number. */
@@ -233,13 +294,15 @@ args_strtonum(struct args *args, u_char ch, long long minval, long long maxval,
const char *errstr;
long long ll;
struct args_entry *entry;
+ struct args_value *value;
if ((entry = args_find(args, ch)) == NULL) {
*cause = xstrdup("missing");
return (0);
}
+ value = TAILQ_LAST(&entry->values, args_values);
- ll = strtonum(entry->value, minval, maxval, &errstr);
+ ll = strtonum(value->value, minval, maxval, &errstr);
if (errstr != NULL) {
*cause = xstrdup(errstr);
return (0);
diff --git a/cmd-new-window.c b/cmd-new-window.c
index 1007c597..6cb33dd9 100644
--- a/cmd-new-window.c
+++ b/cmd-new-window.c
@@ -38,9 +38,9 @@ const struct cmd_entry cmd_new_window_entry = {
.name = "new-window",
.alias = "neww",
- .args = { "ac:dF:kn:Pt:", 0, -1 },
- .usage = "[-adkP] [-c start-directory] [-F format] [-n window-name] "
- CMD_TARGET_WINDOW_USAGE " [command]",
+ .args = { "ac:de:F:kn:Pt:", 0, -1 },
+ .usage = "[-adkP] [-c start-directory] [-e environment] [-F format] "
+ "[-n window-name] " CMD_TARGET_WINDOW_USAGE " [command]",
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
@@ -60,8 +60,9 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
int idx = item->target.idx;
struct winlink *new_wl;
char *cause = NULL, *cp;
- const char *template;
+ const char *template, *add;
struct cmd_find_state fs;
+ struct args_value *value;
if (args_has(args, 'a') && (idx = winlink_shuffle_up(s, wl)) == -1) {
cmdq_error(item, "couldn't get a window index");
@@ -75,6 +76,13 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
sc.name = args_get(args, 'n');
sc.argc = args->argc;
sc.argv = args->argv;
+ sc.environ = environ_create();
+
+ add = args_first_value(args, 'e', &value);
+ while (add != NULL) {
+ environ_put(sc.environ, add);
+ add = args_next_value(&value);
+ }
sc.idx = idx;
sc.cwd = args_get(args, 'c');
@@ -107,5 +115,6 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
cmd_find_from_winlink(&fs, new_wl, 0);
cmdq_insert_hook(s, item, &fs, "after-new-window");
+ environ_free(sc.environ);
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-respawn-pane.c b/cmd-respawn-pane.c
index 44234315..5e23fa15 100644
--- a/cmd-respawn-pane.c
+++ b/cmd-respawn-pane.c
@@ -34,9 +34,9 @@ const struct cmd_entry cmd_respawn_pane_entry = {
.name = "respawn-pane",
.alias = "respawnp",
- .args = { "c:kt:", 0, -1 },
- .usage = "[-c start-directory] [-k] " CMD_TARGET_PANE_USAGE
- " [command]",
+ .args = { "c:e:kt:", 0, -1 },
+ .usage = "[-k] [-c start-directory] [-e environment] "
+ CMD_TARGET_PANE_USAGE " [command]",
.target = { 't', CMD_FIND_PANE, 0 },
@@ -53,6 +53,8 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
char *cause = NULL;
+ const char *add;
+ struct args_value *value;
memset(&sc, 0, sizeof sc);
sc.item = item;
@@ -65,6 +67,13 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
sc.name = NULL;
sc.argc = args->argc;
sc.argv = args->argv;
+ sc.environ = environ_create();
+
+ add = args_first_value(args, 'e', &value);
+ while (add != NULL) {
+ environ_put(sc.environ, add);
+ add = args_next_value(&value);
+ }
sc.idx = -1;
sc.cwd = args_get(args, 'c');
@@ -82,5 +91,6 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
wp->flags |= PANE_REDRAW;
server_status_window(wp->window);
+ environ_free(sc.environ);
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c
index 2ccb2fde..aec22912 100644
--- a/cmd-respawn-window.c
+++ b/cmd-respawn-window.c
@@ -34,9 +34,9 @@ const struct cmd_entry cmd_respawn_window_entry = {
.name = "respawn-window",
.alias = "respawnw",
- .args = { "c:kt:", 0, -1 },
- .usage = "[-c start-directory] [-k] " CMD_TARGET_WINDOW_USAGE
- " [command]",
+ .args = { "c:e:kt:", 0, -1 },
+ .usage = "[-k] [-c start-directory] [-e environment] "
+ CMD_TARGET_WINDOW_USAGE " [command]",
.target = { 't', CMD_FIND_WINDOW, 0 },
@@ -52,6 +52,8 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
char *cause = NULL;
+ const char *add;
+ struct args_value *value;
memset(&sc, 0, sizeof sc);
sc.item = item;
@@ -61,6 +63,13 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
sc.name = NULL;
sc.argc = args->argc;
sc.argv = args->argv;
+ sc.environ = environ_create();
+
+ add = args_first_value(args, 'e', &value);
+ while (add != NULL) {
+ environ_put(sc.environ, add);
+ add = args_next_value(&value);
+ }
sc.idx = -1;
sc.cwd = args_get(args, 'c');
@@ -77,5 +86,6 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
server_redraw_window(wl->window);
+ environ_free(sc.environ);
return (CMD_RETURN_NORMAL);
}
diff --git a/cmd-split-window.c b/cmd-split-window.c
index 597a5c96..3b9040dc 100644
--- a/cmd-split-window.c
+++ b/cmd-split-window.c
@@ -40,8 +40,8 @@ const struct cmd_entry cmd_split_window_entry = {
.name = "split-window",
.alias = "splitw",
- .args = { "bc:dfF:l:hp:Pt:v", 0, -1 },
- .usage = "[-bdfhvP] [-c start-directory] [-F format] "
+ .args = { "bc:de:fF:l:hp:Pt:v", 0, -1 },
+ .usage = "[-bdefhvP] [-c start-directory] [-e environment] [-F format] "
"[-p percentage|-l size] " CMD_TARGET_PANE_USAGE " [command]",
.target = { 't', CMD_FIND_PANE, 0 },
@@ -64,8 +64,9 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
struct layout_cell *lc;
struct cmd_find_state fs;
int size, percentage, flags;
- const char *template;
+ const char *template, *add;
char *cause, *cp;
+ struct args_value *value;
if (args_has(args, 'h'))
type = LAYOUT_LEFTRIGHT;
@@ -117,6 +118,13 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
sc.name = NULL;
sc.argc = args->argc;
sc.argv = args->argv;
+ sc.environ = environ_create();
+
+ add = args_first_value(args, 'e', &value);
+ while (add != NULL) {
+ environ_put(sc.environ, add);
+ add = args_next_value(&value);
+ }
sc.idx = -1;
sc.cwd = args_get(args, 'c');
@@ -146,5 +154,6 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
cmd_find_from_winlink_pane(&fs, wl, new_wp, 0);
cmdq_insert_hook(s, item, &fs, "after-split-window");
+ environ_free(sc.environ);
return (CMD_RETURN_NORMAL);
}
diff --git a/spawn.c b/spawn.c
index 0565fee3..8e577ff5 100644
--- a/spawn.c
+++ b/spawn.c
@@ -293,6 +293,8 @@ spawn_pane(struct spawn_context *sc, char **cause)
/* Create an environment for this pane. */
child = environ_for_session(s, 0);
+ if (sc->environ != NULL)
+ environ_copy(sc->environ, child);
environ_set(child, "TMUX_PANE", "%%%u", new_wp->id);
/*
diff --git a/tmux.1 b/tmux.1
index e5343991..80e51a69 100644
--- a/tmux.1
+++ b/tmux.1
@@ -1784,6 +1784,7 @@ option.
.It Xo Ic new-window
.Op Fl adkP
.Op Fl c Ar start-directory
+.Op Fl e Ar environment
.Op Fl F Ar format
.Op Fl n Ar window-name
.Op Fl t Ar target-window
@@ -1823,6 +1824,12 @@ See the
.Ic remain-on-exit
option to change this behaviour.
.Pp
+.Fl e
+takes the form
+.Ql VARIABLE=value
+and sets an environment variable for the newly created window; it may be
+specified multiple times.
+.Pp
The
.Ev TERM
environment variable must be set to
@@ -1835,7 +1842,9 @@ for all programs running
New windows will automatically have
.Ql TERM=screen
added to their environment, but care must be taken not to reset this in shell
-start-up files.
+start-up files or by the
+.Fl e
+option.
.Pp
The
.Fl P
@@ -1994,8 +2003,9 @@ This command will automatically set
.Ic window-size
to manual in the window options.
.It Xo Ic respawn-pane
-.Op Fl c Ar start-directory
.Op Fl k
+.Op Fl c Ar start-directory
+.Op Fl e Ar environment
.Op Fl t Ar target-pane
.Op Ar shell-command
.Xc
@@ -2011,9 +2021,15 @@ The pane must be already inactive, unless
is given, in which case any existing command is killed.
.Fl c
specifies a new working directory for the pane.
+The
+.Fl e
+option has the same meaning as for the
+.Ic new-window
+command.
.It Xo Ic respawn-window
-.Op Fl c Ar start-directory
.Op Fl k
+.Op Fl c Ar start-directory
+.Op Fl e Ar environment
.Op Fl t Ar target-window
.Op Ar shell-command
.Xc
@@ -2029,6 +2045,11 @@ The window must be already inactive, unless
is given, in which case any existing command is killed.
.Fl c
specifies a new working directory for the window.
+The
+.Fl e
+option has the same meaning as for the
+.Ic new-window
+command.
.It Xo Ic rotate-window
.Op Fl DU
.Op Fl t Ar target-window
@@ -2147,6 +2168,7 @@ the command behaves like
.It Xo Ic split-window
.Op Fl bdfhvP
.Op Fl c Ar start-directory
+.Op Fl e Ar environment
.Oo Fl l
.Ar size |
.Fl p Ar percentage Oc
diff --git a/tmux.h b/tmux.h
index 550c9332..0e79d429 100644
--- a/tmux.h
+++ b/tmux.h
@@ -37,6 +37,7 @@
extern char **environ;
struct args;
+struct args_value;
struct client;
struct cmd_find_state;
struct cmdq_item;
@@ -1578,6 +1579,7 @@ struct spawn_context {
const char *name;
char **argv;
int argc;
+ struct environ *environ;
int idx;
const char *cwd;
@@ -1871,6 +1873,8 @@ void args_free(struct args *);
char *args_print(struct args *);
int args_has(struct args *, u_char);
const char *args_get(struct args *, u_char);
+const char *args_first_value(struct args *, u_char, struct args_value **);
+const char *args_next_value(struct args_value **);
long long args_strtonum(struct args *, u_char, long long, long long,
char **);