sandy

text editor
git clone git://git.suckless.org/sandy
Log | Files | Refs | README | LICENSE

commit bd4f1dd402431fa5b52cf4fcf0a984e89e638e9d
parent d5d6d20653a78e35291fc3e207c4bfdcbe6b3d53
Author: Dimitris Zervas <dzervas@dzervas.gr>
Date:   Sun, 13 Jul 2014 20:20:12 +0300

Added mode support to all keys

Diffstat:
config.def.h | 7+++----
config.h | 7+++----
sandy.c | 168+++++++++++++++++++++++++++++++++++++++----------------------------------------
3 files changed, 89 insertions(+), 93 deletions(-)

diff --git a/config.def.h b/config.def.h @@ -89,7 +89,6 @@ static const Key curskeys[] = { /* Plain keys here, no CONTROL or META */ { .keyv.i = KEY_NPAGE, { 0, 0, 0, 0 }, f_move, { .m = m_nextscr } }, { .keyv.i = KEY_UP, { t_sent,0, 0, 0 }, f_adjective, { .m = m_prevline } }, { .keyv.i = KEY_UP, { 0, 0, 0, 0 }, f_move, { .m = m_prevline } }, -{ .keyv.i = KEY_DOWN, { t_sent,0, 0, 0 }, f_move, { .m = m_nextline } }, { .keyv.i = KEY_DOWN, { t_sent,0, 0, 0 }, f_adjective, { .m = m_nextline } }, { .keyv.i = KEY_DOWN, { 0, 0, 0, 0 }, f_move, { .m = m_nextline } }, { .keyv.i = KEY_LEFT, { t_sent,0, 0, 0 }, f_adjective, { .m = m_prevchar } }, @@ -186,11 +185,11 @@ static const Key commkeys[] = { /* Command mode keys here */ { .keyv.c = { 'b' }, { t_sent,0, 0, 0 }, f_adjective, { .m = m_prevword } }, { .keyv.c = { 'b' }, { 0, 0, 0, 0 }, f_move, { .m = m_prevword } }, { .keyv.c = { 'c' }, { t_sel, t_rw, 0, 0 }, f_delete, { .m = m_tosel } }, -{ .keyv.c = { 'c' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_adjective } }, /* TODO: queue insert mode, similar to 'y' */ +{ .keyv.c = { 'c' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_sentence } }, /* TODO: queue insert mode, similar to 'y' */ { .keyv.c = { 'C' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_eol } }, { .keyv.c = { 'C' }, { t_rw, 0, 0, 0 }, f_toggle, { .i = S_Command } }, { .keyv.c = { 'd' }, { t_sel, t_rw, 0, 0 }, f_delete, { .m = m_tosel } }, -{ .keyv.c = { 'd' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_adjective } }, +{ .keyv.c = { 'd' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_sentence } }, { .keyv.c = { 'D' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_eol } }, { .keyv.c = { 'g' }, { t_sent,0, 0, 0 }, f_adjective, { .m = m_bof } }, { .keyv.c = { 'g' }, { 0, 0, 0, 0 }, f_move, { .m = m_bof } }, @@ -235,7 +234,7 @@ static const Key commkeys[] = { /* Command mode keys here */ { .keyv.c = { 'x' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_nextchar } }, { .keyv.c = { 'X' }, { t_sel, t_rw, 0, 0 }, f_delete, { .m = m_tosel } }, { .keyv.c = { 'X' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_prevchar } }, -{ .keyv.c = { 'y' }, { t_rw, 0, 0, 0 }, f_pipero, { .m = m_adjective, .v = TOCLIP } }, /* TODO: won't work since Arg is a union */ +{ .keyv.c = { 'y' }, { t_rw, 0, 0, 0 }, f_pipero, { .m = m_sentence, .v = TOCLIP } }, /* TODO: won't work since Arg is a union */ { .keyv.c = { ';' }, { 0, 0, 0, 0 }, f_spawn, CMD_P }, { .keyv.c = { ':' }, { 0, 0, 0, 0 }, f_spawn, CMD_P }, { .keyv.c = { '\'' }, { 0, 0, 0, 0 }, f_move, { .m = m_tomark } }, diff --git a/config.h b/config.h @@ -91,7 +91,6 @@ static const Key curskeys[] = { /* Plain keys here, no CONTROL or META */ { .keyv.i = KEY_NPAGE, { 0, 0, 0, 0 }, f_move, { .m = m_nextscr } }, { .keyv.i = KEY_UP, { t_sent,0, 0, 0 }, f_adjective, { .m = m_prevline } }, { .keyv.i = KEY_UP, { 0, 0, 0, 0 }, f_move, { .m = m_prevline } }, -{ .keyv.i = KEY_DOWN, { t_sent,0, 0, 0 }, f_move, { .m = m_nextline } }, { .keyv.i = KEY_DOWN, { t_sent,0, 0, 0 }, f_adjective, { .m = m_nextline } }, { .keyv.i = KEY_DOWN, { 0, 0, 0, 0 }, f_move, { .m = m_nextline } }, { .keyv.i = KEY_LEFT, { t_sent,0, 0, 0 }, f_adjective, { .m = m_prevchar } }, @@ -178,11 +177,11 @@ static const Key commkeys[] = { /* Command mode keys here */ { .keyv.c = { 'b' }, { t_sent,0, 0, 0 }, f_adjective, { .m = m_prevword } }, { .keyv.c = { 'b' }, { 0, 0, 0, 0 }, f_move, { .m = m_prevword } }, { .keyv.c = { 'c' }, { t_sel, t_rw, 0, 0 }, f_delete, { .m = m_tosel } }, -{ .keyv.c = { 'c' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_adjective } }, /* TODO: queue insert mode, similar to 'y' */ +{ .keyv.c = { 'c' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_sentence } }, /* TODO: queue insert mode, similar to 'y' */ { .keyv.c = { 'C' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_eol } }, { .keyv.c = { 'C' }, { t_rw, 0, 0, 0 }, f_toggle, { .i = S_Command } }, { .keyv.c = { 'd' }, { t_sel, t_rw, 0, 0 }, f_delete, { .m = m_tosel } }, -{ .keyv.c = { 'd' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_adjective } }, +{ .keyv.c = { 'd' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_sentence } }, { .keyv.c = { 'D' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_eol } }, { .keyv.c = { 'g' }, { t_sent,0, 0, 0 }, f_adjective, { .m = m_bof } }, { .keyv.c = { 'g' }, { 0, 0, 0, 0 }, f_move, { .m = m_bof } }, @@ -227,7 +226,7 @@ static const Key commkeys[] = { /* Command mode keys here */ { .keyv.c = { 'x' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_nextchar } }, { .keyv.c = { 'X' }, { t_sel, t_rw, 0, 0 }, f_delete, { .m = m_tosel } }, { .keyv.c = { 'X' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_prevchar } }, -{ .keyv.c = { 'y' }, { t_rw, 0, 0, 0 }, f_pipero, { .m = m_adjective, .v = TOCLIP } }, /* TODO: won't work since Arg is a union */ +{ .keyv.c = { 'y' }, { t_rw, 0, 0, 0 }, f_pipero, { .m = m_sentence, .v = TOCLIP } }, /* TODO: won't work since Arg is a union */ { .keyv.c = { ';' }, { 0, 0, 0, 0 }, f_spawn, CMD_P }, { .keyv.c = { ':' }, { 0, 0, 0, 0 }, f_spawn, CMD_P }, { .keyv.c = { '\'' }, { 0, 0, 0, 0 }, f_move, { .m = m_tomark } }, diff --git a/sandy.c b/sandy.c @@ -171,6 +171,7 @@ static Filepos fmrk = { NULL, 0 }; /* Mark */ static int syntx = -1; /* Current syntax index */ static regex_t *find_res[2]; /* Compiled regex for search term */ static int sel_re = 0; /* Index to the above, we keep 2 REs so regexec does not segfault */ +static char c[7]; /* Used to store input */ static char *fifopath = NULL; /* Path to command fifo */ static char *filename = NULL; /* Path to file loade on buffer */ static char *title = NULL; /* Screen title */ @@ -226,6 +227,7 @@ static bool i_deltext(Filepos, Filepos); static void i_die(char *str); static void i_dirtyrange(Line*, Line*); static bool i_dotests(bool (*const a[])(void)); +static bool i_dokeys(const Key bindings[], int index, bool multi); static void i_edit(void); static void i_find(bool); static char *i_gettext(Filepos, Filepos); @@ -264,7 +266,6 @@ static bool t_vis(void); static bool t_warn(void); /* m_ functions represent a cursor movement and can be passed in an Arg */ -static Filepos m_adjective(Filepos); static Filepos m_bof(Filepos); static Filepos m_bol(Filepos); static Filepos m_smartbol(Filepos); @@ -278,6 +279,8 @@ static Filepos m_nextline(Filepos); static Filepos m_prevline(Filepos); static Filepos m_nextscr(Filepos); static Filepos m_prevscr(Filepos); +static Filepos m_parameter(Filepos); +static Filepos m_sentence(Filepos); static Filepos m_stay(Filepos); static Filepos m_tomark(Filepos); static Filepos m_tosel(Filepos); @@ -759,11 +762,58 @@ i_dotests(bool (*const a[])(void)) { } else return TRUE; } +bool +i_dokeys(const Key bindings[], int index, bool multi) { + int i; + + if(bindings[index].func != f_insert) statusflags&=~(S_GroupUndo); + + /* Handle sentences */ + if(t_sent()) { + if(bindings[index].func == verb) i_multiply(verb, (const Arg){ .m = m_nextline }); + + if(bindings[index].func != f_adjective) { + statusflags&=~S_Sentence; + return FALSE; + } + } else if(bindings[index].arg.m == m_sentence) { + statusflags|=(long)S_Sentence; + verb=bindings[index].func; + return FALSE; + } + + /* Handle parameter sentences (verb is used here to define the command to execute) */ + if(statusflags & S_Parameter) { + statusflags&=~S_Parameter; + i_multiply(verb, (const Arg){ .v = c }); + return FALSE; + } else if(bindings[index].arg.m == m_parameter) { + statusflags|=(long)S_Parameter; + verb=bindings[index].func; + return FALSE; + } + + i_multiply(bindings[index].func, bindings[index].arg); + + /* Handle multi-function commands */ + if(multi) { + i=-1; + + while(1) + if(bindings[index].test[++i]) { + if(bindings[index].test[i] != bindings[index+1].test[i]) { + return FALSE; + } + } else return TRUE; + } + + return FALSE; +} + void /* Main editing loop */ i_edit(void) { - int ch, i, j; - char c[7]; - bool pass; + int ch, i; + bool multif; fd_set fds; Filepos oldsel, oldcur; @@ -808,21 +858,14 @@ i_edit(void) { #endif /* HANDLE_MOUSE */ for(i=0; i<LENGTH(curskeys); i++) { if(ch == curskeys[i].keyv.i && i_dotests(curskeys[i].test) ) { - -#if VIM_BINDINGS - if(t_sent()) { - if(curskeys[i].func == verb) i_multiply(verb, (const Arg){ .m = m_nextline }); - - if(curskeys[i].func != f_adjective) { - statusflags&=~S_Sentence; - break; + if(i+1 < LENGTH(curskeys)) { + if(curskeys[i].keyv.i == curskeys[i+1].keyv.i) { + multif = TRUE; } - } -#endif /* VIM_BINDINGS */ + } else multif = FALSE; - if(curskeys[i].func != f_insert) statusflags&=~(S_GroupUndo); - i_multiply(curskeys[i].func, curskeys[i].arg); - break; + if(i_dokeys(curskeys, i, multif)) continue; + else break; } } continue; @@ -843,29 +886,22 @@ i_edit(void) { if(!(statusflags&S_InsEsc) && ISCTRL(c[0])) { for(i=0; i<LENGTH(stdkeys); i++) { if(memcmp(c, stdkeys[i].keyv.c, sizeof stdkeys[i].keyv.c) == 0 && i_dotests(stdkeys[i].test) ) { - -#if VIM_BINDINGS - if(t_sent()) { - if(stdkeys[i].func == verb) i_multiply(verb, (const Arg){ .m = m_nextline }); - - if(stdkeys[i].func != f_adjective) { - statusflags&=~S_Sentence; - break; + if(i+1 < LENGTH(stdkeys)) { + if(memcmp(stdkeys[i+1].keyv.c, stdkeys[i].keyv.c, sizeof stdkeys[i].keyv.c) == 0) { + multif = TRUE; } - } -#endif /* VIM_BINDINGS */ + } else multif = FALSE; - if(stdkeys[i].func != f_insert) statusflags&=~(S_GroupUndo); - i_multiply(stdkeys[i].func, stdkeys[i].arg); - break; + if(i_dokeys(stdkeys, i, multif)) continue; + else break; } } continue; } statusflags&=~(S_InsEsc); -#if VIM_BINDINGS if(t_rw() && t_ins()) f_insert(&(const Arg){ .v = c }); +#if VIM_BINDINGS else if(!t_ins()) { if(ch >= '0' && ch <= '9' && !(statusflags & S_Parameter)) { if(statusflags & S_Multiply) { @@ -877,62 +913,17 @@ i_edit(void) { } } else for(i=0; i<LENGTH(commkeys); i++) { if(memcmp(c, commkeys[i].keyv.c, sizeof commkeys[i].keyv.c) == 0 && i_dotests(commkeys[i].test) ) { - if(commkeys[i].func != f_insert) statusflags&=~(S_GroupUndo); - - /* Handle sentences */ - // FIXME: Find a better way to tell if a func is a verb or parameter - if(t_sent()) { - if(commkeys[i].func == verb) i_multiply(verb, (const Arg){ .m = m_nextline }); - - if(commkeys[i].func != f_adjective) { - statusflags&=~S_Sentence; - break; - } - } else if(commkeys[i].arg.m == m_adjective) { - statusflags|=(long)S_Sentence; - verb=commkeys[i].func; - break; - } - - /* Handle parameter sentences (verb is used here to define the command to execute) */ - if(statusflags & S_Parameter) { - statusflags&=~S_Parameter; - i_multiply(verb, (const Arg){ .v = c }); - break; - } else if(commkeys[i].arg.m == m_adjective) { - statusflags|=(long)S_Parameter; - verb=commkeys[i].func; - break; - } - - i_multiply(commkeys[i].func, commkeys[i].arg); - - /* Handle multi-function commands */ - // TODO: Find a way to handle multi-function verbs if(i+1 < LENGTH(commkeys)) { if(memcmp(commkeys[i+1].keyv.c, commkeys[i].keyv.c, sizeof commkeys[i].keyv.c) == 0) { - j=-1; - pass=TRUE; - - while(1) - if(commkeys[i].test[++j]) { - if(commkeys[i].test[j] != commkeys[i+1].test[j]) { - pass=FALSE; - break; - } - } else break; - - if(pass) continue; - else break; + multif = TRUE; } - } + } else multif = FALSE; - break; + if(i_dokeys(commkeys, i, multif)) continue; + else break; } } } -#else - if(t_rw()) f_insert(&(const Arg){ .v = c }); #endif /* VIM_BINDINGS */ else tmptitle="WARNING! File is read-only!!!"; @@ -1642,11 +1633,6 @@ i_writefile(char *fname) { /* M_* FUNCTIONS Represent a cursor motion, always take a Filepos and return an update Filepos */ -Filepos /* Go to where the adjective says */ -m_adjective(Filepos pos) { - /* WARNING: this code is actually not used */ - return pos; -} Filepos /* Go to beginning of file */ m_bof(Filepos pos) { @@ -1776,6 +1762,12 @@ m_nextscr(Filepos pos) { return pos; } +Filepos /* Go to where the adjective says */ +m_parameter(Filepos pos) { + /* WARNING: this code is actually not used */ + return pos; +} + Filepos /* Backup as many lines as the screen size */ m_prevscr(Filepos pos) { int i; @@ -1787,6 +1779,12 @@ m_prevscr(Filepos pos) { return pos; } +Filepos /* Go to where the adjective says */ +m_sentence(Filepos pos) { + /* WARNING: this code is actually not used */ + return pos; +} + Filepos /* Do not move */ m_stay(Filepos pos) { return pos;