diff options
| -rw-r--r-- | config.def.h | 4 | ||||
| -rw-r--r-- | text.c | 38 | ||||
| -rw-r--r-- | text.h | 10 | ||||
| -rw-r--r-- | vis.c | 69 |
4 files changed, 90 insertions, 31 deletions
diff --git a/config.def.h b/config.def.h index 09ba706..044c530 100644 --- a/config.def.h +++ b/config.def.h @@ -67,8 +67,8 @@ static Command cmds[] = { { { "wq", }, cmd_wq, CMD_OPT_FORCE }, { { "write", "w" }, cmd_write, CMD_OPT_FORCE }, { { "xit", }, cmd_xit, CMD_OPT_FORCE }, - { { "earlier" }, cmd_earlier, CMD_OPT_NONE }, - { { "later" }, cmd_later, CMD_OPT_NONE }, + { { "earlier" }, cmd_earlier_later, CMD_OPT_NONE }, + { { "later" }, cmd_earlier_later, CMD_OPT_NONE }, { { "!", }, cmd_filter, CMD_OPT_NONE }, { /* array terminator */ }, }; @@ -647,14 +647,36 @@ static size_t history_traverse_to(Text *txt, Action *a) { return pos; } -size_t text_earlier(Text *txt) { - Action *earlier = txt->history->earlier; - return history_traverse_to(txt, earlier); -} - -size_t text_later(Text *txt) { - Action *later = txt->history->later; - return history_traverse_to(txt, later); +size_t text_earlier(Text *txt, int count) { + Action *a = txt->history; + while (count-- > 0 && a->earlier) + a = a->earlier; + return history_traverse_to(txt, a); +} + +size_t text_later(Text *txt, int count) { + Action *a = txt->history; + while (count-- > 0 && a->later) + a = a->later; + return history_traverse_to(txt, a); +} + +size_t text_restore(Text *txt, time_t time) { + Action *a = txt->history; + while (time < a->time && a->earlier) + a = a->earlier; + while (time > a->time && a->later) + a = a->later; + time_t diff = labs(a->time - time); + if (a->earlier && a->earlier != txt->history && labs(a->earlier->time - time) < diff) + a = a->earlier; + if (a->later && a->later != txt->history && labs(a->later->time - time) < diff) + a = a->earlier; + return history_traverse_to(txt, a); +} + +time_t text_state(Text *txt) { + return txt->history->time; } bool text_save(Text *txt, const char *filename) { @@ -2,6 +2,7 @@ #define TEXT_H #include <stdbool.h> +#include <time.h> #include <sys/types.h> #define EPOS ((size_t)-1) /* invalid position */ @@ -49,8 +50,13 @@ void text_snapshot(Text*); * the change occured or EPOS if nothing could be undo/redo. */ size_t text_undo(Text*); size_t text_redo(Text*); -size_t text_earlier(Text*); -size_t text_later(Text*); +/* move chronlogically to the count earlier/later revision */ +size_t text_earlier(Text*, int count); +size_t text_later(Text*, int count); +/* restore the text to the state closest to the time given */ +size_t text_restore(Text*, time_t); +/* get creation time of current state */ +time_t text_state(Text*); size_t text_pos_by_lineno(Text*, size_t lineno); size_t text_lineno_by_pos(Text*, size_t pos); @@ -25,6 +25,7 @@ #include <fcntl.h> #include <limits.h> #include <ctype.h> +#include <time.h> #include <sys/select.h> #include <sys/types.h> #include <sys/wait.h> @@ -419,10 +420,8 @@ static bool cmd_write(Filerange*, enum CmdOpt, const char *argv[]); static bool cmd_saveas(Filerange*, enum CmdOpt, const char *argv[]); /* filter range through external program argv[1] */ static bool cmd_filter(Filerange*, enum CmdOpt, const char *argv[]); -/* switch to the previous saved state of the text, chronologically */ -static bool cmd_earlier(Filerange*, enum CmdOpt, const char *argv[]); -/* switch to the next saved state of the text, chronologically */ -static bool cmd_later(Filerange*, enum CmdOpt, const char *argv[]); +/* switch to the previous/next saved state of the text, chronologically */ +static bool cmd_earlier_later(Filerange*, enum CmdOpt, const char *argv[]); static void action_reset(Action *a); static void switchmode_to(Mode *new_mode); @@ -955,7 +954,7 @@ static void redo(const Arg *arg) { } static void earlier(const Arg *arg) { - size_t pos = text_earlier(vis->win->file->text); + size_t pos = text_earlier(vis->win->file->text, MAX(vis->action.count, 1)); if (pos != EPOS) { view_cursor_to(vis->win->view, pos); /* redraw all windows in case some display the same file */ @@ -964,7 +963,7 @@ static void earlier(const Arg *arg) { } static void later(const Arg *arg) { - size_t pos = text_later(vis->win->file->text); + size_t pos = text_later(vis->win->file->text, MAX(vis->action.count, 1)); if (pos != EPOS) { view_cursor_to(vis->win->view, pos); /* redraw all windows in case some display the same file */ @@ -1879,20 +1878,52 @@ static bool cmd_filter(Filerange *range, enum CmdOpt opt, const char *argv[]) { return status == 0; } -static bool cmd_earlier(Filerange *range, enum CmdOpt opt, const char *argv[]) { - if (argv[1]) - return false; - //TODO eventually support time arguments - text_earlier(vis->win->file->text); - return true; -} +static bool cmd_earlier_later(Filerange *range, enum CmdOpt opt, const char *argv[]) { + Text *txt = vis->win->file->text; + char *unit = ""; + long count = 1; + size_t pos = EPOS; + if (argv[1]) { + errno = 0; + count = strtol(argv[1], &unit, 10); + if (errno || unit == argv[1] || count < 0) { + editor_info_show(vis, "Invalid number"); + return false; + } -static bool cmd_later(Filerange *range, enum CmdOpt opt, const char *argv[]) { - if (argv[1]) - return false; - //TODO eventually support time arguments - text_later(vis->win->file->text); - return true; + if (*unit) { + while (*unit && isspace((unsigned char)*unit)) + unit++; + switch (*unit) { + case 'd': count *= 24; + case 'h': count *= 60; + case 'm': count *= 60; + case 's': break; + default: + editor_info_show(vis, "Unknown time specifier (use: s,m,h or d)"); + return false; + } + + if (argv[0][0] == 'e') + count = -count; /* earlier, move back in time */ + + pos = text_restore(txt, text_state(txt) + count); + } + } + + if (!*unit) { + if (argv[0][0] == 'e') + pos = text_earlier(txt, count); + else + pos = text_later(txt, count); + } + + time_t state = text_state(txt); + char buf[32]; + strftime(buf, sizeof buf, "State from %H:%M", localtime(&state)); + editor_info_show(vis, "%s", buf); + + return pos != EPOS; } static Filepos parse_pos(char **cmd) { |
