Skip to content

Commit

Permalink
make tb_print* functions a little kinder
Browse files Browse the repository at this point in the history
* handle newlines. previously they would mess up rendering.
* replace other non-printable codepoints with U+FFFD.
* skip over cells that would go out of bounds instead of erroring.
  • Loading branch information
adsr committed Sep 3, 2024
1 parent cd42ba3 commit b075ddd
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 13 deletions.
66 changes: 53 additions & 13 deletions termbox2.h
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,18 @@ int tb_poll_event(struct tb_event *event);
int tb_get_fds(int *ttyfd, int *resizefd);

/* Print and printf functions. Specify param out_w to determine width of printed
* string. Incomplete trailing UTF-8 byte sequences are replaced with U+FFFD.
* string.
*
* Non-printable characters and truncated UTF-8 byte sequences are replaced with
* U+FFFD.
*
* Newlines (`\n`) are supported with the caveat that out_w will return the
* width of the string as if it were on a single line.
*
* If the starting coordinate is out of bounds, TB_ERR_OUT_OF_BOUNDS is
* returned. Beyond that, portions of the string that would go out of bounds are
* ignored.
*
* For finer control, use tb_set_cell().
*/
int tb_print(int x, int y, uintattr_t fg, uintattr_t bg, const char *str);
Expand Down Expand Up @@ -1550,6 +1561,7 @@ static int cellbuf_init(struct cellbuf_t *c, int w, int h);
static int cellbuf_free(struct cellbuf_t *c);
static int cellbuf_clear(struct cellbuf_t *c);
static int cellbuf_get(struct cellbuf_t *c, int x, int y, struct tb_cell **out);
static int cellbuf_in_bounds(struct cellbuf_t *c, int x, int y);
static int cellbuf_resize(struct cellbuf_t *c, int w, int h);
static int bytebuf_puts(struct bytebuf_t *b, const char *str);
static int bytebuf_nputs(struct bytebuf_t *b, const char *str, size_t nstr);
Expand Down Expand Up @@ -1858,14 +1870,21 @@ 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;
int rv, w, ix;
uint32_t uni;
int w, ix = x;
if (out_w) {
*out_w = 0;

if_not_init_return();

if (!cellbuf_in_bounds(&global.back, x, y)) {
return TB_ERR_OUT_OF_BOUNDS;
}

ix = x;
if (out_w) *out_w = 0;

while (*str) {
rv = tb_utf8_char_to_unicode(&uni, str);

if (rv < 0) {
uni = 0xfffd; // replace invalid UTF-8 char with U+FFFD
str += rv * -1;
Expand All @@ -1874,18 +1893,32 @@ int tb_print_ex(int x, int y, uintattr_t fg, uintattr_t bg, size_t *out_w,
} else {
break; // shouldn't get here
}

if (uni == '\n') { // TODO \r, \t, \v, \f, etc?
x = ix;
y += 1;
continue;
} else if (!iswprint((wint_t)uni)) {
uni = 0xfffd; // replace non-printable with U+FFFD
}

w = wcwidth((wchar_t)uni);
if (w < 0) w = 1;
if (w == 0 && x > ix) {
if_err_return(rv, tb_extend_cell(x - 1, y, uni));
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));
}
} else {
if_err_return(rv, tb_set_cell(x, y, uni, fg, bg));
if (cellbuf_in_bounds(&global.back, x, y)) {
if_err_return(rv, tb_set_cell(x, y, uni, fg, bg));
}
}

x += w;
if (out_w) {
*out_w += w;
}
if (out_w) *out_w += w;
}

return TB_OK;
}

Expand Down Expand Up @@ -3361,14 +3394,21 @@ static int cellbuf_clear(struct cellbuf_t *c) {

static int cellbuf_get(struct cellbuf_t *c, int x, int y,
struct tb_cell **out) {
if (x < 0 || x >= c->width || y < 0 || y >= c->height) {
if (!cellbuf_in_bounds(c, x, y)) {
*out = NULL;
return TB_ERR_OUT_OF_BOUNDS;
}
*out = &c->cells[(y * c->width) + x];
return TB_OK;
}

static int cellbuf_in_bounds(struct cellbuf_t *c, int x, int y) {
if (x < 0 || x >= c->width || y < 0 || y >= c->height) {
return 0;
}
return 1;
}

static int cellbuf_resize(struct cellbuf_t *c, int w, int h) {
int rv;

Expand Down
24 changes: 24 additions & 0 deletions tests/test_print/expected.ansi
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#5 line1
#5 line2
#5 line3
#5escape=[�]
#5tab=[�]
#5oob_rv1=-9
#5oob_rv2=-9












#5 01234
#5 01234
#5 01234
#5 01234
#5 01234
25 changes: 25 additions & 0 deletions tests/test_print/test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);

$test->ffi->tb_init();

$w = $test->ffi->tb_width();
$h = $test->ffi->tb_height();

$y = 0;
$test->ffi->tb_print(1, $y++, 0, 0, "line1\nline2\nline3");
$y += 2;

$test->ffi->tb_print(0, $y++, 0, 0, "escape=[\x1b]");
$test->ffi->tb_print(0, $y++, 0, 0, "tab=[\t]");

$oob_rv1 = $test->ffi->tb_print($w, $h, 0, 0, "oob1");
$oob_rv2 = $test->ffi->tb_print(-1, -1, 0, 0, "oob2");
$test->ffi->tb_printf(0, $y++, 0, 0, "oob_rv1=%d", $oob_rv1);
$test->ffi->tb_printf(0, $y++, 0, 0, "oob_rv2=%d", $oob_rv2);

$test->ffi->tb_print($w - 5, $h - 5, 0, 0, str_repeat("0123456789\n", 10));

$test->ffi->tb_present();

$test->screencap();

0 comments on commit b075ddd

Please sign in to comment.