mirror of
https://github.com/tmux/tmux.git
synced 2024-12-04 19:58:48 +00:00
Change how escaping is processed for formats so that ## and # can be
used in styles. Also add a 'w' format modifier for the width. From Chas J Owens IV in GitHub issue 2389.
This commit is contained in:
parent
1326529f99
commit
61e55fa50d
174
format-draw.c
174
format-draw.c
@ -486,6 +486,18 @@ format_draw_right(struct screen_write_ctx *octx, u_int available, u_int ocx,
|
||||
focus_end, frs);
|
||||
}
|
||||
|
||||
/* Draw multiple characters. */
|
||||
static void
|
||||
format_draw_many(struct screen_write_ctx *ctx, struct style *sy, char ch,
|
||||
u_int n)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
utf8_set(&sy->gc.data, ch);
|
||||
for (i = 0; i < n; i++)
|
||||
screen_write_cell(ctx, &sy->gc);
|
||||
}
|
||||
|
||||
/* Draw a format to a screen. */
|
||||
void
|
||||
format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
|
||||
@ -509,10 +521,10 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
|
||||
size_t size = strlen(expanded);
|
||||
struct screen *os = octx->s, s[TOTAL];
|
||||
struct screen_write_ctx ctx[TOTAL];
|
||||
u_int ocx = os->cx, ocy = os->cy, i, width[TOTAL];
|
||||
u_int ocx = os->cx, ocy = os->cy, n, i, width[TOTAL];
|
||||
u_int map[] = { LEFT, LEFT, CENTRE, RIGHT };
|
||||
int focus_start = -1, focus_end = -1;
|
||||
int list_state = -1, fill = -1;
|
||||
int list_state = -1, fill = -1, even;
|
||||
enum style_align list_align = STYLE_ALIGN_DEFAULT;
|
||||
struct grid_cell gc, current_default;
|
||||
struct style sy, saved_sy;
|
||||
@ -547,6 +559,34 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
|
||||
*/
|
||||
cp = expanded;
|
||||
while (*cp != '\0') {
|
||||
/* Handle sequences of #. */
|
||||
if (cp[0] == '#' && cp[1] != '[' && cp[1] != '\0') {
|
||||
for (n = 1; cp[n] == '#'; n++)
|
||||
/* nothing */;
|
||||
if (cp[n] != '[') {
|
||||
width[current] += n;
|
||||
cp += n;
|
||||
format_draw_many(&ctx[current], &sy, '#', n);
|
||||
continue;
|
||||
}
|
||||
even = ((n % 2) == 0);
|
||||
if (even)
|
||||
cp += (n + 1);
|
||||
else
|
||||
cp += (n - 1);
|
||||
if (sy.ignore)
|
||||
continue;
|
||||
format_draw_many(&ctx[current], &sy, '#', n / 2);
|
||||
width[current] += (n / 2);
|
||||
if (even) {
|
||||
utf8_set(ud, '[');
|
||||
screen_write_cell(&ctx[current], &sy.gc);
|
||||
width[current]++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Is this not a style? */
|
||||
if (cp[0] != '#' || cp[1] != '[' || sy.ignore) {
|
||||
/* See if this is a UTF-8 character. */
|
||||
if ((more = utf8_open(ud, *cp)) == UTF8_MORE) {
|
||||
@ -796,13 +836,33 @@ u_int
|
||||
format_width(const char *expanded)
|
||||
{
|
||||
const char *cp, *end;
|
||||
u_int width = 0;
|
||||
u_int n, width = 0;
|
||||
struct utf8_data ud;
|
||||
enum utf8_state more;
|
||||
|
||||
cp = expanded;
|
||||
while (*cp != '\0') {
|
||||
if (cp[0] == '#' && cp[1] == '[') {
|
||||
if (*cp == '#') {
|
||||
for (n = 1; cp[n] == '#'; n++)
|
||||
/* nothing */;
|
||||
if (cp[n] != '[') {
|
||||
width += n;
|
||||
cp += n;
|
||||
continue;
|
||||
}
|
||||
width += (n / 2); /* one for each ## */
|
||||
|
||||
if ((n % 2) == 0) {
|
||||
/*
|
||||
* An even number of #s means that all #s are
|
||||
* escaped, so not a style.
|
||||
*/
|
||||
width++; /* one for the [ */
|
||||
cp += (n + 1);
|
||||
continue;
|
||||
}
|
||||
cp += (n - 1); /* point to the [ */
|
||||
|
||||
end = format_skip(cp + 2, "]");
|
||||
if (end == NULL)
|
||||
return (0);
|
||||
@ -823,19 +883,57 @@ format_width(const char *expanded)
|
||||
return (width);
|
||||
}
|
||||
|
||||
/* Trim on the left, taking #[] into account. */
|
||||
/*
|
||||
* Trim on the left, taking #[] into account. Note, we copy the whole set of
|
||||
* unescaped #s, but only add their escaped size to width. This is because the
|
||||
* format_draw function will actually do the escaping when it runs
|
||||
*/
|
||||
char *
|
||||
format_trim_left(const char *expanded, u_int limit)
|
||||
{
|
||||
char *copy, *out;
|
||||
const char *cp = expanded, *end;
|
||||
u_int width = 0;
|
||||
u_int even, n, width = 0;
|
||||
struct utf8_data ud;
|
||||
enum utf8_state more;
|
||||
|
||||
out = copy = xmalloc(strlen(expanded) + 1);
|
||||
out = copy = xcalloc(1, strlen(expanded) + 1);
|
||||
while (*cp != '\0') {
|
||||
if (cp[0] == '#' && cp[1] == '[') {
|
||||
if (width >= limit)
|
||||
break;
|
||||
if (*cp == '#') {
|
||||
for (end = cp + 1; *end == '#'; end++)
|
||||
/* nothing */;
|
||||
n = end - cp;
|
||||
if (*end != '[') {
|
||||
if (n > limit - width)
|
||||
n = limit - width;
|
||||
memcpy(out, cp, n);
|
||||
out += n;
|
||||
width += n;
|
||||
cp = end;
|
||||
continue;
|
||||
}
|
||||
even = ((n % 2) == 0);
|
||||
|
||||
n /= 2;
|
||||
if (n > limit - width)
|
||||
n = limit - width;
|
||||
width += n;
|
||||
n *= 2;
|
||||
memcpy(out, cp, n);
|
||||
out += n;
|
||||
|
||||
if (even) {
|
||||
if (width + 1 <= limit) {
|
||||
*out++ = '[';
|
||||
width++;
|
||||
}
|
||||
cp = end + 1;
|
||||
continue;
|
||||
}
|
||||
cp = end - 1;
|
||||
|
||||
end = format_skip(cp + 2, "]");
|
||||
if (end == NULL)
|
||||
break;
|
||||
@ -873,7 +971,7 @@ format_trim_right(const char *expanded, u_int limit)
|
||||
{
|
||||
char *copy, *out;
|
||||
const char *cp = expanded, *end;
|
||||
u_int width = 0, total_width, skip;
|
||||
u_int width = 0, total_width, skip, old_n, even, n;
|
||||
struct utf8_data ud;
|
||||
enum utf8_state more;
|
||||
|
||||
@ -882,12 +980,64 @@ format_trim_right(const char *expanded, u_int limit)
|
||||
return (xstrdup(expanded));
|
||||
skip = total_width - limit;
|
||||
|
||||
out = copy = xmalloc(strlen(expanded) + 1);
|
||||
out = copy = xcalloc(1, strlen(expanded) + 1);
|
||||
while (*cp != '\0') {
|
||||
if (cp[0] == '#' && cp[1] == '[') {
|
||||
if (*cp == '#') {
|
||||
for (end = cp + 1; *end == '#'; end++)
|
||||
/* nothing */;
|
||||
old_n = n = end - cp;
|
||||
if (*end != '[') {
|
||||
if (width <= skip) {
|
||||
if (skip - width >= n)
|
||||
n = 0;
|
||||
else
|
||||
n -= (skip - width);
|
||||
}
|
||||
if (n != 0) {
|
||||
memcpy(out, cp, n);
|
||||
out += n;
|
||||
}
|
||||
|
||||
/*
|
||||
* The width always increases by the full
|
||||
* amount even if we can't copy anything yet.
|
||||
*/
|
||||
width += old_n;
|
||||
cp = end;
|
||||
continue;
|
||||
}
|
||||
even = ((n % 2) == 0);
|
||||
|
||||
n /= 2;
|
||||
if (width <= skip) {
|
||||
if (skip - width >= n)
|
||||
n = 0;
|
||||
else
|
||||
n -= (skip - width);
|
||||
}
|
||||
if (n != 0) {
|
||||
/*
|
||||
* Copy the full amount because it hasn't been
|
||||
* escaped yet.
|
||||
*/
|
||||
memcpy(out, cp, old_n);
|
||||
out += old_n;
|
||||
}
|
||||
cp += old_n;
|
||||
width += (old_n / 2) - even;
|
||||
|
||||
if (even) {
|
||||
if (width > skip)
|
||||
*out++ = '[';
|
||||
width++;
|
||||
continue;
|
||||
}
|
||||
cp = end - 1;
|
||||
|
||||
end = format_skip(cp + 2, "]");
|
||||
if (end == NULL)
|
||||
if (end == NULL) {
|
||||
break;
|
||||
}
|
||||
memcpy(out, cp, end + 1 - cp);
|
||||
out += (end + 1 - cp);
|
||||
cp = end + 1;
|
||||
|
40
format.c
40
format.c
@ -98,6 +98,7 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
|
||||
#define FORMAT_PANES 0x200
|
||||
#define FORMAT_PRETTY 0x400
|
||||
#define FORMAT_LENGTH 0x800
|
||||
#define FORMAT_WIDTH 0x1000
|
||||
|
||||
/* Limit on recursion. */
|
||||
#define FORMAT_LOOP_LIMIT 10
|
||||
@ -1671,7 +1672,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
||||
|
||||
/*
|
||||
* Modifiers are a ; separated list of the forms:
|
||||
* l,m,C,b,d,n,t,q,E,T,S,W,P,<,>
|
||||
* l,m,C,b,d,n,t,w,q,E,T,S,W,P,<,>
|
||||
* =a
|
||||
* =/a
|
||||
* =/a/
|
||||
@ -1688,7 +1689,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
||||
cp++;
|
||||
|
||||
/* Check single character modifiers with no arguments. */
|
||||
if (strchr("lbdnqETSWP<>", cp[0]) != NULL &&
|
||||
if (strchr("lbdnqwETSWP<>", cp[0]) != NULL &&
|
||||
format_is_end(cp[1])) {
|
||||
format_add_modifier(&list, count, cp, 1, NULL, 0);
|
||||
cp++;
|
||||
@ -2184,6 +2185,9 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
||||
if (errptr != NULL)
|
||||
width = 0;
|
||||
break;
|
||||
case 'w':
|
||||
modifiers |= FORMAT_WIDTH;
|
||||
break;
|
||||
case 'e':
|
||||
if (fm->argc < 1 || fm->argc > 3)
|
||||
break;
|
||||
@ -2456,13 +2460,19 @@ done:
|
||||
format_log(es, "applied padding width %d: %s", width, value);
|
||||
}
|
||||
|
||||
/* Replace with the length if needed. */
|
||||
/* Replace with the length or width if needed. */
|
||||
if (modifiers & FORMAT_LENGTH) {
|
||||
xasprintf(&new, "%zu", strlen(value));
|
||||
free(value);
|
||||
value = new;
|
||||
format_log(es, "replacing with length: %s", new);
|
||||
}
|
||||
if (modifiers & FORMAT_WIDTH) {
|
||||
xasprintf(&new, "%u", format_width(value));
|
||||
free(value);
|
||||
value = new;
|
||||
format_log(es, "replacing with width: %s", new);
|
||||
}
|
||||
|
||||
/* Expand the buffer and copy in the value. */
|
||||
valuelen = strlen(value);
|
||||
@ -2589,8 +2599,30 @@ format_expand1(struct format_expand_state *es, const char *fmt)
|
||||
break;
|
||||
fmt += n + 1;
|
||||
continue;
|
||||
case '}':
|
||||
case '#':
|
||||
/*
|
||||
* If ##[ (with two or more #s), then it is a style and
|
||||
* can be left for format_draw to handle.
|
||||
*/
|
||||
ptr = fmt;
|
||||
n = 2;
|
||||
while (*ptr == '#') {
|
||||
ptr++;
|
||||
n++;
|
||||
}
|
||||
if (*ptr == '[') {
|
||||
format_log(es, "found #*%zu[", n);
|
||||
while (len - off < n + 2) {
|
||||
buf = xreallocarray(buf, 2, len);
|
||||
len *= 2;
|
||||
}
|
||||
memcpy(buf + off, fmt - 2, n + 1);
|
||||
off += n + 1;
|
||||
fmt = ptr + 1;
|
||||
continue;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case '}':
|
||||
case ',':
|
||||
format_log(es, "found #%c", ch);
|
||||
while (len - off < 2) {
|
||||
|
4
tmux.1
4
tmux.1
@ -4591,7 +4591,9 @@ pads the string to a given width, for example
|
||||
will result in a width of at least 10 characters.
|
||||
A positive width pads on the left, a negative on the right.
|
||||
.Ql n
|
||||
expands to the length of the variable, for example
|
||||
expands to the length of the variable and
|
||||
.Ql w
|
||||
to its width when displayed, for example
|
||||
.Ql #{n:window_name} .
|
||||
.Pp
|
||||
Prefixing a time variable with
|
||||
|
Loading…
Reference in New Issue
Block a user