edo

Experimental text editor.
Log | Files | Refs | LICENSE

commit 1d9b68f7e0d73a9206b1841f134708d7ad17113e
parent d1e14aafe3edd19e4350a0378a5ac1ac87da8ec5
Author: Claudio Alessi <smoppy@gmail.com>
Date:   Mon, 24 Nov 2025 12:21:21 +0100

Implement fine clipping when scrolling horizontally.

Toy implementation, just to sort things out in my mind.

Diffstat:
Medo.c | 56+++++++++++++++++++++++++-------------------------------
Mtui.c | 60++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Mui.h | 3++-
3 files changed, 79 insertions(+), 40 deletions(-)

diff --git a/edo.c b/edo.c @@ -61,7 +61,8 @@ void view_cursor_left(View *v); void view_cursor_right(View *v); void view_cursor_up(View *v); void view_cursor_down(View *v); -int view_col2x(View *v, Line *line, int col); +int view_idx2col(View *v, Line *line, int idx); +int view_col2idx(View *v, Line *line, int col); void view_scroll_fix(View *v); void draw_view(View *v); @@ -277,7 +278,6 @@ view_cursor_left(View *v) { void view_cursor_right(View *v) { - //if(!v->buf->lines_tot) return; Line *l = v->buf->lines[v->line_num]; if(v->col_num < l->len) @@ -294,7 +294,6 @@ view_cursor_up(View *v) { void view_cursor_down(View *v) { - //if(!v->buf->lines_tot) return; if(v->line_num < v->buf->lines_tot - 1) { ++v->line_num; view_cursor_hfix(v); @@ -302,9 +301,15 @@ view_cursor_down(View *v) { } int -view_col2x(View *v, Line *line, int col) { +view_idx2col(View *v, Line *line, int idx) { (void)v; - return ui->text_width(line->buf, col); + 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); } void @@ -326,51 +331,40 @@ void draw_view(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); - assert(l); - - len = l->len - v->col_offset; + idx = view_col2idx(v, l, v->col_offset); + len = l->len - idx; - /* lines may be hidden when scrolling horizontally */ - if(len < 0) continue; + /* fine clipping */ + sx = view_idx2col(v, l, idx); + shift = sx - v->col_offset; - if(len > v->screen_cols) len = v->screen_cols; - ui->draw_text(0, y, l->buf + v->col_offset, len); + ui->draw_line(shift, y, l->buf + idx, len); } - Line *curline = buffer_get_line(v->buf, v->line_num); - int cx, cy; - if(curline) { - cx = view_col2x(v, curline, v->col_num); /* absolute */ - cx -= view_col2x(v, curline, v->col_offset); /* offset */ - cy = v->line_num - v->row_offset; + l = buffer_get_line(v->buf, v->line_num); + if(l) { + row = view_idx2col(v, l, v->col_num); + row -= v->col_offset; + y = v->line_num - v->row_offset; } else { - cx = cy = 0; + row = y = 0; } -#if 0 - char *t = ecalloc(1, 128); - int tl; - tl = snprintf(t, 128, "\"%s\" %ld lines [%dx%d] (%d/%d)", - v->buf->file_name ? v->buf->file_name : "[none]", v->buf->lines_tot, - v->screen_cols, v->screen_rows, v->col_num, v->buf->lines[0]->len - ); - ui->draw_text(0, v->screen_rows, t, tl); - free(t); -#endif - - ui->move_cursor(cx, cy); + ui->move_cursor(row, y); ui->frame_flush(); } diff --git a/tui.c b/tui.c @@ -13,7 +13,6 @@ #define CURPOS "\33[%d;%dH" //#define CLEARLEFT "\33[1K" #define CLEARRIGHT "\33[0K" -#define CLEARLINE "\33[2K" #define CURHIDE "\33[?25l" #define CURSHOW "\33[?25h" @@ -42,7 +41,7 @@ int tui_text_width(char *s, int len); void tui_get_window_size(int *rows, int *cols); void tui_exit(void); void tui_move_cursor(int x, int y); -void tui_draw_text(int c, int r, char *txt, int len); +void tui_draw_line(int c, int r, char *txt, int len); void tui_draw_symbol(int r, int c, Symbol sym); void tui_init(void); @@ -116,8 +115,8 @@ tui_frame_flush(void) { int tui_text_width(char *s, int len) { - int w = 0, i; int tabstop = 8; + int w = 0, i; for(i = 0; i < len; i++) { if(s[i] == '\t') @@ -128,6 +127,21 @@ tui_text_width(char *s, int len) { 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; +} + void tui_get_window_size(int *rows, int *cols) { *rows = ws.ws_row; @@ -146,9 +160,38 @@ tui_move_cursor(int c, int r) { } void -tui_draw_text(int c, int r, char *txt, int len) { - tui_move_cursor(c, r); - ab_printf(&frame, CLEARLINE "%.*s", len, txt); +tui_draw_line(int c, int r, char *txt, int len) { + if(c >= ws.ws_col || r >= ws.ws_row) return; + + int x = c; + int tabstop = 8; + int i = 0; + int cw, clen; + + tui_move_cursor(x < 0 ? 0 : x, r); + while(i < len) { + cw = (txt[i] == '\t' ? tabstop : 1); + + if(x + cw <= 0) + continue; + + if(txt[i] == '\t') { + int spaces = tabstop; + clen = 1; + + if(x < 0) spaces += x; + if(x + cw > ws.ws_col) spaces -= (x + cw - ws.ws_col); + while(spaces--) ab_write(&frame, " ", 1); + } else { + if(x + cw > ws.ws_col) break; + clen = 1; + ab_write(&frame, txt + i, clen); + } + + x += cw; + i += clen; + } + ab_write(&frame, CLEARRIGHT, strlen(CLEARRIGHT)); } void @@ -161,7 +204,7 @@ tui_draw_symbol(int c, int r, Symbol sym) { } tui_move_cursor(c, r); - ab_printf(&frame, CLEARRIGHT "%c", symch); + ab_printf(&frame, "%c" CLEARRIGHT, symch); } void @@ -210,8 +253,9 @@ 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_text = tui_draw_text, + .draw_line = tui_draw_line, .draw_symbol = tui_draw_symbol, .get_window_size = tui_get_window_size, .next_event = tui_next_event diff --git a/ui.h b/ui.h @@ -24,8 +24,9 @@ typedef struct { void (*frame_start)(void); void (*frame_flush)(void); int (*text_width)(char *s, int len); + int (*text_index_at)(char *s, int idx); void (*move_cursor)(int x, int y); - void (*draw_text)(int r, int c, char *txt, int len); + void (*draw_line)(int r, int c, char *txt, int len); void (*draw_symbol)(int r, int c, Symbol sym); void (*get_window_size)(int *rows, int *cols); Event (*next_event)(void);