aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc André Tanner <mat@brain-dump.org>2014-09-12 11:29:28 +0200
committerMarc André Tanner <mat@brain-dump.org>2014-09-12 11:29:28 +0200
commit6df6386c3af1420d9b0d676d5b9da660ab6f99d4 (patch)
treee9b717be17c69d090b9cd1d2fda6841620407819
parentbc8ad2d9e83096685dac4a7af3b1080b012eb24d (diff)
downloadvis-6df6386c3af1420d9b0d676d5b9da660ab6f99d4.tar.gz
vis-6df6386c3af1420d9b0d676d5b9da660ab6f99d4.tar.xz
Restore cursor position after an undo/redo
-rw-r--r--editor.c3
-rw-r--r--text.c28
-rw-r--r--text.h6
-rw-r--r--vis.c12
4 files changed, 33 insertions, 16 deletions
diff --git a/editor.c b/editor.c
index 455f3ae..ad3da53 100644
--- a/editor.c
+++ b/editor.c
@@ -484,7 +484,8 @@ static void editor_prompt_update(Prompt *prompt) {
static void editor_prompt_clear(Prompt *prompt) {
Text *text = prompt->win->text;
- while (text_undo(text));
+ while (text_undo(text) != (size_t)-1);
+ window_cursor_to(prompt->win->win, 0);
}
void editor_prompt_hide(Editor *ed) {
diff --git a/text.c b/text.c
index 92a0644..b68d707 100644
--- a/text.c
+++ b/text.c
@@ -84,7 +84,8 @@ typedef struct Change Change;
struct Change {
Span old; /* all pieces which are being modified/swapped out by the change */
Span new; /* all pieces which are introduced/swapped in by the change */
- Change *next;
+ size_t pos; /* absolute position at which the change occured */
+ Change *next; /* next change which is part of the same action */
};
/* An Action is a list of Changes which are used to undo/redo all modifications
@@ -144,7 +145,7 @@ static Location piece_get_extern(Text *txt, size_t pos);
static void span_init(Span *span, Piece *start, Piece *end);
static void span_swap(Text *txt, Span *old, Span *new);
/* change management */
-static Change *change_alloc(Text *txt);
+static Change *change_alloc(Text *txt, size_t pos);
static void change_free(Change *c);
/* action management */
static Action *action_alloc(Text *txt);
@@ -439,7 +440,7 @@ static Location piece_get_extern(Text *txt, size_t pos) {
/* allocate a new change, associate it with current action or a newly
* allocated one if none exists. */
-static Change *change_alloc(Text *txt) {
+static Change *change_alloc(Text *txt, size_t pos) {
Action *a = txt->current_action;
if (!a) {
a = action_alloc(txt);
@@ -449,6 +450,7 @@ static Change *change_alloc(Text *txt) {
Change *c = calloc(1, sizeof(Change));
if (!c)
return NULL;
+ c->pos = pos;
c->next = a->change;
a->change = c;
return c;
@@ -501,7 +503,7 @@ bool text_insert_raw(Text *txt, size_t pos, const char *data, size_t len) {
if (cache_insert(txt, p, off, data, len))
return true;
- Change *c = change_alloc(txt);
+ Change *c = change_alloc(txt, pos);
if (!c)
return false;
@@ -547,31 +549,35 @@ bool text_insert(Text *txt, size_t pos, const char *data) {
}
/* undo all changes of the last action, return whether changes existed */
-bool text_undo(Text *txt) {
+size_t text_undo(Text *txt) {
+ size_t pos = -1;
Action *a = action_pop(&txt->undo);
if (!a)
- return false;
+ return pos;
for (Change *c = a->change; c; c = c->next) {
span_swap(txt, &c->new, &c->old);
+ pos = c->pos;
}
action_push(&txt->redo, a);
lineno_cache_invalidate(&txt->lines);
- return true;
+ return pos;
}
/* redo all changes of the last action, return whether changes existed */
-bool text_redo(Text *txt) {
+size_t text_redo(Text *txt) {
+ size_t pos = -1;
Action *a = action_pop(&txt->redo);
if (!a)
- return false;
+ return pos;
for (Change *c = a->change; c; c = c->next) {
span_swap(txt, &c->old, &c->new);
+ pos = c->pos;
}
action_push(&txt->undo, a);
lineno_cache_invalidate(&txt->lines);
- return true;
+ return pos;
}
/* save current content to given filename. the data is first saved to
@@ -706,7 +712,7 @@ bool text_delete(Text *txt, size_t pos, size_t len) {
return true;
size_t cur; // how much has already been deleted
bool midway_start = false, midway_end = false;
- Change *c = change_alloc(txt);
+ Change *c = change_alloc(txt, pos);
if (!c)
return false;
Piece *before, *after; // unmodified pieces before / after deletion point
diff --git a/text.h b/text.h
index bedd16b..2cec7b1 100644
--- a/text.h
+++ b/text.h
@@ -33,8 +33,10 @@ bool text_insert(Text*, size_t pos, const char *data);
bool text_insert_raw(Text*, size_t pos, const char *data, size_t len);
bool text_delete(Text*, size_t pos, size_t len);
void text_snapshot(Text*);
-bool text_undo(Text*);
-bool text_redo(Text*);
+/* undo/redos to the last snapshoted state. returns the position where
+ * the change occured or (size_t)-1 if nothing could be undo/redo. */
+size_t text_undo(Text*);
+size_t text_redo(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 88cefd2..b2559d7 100644
--- a/vis.c
+++ b/vis.c
@@ -593,13 +593,21 @@ static void mark_line(const Arg *arg) {
}
static void undo(const Arg *arg) {
- if (text_undo(vis->win->text))
+ size_t pos = text_undo(vis->win->text);
+ if (pos != (size_t)-1) {
+ window_cursor_to(vis->win->win, pos);
+ /* redraw all windows in case some display the same file */
editor_draw(vis);
+ }
}
static void redo(const Arg *arg) {
- if (text_redo(vis->win->text))
+ size_t pos = text_redo(vis->win->text);
+ if (pos != (size_t)-1) {
+ window_cursor_to(vis->win->win, pos);
+ /* redraw all windows in case some display the same file */
editor_draw(vis);
+ }
}
static void zero(const Arg *arg) {