diff options
| author | WormHeamer | 2025-12-28 04:19:59 -0500 |
|---|---|---|
| committer | WormHeamer | 2025-12-28 04:19:59 -0500 |
| commit | 615601fb355709d611d18f878f77c993c312f6aa (patch) | |
| tree | 5fb32e00c201944f9c77308da1ab9bee443bdf7c | |
| parent | 9f4310c24ca39284ad768a82d368e749b18fd76c (diff) | |
lots of features & bugfixes both
| -rw-r--r-- | Makefile | 4 | ||||
| -rw-r--r-- | main.c | 179 | ||||
| -rw-r--r-- | txt.c | 33 | ||||
| -rw-r--r-- | txt.h | 3 | ||||
| -rw-r--r-- | utf8.h | 12 | ||||
| -rw-r--r-- | vui.c | 12 |
6 files changed, 190 insertions, 53 deletions
@@ -10,10 +10,10 @@ OBJ != find -type f -name '*.c' | sed 's/\.c$$/.o/' DEBUG = 0 CFLAGS_0 = -O2 -DNDEBUG -CFLAGS_1 = -O0 -g3 # -fsanitize=address,undefined +CFLAGS_1 = -O0 -g3 -fsanitize=undefined CFLAGS_2 = -O2 -g3 -DNDEBUG LDFLAGS_0 = -s -LDFLAGS_1 = -g3 # -fsanitize=address,undefined +LDFLAGS_1 = -g3 -fsanitize=undefined LDFLAGS_2 = -O2 -g3 PREFIX ?= ${HOME}/.local @@ -69,62 +69,149 @@ u32 del_between(Txt *t, u32 a, u32 b) { return txt_delete(t, b, b - a); } +TxtLoc next_newline(Txt *t, TxtLoc l) { + do l = txt_next(t, l); + while (!txt_at_end(t, l) && txt_byte(t, l) != '\n'); + return l; +} + +TxtLoc prev_newline(Txt *t, TxtLoc l) { + do l = txt_prev(t, l); + while (!txt_at_start(t, l) && txt_byte(t, l) != '\n'); + return l; +} + +TxtLoc start_of_line(Txt *t, TxtLoc l) { + l = prev_newline(t, l); + if (!txt_at_start(t,l) && txt_byte(t, l) == '\n') l = txt_next(t, l); + return l; +} + +TxtLoc prev_line(Txt *t, TxtLoc l) { + TxtLoc start = start_of_line(t, l); + u32 n = 0; + for (TxtLoc tmp = start; txt_before(tmp, l); txt_chr_next(t, &tmp)) n++; + TxtLoc start_up = start_of_line(t, txt_prev(t, start)); + while (n--) { + if (txt_chr_next(t, &start_up) == '\n') { + start_up = txt_prev(t, start_up); + break; + } + } + return start_up; +} + +TxtLoc next_line(Txt *t, TxtLoc l) { + TxtLoc start = start_of_line(t, l); + u32 n = 0; + for (TxtLoc tmp = start; txt_before(tmp, l); txt_chr_next(t, &tmp)) n++; + TxtLoc start_dn = txt_byte(t, l) == '\n' ? txt_next(t, l) : txt_next(t, next_newline(t, l)); + while (n--) { + if (txt_chr_next(t, &start_dn) == '\n') { + start_dn = txt_prev(t, start_dn); + break; + } + } + return start_dn; +} + +u32 move_line_up(Txt *t, u32 cur) { + return txt_ofs(t, prev_line(t, txt_at(t, cur))); +} + +u32 move_line_down(Txt *t, u32 cur) { + return txt_ofs(t, next_line(t, txt_at(t, cur))); +} + +int empty_line(Txt *t, TxtLoc l) { + return txt_byte(t, start_of_line(t, l)) == '\n'; +} + +TxtLoc next_par(Txt *t, TxtLoc l) { + while (!txt_at_end(t, l) && empty_line(t, l)) l = next_line(t, l); + while (!txt_at_end(t, l) && !empty_line(t, l)) l = next_line(t, l); + return l; +} + +TxtLoc prev_par(Txt *t, TxtLoc l) { + while (!txt_at_start(t, l) && empty_line(t, l)) l = prev_line(t, l); + while (!txt_at_start(t, l) && !empty_line(t, l)) l = prev_line(t, l); + return l; +} + +u32 move_par_up(Txt *t, u32 cur) { + return txt_ofs(t, prev_par(t, txt_at(t, cur))); +} + +u32 move_par_down(Txt *t, u32 cur) { + return txt_ofs(t, next_par(t, txt_at(t, cur))); +} + /* main */ #define ODD_ATTR (FG_CYAN | BG_BLACK) #define EVEN_ATTR (FG_WHITE | BG_BLACK) +void find_view_window(Txt *t, u32 curs, TxtLoc *start, TxtLoc *end) { + TxtLoc l = txt_at(t, curs); + u32 n = LINES; + u32 u = LINES / 2; + TxtLoc a = l; + for (u32 i = 0; i < u; i++) a = prev_newline(t, a); + TxtLoc b = a; + while (!txt_at_end(t, b) && n--) b = next_newline(t, b); + if (!txt_at_start(t,a) && txt_byte(t,a) == '\n') a = txt_next(t, a); + *start = a; + *end = b; +} + void draw(void *ctx) { (void)ctx; -redraw:; vui_clear(); - static int max_y = 0; int x = 0, y = 0; - u32 ofs = 0; + TxtLoc start, end; + find_view_window(&txt, cur, &start, &end); + + vui_aprintf(-1, 0, ODD_ATTR, "%u pieces", txt.ptbl.n); for (u32 i = 0; i < txt.ptbl.n; i++) { - Arena stk = scratch; TxtPiece *p = &txt.ptbl.v[i]; - const char *s = txt.buf[p->buf].s + p->ofs; - - u32 bufn = utf8_decode_len(s, p->n); - u32 *buf = new_arr(&scratch, u32, bufn); - utf8_decode(buf, s, bufn); - VuiAttr a = i&1 ? ODD_ATTR : EVEN_ATTR; - vui_aprintf(-1, i, a, "%u, %u (%s)", p->ofs, p->n, p->buf == TXT_ADD ? "add" : "src"); - - for (u32 j = 0; j < bufn; j++) { - u32 c = buf[j]; - if (ofs == cur) vui_curs_pos(x, y - (max_y - LINES + 1)); - if (c != '\r' && c != '\n') { - vui_chra(x++, y - (max_y - LINES + 1), c, a); - } - if (c == '\n') { - x = 0; - y++; - } - ofs += UTF8_CP_LEN(c); - } - scratch = stk; - } - if (ofs == cur) vui_curs_pos(x, y - (max_y - LINES + 1)); - if (y > max_y) { - max_y = y; - goto redraw; + vui_aprintf(-1, i+1, a, "%u, %u (%s)", p->ofs, p->n, p->buf == TXT_ADD ? "add" : "src"); } + TxtLoc l = txt_at(&txt, cur); + int cur_found = 0; + vui_printf(-1, -3, "(%u.%u)-(%u.%u)", start.p, start.i, end.p, end.i); + while (txt_before(start, end)) { + if (l.p == start.p && l.i == start.i) { + cur_found = 1; + vui_curs_pos(x, y); + } + u32 c = txt_chr_next(&txt, &start); + if (c == '\n') { + x = 0; + y++; + } else if (c) { + vui_chr(x++, y, c); + } + } + ASSERT(start.i <= txt.ptbl.v[start.p].n); + vui_printf(-1, -4, "end(%u.%u)", start.p, start.i); + if (!cur_found) vui_curs_pos(x, y); u32 c = txt_chr(&txt, l); vui_printf(-1, -1, "%u, %u - %02x (%c)", l.p, l.i, c, (c < 0x20 || c > 0x7e) ? ' ' : c); u32 used = scratch.beg - scratch.start, max = scratch.end - scratch.start; vui_printf(-1, -2, "scratch %.02f/%.02fk", used/1024.0, max/1024.0); } -int main(void) { +int main(int argc, const char **argv) { scratch = arena_init(1L << 20); vui_init(); vui_curs_vis(1); vui_redraw_fn(draw); - if (txt_load(&txt, "test.txt")) err(1, "couldn't open file"); + const char *path = "test.txt"; + if (argc > 1) path = argv[1]; + if (txt_load(&txt, path)) err(1, "couldn't open file"); cur = txt.len; for (;;) { scratch.beg = scratch.start; @@ -149,6 +236,30 @@ int main(void) { case KEY_RIGHT | KEY_CTRL_BIT: cur = move_word_fwd(&txt, cur); break; + case KEY_UP: + cur = move_line_up(&txt, cur); + break; + case KEY_DOWN: + cur = move_line_down(&txt, cur); + break; + case KEY_UP | KEY_CTRL_BIT: + cur = move_par_up(&txt, cur); + break; + case KEY_DOWN | KEY_CTRL_BIT: + cur = move_par_down(&txt, cur); + break; + case KEY_PGUP: + for (u32 i = 0; i < LINES; i += 3) cur = move_line_up(&txt, cur); + break; + case KEY_PGDN: + for (u32 i = 0; i < LINES; i += 3) cur = move_line_down(&txt, cur); + break; + case KEY_HOME: + cur = txt_ofs(&txt, start_of_line(&txt, txt_at(&txt, cur))); + break; + case KEY_END: + cur = txt_ofs(&txt, next_newline(&txt, txt_at(&txt, cur))); + break; case 0x17 /* ^W */: cur = del_between(&txt, move_word_back(&txt, cur), cur); break; @@ -156,8 +267,8 @@ int main(void) { cur = del_between(&txt, cur, move_word_fwd(&txt, cur)); break; case 0x13 /* ^S */: - txt_save(&txt, "test.txt"); - txt_load(&txt, "test.txt"); + txt_save(&txt, path); + //txt_load(&txt, "test.txt"); break; case '\r': cur = txt_insert_c(&txt, cur, '\n'); @@ -198,7 +198,7 @@ void txt_free(Txt *t) { u8 txt_byte(Txt *t, TxtLoc l) { TxtPiece *p = &t->ptbl.v[l.p]; TxtBuf *b = &t->buf[p->buf]; - if (l.p < t->ptbl.n && l.i == p->n) p++, l.i = 0; + //if (l.p < t->ptbl.n && l.i == p->n) p++, l.i = 0; if (p->ofs + l.i >= b->n) return 0; return b->s[p->ofs + l.i]; } @@ -206,7 +206,10 @@ u8 txt_byte(Txt *t, TxtLoc l) { u32 txt_chr(Txt *t, TxtLoc l) { TxtPiece *p = &t->ptbl.v[l.p]; TxtBuf *b = &t->buf[p->buf]; - if (l.p < t->ptbl.n && l.i == p->n) p++, l.i = 0; + /* + * is this ever executed? + * if (l.p < t->ptbl.n && l.i == p->n) p++, l.i = 0; + */ return utf8_decode_at(b->s, p->ofs + l.i, b->n); } @@ -232,12 +235,14 @@ u32 txt_ofs(Txt *b, TxtLoc l) { TxtLoc txt_next(Txt *b, TxtLoc l) { TxtPiece *p = &b->ptbl.v[l.p]; - if (l.i+1 < p->n) return (TxtLoc) { l.p, l.i + 1 }; - if (l.p+1 < b->ptbl.n) { - return (TxtLoc) { l.p + 1, l.i }; + if (l.p + 1 < b->ptbl.n) { + if (l.i + 1 < p->n) l.i++; + else l.p++, l.i = 0; } else { - return (TxtLoc) { l.p, p->n }; + l.i++; + if (l.i > p->n) l.i = p->n; } + return l; } TxtLoc txt_prev(Txt *b, TxtLoc l) { @@ -258,3 +263,19 @@ int txt_at_start(Txt *b, TxtLoc l) { int txt_at_end(Txt *b, TxtLoc l) { return l.p + 1 == b->ptbl.n && l.i == b->ptbl.v[l.p].n; } + +int txt_before(TxtLoc a, TxtLoc b) { + return a.p < b.p || (a.p == b.p && a.i < b.i); +} + +int txt_after(TxtLoc a, TxtLoc b) { + return a.p > b.p || (a.p == b.p && a.i > b.i); +} + +u32 txt_chr_next(Txt *t, TxtLoc *l) { + if (txt_at_end(t, *l)) return 0; + u32 c = txt_chr(t, *l); + u32 n = UTF8_CP_LEN(c); + for (u32 i = 0; i < n; i++) *l = txt_next(t, *l); + return c; +} @@ -46,8 +46,11 @@ TxtLoc txt_next(Txt *b, TxtLoc l); TxtLoc txt_prev(Txt *b, TxtLoc l); int txt_at_start(Txt *b, TxtLoc l); int txt_at_end(Txt *b, TxtLoc l); +int txt_before(TxtLoc a, TxtLoc b); +int txt_after(TxtLoc a, TxtLoc b); u32 txt_chr(Txt *b, TxtLoc l); u8 txt_byte(Txt *b, TxtLoc l); +u32 txt_chr_next(Txt *b, TxtLoc *l); #endif @@ -6,6 +6,9 @@ #include "wrmr.h" #define UTF8_INVALID 0xFFFD /* replacement character */ +#define UTF8_CP_LEN_BITS ((uint64_t)0xFFEAA550000) +#define UTF8_CP_SHIFT(cp) ((32 - stdc_leading_zeros((uint32_t)(cp))) << 1) +#define UTF8_CP_LEN(cp) (1 + ((UTF8_CP_LEN_BITS >> UTF8_CP_SHIFT(cp)) & 3)) u32 utf8_decode_len(const char *src, u32 ch_count); u32 utf8_encode_len(const u32 *src, u32 cp_count); @@ -18,9 +21,6 @@ u32 utf8_decode_at(const char *s, u32 i, u32 n); #include <stdbit.h> /* packed array of 2-bit lengths for codepoints 0..10FFFF */ -#define UTF8_CP_LEN_BITS ((uint64_t)0xFFEAA550000) -#define UTF8_CP_SHIFT(cp) ((32 - stdc_leading_zeros((uint32_t)(cp))) << 1) -#define UTF8_CP_LEN(cp) (1 + ((UTF8_CP_LEN_BITS >> UTF8_CP_SHIFT(cp)) & 3)) u32 utf8_encode_len(const u32 *src, u32 cp_count) { u32 len = 0; @@ -72,14 +72,14 @@ void utf8_decode(u32 *dst, const char *src, u32 cp_count) { u32 utf8_decode_at(const char *s, u32 i, u32 n) { if (i >= n) return 0; - u32 cp = (u8)s[i++]; + u32 cp = (u8)s[i]; u32 b = stdc_leading_ones((u8)cp); if (!b) return cp; u32 end = i + b - 1; if (end >= n) return 0; cp &= 0xff >> b; - while (i < end) { - u8 c = s[i++]; + while (++i <= end) { + u8 c = s[i]; cp = (cp << 6) | (c & 0x3f); } return cp; @@ -217,15 +217,17 @@ void vui_init(void) { tcgetattr(STDIN_FILENO, &vui_init_stdin_tos); vui_raw_stdin_tos = vui_init_stdin_tos; /* - vui_raw_stdin_tos.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG); - vui_raw_stdin_tos.c_lflag |= IGNBRK; - */ - vui_raw_stdin_tos.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); - //vui_raw_stdin_tos.c_oflag &= ~OPOST; vui_raw_stdin_tos.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); vui_raw_stdin_tos.c_cflag &= ~(CSIZE | PARENB); vui_raw_stdin_tos.c_cflag |= CS8; + */ + //vui_raw_stdin_tos.c_lflag &= ~(ECHO | ECHONL | ICANON); + + vui_raw_stdin_tos.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + vui_raw_stdin_tos.c_oflag &= ~(OPOST); + vui_raw_stdin_tos.c_cflag |= (CS8); + vui_raw_stdin_tos.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); tcsetattr(STDIN_FILENO, TCSANOW, &vui_raw_stdin_tos); |
