From 27bfb56ad5e19afa686ed6a99bf8b205fac98aef Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 23 May 2019 14:03:44 +0000 Subject: [PATCH 1/2] Break the argument escaping code into a separate function and use it to escape key bindings in list-keys. Also escape ~ and ; and $ properly. --- arguments.c | 61 +++++++++++++++++++++++++++++++------------------ cmd-list-keys.c | 13 +++++++---- cmd-list.c | 12 ++++++---- cmd-parse.y | 2 +- options.c | 2 +- tmux.h | 3 ++- utf8.c | 7 +++++- 7 files changed, 65 insertions(+), 35 deletions(-) diff --git a/arguments.c b/arguments.c index f7288e81..eebb79ff 100644 --- a/arguments.c +++ b/arguments.c @@ -141,23 +141,15 @@ static void args_print_add_value(char **buf, size_t *len, struct args_entry *entry, struct args_value *value) { - static const char quoted[] = " #\"';$"; - char *escaped; - int flags; + char *escaped; if (**buf != '\0') args_print_add(buf, len, " -%c ", entry->flag); else args_print_add(buf, len, "-%c ", entry->flag); - flags = VIS_OCTAL|VIS_TAB|VIS_NL; - if (value->value[strcspn(value->value, quoted)] != '\0') - flags |= VIS_DQ; - utf8_stravis(&escaped, value->value, flags); - if (flags & VIS_DQ) - args_print_add(buf, len, "\"%s\"", escaped); - else - args_print_add(buf, len, "%s", escaped); + escaped = args_escape(value->value); + args_print_add(buf, len, "%s", escaped); free(escaped); } @@ -165,21 +157,13 @@ args_print_add_value(char **buf, size_t *len, struct args_entry *entry, static void args_print_add_argument(char **buf, size_t *len, const char *argument) { - static const char quoted[] = " #\"';$"; - char *escaped; - int flags; + char *escaped; if (**buf != '\0') args_print_add(buf, len, " "); - flags = VIS_OCTAL|VIS_TAB|VIS_NL; - if (argument[strcspn(argument, quoted)] != '\0') - flags |= VIS_DQ; - utf8_stravis(&escaped, argument, flags); - if (flags & VIS_DQ) - args_print_add(buf, len, "\"%s\"", escaped); - else - args_print_add(buf, len, "%s", escaped); + escaped = args_escape(argument); + args_print_add(buf, len, "%s", escaped); free(escaped); } @@ -219,6 +203,39 @@ args_print(struct args *args) return (buf); } +/* Escape an argument. */ +char * +args_escape(const char *s) +{ + static const char quoted[] = " #\"';$"; + char *escaped, *result; + int flags; + + if ((strchr(quoted, s[0]) != NULL || s[0] == '~') && s[1] == '\0') { + xasprintf(&escaped, "\\%c", s[0]); + return (escaped); + } + + flags = VIS_OCTAL|VIS_TAB|VIS_NL; + if (s[strcspn(s, quoted)] != '\0') + flags |= VIS_DQ; + utf8_stravis(&escaped, s, flags); + + if (flags & VIS_DQ) { + if (*escaped == '~') + xasprintf(&result, "\"\\%s\"", escaped); + else + xasprintf(&result, "\"%s\"", escaped); + } else { + if (*escaped == '~') + xasprintf(&result, "\\%s", escaped); + else + result = xstrdup(escaped); + } + free(escaped); + return (result); +} + /* Return if an argument is present. */ int args_has(struct args *args, u_char ch) diff --git a/cmd-list-keys.c b/cmd-list-keys.c index 5efb0cd2..57f65c8e 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -60,8 +60,8 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item) struct args *args = self->args; struct key_table *table; struct key_binding *bd; - const char *key, *tablename, *r; - char *cp, tmp[BUFSIZ]; + const char *tablename, *r; + char *key, *cp, tmp[BUFSIZ]; int repeat, width, tablewidth, keywidth; if (self->entry == &cmd_list_commands_entry) @@ -83,7 +83,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item) } bd = key_bindings_first(table); while (bd != NULL) { - key = key_string_lookup_key(bd->key); + key = args_escape(key_string_lookup_key(bd->key)); if (bd->flags & KEY_BINDING_REPEAT) repeat = 1; @@ -95,6 +95,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item) if (width > keywidth) keywidth = width; + free(key); bd = key_bindings_next(table, bd); } table = key_bindings_next_table(table); @@ -108,7 +109,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item) } bd = key_bindings_first(table); while (bd != NULL) { - key = key_string_lookup_key(bd->key); + key = args_escape(key_string_lookup_key(bd->key)); if (!repeat) r = ""; @@ -128,11 +129,13 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item) strlcat(tmp, " ", sizeof tmp); free(cp); - cp = cmd_list_print(bd->cmdlist); + cp = cmd_list_print(bd->cmdlist, 1); strlcat(tmp, cp, sizeof tmp); free(cp); cmdq_print(item, "bind-key %s", tmp); + + free(key); bd = key_bindings_next(table, bd); } table = key_bindings_next_table(table); diff --git a/cmd-list.c b/cmd-list.c index ead0fb61..fdf2095d 100644 --- a/cmd-list.c +++ b/cmd-list.c @@ -129,7 +129,7 @@ cmd_list_free(struct cmd_list *cmdlist) } char * -cmd_list_print(struct cmd_list *cmdlist) +cmd_list_print(struct cmd_list *cmdlist, int escaped) { struct cmd *cmd; char *buf, *this; @@ -141,12 +141,16 @@ cmd_list_print(struct cmd_list *cmdlist) TAILQ_FOREACH(cmd, &cmdlist->list, qentry) { this = cmd_print(cmd); - len += strlen(this) + 3; + len += strlen(this) + 4; buf = xrealloc(buf, len); strlcat(buf, this, len); - if (TAILQ_NEXT(cmd, qentry) != NULL) - strlcat(buf, " ; ", len); + if (TAILQ_NEXT(cmd, qentry) != NULL) { + if (escaped) + strlcat(buf, " \\; ", len); + else + strlcat(buf, " ; ", len); + } free(this); } diff --git a/cmd-parse.y b/cmd-parse.y index 8b8f33ab..e576d776 100644 --- a/cmd-parse.y +++ b/cmd-parse.y @@ -663,7 +663,7 @@ cmd_parse_from_file(FILE *f, struct cmd_parse_input *pi) cmd_list_free(cmdlist); } - s = cmd_list_print(result); + s = cmd_list_print(result, 0); log_debug("%s: %s", __func__, s); free(s); diff --git a/options.c b/options.c index fa8752b0..7d79cf30 100644 --- a/options.c +++ b/options.c @@ -122,7 +122,7 @@ options_value_tostring(struct options_entry *o, union options_value *ov, char *s; if (OPTIONS_IS_COMMAND(o)) - return (cmd_list_print(ov->cmdlist)); + return (cmd_list_print(ov->cmdlist, 0)); if (OPTIONS_IS_STYLE(o)) return (xstrdup(style_tostring(&ov->style))); if (OPTIONS_IS_NUMBER(o)) { diff --git a/tmux.h b/tmux.h index f996b1f4..8f8bd902 100644 --- a/tmux.h +++ b/tmux.h @@ -1950,6 +1950,7 @@ void args_set(struct args *, u_char, const char *); struct args *args_parse(const char *, int, char **); void args_free(struct args *); char *args_print(struct args *); +char *args_escape(const char *); int args_has(struct args *, u_char); const char *args_get(struct args *, u_char); const char *args_first_value(struct args *, u_char, struct args_value **); @@ -2022,7 +2023,7 @@ void cmd_list_append(struct cmd_list *, struct cmd *); void cmd_list_move(struct cmd_list *, struct cmd_list *); struct cmd_list *cmd_list_parse(int, char **, const char *, u_int, char **); void cmd_list_free(struct cmd_list *); -char *cmd_list_print(struct cmd_list *); +char *cmd_list_print(struct cmd_list *, int); /* cmd-queue.c */ struct cmdq_item *cmdq_get_command(struct cmd_list *, struct cmd_find_state *, diff --git a/utf8.c b/utf8.c index 08990634..29bbfa9e 100644 --- a/utf8.c +++ b/utf8.c @@ -18,6 +18,7 @@ #include +#include #include #include #include @@ -182,7 +183,11 @@ utf8_strvis(char *dst, const char *src, size_t len, int flag) /* Not a complete, valid UTF-8 character. */ src -= ud.have; } - if (src < end - 1) + if (src[0] == '$' && src < end - 1) { + if (isalpha((u_char)src[1]) || src[1] == '_') + *dst++ = '\\'; + *dst++ = '$'; + } else if (src < end - 1) dst = vis(dst, src[0], flag, src[1]); else if (src < end) dst = vis(dst, src[0], flag, '\0'); From eb8b51effcd2dee7b95c811c894bf29387a272c9 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 23 May 2019 14:44:33 +0000 Subject: [PATCH 2/2] Fix drawing of status-right when it is aligned to the centre, GitHub issue 1754. --- format-draw.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/format-draw.c b/format-draw.c index 51404254..f8882ac2 100644 --- a/format-draw.c +++ b/format-draw.c @@ -345,12 +345,6 @@ format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx, /* Write left at 0. */ format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left); - /* Write after at available - width_after. */ - format_draw_put(octx, ocx, ocy, after, frs, - available - width_after, - after->cx - width_after, - width_after); - /* Write right at available - width_right. */ format_draw_put(octx, ocx, ocy, right, frs, available - width_right, @@ -374,10 +368,10 @@ format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx, /* * Write after at - * middle + width_list / 2 - width_centre. + * middle - width_list / 2 + width_list */ format_draw_put(octx, ocx, ocy, after, frs, - middle + width_list / 2, + middle - width_list / 2 + width_list, 0, width_after);