From 7487f1beea2cb54e1ce2e459e4777901b51aab75 Mon Sep 17 00:00:00 2001 From: Adam Saponara Date: Tue, 17 Dec 2024 22:12:25 -0500 Subject: [PATCH] fix bug with adding combining chars to a full-width char the logic was incorrectly sending the combinin char to x-1, but that assumed a wcwidth==1 char. save last printed x coord and use that instead. xterm's ansi output for this is a little strange. unlike other `expected.ansi` files, cat-ing this one to stdout doesn't seem to render the correct output, and if you peek at its contents you'll see some "\xef\xbf\xbf" (U+FFFF) which is an invalid codepoint. in any case, it still picks up the regression so i'm adding it. --- termbox2.h | 14 ++++++++------ tests/test_egc/expected.ansi | 4 ++-- tests/test_egc/test.php | 12 +++++++++++- tests/test_prepend.php | 4 +--- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/termbox2.h b/termbox2.h index 265cdab..4160687 100644 --- a/termbox2.h +++ b/termbox2.h @@ -1869,7 +1869,7 @@ int tb_print(int x, int y, uintattr_t fg, uintattr_t bg, const char *str) { int tb_print_ex(int x, int y, uintattr_t fg, uintattr_t bg, size_t *out_w, const char *str) { - int rv, w, ix; + int rv, w, ix, x_prev; uint32_t uni; if_not_init_return(); @@ -1879,6 +1879,7 @@ int tb_print_ex(int x, int y, uintattr_t fg, uintattr_t bg, size_t *out_w, } ix = x; + x_prev = x; if (out_w) *out_w = 0; while (*str) { @@ -1895,6 +1896,7 @@ int tb_print_ex(int x, int y, uintattr_t fg, uintattr_t bg, size_t *out_w, if (uni == '\n') { // TODO: \r, \t, \v, \f, etc? x = ix; + x_prev = x; y += 1; continue; } else if (!iswprint((wint_t)uni)) { @@ -1905,17 +1907,17 @@ int tb_print_ex(int x, int y, uintattr_t fg, uintattr_t bg, size_t *out_w, if (w < 0) { return TB_ERR; // shouldn't happen if iswprint } else if (w == 0) { // combining character - if (cellbuf_in_bounds(&global.back, x - 1, y)) { - if_err_return(rv, tb_extend_cell(x - 1, y, uni)); + if (cellbuf_in_bounds(&global.back, x_prev, y)) { + if_err_return(rv, tb_extend_cell(x_prev, y, uni)); } } else { if (cellbuf_in_bounds(&global.back, x, y)) { if_err_return(rv, tb_set_cell(x, y, uni, fg, bg)); } + x_prev = x; + x += w; + if (out_w) *out_w += w; } - - x += w; - if (out_w) *out_w += w; } return TB_OK; diff --git a/tests/test_egc/expected.ansi b/tests/test_egc/expected.ansi index 69cda5c..efb36e2 100644 --- a/tests/test_egc/expected.ansi +++ b/tests/test_egc/expected.ansi @@ -1,7 +1,7 @@ #5aёb #5cёd - - +#5I￿̤ͯ +#5I￿̤ͯ diff --git a/tests/test_egc/test.php b/tests/test_egc/test.php index f6a59ff..a5a6f52 100755 --- a/tests/test_egc/test.php +++ b/tests/test_egc/test.php @@ -18,12 +18,22 @@ $test->ffi->tb_set_cell(0, $y, ord('a'), 0, 0); $test->ffi->tb_set_cell_ex(1, $y, $test->ffi->cast('uint32_t *', FFI::addr($ech)), 2, 0, 0); $test->ffi->tb_set_cell(2, $y, ord('b'), 0, 0); -++$y; // Same effect with tb_extend_cell +++$y; $test->ffi->tb_set_cell(0, $y, ord('c'), 0, 0); $test->ffi->tb_set_cell(1, $y, $ech[0], 0, 0); $test->ffi->tb_extend_cell(1, $y, $ech[1]); $test->ffi->tb_set_cell(2, $y, ord('d'), 0, 0); +// Another example with 2 combining characters +++$y; +$test->ffi->tb_set_cell(0, $y, 0xff29, 0, 0); // fullwidth latin capital letter i +$test->ffi->tb_extend_cell(0, $y, 0x0324); // combining diaeresis below +$test->ffi->tb_extend_cell(0, $y, 0x036f); // combining latin small letter x + +// Same as above via tb_print (should be equivalent) +++$y; +$test->ffi->tb_print(0, $y, 0, 0, "\xef\xbc\xa9\xcc\xa4\xcd\xaf"); + $test->ffi->tb_present(); $test->screencap(); diff --git a/tests/test_prepend.php b/tests/test_prepend.php index 459bd41..0d6325d 100644 --- a/tests/test_prepend.php +++ b/tests/test_prepend.php @@ -26,9 +26,7 @@ $test = new class() { $this->test = $test; } public function __call(string $name, array $args) { - if ($name !== 'tb_set_cell') { - $this->test->log("ffi $name " . json_encode($args)); - } + $this->test->log("ffi $name " . json_encode($args)); return $this->ffi->$name(...$args); } }; -- 2.39.5