#include #include #include #include #include #include #include #include #define ARENA_IMPL #define UTF8_IMPL #include "wrmr.h" #include "arena.h" #include "txt.h" #include "vui.h" #include "utf8.h" Arena scratch = { 0 }; Txt txt = { 0 }; u32 cur = 0; int is_space(u32 c) { return c <= 0x20 && c != 0; } u32 move_word_back(Txt *t, u32 cur) { TxtLoc l = txt_at(t, cur); while (!txt_at_start(t,l)) { TxtLoc n = txt_prev(t, l); if (!is_space(txt_chr(t, n))) break; l = n; } while (!txt_at_start(t,l)) { TxtLoc n = txt_prev(t, l); if (is_space(txt_chr(t, n))) break; l = n; } return txt_ofs(t, l); } u32 move_word_fwd(Txt *t, u32 cur) { TxtLoc l = txt_at(t, cur); while (!txt_at_end(t,l) && is_space(txt_chr(t, l))) l = txt_next(t, l); while (!txt_at_end(t,l) && !is_space(txt_chr(t, l))) l = txt_next(t, l); return txt_ofs(t, l); } u32 move_char_back(Txt *t, u32 cur) { while (cur > 0) { cur--; u8 c = txt_byte(t, txt_at(t, cur)); if ((c & 0xc0) != 0x80) break; } return cur; } u32 move_char_fwd(Txt *t, u32 cur) { u8 b = txt_byte(t, txt_at(t, cur)); u32 n = stdc_leading_ones(b); if (cur + n >= t->len) return t->len; return cur + n + !n; } u32 del_between(Txt *t, u32 a, u32 b) { if (b < a) { u32 t = a; a = b; b = t; } //if (b - a > 10) TRAP(); return txt_delete(t, b, b - a); } /* main */ #define ODD_ATTR (FG_CYAN | BG_BLACK) #define EVEN_ATTR (FG_WHITE | BG_BLACK) void draw(void *ctx) { (void)ctx; redraw:; vui_clear(); static int max_y = 0; int x = 0, y = 0; u32 ofs = 0; 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; } TxtLoc l = txt_at(&txt, cur); 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) { 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"); cur = txt.len; for (;;) { scratch.beg = scratch.start; draw(NULL); vui_blit(); u32 c = vui_key(); switch (c) { case KEY_ESC: goto brk; case KEY_BKSP: cur = txt_delete_c(&txt, cur); break; case KEY_LEFT: cur = move_char_back(&txt, cur); break; case KEY_LEFT | KEY_CTRL_BIT: cur = move_word_back(&txt, cur); break; case KEY_RIGHT: cur = move_char_fwd(&txt, cur); break; case KEY_RIGHT | KEY_CTRL_BIT: cur = move_word_fwd(&txt, cur); break; case 0x17 /* ^W */: cur = del_between(&txt, move_word_back(&txt, cur), cur); break; case 0x05 /* ^E */: cur = del_between(&txt, cur, move_word_fwd(&txt, cur)); break; case 0x13 /* ^S */: txt_save(&txt, "test.txt"); txt_load(&txt, "test.txt"); break; case '\r': cur = txt_insert_c(&txt, cur, '\n'); break; default: if (c >= ' ' && c <= KEY_UTF8_MAX) cur = txt_insert_c(&txt, cur, c); break; } } brk: vui_fini(); arena_free(&scratch); return 0; }