aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc André Tanner <mat@brain-dump.org>2015-06-27 15:19:10 +0200
committerMarc André Tanner <mat@brain-dump.org>2015-06-27 15:19:10 +0200
commitaf43549eb3a6add4c9ae5ac86f30fc2bd0325ac6 (patch)
treee8ae9061e00db9d9c8fa2cbce39e488c8857dd3d
parent13caec50e0974961f31c2b03ad3ba64e0042f6e1 (diff)
downloadvis-af43549eb3a6add4c9ae5ac86f30fc2bd0325ac6.tar.gz
vis-af43549eb3a6add4c9ae5ac86f30fc2bd0325ac6.tar.xz
Make :earlier and :later accept arguments similar to vim
Currently the following arguments are accepted: {count} Go to older text state {count} times. {N}s Go to older text state about {N} seconds before. {N}m Go to older text state about {N} minutes before. {N}h Go to older text state about {N} hours before. {N}d Go to older text state about {N} days before
-rw-r--r--config.def.h4
-rw-r--r--text.c38
-rw-r--r--text.h10
-rw-r--r--vis.c69
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 */ },
};
diff --git a/text.c b/text.c
index cb7e1c7..f19d5cb 100644
--- a/text.c
+++ b/text.c
@@ -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) {
diff --git a/text.h b/text.h
index f5091c5..e015abb 100644
--- a/text.h
+++ b/text.h
@@ -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);
diff --git a/vis.c b/vis.c
index 2529f65..b85ae47 100644
--- a/vis.c
+++ b/vis.c
@@ -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) {