sandy

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

commit f4e4e27c77714c1187ed15c8081b837ec88a71f3
parent 1dc2cbdc25a06e5312792fa9e990cf687edd7f58
Author: Rafael Garcia <rafael.garcia.gallego@gmail.com>
Date:   Sun,  5 Jun 2011 02:57:27 +0200

Grouped undos, repeat last operation.
Diffstat:
TODO | 5++---
config.def.h | 2+-
sandy.c | 53++++++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 53 insertions(+), 7 deletions(-)

diff --git a/TODO b/TODO @@ -8,9 +8,8 @@ In no particular order, at sandy.c: - BUG: Deal with the bigger-than-window line - Improve regex search (backwards!!) - Improve syntax highlight, multiline? -- Groups Undos -- Repeat operation (or last pipe at least!) -- Clarify on undo/redo/repeat +- Group delete undos? +- Limit insertion undo grouping? At config.def.h: - Bindings! diff --git a/config.def.h b/config.def.h @@ -134,7 +134,7 @@ static const Key stdkeys[] = { { CONTROL('\\'),{ 0, 0, 0, 0 }, f_spawn, PIPE }, { CONTROL(']'), { 0, 0, 0, 0 }, f_extsel, { .i = ExtDefault } }, { CONTROL('^'), { t_redo,t_rw, 0, 0 }, f_undo, { .i = -1 } }, -/*{ CONTROL('^'), { t_rw, 0, 0, 0 }, f_undo, { .i = 0 } }, */ /* TODO: repeat, implement */ +{ CONTROL('^'), { t_rw, 0, 0, 0 }, f_repeat, { 0 } }, { CONTROL('_'), { t_undo,t_rw, 0, 0 }, f_undo, { .i = 1 } }, { CONTROL('?'), { t_sel, t_rw, 0, 0 }, f_pipe, TOCLIP }, { CONTROL('?'), { t_rw, 0, 0, 0 }, f_delete, { .m = m_prevchar } }, diff --git a/sandy.c b/sandy.c @@ -109,7 +109,7 @@ enum { DefBG, CurBG, SelBG, /* Warning: BGs MUST have a matching FG */ LastB enum { ExtDefault, ExtWord, ExtLines, ExtAll, }; /* To use in lastaction */ -enum { LastNone, LastDelete, LastInsert, LastPipe, }; +enum { LastNone, LastDelete, LastInsert, LastPipe, LastPipeRO, }; /* Environment variables index */ enum { EnvFind, EnvPipe, EnvLine, EnvOffset, EnvFile, EnvSyntax, EnvFifo, EnvLast, }; @@ -187,6 +187,7 @@ static void f_offset(const Arg*); static void f_pipe(const Arg*); static void f_pipelines(const Arg*); static void f_pipero(const Arg*); +static void f_repeat(const Arg*); static void f_save(const Arg*); static void f_select(const Arg*); static void f_spawn(const Arg*); @@ -198,6 +199,7 @@ static void f_warn(const Arg *arg); /* i_* funcions are called from inside the main code only */ static Filepos i_addtext(char*, Filepos); +static void i_addtoundo(Filepos, const char*); static void i_addundo(bool, Filepos, Filepos, char*); static void i_advpos(Filepos *pos, int o); static void i_calcvlen(Line *l); @@ -284,6 +286,7 @@ f_delete(const Arg *arg) { fcur=fsel=pos0; statusflags|=S_Modified; statusflags&=~S_Selecting; + lastaction=LastDelete; } void /* Extend the selection as per arg->i (see enums above) */ @@ -333,11 +336,15 @@ f_insert(const Arg *arg) { undos->flags^=RedoMore; } fsel=i_addtext((char*)arg->v, fcur); - i_addundo(TRUE, fcur, fsel, i_strdup(arg->v)); + if(!killsel && undos && (undos->flags & UndoIns) && fcur.o == undos->endo && undos->endl == i_lineno(fcur.l)) { + i_addtoundo(fsel, arg->v); + } else + i_addundo(TRUE, fcur, fsel, i_strdup(arg->v)); if(killsel) undos->flags^=UndoMore; fcur=fsel; statusflags|=S_Modified; statusflags&=~S_Selecting; + lastaction=LastInsert; } void /* Go to atoi(arg->v) line */ @@ -374,6 +381,7 @@ void /* Pipe selection through arg->v external command. Your responsibility: cal f_pipe(const Arg *arg) { i_pipetext(arg->v); statusflags|=S_Modified; + lastaction=LastPipe; } void /* Pipe full lines including the selection through arg->v external command. Your responsibility: call only if t_rw() */ @@ -381,6 +389,7 @@ f_pipelines(const Arg *arg) { f_extsel(&(const Arg){ .i = ExtLines }); i_pipetext(arg->v); statusflags|=S_Modified; + lastaction=LastPipe; } void /* Pipe selection through arg->v external command but do not update text on screen */ @@ -390,6 +399,32 @@ f_pipero(const Arg *arg) { statusflags|=S_Readonly; i_pipetext(arg->v); statusflags=oldsf&(~S_Selecting); + lastaction=LastPipeRO; +} + +void /* Repeat the last action */ +f_repeat(const Arg *arg) { + Filepos pos; + i_sortpos(&fsel, &fcur); + switch(lastaction) { + case LastDelete: + if(t_sel()) f_delete(&(const Arg){ .m = m_tosel }); + break; + case LastInsert: + if(undos && undos->flags & UndoIns) { + pos=fsel; + f_insert(&(const Arg){ .v = undos->str }); + fsel=pos; + } + break; + case LastPipe: + f_pipe(&(const Arg) { .v = getenv(envs[EnvPipe]) }); + break; + case LastPipeRO: + f_pipero(&(const Arg) { .v = getenv(envs[EnvPipe]) }); + break; + } + statusflags&=~S_Selecting; } void /* Save file with arg->v filename, same if NULL. Your responsibility: call only if t_mod() */ @@ -530,7 +565,19 @@ f_warn(const Arg *arg) { /* I_* FUNCTIONS Called internally from the program code */ -void /* Add undo information to the undo ring */ +void /* Add information to the last undo in the ring */ +i_addtoundo(Filepos newend, const char *s) { + int oldsiz, newsiz; + + oldsiz=strlen(undos->str), newsiz=strlen(s); + undos->endl=i_lineno(newend.l); + undos->endo=newend.o; + if((undos->str=(char*)realloc(undos->str, 1+oldsiz+newsiz)) == NULL) + i_die("Can't malloc.\n"); + strncat(undos->str, s, newsiz); +} + +void /* Add new undo information to the undo ring */ i_addundo(bool ins, Filepos start, Filepos end, char *s) { Undo *u;