edo

Experimental text editor.
Log | Files | Refs | LICENSE

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:
Mtui.c | 93+++++++++++++++++++++++++++++++++----------------------------------------------
Mutf8.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); }