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);
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 {
#include <X.h>
#include <utf.h>
#include <edit.h>
+#include <ctype.h>
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;
}
};
+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) {
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,
}
/* 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) {
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);