From 2dc0651b14485723b09eb909d93fbae5b9839b02 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Thu, 10 Nov 2016 13:37:07 -0500 Subject: [PATCH] first pass at simplified non-modal editor --- inc/edit.h | 33 +++++++++ libedit/keyboard.c | 2 +- xedit.c | 178 +++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 199 insertions(+), 14 deletions(-) diff --git a/inc/edit.h b/inc/edit.h index c294c47..17740ca 100644 --- a/inc/edit.h +++ b/inc/edit.h @@ -47,6 +47,11 @@ typedef struct buf { Log* redo; /* redo list */ } Buf; +typedef struct { + size_t beg; + size_t end; +} Sel; + void buf_load(Buf* buf, char* path); void buf_save(Buf* buf); void buf_init(Buf* buf); @@ -73,6 +78,34 @@ unsigned buf_setcol(Buf* buf, unsigned pos, unsigned col); char* buf_getstr(Buf* buf, unsigned beg, unsigned end); unsigned buf_putstr(Buf* buf, unsigned beg, unsigned end, char* str); +/* +void buf_load(Buf* buf, char* path); +void buf_save(Buf* buf); +void buf_init(Buf* buf); +void buf_ins(Buf* buf, Sel csr, Rune); +void buf_del(Buf* buf, Sel csr); +Sel buf_undo(Buf* buf, Sel csr); +Sel buf_redo(Buf* buf, Sel csr); +Rune buf_get(Buf* buf, Sel csr); +void buf_setlocked(Buf* buf, bool locked); +bool buf_locked(Buf* buf); +bool buf_iseol(Buf* buf, Sel csr); +Sel buf_bol(Buf* buf, Sel csr); +Sel buf_eol(Buf* buf, Sel csr); +Sel buf_bow(Buf* buf, Sel csr); +Sel buf_eow(Buf* buf, Sel csr); +Sel buf_lscan(Buf* buf, Sel csr, Rune r); +Sel buf_rscan(Buf* buf, Sel csr, Rune r); +Sel buf_find(Buf* buf, Sel csr); +Sel buf_end(Buf* buf); +Sel buf_byrune(Buf* buf, Sel csr, int count); +Sel buf_byline(Buf* buf, Sel csr, int count); +Sel buf_getcol(Buf* buf, Sel csr); +Sel buf_setcol(Buf* buf, Sel csr, unsigned col); +char* buf_getstr(Buf* buf, Sel csr); +Sel buf_putstr(Buf* buf, Sel csr, char* str); +*/ + /* Charset Handling *****************************************************************************/ enum { diff --git a/libedit/keyboard.c b/libedit/keyboard.c index d530e32..e79d799 100644 --- a/libedit/keyboard.c +++ b/libedit/keyboard.c @@ -121,7 +121,7 @@ static void undo(void) { } static void redo(void) { - SelBeg = SelEnd = buf_redo(&Buffer, SelEnd); + SelBeg = SelEnd = buf_redo(&Buffer, SelEnd)+1; TargetCol = buf_getcol(&Buffer, SelEnd); } diff --git a/xedit.c b/xedit.c index 0d9c491..99b6055 100644 --- a/xedit.c +++ b/xedit.c @@ -2,9 +2,27 @@ #include #include #include +#include static void redraw(int width, int height); static void mouse_handler(MouseAct act, MouseBtn btn, int x, int y); +void handle_key(Rune key); + +static void quit(void); +static void write(void); +static void undo(void); +static void redo(void); +static void cut(void); +static void copy(void); +static void paste(void); +static void cursor_up(void); +static void cursor_dn(void); +static void cursor_left(void); +static void cursor_right(void); +static void cursor_bol(void); +static void cursor_eol(void); +static void dot_delete(void); +static void dot_backspace(void); Buf Buffer; unsigned TargetCol = 0; @@ -37,6 +55,151 @@ static XConfig Config = { } }; +typedef struct { + Rune key; + void (*action)(void); +} KeyBinding_T; + +static KeyBinding_T Insert[] = { + { KEY_CTRL_Q, quit }, + { KEY_CTRL_S, write }, + { KEY_CTRL_Z, undo }, + { KEY_CTRL_Y, redo }, + { KEY_CTRL_X, cut }, + { KEY_CTRL_C, copy }, + { KEY_CTRL_V, paste }, + { KEY_UP, cursor_up }, + { KEY_DOWN, cursor_dn }, + { KEY_LEFT, cursor_left }, + { KEY_RIGHT, cursor_right }, + { KEY_HOME, cursor_bol }, + { KEY_END, cursor_eol }, + { KEY_DELETE, dot_delete }, + { KEY_BACKSPACE, dot_backspace }, + { 0, NULL } +}; + +static void process_table(KeyBinding_T* bindings, Rune key) { + while (bindings->key) { + if (key == bindings->key) { + bindings->action(); + return; + } + bindings++; + } + /* skip control and nonprintable characters */ + if ((!isspace(key) && key < 0x20) || + (key >= 0xE000 && key <= 0xF8FF)) + return; + /* fallback to just inserting the rune */ + buf_ins(&Buffer, SelEnd++, key); + SelBeg = SelEnd; + TargetCol = buf_getcol(&Buffer, SelEnd); +} + +void handle_key(Rune key) { + /* ignore invalid keys */ + if (key == RUNE_ERR) return; + /* handle the proper line endings */ + if (key == '\r') key = '\n'; + if (key == '\n' && Buffer.crlf) key = RUNE_CRLF; + /* handle the key */ + process_table(Insert, key); +} + +static void quit(void) { + static uint32_t num_clicks = 0; + static uint32_t prevtime = 0; + uint32_t now = getmillis(); + num_clicks = (now - prevtime < 250 ? num_clicks+1 : 1); + prevtime = now; + if (!Buffer.modified || num_clicks >= 2) + exit(0); +} + +static void write(void) { + buf_save(&Buffer); +} + +static void undo(void) { + SelBeg = SelEnd = buf_undo(&Buffer, SelEnd); + TargetCol = buf_getcol(&Buffer, SelEnd); +} + +static void redo(void) { + SelBeg = SelEnd = buf_redo(&Buffer, SelEnd); + TargetCol = buf_getcol(&Buffer, SelEnd); +} + +static void cut(void) { + char* str = buf_getstr(&Buffer, SelBeg, SelEnd); + clipcopy(str); + free(str); + dot_delete(); +} + +static void copy(void) { + char* str = buf_getstr(&Buffer, SelBeg, SelEnd); + clipcopy(str); + free(str); +} + +static void paste(void) { + char* str = clippaste(); + buf_putstr(&Buffer, SelBeg, SelEnd, str); + free(str); +} + +static void cursor_up(void) { + SelBeg = SelEnd = buf_byline(&Buffer, SelEnd, -1); + SelBeg = SelEnd = buf_setcol(&Buffer, SelEnd, TargetCol); +} + +static void cursor_dn(void) { + SelBeg = SelEnd = buf_byline(&Buffer, SelEnd, 1); + SelBeg = SelEnd = buf_setcol(&Buffer, SelEnd, TargetCol); +} + +static void cursor_left(void) { + SelBeg = SelEnd = buf_byrune(&Buffer, SelEnd, -1); + TargetCol = buf_getcol(&Buffer, SelEnd); +} + +static void cursor_right(void) { + SelBeg = SelEnd = buf_byrune(&Buffer, SelEnd, 1); + TargetCol = buf_getcol(&Buffer, SelEnd); +} + +static void cursor_bol(void) { + SelBeg = SelEnd = buf_bol(&Buffer, SelEnd); + TargetCol = 0; +} + +static void cursor_eol(void) { + SelBeg = SelEnd = buf_eol(&Buffer, SelEnd); + TargetCol = (unsigned)-1; +} + +static void dot_delete(void) { + if (SelEnd == buf_end(&Buffer)) return; + size_t n = SelEnd - SelBeg; + bool locked = buf_locked(&Buffer); + if (locked || !n) n++; + buf_setlocked(&Buffer,false); + for (size_t i = 0; i < n; i++) + buf_del(&Buffer, SelBeg); + SelEnd = SelBeg; + TargetCol = buf_getcol(&Buffer, SelEnd); + buf_setlocked(&Buffer, locked); +} + +static void dot_backspace(void) { + if (SelBeg > 0 && SelBeg == SelEnd) SelBeg--; + while (SelBeg < SelEnd) + buf_del(&Buffer, --SelEnd); + TargetCol = buf_getcol(&Buffer, SelEnd); +} + static void draw_runes(unsigned x, unsigned y, int fg, int bg, UGlyph* glyphs, size_t rlen) { XftGlyphFontSpec specs[rlen]; while (rlen) { @@ -90,18 +253,6 @@ static void draw_status(int fg, unsigned ncols) { draw_runes(0, 0, fg, 0, glyphs, status - glyphs); } -static void draw_cursor(unsigned csrx, unsigned csry) { - unsigned rwidth; - UGlyph* csrrune = screen_getglyph(csry, csrx, &rwidth); - csrrune->attr = (CLR_BASE3 << 8 | CLR_BASE03); - if (buf_locked(&Buffer)) { - x11_draw_rect(CLR_BASE3, csrx * Fonts.base.width, (csry+1) * Fonts.base.height, rwidth * Fonts.base.width, Fonts.base.height); - draw_glyphs(csrx * Fonts.base.width, (csry+2) * Fonts.base.height, csrrune, 1, rwidth); - } else { - x11_draw_rect(CLR_BASE3, csrx * Fonts.base.width, (csry+1) * Fonts.base.height, 1, Fonts.base.height); - } -} - static void redraw(int width, int height) { /* update the screen size if needed */ screen_setsize(&Buffer, @@ -128,7 +279,7 @@ static void redraw(int width, int height) { } /* Place cursor on screen */ - draw_cursor(csrx, csry); + x11_draw_rect(CLR_BASE3, csrx * Fonts.base.width, (csry+1) * Fonts.base.height, 1, Fonts.base.height); } static void mouse_handler(MouseAct act, MouseBtn btn, int x, int y) { @@ -146,6 +297,7 @@ int main(int argc, char** argv) { buf_init(&Buffer); if (argc > 1) buf_load(&Buffer, argv[1]); + buf_setlocked(&Buffer, false); /* initialize the display engine */ x11_init(&Config); x11_window("edit", Width, Height); -- 2.52.0