Merge branch 'master' of github.com:tmux/tmux

This commit is contained in:
Nicholas Marriott 2017-10-11 08:03:55 +01:00
commit 60074a6bc6
3 changed files with 166 additions and 35 deletions

172
cfg.c
View File

@ -26,6 +26,17 @@
#include "tmux.h" #include "tmux.h"
/* Condition for %if, %elif, %else and %endif. */
struct cfg_cond {
size_t line; /* line number of %if */
int met; /* condition was met */
int skip; /* skip later %elif/%else */
int saw_else; /* saw a %else */
TAILQ_ENTRY(cfg_cond) entry;
};
TAILQ_HEAD(cfg_conds, cfg_cond);
static char *cfg_file; static char *cfg_file;
int cfg_finished; int cfg_finished;
static char **cfg_causes; static char **cfg_causes;
@ -101,6 +112,124 @@ start_cfg(void)
cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL)); cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL));
} }
static int
cfg_check_condition(const char *path, size_t line, const char *p, int *skip)
{
struct format_tree *ft;
char *s;
int result;
while (isspace((u_char)*p))
p++;
if (p[0] == '\0') {
cfg_add_cause("%s:%zu: invalid condition", path, line);
*skip = 1;
return (0);
}
ft = format_create(NULL, NULL, FORMAT_NONE, FORMAT_NOJOBS);
s = format_expand(ft, p);
result = format_true(s);
free(s);
format_free(ft);
*skip = result;
return (result);
}
static void
cfg_handle_if(const char *path, size_t line, struct cfg_conds *conds,
const char *p)
{
struct cfg_cond *cond;
struct cfg_cond *parent = TAILQ_FIRST(conds);
/*
* Add a new condition. If a previous condition exists and isn't
* currently met, this new one also can't be met.
*/
cond = xcalloc(1, sizeof *cond);
cond->line = line;
if (parent == NULL || parent->met)
cond->met = cfg_check_condition(path, line, p, &cond->skip);
else
cond->skip = 1;
cond->saw_else = 0;
TAILQ_INSERT_HEAD(conds, cond, entry);
}
static void
cfg_handle_elif(const char *path, size_t line, struct cfg_conds *conds,
const char *p)
{
struct cfg_cond *cond = TAILQ_FIRST(conds);
/*
* If a previous condition exists and wasn't met, check this
* one instead and change the state.
*/
if (cond == NULL || cond->saw_else)
cfg_add_cause("%s:%zu: unexpected %%elif", path, line);
else if (!cond->skip)
cond->met = cfg_check_condition(path, line, p, &cond->skip);
else
cond->met = 0;
}
static void
cfg_handle_else(const char *path, size_t line, struct cfg_conds *conds)
{
struct cfg_cond *cond = TAILQ_FIRST(conds);
/*
* If a previous condition exists and wasn't met and wasn't already
* %else, use this one instead.
*/
if (cond == NULL || cond->saw_else) {
cfg_add_cause("%s:%zu: unexpected %%else", path, line);
return;
}
cond->saw_else = 1;
cond->met = !cond->skip;
cond->skip = 1;
}
static void
cfg_handle_endif(const char *path, size_t line, struct cfg_conds *conds)
{
struct cfg_cond *cond = TAILQ_FIRST(conds);
/*
* Remove previous condition if one exists.
*/
if (cond == NULL) {
cfg_add_cause("%s:%zu: unexpected %%endif", path, line);
return;
}
TAILQ_REMOVE(conds, cond, entry);
free(cond);
}
static void
cfg_handle_directive(const char *p, const char *path, size_t line,
struct cfg_conds *conds)
{
int n = 0;
while (p[n] != '\0' && !isspace((u_char)p[n]))
n++;
if (strncmp(p, "%if", n) == 0)
cfg_handle_if(path, line, conds, p + n);
else if (strncmp(p, "%elif", n) == 0)
cfg_handle_elif(path, line, conds, p + n);
else if (strcmp(p, "%else") == 0)
cfg_handle_else(path, line, conds);
else if (strcmp(p, "%endif") == 0)
cfg_handle_endif(path, line, conds);
else
cfg_add_cause("%s:%zu: invalid directive: %s", path, line, p);
}
int int
load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet) load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
{ {
@ -108,11 +237,13 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
const char delim[3] = { '\\', '\\', '\0' }; const char delim[3] = { '\\', '\\', '\0' };
u_int found = 0; u_int found = 0;
size_t line = 0; size_t line = 0;
char *buf, *cause1, *p, *q, *s; char *buf, *cause1, *p, *q;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmdq_item *new_item; struct cmdq_item *new_item;
int condition = 0; struct cfg_cond *cond, *cond1;
struct format_tree *ft; struct cfg_conds conds;
TAILQ_INIT(&conds);
log_debug("loading %s", path); log_debug("loading %s", path);
if ((f = fopen(path, "rb")) == NULL) { if ((f = fopen(path, "rb")) == NULL) {
@ -136,33 +267,12 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
while (q != p && isspace((u_char)*q)) while (q != p && isspace((u_char)*q))
*q-- = '\0'; *q-- = '\0';
if (condition != 0 && strcmp(p, "%endif") == 0) { if (*p == '%') {
condition = 0; cfg_handle_directive(p, path, line, &conds);
continue; continue;
} }
if (strncmp(p, "%if ", 4) == 0) { cond = TAILQ_FIRST(&conds);
if (condition != 0) { if (cond != NULL && !cond->met)
cfg_add_cause("%s:%zu: nested %%if", path,
line);
continue;
}
ft = format_create(NULL, NULL, FORMAT_NONE,
FORMAT_NOJOBS);
s = p + 3;
while (isspace((u_char)*s))
s++;
s = format_expand(ft, s);
if (*s != '\0' && (s[0] != '0' || s[1] != '\0'))
condition = 1;
else
condition = -1;
free(s);
format_free(ft);
continue;
}
if (condition == -1)
continue; continue;
cmdlist = cmd_string_parse(p, path, line, &cause1); cmdlist = cmd_string_parse(p, path, line, &cause1);
@ -189,6 +299,12 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
} }
fclose(f); fclose(f);
TAILQ_FOREACH_REVERSE_SAFE(cond, &conds, cfg_conds, entry, cond1) {
cfg_add_cause("%s:%zu: unterminated %%if", path, cond->line);
TAILQ_REMOVE(&conds, cond, entry);
free(cond);
}
return (found); return (found);
} }

27
tmux.1
View File

@ -980,22 +980,37 @@ them with
and and
.Em %endif .Em %endif
lines. lines.
Additional
.Em %elif
and
.Em %else
lines may also be used.
The argument to The argument to
.Em %if .Em %if
is expanded as a format and if it evaluates to false and
(zero or empty), subsequent lines are ignored until .Em %elif
is expanded as a format and if it evaluates to false (zero or empty),
subsequent lines are ignored until the next
.Em %elif ,
.Em %else
or
.Em %endif . .Em %endif .
For example: For example:
.Bd -literal -offset indent .Bd -literal -offset indent
%if #{==:#{host},myhost} %if #{==:#{host},myhost}
set -g status-style bg=red set -g status-style bg=red
%elif #{==:#{host},myotherhost}
set -g status-style bg=green
%else
set -g status-style bg=blue
%endif %endif
.Ed .Ed
.Pp .Pp
Will change the status line to red if running on Will change the status line to red if running on
.Ql myhost . .Ql myhost ,
.Em %if green if running on
may not be nested. .Ql myotherhost ,
or blue if running on another host.
.It Ic start-server .It Ic start-server
.D1 (alias: Ic start ) .D1 (alias: Ic start )
Start the Start the
@ -3638,7 +3653,7 @@ The following variables are available, where appropriate:
.It Li "cursor_y" Ta "" Ta "Cursor Y position in pane" .It Li "cursor_y" Ta "" Ta "Cursor Y position in pane"
.It Li "history_bytes" Ta "" Ta "Number of bytes in window history" .It Li "history_bytes" Ta "" Ta "Number of bytes in window history"
.It Li "history_limit" Ta "" Ta "Maximum window history lines" .It Li "history_limit" Ta "" Ta "Maximum window history lines"
.It Li "history_size" Ta "" Ta "Size of history in bytes" .It Li "history_size" Ta "" Ta "Size of history in lines"
.It Li "hook" Ta "" Ta "Name of running hook, if any" .It Li "hook" Ta "" Ta "Name of running hook, if any"
.It Li "hook_pane" Ta "" Ta "ID of pane where hook was run, if any" .It Li "hook_pane" Ta "" Ta "ID of pane where hook was run, if any"
.It Li "hook_session" Ta "" Ta "ID of session where hook was run, if any" .It Li "hook_session" Ta "" Ta "ID of session where hook was run, if any"

View File

@ -271,7 +271,7 @@ static const struct tty_default_key_code tty_default_code_keys[] = {
{ TTYC_KDC5, KEYC_DC|KEYC_CTRL|KEYC_XTERM }, { TTYC_KDC5, KEYC_DC|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KDC6, KEYC_DC|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM }, { TTYC_KDC6, KEYC_DC|KEYC_SHIFT|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KDC7, KEYC_DC|KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM }, { TTYC_KDC7, KEYC_DC|KEYC_ESCAPE|KEYC_CTRL|KEYC_XTERM },
{ TTYC_KIND, KEYC_UP|KEYC_SHIFT|KEYC_XTERM }, { TTYC_KIND, KEYC_DOWN|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KDN2, KEYC_DOWN|KEYC_SHIFT|KEYC_XTERM }, { TTYC_KDN2, KEYC_DOWN|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KDN3, KEYC_DOWN|KEYC_ESCAPE|KEYC_XTERM }, { TTYC_KDN3, KEYC_DOWN|KEYC_ESCAPE|KEYC_XTERM },
{ TTYC_KDN4, KEYC_DOWN|KEYC_SHIFT|KEYC_ESCAPE|KEYC_XTERM }, { TTYC_KDN4, KEYC_DOWN|KEYC_SHIFT|KEYC_ESCAPE|KEYC_XTERM },