Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions dvtm.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,13 +379,21 @@ drawbar(void) {
wchar_t wbuf[sizeof bar.text];
size_t numchars = mbstowcs(wbuf, bar.text, sizeof bar.text);

if (numchars != (size_t)-1 && (width = wcswidth(wbuf, maxwidth)) != -1) {
width = 0;
for (size_t i = 0; numchars != (size_t)-1 && i < numchars && width != -1; i++) {
int w = vt_wcwidth(wbuf[i]);
width = w < 0 ? -1 : width + w;
if (width > maxwidth)
break;
}

if (numchars != (size_t)-1 && width != -1) {
int pos;
for (pos = 0; pos + width < maxwidth; pos++)
addch(' ');

for (size_t i = 0; i < numchars; i++) {
pos += wcwidth(wbuf[i]);
pos += vt_wcwidth(wbuf[i]);
if (pos > maxwidth)
break;
addnwstr(wbuf+i, 1);
Expand Down
20 changes: 20 additions & 0 deletions test/test-vt.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,25 @@ static void test_device_attributes(void)
}
}

static void test_wcwidth(void)
{
term = "WCWIDTH";
CHECK(vt_wcwidth(L'a') == 1);
CHECK(vt_wcwidth(L'\0') == 0);
CHECK(vt_wcwidth(L'\n') == -1);
CHECK(vt_wcwidth(0x4E2D) == 2);
CHECK(vt_wcwidth(0x1F600) == 2);
CHECK(vt_wcwidth(0x1FAE9) == 2);
CHECK(vt_wcwidth(0x0301) == 0);
CHECK(vt_wcwidth(0x200D) == 0);
CHECK(vt_wcwidth(0x00E9) == 1);

Vt *t = vt_create(3, 10, 0);
feed(t, "\xf0\x9f\xab\xa9x");
CHECK(t->buffer->curs_col == 3);
vt_destroy(t);
}

int main(void)
{
setlocale(LC_CTYPE, "C.UTF-8");
Expand Down Expand Up @@ -191,6 +210,7 @@ int main(void)
setenv("TERMINFO", dir, 1);

test_device_attributes();
test_wcwidth();
test_term("xterm", COLOR_RED, COLOR_RED, COLOR_BLACK, COLOR_BLACK);
test_term("xterm-256color", 196, 196, 16, 16);
if (direct) {
Expand Down
23 changes: 23 additions & 0 deletions tools/gen-wcwidth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env python3
"""Generate wcwidth_table.h from the Unicode tables of the wcwidth package.

usage: pip install wcwidth && tools/gen-wcwidth.py > wcwidth_table.h
"""
import wcwidth.table_wide as wide
import wcwidth.table_zero as zero

version = max(wide.WIDE_EASTASIAN, key=lambda v: tuple(map(int, v.split('.'))))


print('typedef struct { unsigned int lo, hi; } WidthRange;\n')


def emit(name, ranges):
print(f'static const WidthRange {name}[] = {{')
for lo, hi in ranges:
print(f'\t{{ 0x{lo:04X}, 0x{hi:04X} }},')
print('};\n')


emit('wcwidth_zero', [r for r in zero.ZERO_WIDTH[version] if r[1] >= 0x80])
emit('wcwidth_wide', wide.WIDE_EASTASIAN[version])
34 changes: 32 additions & 2 deletions vt.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#endif

#include "vt.h"
#include "wcwidth_table.h"

#ifdef _AIX
# include "forkpty-aix.c"
Expand Down Expand Up @@ -1132,6 +1133,35 @@ static void interpret_csi(Vt *t)
}
}

static bool in_ranges(const WidthRange *r, size_t n, unsigned int c)
{
size_t lo = 0, hi = n;
while (lo < hi) {
size_t mid = lo + (hi - lo) / 2;
if (c < r[mid].lo)
hi = mid;
else if (c > r[mid].hi)
lo = mid + 1;
else
return true;
}
return false;
}

int vt_wcwidth(wchar_t wc)
{
unsigned int c = wc;
if (c < 0x20 || (c >= 0x7f && c < 0xa0))
return c ? -1 : 0;
if (c < 0x300)
return 1;
if (in_ranges(wcwidth_zero, sizeof wcwidth_zero / sizeof *wcwidth_zero, c))
return 0;
if (in_ranges(wcwidth_wide, sizeof wcwidth_wide / sizeof *wcwidth_wide, c))
return 2;
return 1;
}

/* Interpret an 'index' (IND) sequence */
static void interpret_csi_ind(Vt *t)
{
Expand Down Expand Up @@ -1402,7 +1432,7 @@ static void put_wc(Vt *t, wchar_t wc)
wc = gc;
}
width = 1;
} else if ((width = wcwidth(wc)) < 1) {
} else if ((width = vt_wcwidth(wc)) < 1) {
width = 1;
}
Buffer *b = t->buffer;
Expand Down Expand Up @@ -1576,7 +1606,7 @@ void vt_draw(Vt *t, WINDOW *win, int srow, int scol)
size_t len = wcrtomb(buf, cell->text, NULL);
if (len != (size_t)-1) {
waddnstr(win, buf, len);
if (wcwidth(cell->text) > 1)
if (vt_wcwidth(cell->text) > 1)
j++;
}
} else {
Expand Down
2 changes: 2 additions & 0 deletions vt.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <curses.h>
#include <stdbool.h>
#include <sys/types.h>
#include <wchar.h>

#ifndef NCURSES_MOUSE_VERSION
#define mmask_t unsigned long
Expand Down Expand Up @@ -56,6 +57,7 @@ void vt_dirty(Vt*);
void vt_draw(Vt*, WINDOW *win, int startrow, int startcol);
int vt_color_get(Vt*, int fg, int bg);
int vt_color_reserve(int fg, int bg);
int vt_wcwidth(wchar_t wc);

void vt_scroll(Vt*, int rows);
void vt_noscroll(Vt*);
Expand Down
Loading
Loading