tvi: undo and redo move to the first changed line - neatvi - [fork] simple vi-t… | |
git clone git://src.adamsgaard.dk/neatvi | |
Log | |
Files | |
Refs | |
README | |
--- | |
commit 195dc5459fae177fba03ed32db9e0e1dd57fb972 | |
parent 36dab822780af2effa399289db2caa52398de43e | |
Author: Ali Gholami Rudi <[email protected]> | |
Date: Thu, 4 Jun 2015 08:49:39 +0430 | |
vi: undo and redo move to the first changed line | |
Also '[ and '] point to the first and last changed lines. | |
Diffstat: | |
M ex.c | 2 +- | |
M lbuf.c | 46 +++++++++++++++++++++++------… | |
M vi.c | 26 ++++++++++++++++---------- | |
M vi.h | 6 +++--- | |
4 files changed, 55 insertions(+), 25 deletions(-) | |
--- | |
diff --git a/ex.c b/ex.c | |
t@@ -118,7 +118,7 @@ static int ex_lineno(char *num) | |
if (num[0] == '+') | |
n = xrow + (num[1] ? ex_lineno(num + 1) : 1); | |
if (num[0] == '\'') | |
- lbuf_markpos(xb, num[1], &n, NULL); | |
+ lbuf_jump(xb, num[1], &n, NULL); | |
if (num[0] == '/' && num[1]) | |
n = ex_search(num); | |
if (num[0] == '?' && num[1]) | |
diff --git a/lbuf.c b/lbuf.c | |
t@@ -4,7 +4,7 @@ | |
#include <unistd.h> | |
#include "vi.h" | |
-#define MARK(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' : 30) | |
+#define NMARKS 128 | |
/* line operations */ | |
struct lopt { | |
t@@ -16,14 +16,15 @@ struct lopt { | |
/* line buffers */ | |
struct lbuf { | |
- int mark[32]; /* mark lines */ | |
- int mark_off[32]; /* mark line offsets */ | |
+ int mark[NMARKS]; /* mark lines */ | |
+ int mark_off[NMARKS]; /* mark line offsets */ | |
struct lopt hist[128]; /* buffer history */ | |
int undo; /* current index into hist[] */ | |
int useq; /* current operation sequence */ | |
char **ln; /* lines */ | |
int ln_n; /* number of lbuf in l[] */ | |
int ln_sz; /* size of l[] */ | |
+ int mark_mod; /* clear modification marks */ | |
}; | |
struct lbuf *lbuf_make(void) | |
t@@ -70,6 +71,7 @@ static void lbuf_insert(struct lbuf *lb, int pos, char *s) | |
int len = strlen(s); | |
struct sbuf *sb; | |
int lb_len = lbuf_len(lb); | |
+ int beg = pos, end; | |
int i; | |
sb = sbuf_make(); | |
for (i = 0; i < len; i++) { | |
t@@ -83,6 +85,12 @@ static void lbuf_insert(struct lbuf *lb, int pos, char *s) | |
for (i = 0; i < LEN(lb->mark); i++) /* updating marks */ | |
if (lb->mark[i] >= pos) | |
lb->mark[i] += lbuf_len(lb) - lb_len; | |
+ end = beg + lbuf_len(lb) - lb_len; | |
+ if (lb->mark_mod || lb->mark['['] < 0 || lb->mark['['] > beg) | |
+ lbuf_mark(lb, '[', beg, 0); | |
+ if (lb->mark_mod || lb->mark[']'] < 0 || lb->mark[']'] < end - 1) | |
+ lbuf_mark(lb, ']', end - 1, 0); | |
+ lb->mark_mod = 0; | |
} | |
/* low-level deletion */ | |
t@@ -96,6 +104,11 @@ static void lbuf_delete(struct lbuf *lb, int beg, int end) | |
for (i = 0; i < LEN(lb->mark); i++) /* updating marks */ | |
if (lb->mark[i] > beg) | |
lb->mark[i] = MAX(beg, lb->mark[i] + beg - end); | |
+ if (lb->mark_mod || lb->mark['['] < 0 || lb->mark['['] > beg) | |
+ lbuf_mark(lb, '[', beg, 0); | |
+ if (lb->mark_mod || lb->mark[']'] < 0 || lb->mark[']'] < beg) | |
+ lbuf_mark(lb, ']', beg, 0); | |
+ lb->mark_mod = 0; | |
} | |
/* append undo/redo history */ | |
t@@ -180,17 +193,19 @@ int lbuf_len(struct lbuf *lb) | |
void lbuf_mark(struct lbuf *lbuf, int mark, int pos, int off) | |
{ | |
- lbuf->mark[MARK(mark)] = pos; | |
- lbuf->mark_off[MARK(mark)] = off; | |
+ if (mark >= NMARKS) | |
+ return; | |
+ lbuf->mark[mark] = pos; | |
+ lbuf->mark_off[mark] = off; | |
} | |
-int lbuf_markpos(struct lbuf *lbuf, int mark, int *pos, int *off) | |
+int lbuf_jump(struct lbuf *lbuf, int mark, int *pos, int *off) | |
{ | |
- if (lbuf->mark[MARK(mark)] < 0) | |
+ if (mark >= NMARKS || lbuf->mark[mark] < 0) | |
return 1; | |
- *pos = lbuf->mark[MARK(mark)]; | |
+ *pos = lbuf->mark[mark]; | |
if (off) | |
- *off = lbuf->mark_off[MARK(mark)]; | |
+ *off = lbuf->mark_off[mark]; | |
return 0; | |
} | |
t@@ -200,10 +215,13 @@ static struct lopt *lbuf_lopt(struct lbuf *lb, int i) | |
return i >= 0 && i < LEN(lb->hist) && lo->buf ? lo : NULL; | |
} | |
-void lbuf_undo(struct lbuf *lb) | |
+int lbuf_undo(struct lbuf *lb) | |
{ | |
struct lopt *lo = lbuf_lopt(lb, lb->undo); | |
int useq = lo ? lo->seq : 0; | |
+ if (!lo) | |
+ return 1; | |
+ lb->mark_mod = 1; | |
while (lo && lo->seq == useq) { | |
lb->undo++; | |
if (lo->ins) | |
t@@ -212,12 +230,16 @@ void lbuf_undo(struct lbuf *lb) | |
lbuf_insert(lb, lo->beg, lo->buf); | |
lo = lbuf_lopt(lb, lb->undo); | |
} | |
+ return 0; | |
} | |
-void lbuf_redo(struct lbuf *lb) | |
+int lbuf_redo(struct lbuf *lb) | |
{ | |
struct lopt *lo = lbuf_lopt(lb, lb->undo - 1); | |
int useq = lo ? lo->seq : 0; | |
+ if (!lo) | |
+ return 1; | |
+ lb->mark_mod = 1; | |
while (lo && lo->seq == useq) { | |
lb->undo--; | |
if (lo->ins) | |
t@@ -226,6 +248,7 @@ void lbuf_redo(struct lbuf *lb) | |
lbuf_delete(lb, lo->beg, lo->end); | |
lo = lbuf_lopt(lb, lb->undo - 1); | |
} | |
+ return 0; | |
} | |
void lbuf_undofree(struct lbuf *lb) | |
t@@ -239,5 +262,6 @@ void lbuf_undofree(struct lbuf *lb) | |
void lbuf_undomark(struct lbuf *lbuf) | |
{ | |
+ lbuf->mark_mod = 1; | |
lbuf->useq++; | |
} | |
diff --git a/vi.c b/vi.c | |
t@@ -233,9 +233,7 @@ static int vi_motionln(int *row, int cmd) | |
case '\'': | |
if ((mark = vi_read()) <= 0) | |
return -1; | |
- if (!islower(mark) && !strchr("'`", mark)) | |
- return -1; | |
- if (lbuf_markpos(xb, mark, &mark_row, &mark_off)) | |
+ if (lbuf_jump(xb, mark, &mark_row, &mark_off)) | |
return -1; | |
*row = mark_row; | |
break; | |
t@@ -467,9 +465,7 @@ static int vi_motion(int *row, int *off) | |
case '`': | |
if ((mark = vi_read()) <= 0) | |
return -1; | |
- if (!islower(mark) && !strchr("'`", mark)) | |
- return -1; | |
- if (lbuf_markpos(xb, mark, &mark_row, &mark_off)) | |
+ if (lbuf_jump(xb, mark, &mark_row, &mark_off)) | |
return -1; | |
*row = mark_row; | |
*off = mark_off; | |
t@@ -1020,12 +1016,22 @@ static void vi(void) | |
redraw = 1; | |
break; | |
case 'u': | |
- lbuf_undo(xb); | |
- redraw = 1; | |
+ if (!lbuf_undo(xb)) { | |
+ lbuf_jump(xb, '[', &xrow, &xoff); | |
+ xoff = lbuf_indents(xb, xrow); | |
+ redraw = 1; | |
+ } else { | |
+ snprintf(vi_msg, sizeof(vi_msg), "undo… | |
+ } | |
break; | |
case TK_CTL('r'): | |
- lbuf_redo(xb); | |
- redraw = 1; | |
+ if (!lbuf_redo(xb)) { | |
+ lbuf_jump(xb, '[', &xrow, &xoff); | |
+ xoff = lbuf_indents(xb, xrow); | |
+ redraw = 1; | |
+ } else { | |
+ snprintf(vi_msg, sizeof(vi_msg), "redo… | |
+ } | |
break; | |
case TK_CTL('g'): | |
vc_status(); | |
diff --git a/vi.h b/vi.h | |
t@@ -16,9 +16,9 @@ void lbuf_put(struct lbuf *lbuf, int pos, char *s); | |
char *lbuf_get(struct lbuf *lbuf, int pos); | |
int lbuf_len(struct lbuf *lbuf); | |
void lbuf_mark(struct lbuf *lbuf, int mark, int pos, int off); | |
-int lbuf_markpos(struct lbuf *lbuf, int mark, int *pos, int *off); | |
-void lbuf_undo(struct lbuf *lbuf); | |
-void lbuf_redo(struct lbuf *lbuf); | |
+int lbuf_jump(struct lbuf *lbuf, int mark, int *pos, int *off); | |
+int lbuf_undo(struct lbuf *lbuf); | |
+int lbuf_redo(struct lbuf *lbuf); | |
void lbuf_undomark(struct lbuf *lbuf); | |
void lbuf_undofree(struct lbuf *lbuf); | |
int lbuf_indents(struct lbuf *lb, int r); |