commit 02022354435f2f3f5763766e72613caf28d6f67f
parent 44ad005fb1be3e86ab1301896d4cc8a708af69cf
Author: Claudio Alessi <smoppy@gmail.com>
Date: Sun, 11 Jan 2026 18:07:09 +0100
Simplify TUI line drawing and other fixes.
The tui_draw_line_compat() function has been rewritten from scratch,
even though is strongly inspired by the old one. Now it's more simple
and clear. I didn't figured out yet how to properly overwrite a cell
without changing color attributes while preventing to have overlapsing
characters on the same cell. I suspect this in not 100% feasible.
I also fixed a bug in utf8_len_compat() which was preventing to focus
the tab character and likely others characters having wcwidth() < 0.
Diffstat:
| M | tui.c | | | 93 | +++++++++++++++++++++++++++++++++---------------------------------------------- |
| M | utf8.c | | | 17 | +++++++---------- |
2 files changed, 46 insertions(+), 64 deletions(-)
diff --git a/tui.c b/tui.c
@@ -22,6 +22,7 @@
#define CURSHOW "\33[?25h"
#define ERASECHAR "\33[1X"
+/* UTF-8 Regional Indicator Symbol */
#define IS_RIS(c) ((c) >= 0x1F1E6 && (c) <= 0x1F1FF)
typedef struct {
@@ -190,76 +191,60 @@ tui_move_cursor(int c, int r) {
void
tui_draw_line_compat(UI *ui, int x, int y, Cell *cells, int count) {
char *txt;
- unsigned int cp = 0;
- int was_emoji = 0;
- int i;
+ int neederase, i;
tui_move_cursor(x, y);
for(i = 0; i < count; i++) {
- x += cells[i].width;
txt = cell_get_text(cells + i, ui->pool.data);
- int cw = cells[i].width;
-
- /* TODO: temp code for testing, we'll se how to deal with this later */
- if(txt[0] == '\t') {
- ab_printf(&frame, "%*s", cells[i].width, " ");
- } else {
- int o = 0;
-
- while(o < cells[i].len) {
- int step = utf8_decode(txt + o, cells[i].len - o, &cp);
-
- if(cp == 0x200D) {
- ab_write(&frame, "<200d>", cells[i].width);
- } else {
- int w = wcwidth(cp);
- if(w > 0) cw = w;
-
- if(was_emoji) {
- /* ERASECHAR to clear eventual garbage state */
- const char t[] = "\x1b[48;5;232m"ERASECHAR;
- ab_write(&frame, t, sizeof t - 1);
- }
-
- ab_write(&frame, txt + o, step);
-
- if(was_emoji) {
- const char t[] = "\x1b[0m";
- ab_write(&frame, t, sizeof t - 1);
- }
+ unsigned int cp;
+ int o = 0;
+
+ neederase = 0;
+ while(o < cells[i].len) {
+ int step = utf8_decode(txt + o, cells[i].len - o, &cp);
+ int w = wcwidth(cp);
+ int cw = w > 0 ? w : cells[i].width;
+
+ if(cells[i].len > 1 && (cells[i].width == 1 || IS_RIS(cp)))
+ neederase = 1;
+
+ switch(cp) {
+ case 0x200D:
+ ab_write(&frame, "<200d>", cells[i].width);
+ break;
+ case '\t':
+ for(int t = 0; t < cells[i].width; t++)
+ ab_write(&frame, " ", 1);
+ break;
+ default:
+ if(neederase) {
+ const char t[] = "\x1b[48;5;232m"ERASECHAR;
+ ab_write(&frame, t, sizeof t - 1);
+ }
+ ab_write(&frame, txt + o, step);
+ if(neederase) {
+ const char t[] = "\x1b[0m";
+ ab_write(&frame, t, sizeof t - 1);
}
- o += step;
+ break;
}
- }
- /* pad if needed */
- if(cw < cells[i].width) {
- tui_move_cursor(x - cells[i].width + cw, y);
+ /* pad clusters having unexpected width */
+ if(cw < cells[i].width)
+ while(cw++ < cells[i].width) ab_write(&frame, " ", 1);
- const char t[] = "\x1b[48;5;233m";
- ab_write(&frame, t, sizeof t - 1);
+ /* no more visual characters expected for this cell */
+ if(neederase) break;
- while(cw++ < cells[i].width) ab_write(&frame, " ", 1);
-
- const char t2[] = "\x1b[0m";
- ab_write(&frame, t2, sizeof t2 - 1);
+ o += step;
}
- was_emoji = cells[i].len > 1 || IS_RIS(cp);
- if(was_emoji) tui_move_cursor(x, y);
- }
-
- /* TODO: this only happens with ambi characters? */
- if(was_emoji) {
- const char t[] = "\x1b[48;5;232m \x1b[0m";
- ab_write(&frame, t, sizeof t - 1);
+ x += cells[i].width;
}
-
ab_write(&frame, CLEARRIGHT, strlen(CLEARRIGHT));
}
-
void
tui_draw_line(UI *ui, int x, int y, Cell *cells, int count) {
assert(x < ws.ws_col && y < ws.ws_row);
diff --git a/utf8.c b/utf8.c
@@ -8,18 +8,15 @@ size_t utf8_len_compat(char *buf, int len);
size_t
utf8_len_compat(char *buf, int len) {
- int i = 0, step, next;
uint_least32_t cp;
+ int step, i;
- step = utf8_decode(buf, len, &cp);
- i += step;
-
- if(cp == 0x200D) return i;
+ i = step = utf8_decode(buf, len, &cp);
+ if(wcwidth(cp) < 0) return step;
while(i < len) {
- next = utf8_decode(buf + i, len - i, &cp);
- if(cp == 0x200D) break;
- if(wcwidth((wchar_t)cp) > 0) break;
- i += next;
+ step = utf8_decode(buf + i, len - i, &cp);
+ if(cp == 0x200D || wcwidth(cp)) break;
+ i += step;
}
return i;
}
@@ -31,5 +28,5 @@ utf8_len(char *buf, int len) {
int
utf8_decode(char *buf, int len, unsigned int *cp) {
- return grapheme_decode_utf8(buf, len, (uint_least32_t *)cp);
+ return grapheme_decode_utf8(buf, len, cp);
}