Allow escaping , and } with # in #{}; GitHub issue 1332.

This commit is contained in:
nicm 2018-05-22 08:49:12 +00:00
parent f2f9605c63
commit 2a04665626
2 changed files with 39 additions and 19 deletions

View File

@ -837,18 +837,22 @@ found:
return (copy); return (copy);
} }
/* Skip until comma. */ /* Skip until end. */
static char * static const char *
format_skip(char *s) format_skip(const char *s, char end)
{ {
int brackets = 0; int brackets = 0;
for (; *s != '\0'; s++) { for (; *s != '\0'; s++) {
if (*s == '{') if (*s == '#' && s[1] == '{')
brackets++; brackets++;
if (*s == '#' && strchr(",#{}", s[1]) != NULL) {
s++;
continue;
}
if (*s == '}') if (*s == '}')
brackets--; brackets--;
if (*s == ',' && brackets == 0) if (*s == end && brackets == 0)
break; break;
} }
if (*s == '\0') if (*s == '\0')
@ -862,7 +866,7 @@ format_choose(char *s, char **left, char **right)
{ {
char *cp; char *cp;
cp = format_skip(s); cp = (char *)format_skip(s, ',');
if (cp == NULL) if (cp == NULL)
return (-1); return (-1);
*cp = '\0'; *cp = '\0';
@ -892,6 +896,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
size_t valuelen, newlen, fromlen, tolen, used; size_t valuelen, newlen, fromlen, tolen, used;
long limit = 0; long limit = 0;
int modifiers = 0, compare = 0, search = 0; int modifiers = 0, compare = 0, search = 0;
int literal = 0;
/* Make a copy of the key. */ /* Make a copy of the key. */
copy0 = copy = xmalloc(keylen + 1); copy0 = copy = xmalloc(keylen + 1);
@ -900,6 +905,12 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
/* Is there a length limit or whatnot? */ /* Is there a length limit or whatnot? */
switch (copy[0]) { switch (copy[0]) {
case 'l':
if (copy[1] != ':')
break;
literal = 1;
copy += 2;
break;
case 'm': case 'm':
if (copy[1] != ':') if (copy[1] != ':')
break; break;
@ -988,6 +999,12 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
break; break;
} }
/* Is this a literal string? */
if (literal) {
value = xstrdup(copy);
goto done;
}
/* Is this a comparison or a conditional? */ /* Is this a comparison or a conditional? */
if (search) { if (search) {
/* Search in pane. */ /* Search in pane. */
@ -1019,7 +1036,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
free(left); free(left);
} else if (*copy == '?') { } else if (*copy == '?') {
/* Conditional: check first and choose second or third. */ /* Conditional: check first and choose second or third. */
ptr = format_skip(copy); ptr = (char *)format_skip(copy, ',');
if (ptr == NULL) if (ptr == NULL)
goto fail; goto fail;
*ptr = '\0'; *ptr = '\0';
@ -1082,6 +1099,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
} }
/* Expand the buffer and copy in the value. */ /* Expand the buffer and copy in the value. */
done:
valuelen = strlen(value); valuelen = strlen(value);
while (*len - *off < valuelen + 1) { while (*len - *off < valuelen + 1) {
*buf = xreallocarray(*buf, 2, *len); *buf = xreallocarray(*buf, 2, *len);
@ -1179,14 +1197,8 @@ format_expand(struct format_tree *ft, const char *fmt)
fmt += n + 1; fmt += n + 1;
continue; continue;
case '{': case '{':
brackets = 1; ptr = format_skip(fmt - 2, '}');
for (ptr = fmt; *ptr != '\0'; ptr++) { if (ptr == NULL)
if (*ptr == '{')
brackets++;
if (*ptr == '}' && --brackets == 0)
break;
}
if (*ptr != '}' || brackets != 0)
break; break;
n = ptr - fmt; n = ptr - fmt;
@ -1194,12 +1206,14 @@ format_expand(struct format_tree *ft, const char *fmt)
break; break;
fmt += n + 1; fmt += n + 1;
continue; continue;
case '}':
case '#': case '#':
case ',':
while (len - off < 2) { while (len - off < 2) {
buf = xreallocarray(buf, 2, len); buf = xreallocarray(buf, 2, len);
len *= 2; len *= 2;
} }
buf[off++] = '#'; buf[off++] = ch;
continue; continue;
default: default:
s = NULL; s = NULL;

12
tmux.1
View File

@ -3542,11 +3542,17 @@ The possible variables are listed in the table below, or the name of a
.Nm .Nm
option may be used for an option's value. option may be used for an option's value.
Some variables have a shorter alias such as Some variables have a shorter alias such as
.Ql #S , .Ql #S ;
and
.Ql ## .Ql ##
is replaced by a single is replaced by a single
.Ql # . .Ql # ,
.Ql #,
by a
.Ql \&,
and
.Ql #}
by a
.Ql } .
.Pp .Pp
Conditionals are available by prefixing with Conditionals are available by prefixing with
.Ql \&? .Ql \&?