commit 47ed88be9e275f418d465b7c6f629a6491936897
parent c88ed95a963cb253ef1583db7074f3c637818ef8
Author: Dimitris Zervas <dzervas@dzervas.gr>
Date: Wed, 9 Jul 2014 18:22:24 +0300
Added sentence key binding support
Diffstat:
config.h | | | 9 | +++++++-- |
sandy.c | | | 115 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------- |
2 files changed, 91 insertions(+), 33 deletions(-)
diff --git a/config.h b/config.h
@@ -142,6 +142,7 @@ static const Key stdkeys[] = {
#if VIM_BINDINGS
{ .keyv.c = CONTROL('['), { t_nocomm,0, 0, 0 }, f_toggle, { .i = S_Command } },
#endif
+{ .keyv.c = CONTROL('['), { 0, 0, 0, 0 }, 0, { 0 } },
{ .keyv.c = CONTROL('\\'),{ t_rw, 0, 0, 0 }, f_spawn, PIPE },
{ .keyv.c = META('\\'), { t_rw, 0, 0, 0 }, f_spawn, SED },
{ .keyv.c = CONTROL(']'), { 0, 0, 0, 0 }, f_extsel, { .i = ExtDefault } },
@@ -153,11 +154,17 @@ static const Key stdkeys[] = {
};
#if VIM_BINDINGS
+/* In order for a key to execute more than 1 function, add consecutive definitions of the key
+ with the exact same tests */
+
static const Key commkeys[] = { /* Command mode keys here */
/* keyv.c, tests, func, arg */
+{ .keyv.c = { '$' }, { t_sent,0, 0, 0 }, f_adjective, { .m = m_eol } },
+{ .keyv.c = { '^' }, { t_sent,0, 0, 0 }, f_adjective, { .m = m_bol } },
{ .keyv.c = { 'a' }, { 0, 0, 0, 0 }, f_moveboth, { .m = m_nextchar } },
{ .keyv.c = { 'a' }, { 0, 0, 0, 0 }, f_toggle, { .i = S_Command } },
{ .keyv.c = { 'b' }, { 0, 0, 0, 0 }, f_moveboth, { .m = m_prevword } },
+{ .keyv.c = { 'd' }, { t_rw, 0, 0, 0 }, f_delete, { .i = 0 } },
{ .keyv.c = { 'g' }, { 0, 0, 0, 0 }, f_moveboth, { .m = m_bof } },
{ .keyv.c = { 'G' }, { 0, 0, 0, 0 }, f_moveboth, { .m = m_eof } },
{ .keyv.c = { 'i' }, { 0, 0, 0, 0 }, f_toggle, { .i = S_Command } },
@@ -191,7 +198,6 @@ static const Key commkeys[] = { /* Command mode keys here */
{ .keyv.c = { ' ' }, { 0, 0, 0, 0 }, f_moveboth, { .m = m_nextchar } },
/* TODO: Keybindings left:
* numbers and arrows do various things (ex. 5s delete the next 5 chars) (adj)
- * $ until eol (adj)
* ^ until bol (adj)
* q record macro (?)
* w/W go to next word (adj)
@@ -200,7 +206,6 @@ static const Key commkeys[] = { /* Command mode keys here */
* t/T do until char (adj)
* y yank things (verb)
* {/} start/end of paragraph (?)
- * d delete/cut things (verb)
* hjkl movement (adj)
* c replace things (verb)
* v visual mode. may not be implemented.
diff --git a/sandy.c b/sandy.c
@@ -138,6 +138,7 @@ enum { /* To use in statusflags */
S_AutoIndent = 1<<10, /* Perform autoindenting on RET */
S_DumpStdout = 1<<11, /* Dump to stdout instead of writing to a file */
S_Command = 1<<12, /* Command mode */
+ S_Sentence = 1<<13, /* Sentence mode (A verb was pressed and an adjective should be pressed) */
};
enum { /* To use in Undo.flags */
@@ -158,35 +159,41 @@ static const char *envs[EnvLast] = {
};
/* Variables */
-static Line *fstline; /* First line*/
-static Line *lstline; /* Last line */
-static Line *scrline; /* First line seen on screen */
-static Filepos fsel; /* Selection point on file */
-static Filepos fcur; /* Insert position on file, cursor, current position */
-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 *fifopath = NULL; /* Path to command fifo */
-static char *filename = NULL; /* Path to file loade on buffer */
-static char *title = NULL; /* Screen title */
-static char *tmptitle = NULL; /* Screen title, temporary */
-static char *tsl_str = NULL; /* String to print to status line */
-static char *fsl_str = NULL; /* String to come back from status line */
-static WINDOW *titlewin = NULL; /* Title ncurses window, NULL if there is a status line */
-static WINDOW *textwin = NULL; /* Main ncurses window */
-static Undo *undos; /* Undo ring */
-static Undo *redos; /* Redo ring */
-static int textattrs[LastFG][LastBG]; /* Text attributes for each color pair */
-static int savestep=0; /* Index to determine the need to save in undo/redo action */
-static int fifofd; /* Command fifo file descriptor */
-static long statusflags=S_Running; /* Status flags, very important, OR'd (see enums above) */
-static int lastaction=LastNone; /* The last action we took (see enums above) */
-static int cols, lines; /* Ncurses: to use instead of COLS and LINES, wise */
-static mmask_t defmmask = 0; /* Ncurses: mouse event mask */
+static Line *fstline; /* First line*/
+static Line *lstline; /* Last line */
+static Line *scrline; /* First line seen on screen */
+static Filepos fsel; /* Selection point on file */
+static Filepos fcur; /* Insert position on file, cursor, current position */
+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 *fifopath = NULL; /* Path to command fifo */
+static char *filename = NULL; /* Path to file loade on buffer */
+static char *title = NULL; /* Screen title */
+static char *tmptitle = NULL; /* Screen title, temporary */
+static char *tsl_str = NULL; /* String to print to status line */
+static char *fsl_str = NULL; /* String to come back from status line */
+static WINDOW *titlewin = NULL; /* Title ncurses window, NULL if there is a status line */
+static WINDOW *textwin = NULL; /* Main ncurses window */
+static Undo *undos; /* Undo ring */
+static Undo *redos; /* Redo ring */
+static int textattrs[LastFG][LastBG]; /* Text attributes for each color pair */
+static int savestep=0; /* Index to determine the need to save in undo/redo action */
+static int fifofd; /* Command fifo file descriptor */
+#if VIM_BINDINGS
+static long statusflags=S_Running | S_Command; /* Status flags, very important, OR'd (see enums above) */
+#else
+static long statusflags=S_Running; /* Status flags, very important, OR'd (see enums above) */
+#endif
+static int lastaction=LastNone; /* The last action we took (see enums above) */
+static int cols, lines; /* Ncurses: to use instead of COLS and LINES, wise */
+static mmask_t defmmask = 0; /* Ncurses: mouse event mask */
+static void (*verb)(const Arg *arg); /* Verb of current sentence */
/* Functions */
/* f_* functions can be linked to an action or keybinding */
+static void f_adjective(const Arg*);
static void f_center(const Arg*);
static void f_delete(const Arg*);
static void f_extsel(const Arg*);
@@ -250,6 +257,7 @@ static bool t_nocomm(void);
static bool t_rw(void);
static bool t_redo(void);
static bool t_sel(void);
+static bool t_sent(void);
static bool t_undo(void);
static bool t_warn(void);
@@ -281,6 +289,14 @@ static regex_t *syntax_res[LENGTH(syntaxes)][SYN_COLORS];
/* F_* FUNCTIONS
Can be linked to an action or keybinding. Always return void and take const Arg* */
+#if VIM_BINDINGS
+void
+f_adjective(const Arg *arg) {
+ statusflags&=~S_Sentence;
+ verb(arg);
+}
+#endif
+
void /* Make cursor line the one in the middle of the screen if possible, refresh screen */
f_center(const Arg *arg) {
int i=LINES2/2;
@@ -787,6 +803,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(statusflags & S_Sentence && curskeys[i].func != f_adjective) {
+ statusflags&=~S_Sentence;
+ break;
+ }
+#endif
+
if(curskeys[i].func != f_insert) statusflags&=~(S_GroupUndo);
curskeys[i].func(&(curskeys[i].arg));
break;
@@ -810,6 +834,15 @@ 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(statusflags & S_Sentence && stdkeys[i].func != f_adjective) {
+ statusflags&=~S_Sentence;
+ break;
+ }
+#endif
+
+
if(stdkeys[i].func != f_insert) statusflags&=~(S_GroupUndo);
stdkeys[i].func(&(stdkeys[i].arg));
break;
@@ -824,6 +857,18 @@ i_edit(void) {
else if(statusflags & S_Command) {
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(!(statusflags & S_Sentence) && commkeys[i].arg.i == 0) {
+ statusflags|=(long)S_Sentence;
+ verb=commkeys[i].func;
+ break;
+ }
+
+ if(statusflags & S_Sentence && commkeys[i].func != f_adjective) {
+ statusflags&=~S_Sentence;
+ break;
+ }
+
if(commkeys[i].func != f_insert) statusflags&=~(S_GroupUndo);
commkeys[i].func(&(commkeys[i].arg));
@@ -1462,10 +1507,10 @@ i_update(void) {
statusflags&=~S_Warned; /* Reset warning */
snprintf(buf, 4, "%ld%%", (100*ncur)/nlst);
#if VIM_BINDINGS
- snprintf(title, BUFSIZ, "%s %s [%s]%s%s%s%s %ld,%d %s",
- (t_nocomm()?"Insert":"Command"),
+ snprintf(title, BUFSIZ, "%s %s [%s]%s%s%s%s %ld,%d %s %s",
+ (statusflags&S_Command?"Command":"Insert"),
#else
- snprintf(title, BUFSIZ, "%s [%s]%s%s%s%s %ld,%d %s",
+ snprintf(title, BUFSIZ, "%s [%s]%s%s%s%s %ld,%d %s %s",
#endif
(statusflags&S_DumpStdout?"<Stdout>":(filename == NULL?"<No file>":filename)),
(syntx>=0 ? syntaxes[syntx].name : "none"),
@@ -1477,7 +1522,7 @@ i_update(void) {
(scrline==fstline?
(nlst<lines3?"All":"Top"):
(nlst-nscr<lines3?"Bot":buf)
- ));
+ ), (statusflags&S_Sentence?"s":""));
}
if(titlewin) {
int i;
@@ -1738,6 +1783,15 @@ t_sel(void) {
return !(fcur.l==fsel.l && fcur.o == fsel.o);
}
+bool /* TRUE if a sentence has started */
+t_sent(void) {
+#if VIM_BINDINGS
+ return (statusflags & S_Sentence);
+#else
+ return FALSE;
+#endif
+}
+
bool /* TRUE if there is anything to undo */
t_undo(void) {
return (undos != NULL);
@@ -1756,7 +1810,6 @@ main(int argc, char **argv){
/* Use system locale, hopefully UTF-8 */
setlocale(LC_ALL,"");
- statusflags|=S_Command;
ESCDELAY=0; // FIXME: Change this to something else to support num keys?
for(i = 1; i < argc && argv[i][0] == '-' && argv[i][1] != '\0'; i++) {