tvi: undo and redo move to the first changed line - neatvi - [fork] simple vi-type editor with UTF-8 support (HTM) git clone git://src.adamsgaard.dk/neatvi (DIR) Log (DIR) Files (DIR) Refs (DIR) README --- (DIR) commit 195dc5459fae177fba03ed32db9e0e1dd57fb972 (DIR) parent 36dab822780af2effa399289db2caa52398de43e (HTM) Author: Ali Gholami Rudi <ali@rudi.ir> 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(-) --- (DIR) 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]) (DIR) 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++; } (DIR) 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 failed\n"); + } 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 failed\n"); + } break; case TK_CTL('g'): vc_status(); (DIR) 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);