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:
| M | edo.c | | | 56 | +++++++++++++++++++++++++------------------------------- |
| M | tui.c | | | 60 | ++++++++++++++++++++++++++++++++++++++++++++++++++++-------- |
| M | ui.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);