edo

Experimental text editor.
Log | Files | Refs | LICENSE

commit b2b353e2a0f7708de22399901052d5aebc7d23de
parent 897272f33780a8e30538598a8ae09810ffd49fa7
Author: Claudio Alessi <smoppy@gmail.com>
Date:   Sun, 14 Dec 2025 18:58:57 +0100

Add fine clipping, horizontal scroll and some fix.

Better decoupling between the core and the backend. We should be able to
think in terms of "unit points" for the cells instead of TUI columns.
For example in an SDL backend we can think of "width" as pixels without
having to change anything into the core. This is the theory.

Diffstat:
Medo.c | 142+++++++++++++++++++++++++++++++------------------------------------------------
Mtui.c | 31++++++++++---------------------
Mui.h | 3+--
3 files changed, 66 insertions(+), 110 deletions(-)

diff --git a/edo.c b/edo.c @@ -67,8 +67,9 @@ void view_cursor_right(View *v); void view_cursor_up(View *v); void view_cursor_down(View *v); int view_idx2col(View *v, Line *line, int idx); -int view_col2idx(View *v, Line *line, int col); void view_scroll_fix(View *v); +int measure_span(char *s, int len, int start_x); +int render(Cell *cells, char *buf, int buflen, int xoff, int cols); char *cell_get_text(Cell *cell, char *pool_base); void view_place_cursor(View *v); void draw_view(View *v); @@ -317,13 +318,7 @@ int view_idx2col(View *v, Line *line, int idx) { (void)v; if(!line->len) return 0; - return ui->text_width(line->buf, idx); -} - -int -view_col2idx(View *v, Line *line, int col) { - (void)v; - return ui->text_index_at(line->buf, col); + return measure_span(line->buf, idx, 0); } void @@ -335,46 +330,61 @@ view_scroll_fix(View *v) { v->row_offset = v->line_num - v->screen_rows + 1; /* horizontal */ - if(v->col_num < v->col_offset) - v->col_offset = v->col_num; - if(v->col_num >= v->col_offset + v->screen_cols) - v->col_offset = v->col_num - v->screen_cols + 1; -} - -/* - * TODO - * - * - arena pool - * - fine clipping - * - horizontal scroll - */ -void + Line *l = buffer_get_line(v->buf, v->line_num); + int vx = view_idx2col(v, l, v->col_num); + + if(vx < v->col_offset) + v->col_offset = vx; + if(vx >= v->col_offset + v->screen_cols) + v->col_offset = vx - v->screen_cols + 1; +} + +int +measure_span(char *s, int slen, int start_x) { + int x = start_x; + int len, i; + + for(i = 0; i < slen; i += len) { + len = 1; /* TODO: decode UTF8 */ + x += ui->text_width(s + i, len, x); + } + return x - start_x; +} + +int render(Cell *cells, char *buf, int buflen, int xoff, int cols) { - int vx = 0, len, w, i; - - for(i = 0; i < buflen && vx < cols; i++, vx += w) { - if(buf[i] == '\t') { - /* Note: assume tabstop (8) is <= CELL_POOL_THRESHOLD */ - w = 8 - (vx % 8); - len = w; - for(int j = 0; j < w; j++) - cells[i].data.text[j] = ' '; + int nc = 0, vx = 0, i = 0; + int w, len, x; + + while(i < buflen) { + len = 1; /* TODO: decode UTF8 */ + w = ui->text_width(buf + i, len, vx); + + if(vx + w <= xoff) goto next; /* horizontal scroll */ + + x = vx - xoff; + if(x >= cols) break; /* screen has been filled */ + if(x + w > cols) break; /* truncated character (TODO: draw a symbol?) */ + + if(len > CELL_POOL_THRESHOLD) { + /* TODO: manage pool */ + die("Arena pool to be implemented.\n"); } else { - w = 1; - len = 1; - cells[i].data.text[0] = buf[i]; + memcpy(cells[nc].data.text, buf + i, len); } - cells[i].len = len; - cells[i].width = w; + cells[nc].len = len; + cells[nc].width = w; + if(vx < xoff) cells[nc].width -= xoff - vx; /* partial rendering */ - //cells[i].data.pool_idx = 0; - /* - char text[CELL_POOL_THRESHOLD]; - uint32_t pool_idx; - */ + ++nc; +next: + vx += w; + i += len; } + + return nc; } /* TODO: is this the cleaner way to do it? */ @@ -396,9 +406,9 @@ view_place_cursor(View *v) { } void -draw_view_with_cells(View *v) { +draw_view(View *v) { Line *l; - int row, y; + int row, y, nc; ui->frame_start(); view_scroll_fix(v); @@ -412,8 +422,8 @@ draw_view_with_cells(View *v) { ui->draw_symbol(0, y, SYM_EMPTYLINE); continue; } - render(cells, l->buf, l->len, v->col_offset, v->screen_cols); - ui->draw_line_from_cells(ui, 0, y, cells, l->len > v->screen_cols ? v->screen_cols : l->len); + nc = render(cells, l->buf, l->len, v->col_offset, v->screen_cols); + ui->draw_line_from_cells(ui, 0, y, cells, nc); } free(cells); @@ -423,48 +433,6 @@ draw_view_with_cells(View *v) { } void -draw_view_old(View *v) { - Line *l; - int row, len, y; - int idx, sx, shift; - - ui->frame_start(); - view_scroll_fix(v); - - for(y = 0; y < v->screen_rows; y++) { - row = v->row_offset + y; - - if(row >= v->buf->lines_tot) { - ui->draw_symbol(0, y, SYM_EMPTYLINE); - continue; - } - - l = buffer_get_line(v->buf, row); - if(!l->len) { - ui->draw_line(0, y, "", 0); - continue; - } - idx = view_col2idx(v, l, v->col_offset); - len = l->len - idx; - - /* fine clipping */ - sx = view_idx2col(v, l, idx); - shift = sx - v->col_offset; - - ui->draw_line(shift, y, l->buf + idx, len); - } - - view_place_cursor(v); - ui->frame_flush(); -} - -void -draw_view(View *v) { - draw_view_with_cells(v); - //draw_view_old(v); -} - -void textpool_ensure_cap(TextPool *pool, int len) { size_t newlen = pool->len + len; diff --git a/tui.c b/tui.c @@ -39,7 +39,7 @@ int ab_printf(Abuf *ab, const char *fmt, ...); void ab_flush(Abuf *ab); void tui_frame_start(void); void tui_frame_flush(void); -int tui_text_width(char *s, int len); +int tui_text_width(char *s, int len, int x); void tui_get_window_size(int *rows, int *cols); void tui_exit(void); void tui_move_cursor(int x, int y); @@ -115,32 +115,18 @@ tui_frame_flush(void) { } int -tui_text_width(char *s, int len) { +tui_text_width(char *s, int len, int x) { int tabstop = 8; int w = 0, i; for(i = 0; i < len; i++) { if(s[i] == '\t') - w += tabstop - w % tabstop; + w += tabstop - x % tabstop; else ++w; - } - return w; -} - -int -tui_text_index_at(char *str, int target_x) { - int tabstop = 8; - int x = 0, i = 0, w; - - while(str[i]) { - w = (str[i] == '\t') ? tabstop : 1; - if (x + w > target_x) - return i; x += w; - i++; } - return i; + return w; } void @@ -170,8 +156,12 @@ void tui_draw_line_from_cells(UI *ui, int x, int y, Cell *cells, int count) { for(i = 0; i < count; i++) { w += cells[i].width; txt = cell_get_text(&cells[i], ui->pool.data); - ab_write(&frame, txt, cells[i].len); - if(w >= ws.ws_col) break; + + /* 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 + ab_write(&frame, txt, cells[i].len); } ab_write(&frame, CLEARRIGHT, strlen(CLEARRIGHT)); } @@ -270,7 +260,6 @@ UI ui_tui = { .frame_start = tui_frame_start, .frame_flush = tui_frame_flush, .text_width = tui_text_width, - .text_index_at = tui_text_index_at, .move_cursor = tui_move_cursor, .draw_line = tui_draw_line, .draw_line_from_cells = tui_draw_line_from_cells, diff --git a/ui.h b/ui.h @@ -56,8 +56,7 @@ struct UI { void (*exit)(void); void (*frame_start)(void); void (*frame_flush)(void); - int (*text_width)(char *s, int len); - int (*text_index_at)(char *s, int idx); + int (*text_width)(char *s, int len, int x); void (*move_cursor)(int x, int y); void (*draw_line)(int r, int c, char *txt, int len); void (*draw_line_from_cells)(UI *ui, int x, int y, Cell *cells, int count);