summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@cvs.openbsd.org>2020-11-09 09:10:11 +0000
committerNicholas Marriott <nicm@cvs.openbsd.org>2020-11-09 09:10:11 +0000
commitf086e1a57166370dacfd52b341598efef16886df (patch)
tree4addc7a8eaa0bdfec9b947ed0c5c1b0665958b4a /usr.bin
parent857a02c4f88c6f899258cc04f2653e3f8a37de34 (diff)
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.
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/tmux/format-draw.c176
-rw-r--r--usr.bin/tmux/format.c42
-rw-r--r--usr.bin/tmux/tmux.18
3 files changed, 205 insertions, 21 deletions
diff --git a/usr.bin/tmux/format-draw.c b/usr.bin/tmux/format-draw.c
index d01780be2db..d81c1d782a8 100644
--- a/usr.bin/tmux/format-draw.c
+++ b/usr.bin/tmux/format-draw.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: format-draw.c,v 1.20 2020/05/16 16:26:34 nicm Exp $ */
+/* $OpenBSD: format-draw.c,v 1.21 2020/11/09 09:10:10 nicm Exp $ */
/*
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -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;
diff --git a/usr.bin/tmux/format.c b/usr.bin/tmux/format.c
index 5f0b68b6759..82567c5b896 100644
--- a/usr.bin/tmux/format.c
+++ b/usr.bin/tmux/format.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: format.c,v 1.265 2020/11/02 08:21:30 nicm Exp $ */
+/* $OpenBSD: format.c,v 1.266 2020/11/09 09:10:10 nicm Exp $ */
/*
* Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -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) {
diff --git a/usr.bin/tmux/tmux.1 b/usr.bin/tmux/tmux.1
index fff4d7aa32e..94272bb5635 100644
--- a/usr.bin/tmux/tmux.1
+++ b/usr.bin/tmux/tmux.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tmux.1,v 1.802 2020/11/03 08:09:35 nicm Exp $
+.\" $OpenBSD: tmux.1,v 1.803 2020/11/09 09:10:10 nicm Exp $
.\"
.\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
.\"
@@ -14,7 +14,7 @@
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: November 3 2020 $
+.Dd $Mdocdate: November 9 2020 $
.Dt TMUX 1
.Os
.Sh NAME
@@ -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