diff --git a/tmux.1 b/tmux.1 index 68726fc7..52d52f82 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4239,9 +4239,10 @@ An array option allowing widths of Unicode codepoints to be overridden. Note the new width applies to all clients. Each entry is of the form .Em codepoint=width , -where codepoint may be a UTF-8 character or an identifier of the form +where codepoint may be a UTF-8 character, an identifier of the form .Ql U+number -where the number is a hexadecimal number. +where the number is a hexadecimal number, or a range of the form +.Ql U+number-U+number . .It Ic copy-command Ar shell-command Give the command to pipe to if the .Ic copy-pipe diff --git a/utf8.c b/utf8.c index 38f270a8..4df8ccd5 100644 --- a/utf8.c +++ b/utf8.c @@ -291,16 +291,37 @@ utf8_find_in_width_cache(wchar_t wc) return RB_FIND(utf8_width_cache, &utf8_width_cache, &uw); } +/* Add to width cache. */ +static void +utf8_insert_width_cache(wchar_t wc, u_int width) +{ + struct utf8_width_item *uw, *old; + + log_debug("Unicode width cache: %08X=%u", (u_int)wc, width); + + uw = xcalloc(1, sizeof *uw); + uw->wc = wc; + uw->width = width; + uw->allocated = 1; + + old = RB_INSERT(utf8_width_cache, &utf8_width_cache, uw); + if (old != NULL) { + RB_REMOVE(utf8_width_cache, &utf8_width_cache, old); + if (old->allocated) + free(old); + RB_INSERT(utf8_width_cache, &utf8_width_cache, uw); + } +} + /* Parse a single codepoint option. */ static void utf8_add_to_width_cache(const char *s) { - struct utf8_width_item *uw, *old; char *copy, *cp, *endptr; u_int width; const char *errstr; struct utf8_data *ud; - wchar_t wc; + wchar_t wc, wc_start, wc_end; unsigned long long n; copy = xstrdup(s); @@ -320,14 +341,40 @@ utf8_add_to_width_cache(const char *s) errno = 0; n = strtoull(copy + 2, &endptr, 16); if (copy[2] == '\0' || - *endptr != '\0' || n == 0 || n > WCHAR_MAX || (errno == ERANGE && n == ULLONG_MAX)) { free(copy); return; } - wc = n; + wc_start = n; + if (*endptr == '-') { + endptr++; + if (strncmp(endptr, "U+", 2) != 0) { + free(copy); + return; + } + errno = 0; + n = strtoull(endptr + 2, &endptr, 16); + if (*endptr != '\0' || + n == 0 || + n > WCHAR_MAX || + (errno == ERANGE && n == ULLONG_MAX) || + (wchar_t)n < wc_start) { + free(copy); + return; + } + wc_end = n; + } else { + if (*endptr != '\0') { + free(copy); + return; + } + wc_end = wc_start; + } + + for (wc = wc_start; wc <= wc_end; wc++) + utf8_insert_width_cache(wc, width); } else { utf8_no_width = 1; ud = utf8_fromcstr(copy); @@ -347,21 +394,8 @@ utf8_add_to_width_cache(const char *s) return; } free(ud); - } - log_debug("Unicode width cache: %08X=%u", (u_int)wc, width); - - uw = xcalloc(1, sizeof *uw); - uw->wc = wc; - uw->width = width; - uw->allocated = 1; - - old = RB_INSERT(utf8_width_cache, &utf8_width_cache, uw); - if (old != NULL) { - RB_REMOVE(utf8_width_cache, &utf8_width_cache, old); - if (old->allocated) - free(old); - RB_INSERT(utf8_width_cache, &utf8_width_cache, uw); + utf8_insert_width_cache(wc, width); } free(copy);