Allow codepoint-widths to accept ranges, from san65384 at gmail dot com

in GitHub issue 4930.
This commit is contained in:
nicm
2026-03-18 08:38:54 +00:00
parent fd62f419ac
commit f516f8a1d4
2 changed files with 55 additions and 20 deletions

5
tmux.1
View File

@@ -4239,9 +4239,10 @@ An array option allowing widths of Unicode codepoints to be overridden.
Note the new width applies to all clients. Note the new width applies to all clients.
Each entry is of the form Each entry is of the form
.Em codepoint=width , .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 .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 .It Ic copy-command Ar shell-command
Give the command to pipe to if the Give the command to pipe to if the
.Ic copy-pipe .Ic copy-pipe

70
utf8.c
View File

@@ -291,16 +291,37 @@ utf8_find_in_width_cache(wchar_t wc)
return RB_FIND(utf8_width_cache, &utf8_width_cache, &uw); 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. */ /* Parse a single codepoint option. */
static void static void
utf8_add_to_width_cache(const char *s) utf8_add_to_width_cache(const char *s)
{ {
struct utf8_width_item *uw, *old;
char *copy, *cp, *endptr; char *copy, *cp, *endptr;
u_int width; u_int width;
const char *errstr; const char *errstr;
struct utf8_data *ud; struct utf8_data *ud;
wchar_t wc; wchar_t wc, wc_start, wc_end;
unsigned long long n; unsigned long long n;
copy = xstrdup(s); copy = xstrdup(s);
@@ -320,14 +341,40 @@ utf8_add_to_width_cache(const char *s)
errno = 0; errno = 0;
n = strtoull(copy + 2, &endptr, 16); n = strtoull(copy + 2, &endptr, 16);
if (copy[2] == '\0' || if (copy[2] == '\0' ||
*endptr != '\0' ||
n == 0 || n == 0 ||
n > WCHAR_MAX || n > WCHAR_MAX ||
(errno == ERANGE && n == ULLONG_MAX)) { (errno == ERANGE && n == ULLONG_MAX)) {
free(copy); free(copy);
return; 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 { } else {
utf8_no_width = 1; utf8_no_width = 1;
ud = utf8_fromcstr(copy); ud = utf8_fromcstr(copy);
@@ -347,21 +394,8 @@ utf8_add_to_width_cache(const char *s)
return; return;
} }
free(ud); free(ud);
}
log_debug("Unicode width cache: %08X=%u", (u_int)wc, width); utf8_insert_width_cache(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);
} }
free(copy); free(copy);