aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Marriott <nicholas.marriott@gmail.com>2017-10-11 08:03:55 +0100
committerNicholas Marriott <nicholas.marriott@gmail.com>2017-10-11 08:03:55 +0100
commit60074a6bc6284e841d9ddcf8bfd99b362baf4e4f (patch)
tree09db3e0bd29243530a8ea0b1b65dbd617a1f9745
parenta3967de9a58f1773b8ca01a1f98fcafb86b73ac1 (diff)
parent044019d9d670aee86147c51dc74f287e7bebfaab (diff)
downloadrtmux-60074a6bc6284e841d9ddcf8bfd99b362baf4e4f.tar.gz
rtmux-60074a6bc6284e841d9ddcf8bfd99b362baf4e4f.tar.bz2
rtmux-60074a6bc6284e841d9ddcf8bfd99b362baf4e4f.zip
Merge branch 'master' of github.com:tmux/tmux
-rw-r--r--cfg.c172
-rw-r--r--tmux.127
-rw-r--r--tty-keys.c2
3 files changed, 166 insertions, 35 deletions
diff --git a/cfg.c b/cfg.c
index 00ee33b1..827e4c18 100644
--- a/cfg.c
+++ b/cfg.c
@@ -26,6 +26,17 @@
#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;
int cfg_finished;
static char **cfg_causes;
@@ -101,6 +112,124 @@ start_cfg(void)
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
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' };
u_int found = 0;
size_t line = 0;
- char *buf, *cause1, *p, *q, *s;
+ char *buf, *cause1, *p, *q;
struct cmd_list *cmdlist;
struct cmdq_item *new_item;
- int condition = 0;
- struct format_tree *ft;
+ struct cfg_cond *cond, *cond1;
+ struct cfg_conds conds;
+
+ TAILQ_INIT(&conds);
log_debug("loading %s", path);
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))
*q-- = '\0';
- if (condition != 0 && strcmp(p, "%endif") == 0) {
- condition = 0;
+ if (*p == '%') {
+ cfg_handle_directive(p, path, line, &conds);
continue;
}
- if (strncmp(p, "%if ", 4) == 0) {
- if (condition != 0) {
- 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)
+ cond = TAILQ_FIRST(&conds);
+ if (cond != NULL && !cond->met)
continue;
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);
+ 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);
}
diff --git a/tmux.1 b/tmux.1
index 49a5350a..5f07b259 100644
--- a/tmux.1
+++ b/tmux.1
@@ -980,22 +980,37 @@ them with
and
.Em %endif
lines.
+Additional
+.Em %elif
+and
+.Em %else
+lines may also be used.
The argument to
.Em %if
-is expanded as a format and if it evaluates to false
-(zero or empty), subsequent lines are ignored until
+and
+.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 .
For example:
.Bd -literal -offset indent
%if #{==:#{host},myhost}
set -g status-style bg=red
+%elif #{==:#{host},myotherhost}
+set -g status-style bg=green
+%else
+set -g status-style bg=blue
%endif
.Ed
.Pp
Will change the status line to red if running on
-.Ql myhost .
-.Em %if
-may not be nested.
+.Ql myhost ,
+green if running on
+.Ql myotherhost ,
+or blue if running on another host.
.It Ic start-server
.D1 (alias: Ic start )
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 "history_bytes" Ta "" Ta "Number of bytes in window history"
.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_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"
diff --git a/tty-keys.c b/tty-keys.c
index 7c0455f0..febf57f1 100644
--- a/tty-keys.c
+++ b/tty-keys.c
@@ -271,7 +271,7 @@ static const struct tty_default_key_code tty_default_code_keys[] = {
{ TTYC_KDC5, KEYC_DC|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_KIND, KEYC_UP|KEYC_SHIFT|KEYC_XTERM },
+ { TTYC_KIND, KEYC_DOWN|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KDN2, KEYC_DOWN|KEYC_SHIFT|KEYC_XTERM },
{ TTYC_KDN3, KEYC_DOWN|KEYC_ESCAPE|KEYC_XTERM },
{ TTYC_KDN4, KEYC_DOWN|KEYC_SHIFT|KEYC_ESCAPE|KEYC_XTERM },