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);