From bdbc8d37c53bd7702979786c58354bbf2ef6990e Mon Sep 17 00:00:00 2001 From: Ali Gholami Rudi Date: Thu, 28 May 2015 19:43:35 +0430 Subject: [PATCH] vi: rely on line offset instead of column number --- Makefile | 2 +- ex.c | 4 +- mot.c | 186 +++++++++++++++++++++++++ ren.c | 68 +-------- uc.c | 12 +- vi.c | 477 ++++++++++++++++++++++----------------------------------------- vi.h | 16 ++- 7 files changed, 382 insertions(+), 383 deletions(-) create mode 100644 mot.c diff --git a/Makefile b/Makefile index f46ce5c..2d55eac 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ CC = cc CFLAGS = -Wall -O2 LDFLAGS = -OBJS = vi.o ex.o lbuf.o sbuf.o ren.o dir.o syn.o reg.o led.o \ +OBJS = vi.o ex.o lbuf.o mot.o sbuf.o ren.o dir.o syn.o reg.o led.o \ uc.o term.o rset.o cmd.o conf.o all: vi diff --git a/ex.c b/ex.c index 47799d5..6e5a4da 100644 --- a/ex.c +++ b/ex.c @@ -17,7 +17,7 @@ int xvis; /* visual mode */ int xai = 1; /* autoindent option */ int xic = 1; /* ignorecase option */ struct lbuf *xb; /* current buffer */ -int xrow, xcol, xtop; /* current row, column, and top row */ +int xrow, xoff, xtop; /* current row, column, and top row */ int xrow_alt; /* alternate row, column, and top row */ int xled = 1; /* use the line editor */ int xdir = +1; /* current direction context */ @@ -182,7 +182,7 @@ static void ec_edit(char *ec) strcpy(xpath, xpath_tmp); xrow = xrow_alt; xrow_alt = xrow_tmp; - xcol = 0; + xoff = 0; xtop = 0; } else { strcpy(xpath_alt, xpath); diff --git a/mot.c b/mot.c new file mode 100644 index 0000000..93133d3 --- /dev/null +++ b/mot.c @@ -0,0 +1,186 @@ +#include +#include +#include "vi.h" + +int lbuf_indents(struct lbuf *lb, int r) +{ + char *ln = lbuf_get(lb, r); + int o; + if (!ln) + return 0; + for (o = 0; uc_isspace(ln); o++) + ln = uc_next(ln); + return o; +} + +static int uc_nextdir(char **s, char *beg, int dir) +{ + if (dir < 0) { + if (*s == beg) + return 1; + *s = uc_prev(beg, *s); + } else { + *s = uc_next(*s); + if (!(*s)[0]) + return 1; + } + return 0; +} + +int lbuf_findchar(struct lbuf *lb, char *cs, int cmd, int n, int *row, int *off) +{ + char *ln = lbuf_get(lb, *row); + char *s; + int dir = (cmd == 'f' || cmd == 't') ? +1 : -1; + if (!ln) + return 1; + if (n < 0) + dir = -dir; + if (n < 0) + n = -n; + s = uc_chr(ln, *off); + while (n > 0 && !uc_nextdir(&s, ln, dir)) + if (uc_code(s) == uc_code(cs)) + n--; + if (!n && (cmd == 't' || cmd == 'T')) + uc_nextdir(&s, ln, -dir); + if (!n) + *off = uc_off(ln, s - ln); + return n != 0; +} + +int lbuf_search(struct lbuf *lb, char *kw, int dir, int *r, int *o, int *len) +{ + int offs[2]; + int found = 0; + int r0 = *r, o0 = *o; + int i; + struct rset *re = rset_make(1, &kw, xic ? RE_ICASE : 0); + if (!re) + return 1; + for (i = r0; !found && i >= 0 && i < lbuf_len(lb); i += dir) { + char *s = lbuf_get(lb, i); + int off = dir > 0 && r0 == i ? uc_chr(s, o0 + 1) - s : 0; + int flg = off ? RE_NOTBOL : 0; + while (rset_find(re, s + off, 1, offs, flg) >= 0) { + if (dir < 0 && r0 == i && off + offs[0] >= o0) + break; + found = 1; + *o = uc_off(s, off + offs[0]); + *r = i; + *len = offs[1] - offs[0]; + off += offs[1]; + if (dir > 0) + break; + } + } + rset_free(re); + return !found; +} + +int lbuf_paragraphbeg(struct lbuf *lb, int dir, int *row, int *off) +{ + while (*row >= 0 && *row < lbuf_len(lb) && !strcmp("\n", lbuf_get(lb, *row))) + *row += dir; + while (*row >= 0 && *row < lbuf_len(lb) && strcmp("\n", lbuf_get(lb, *row))) + *row += dir; + *row = MAX(0, MIN(*row, lbuf_len(lb) - 1)); + *off = 0; + return 0; +} + +int lbuf_sectionbeg(struct lbuf *lb, int dir, int *row, int *off) +{ + *row += dir; + while (*row >= 0 && *row < lbuf_len(lb) && lbuf_get(lb, *row)[0] != '{') + *row += dir; + *row = MAX(0, MIN(*row, lbuf_len(lb) - 1)); + *off = 0; + return 0; +} + +static int lbuf_lnnext(struct lbuf *lb, int dir, int *r, int *o) +{ + int off = *o + dir; + if (off < 0 || !lbuf_get(lb, *r) || off >= uc_slen(lbuf_get(lb, *r))) + return 1; + *o = off; + return 0; +} + +int lbuf_eol(struct lbuf *lb, int row) +{ + int len = lbuf_get(lb, row) ? uc_slen(lbuf_get(lb, row)) : 0; + return len ? len - 1 : 0; +} + +static int lbuf_next(struct lbuf *lb, int dir, int *r, int *o) +{ + if (dir < 0 && *r >= lbuf_len(lb)) + *r = MAX(0, lbuf_len(lb) - 1); + if (lbuf_lnnext(lb, dir, r, o)) { + if (!lbuf_get(lb, *r + dir)) + return -1; + *r += dir; + *o = dir > 0 ? 0 : lbuf_eol(lb, *r); + return 0; + } + return 0; +} + +/* return a pointer to the character at visual position c of line r */ +static char *lbuf_chr(struct lbuf *lb, int r, int c) +{ + char *ln = lbuf_get(lb, r); + return ln ? uc_chr(ln, c) : ""; +} + +/* move to the last character of the word */ +static int lbuf_wordlast(struct lbuf *lb, int kind, int dir, int *row, int *off) +{ + if (!kind || !(uc_kind(lbuf_chr(lb, *row, *off)) & kind)) + return 0; + while (uc_kind(lbuf_chr(lb, *row, *off)) & kind) + if (lbuf_next(lb, dir, row, off)) + return 1; + if (!(uc_kind(lbuf_chr(lb, *row, *off)) & kind)) + lbuf_next(lb, -dir, row, off); + return 0; +} + +int lbuf_wordbeg(struct lbuf *lb, int big, int dir, int *row, int *off) +{ + int nl = 0; + lbuf_wordlast(lb, big ? 3 : uc_kind(lbuf_chr(lb, *row, *off)), dir, row, off); + if (lbuf_next(lb, dir, row, off)) + return 1; + while (uc_isspace(lbuf_chr(lb, *row, *off))) { + nl = uc_code(lbuf_chr(lb, *row, *off)) == '\n' ? nl + 1 : 0; + if (nl == 2) + return 0; + if (lbuf_next(lb, dir, row, off)) + return 1; + } + return 0; +} + +int lbuf_wordend(struct lbuf *lb, int big, int dir, int *row, int *off) +{ + int nl = uc_code(lbuf_chr(lb, *row, *off)) == '\n' ? -1 : 0; + if (!uc_isspace(lbuf_chr(lb, *row, *off))) + if (lbuf_next(lb, dir, row, off)) + return 1; + while (uc_isspace(lbuf_chr(lb, *row, *off))) { + nl = uc_code(lbuf_chr(lb, *row, *off)) == '\n' ? nl + 1 : 0; + if (nl == 2) { + if (dir < 0) + lbuf_next(lb, -dir, row, off); + return 0; + } + if (lbuf_next(lb, dir, row, off)) + return 1; + } + if (lbuf_wordlast(lb, big ? 3 : uc_kind(lbuf_chr(lb, *row, *off)), dir, row, off)) + return 1; + return 0; +} diff --git a/ren.c b/ren.c index 2c5588f..92369e4 100644 --- a/ren.c +++ b/ren.c @@ -102,20 +102,13 @@ int ren_cursor(char *s, int p) return p >= 0 ? p : 0; } -/* real cursor position; never past EOL */ -int ren_noeol(char *s, int p) +/* return an offset before EOL */ +int ren_noeol(char *s, int o) { - int n; - int *pos; - if (!s) - return 0; - n = uc_slen(s); - pos = ren_position(s); - p = pos_prev(pos, n, p, 1); - if (uc_code(uc_chr(s, ren_off(s, p))) == '\n') - p = pos_prev(pos, n, p, 0); - free(pos); - return p >= 0 ? p : 0; + int n = s ? uc_slen(s) : 0; + if (o >= n) + o = MAX(0, n - 1); + return o > 0 && uc_chr(s, o)[0] == '\n' ? o - 1 : o; } /* the position of the next character */ @@ -129,54 +122,7 @@ int ren_next(char *s, int p, int dir) else p = pos_prev(pos, n, p, 0); free(pos); - return p; -} - -static void swap(int *i1, int *i2) -{ - int t = *i1; - *i1 = *i2; - *i2 = t; -} - -/* the region specified by two visual positions */ -int ren_region(char *s, int c1, int c2, int *l1, int *l2, int closed) -{ - int *ord; /* ord[i]: the order of the i-th char on the screen */ - int o1, o2; - int beg, end; - int n = uc_slen(s); - int i; - if (c1 == c2 && !closed) { - *l1 = ren_off(s, c1); - *l2 = ren_off(s, c2); - return 0; - } - ord = malloc(n * sizeof(ord[0])); - for (i = 0; i < n; i++) - ord[i] = i; - if (xorder) - dir_reorder(s, ord); - - if (c2 < c1) - swap(&c1, &c2); - if (!closed) - c2 = ren_next(s, c2, -1); - beg = ren_off(s, c1); - end = ren_off(s, c2); - if (end < beg) - swap(&beg, &end); - o1 = ord[beg]; - o2 = ord[end]; - if (o2 < o1) - swap(&o1, &o2); - for (i = beg; i <= end; i++) - if (ord[i] < o1 || ord[i] > o2) - break; - *l1 = beg; - *l2 = i; - free(ord); - return 0; + return s && uc_chr(s, ren_off(s, p))[0] != '\n' ? p : -1; } static char *ren_placeholder(char *s) diff --git a/uc.c b/uc.c index a8f7d1c..f71271f 100644 --- a/uc.c +++ b/uc.c @@ -57,7 +57,7 @@ char *uc_beg(char *beg, char *s) } /* find the end of the character at s[i] */ -char *uc_end(char *beg, char *s) +char *uc_end(char *s) { if (!*s || !((unsigned char) *s & 0x80)) return s; @@ -71,10 +71,16 @@ char *uc_end(char *beg, char *s) /* return a pointer to the character following s */ char *uc_next(char *s) { - s = uc_end(s, s); + s = uc_end(s); return *s ? s + 1 : s; } +/* return a pointer to the character preceding s */ +char *uc_prev(char *beg, char *s) +{ + return s == beg ? beg : uc_beg(beg, s - 1); +} + int uc_wid(char *s) { return 1; @@ -153,7 +159,7 @@ int uc_isprint(char *s) int uc_isalpha(char *s) { int c = s ? (unsigned char) *s : 0; - return c <= 0x7f && isalpha(c); + return c > 0x7f || isalpha(c); } int uc_isdigit(char *s) diff --git a/vi.c b/vi.c index 892ef2a..307939d 100644 --- a/vi.c +++ b/vi.c @@ -20,6 +20,7 @@ static int vi_charcmd; /* the character finding command */ static int vi_arg1, vi_arg2; /* the first and second arguments */ static int vi_ybuf; /* current yank buffer */ static char *vi_kmap; /* current insertion keymap */ +static int vi_pcol; /* the column requested by | command */ static void vi_drawmsg(void) { @@ -27,7 +28,7 @@ static void vi_drawmsg(void) vi_msg[0] = '\0'; } -static void vi_draw(void) +static void vi_draw(int xcol) { int i; term_record(); @@ -121,108 +122,53 @@ static int vi_prefix(void) return n; } -static int lbuf_lnnext(struct lbuf *lb, int *r, int *c, int dir) +static int vi_col2off(struct lbuf *lb, int row, int col) { - char *ln = lbuf_get(lb, *r); - int col = ln ? ren_next(ln, *c, dir) : -1; - if (col < 0) - return -1; - *c = col; - return 0; + char *ln = lbuf_get(lb, row); + return ln ? ren_off(ln, col) : 0; } -static void lbuf_eol(struct lbuf *lb, int *r, int *c, int dir) +static int vi_off2col(struct lbuf *lb, int row, int off) { - char *ln = lbuf_get(lb, *r); - *c = dir < 0 ? 0 : MAX(0, ren_wid(ln ? ln : "") - 1); + char *ln = lbuf_get(lb, row); + return ln ? ren_pos(ln, off) : 0; } -static int lbuf_next(struct lbuf *lb, int *r, int *c, int dir) +static int vi_nextoff(struct lbuf *lb, int dir, int *row, int *off) { - if (dir < 0 && *r >= lbuf_len(lb)) - *r = MAX(0, lbuf_len(lb) - 1); - if (lbuf_lnnext(lb, r, c, dir)) { - if (!lbuf_get(lb, *r + dir)) - return -1; - *r += dir; - lbuf_eol(lb, r, c, -dir); - return 0; - } + int o = *off + dir; + if (o < 0 || !lbuf_get(lb, *row) || o >= uc_slen(lbuf_get(lb, *row))) + return 1; + *off = o; return 0; } -/* return a pointer to the character at visual position c of line r */ -static char *lbuf_chr(struct lbuf *lb, int r, int c) -{ - char *ln = lbuf_get(lb, r); - return ln ? uc_chr(ln, ren_off(ln, c)) : ""; -} - -static void lbuf_postindents(struct lbuf *lb, int *r, int *c) +static int vi_nextcol(struct lbuf *lb, int dir, int *row, int *off) { - lbuf_eol(lb, r, c, -1); - while (uc_isspace(lbuf_chr(lb, *r, *c))) - if (lbuf_lnnext(lb, r, c, +1)) - break; + char *ln = lbuf_get(lb, *row); + int col = ln ? ren_pos(ln, *off) : 0; + int o = ln ? ren_next(ln, col, dir) : -1; + if (o < 0) + return -1; + *off = ren_off(ln, o); + return 0; } -static int lbuf_findchar(struct lbuf *lb, int *row, int *col, char *cs, int cmd, int n) +static int vi_findchar(struct lbuf *lb, char *cs, int cmd, int n, int *row, int *off) { - int dir = (cmd == 'f' || cmd == 't') ? +1 : -1; - int c = *col; - if (n < 0) - dir = -dir; - if (n < 0) - n = -n; strcpy(vi_charlast, cs); vi_charcmd = cmd; - while (n > 0 && !lbuf_lnnext(lb, row, &c, dir)) - if (uc_code(lbuf_chr(lb, *row, c)) == uc_code(cs)) - n--; - if (!n) - *col = c; - if (!n && (cmd == 't' || cmd == 'T')) - lbuf_lnnext(lb, row, col, -dir); - return n != 0; + return lbuf_findchar(lb, cs, cmd, n, row, off); } -static int lbuf_search(struct lbuf *lb, char *kw, int dir, int *r, int *c, int *len) -{ - int offs[2]; - int found = 0; - int row = *r, col = *c; - int i; - struct rset *re = rset_make(1, &kw, xic ? RE_ICASE : 0); - if (!re) - return 1; - for (i = row; !found && i >= 0 && i < lbuf_len(lb); i += dir) { - char *s = lbuf_get(lb, i); - int off = dir > 0 && row == i ? uc_chr(s, col + 1) - s : 0; - int flg = off ? RE_NOTBOL : 0; - while (rset_find(re, s + off, 1, offs, flg) >= 0) { - if (dir < 0 && row == i && off + offs[0] >= col) - break; - found = 1; - *c = uc_off(s, off + offs[0]); - *r = i; - *len = offs[1] - offs[0]; - off += offs[1]; - if (dir > 0) - break; - } - } - rset_free(re); - return !found; -} - -static int vi_search(int cmd, int cnt, int *row, int *col) +static int vi_search(int cmd, int cnt, int *row, int *off) { int r = *row; - int c = *col; + int o = *off; int failed = 0; int len = 0; int i, dir; - char *off = ""; + char *soff = ""; if (cmd == '/' || cmd == '?') { char sign[4] = {cmd}; char *kw = vi_prompt(sign, &vi_kmap); @@ -232,7 +178,7 @@ static int vi_search(int cmd, int cnt, int *row, int *col) if (kw[0]) snprintf(vi_findlast, sizeof(vi_findlast), "%s", kw); if (strchr(vi_findlast, cmd)) { - off = strchr(vi_findlast, cmd) + 1; + soff = strchr(vi_findlast, cmd) + 1; *strchr(vi_findlast, cmd) = '\0'; } free(kw); @@ -240,26 +186,26 @@ static int vi_search(int cmd, int cnt, int *row, int *col) dir = cmd == 'N' ? -vi_finddir : vi_finddir; if (!vi_findlast[0] || !lbuf_len(xb)) return 1; - c = ren_off(lbuf_get(xb, *row), *col); + o = *off; for (i = 0; i < cnt; i++) { - if (lbuf_search(xb, vi_findlast, dir, &r, &c, &len)) { + if (lbuf_search(xb, vi_findlast, dir, &r, &o, &len)) { failed = 1; break; } if (i + 1 < cnt && cmd == '/') - c += len; + o += len; } if (!failed) { *row = r; - *col = ren_pos(lbuf_get(xb, r), c); - while (off[0] && isspace((unsigned char) off[0])) - off++; - if (off[0]) { - *col = -1; - if (*row + atoi(off) < 0 || *row + atoi(off) >= lbuf_len(xb)) + *off = o; + while (soff[0] && isspace((unsigned char) soff[0])) + soff++; + if (soff[0]) { + *off = -1; + if (*row + atoi(soff) < 0 || *row + atoi(soff) >= lbuf_len(xb)) failed = 1; else - *row += atoi(off); + *row += atoi(soff); } } if (failed) @@ -267,77 +213,6 @@ static int vi_search(int cmd, int cnt, int *row, int *col) return failed; } -/* move to the last character of the word */ -static int lbuf_wordlast(struct lbuf *lb, int *row, int *col, int kind, int dir) -{ - if (!kind || !(uc_kind(lbuf_chr(lb, *row, *col)) & kind)) - return 0; - while (uc_kind(lbuf_chr(lb, *row, *col)) & kind) - if (lbuf_next(lb, row, col, dir)) - return 1; - if (!(uc_kind(lbuf_chr(lb, *row, *col)) & kind)) - lbuf_next(lb, row, col, -dir); - return 0; -} - -static int lbuf_wordbeg(struct lbuf *lb, int *row, int *col, int big, int dir) -{ - int nl = 0; - lbuf_wordlast(lb, row, col, big ? 3 : uc_kind(lbuf_chr(lb, *row, *col)), dir); - if (lbuf_next(lb, row, col, dir)) - return 1; - while (uc_isspace(lbuf_chr(lb, *row, *col))) { - nl = uc_code(lbuf_chr(lb, *row, *col)) == '\n' ? nl + 1 : 0; - if (nl == 2) - return 0; - if (lbuf_next(lb, row, col, dir)) - return 1; - } - return 0; -} - -static int lbuf_wordend(struct lbuf *lb, int *row, int *col, int big, int dir) -{ - int nl = uc_code(lbuf_chr(lb, *row, *col)) == '\n' ? -1 : 0; - if (!uc_isspace(lbuf_chr(lb, *row, *col))) - if (lbuf_next(lb, row, col, dir)) - return 1; - while (uc_isspace(lbuf_chr(lb, *row, *col))) { - nl = uc_code(lbuf_chr(lb, *row, *col)) == '\n' ? nl + 1 : 0; - if (nl == 2) { - if (dir < 0) - lbuf_next(lb, row, col, -dir); - return 0; - } - if (lbuf_next(lb, row, col, dir)) - return 1; - } - if (lbuf_wordlast(lb, row, col, big ? 3 : uc_kind(lbuf_chr(lb, *row, *col)), dir)) - return 1; - return 0; -} - -static int lbuf_paragraphbeg(struct lbuf *lb, int *row, int *col, int dir) -{ - while (*row >= 0 && *row < lbuf_len(lb) && !strcmp("\n", lbuf_get(lb, *row))) - *row += dir; - while (*row >= 0 && *row < lbuf_len(lb) && strcmp("\n", lbuf_get(lb, *row))) - *row += dir; - *row = MAX(0, MIN(*row, lbuf_len(lb) - 1)); - lbuf_eol(lb, row, col, -1); - return 0; -} - -static int lbuf_sectionbeg(struct lbuf *lb, int *row, int *col, int dir) -{ - *row += dir; - while (*row >= 0 && *row < lbuf_len(lb) && lbuf_get(lb, *row)[0] != '{') - *row += dir; - *row = MAX(0, MIN(*row, lbuf_len(lb) - 1)); - lbuf_eol(lb, row, col, -1); - return 0; -} - /* read a line motion */ static int vi_motionln(int *row, int cmd) { @@ -356,9 +231,11 @@ static int vi_motionln(int *row, int cmd) *row = MIN(*row + cnt - 1, lbuf_len(xb) - 1); break; case '\'': - if ((mark = vi_read()) > 0 && (isalpha(mark) || mark == '\'')) - if (lbuf_markpos(xb, mark) >= 0) - *row = lbuf_markpos(xb, mark); + if ((mark = vi_read()) <= 0 || (!isalpha(mark) && mark != '\'')) + return -1; + if (lbuf_markpos(xb, mark) < 0) + return -1; + *row = lbuf_markpos(xb, mark); break; case 'j': *row = MIN(*row + cnt, lbuf_len(xb) - 1); @@ -398,14 +275,14 @@ static int vi_motionln(int *row, int cmd) return c; } -static char *lbuf_curword(struct lbuf *lb, int row, int col) +static char *vi_curword(struct lbuf *lb, int row, int off) { struct sbuf *sb; char *ln = lbuf_get(lb, row); char *beg, *end; if (!ln) return NULL; - beg = uc_chr(ln, ren_off(ln, ren_noeol(ln, col))); + beg = uc_chr(ln, ren_noeol(ln, off)); end = beg; while (*end && uc_kind(end) == 1) end = uc_next(end); @@ -421,7 +298,7 @@ static char *lbuf_curword(struct lbuf *lb, int row, int col) } /* read a motion */ -static int vi_motion(int *row, int *col) +static int vi_motion(int *row, int *off) { int cnt = (vi_arg1 ? vi_arg1 : 1) * (vi_arg2 ? vi_arg2 : 1); char *ln = lbuf_get(xb, *row); @@ -430,157 +307,158 @@ static int vi_motion(int *row, int *col) int mv; int i; if ((mv = vi_motionln(row, 0))) { - *col = -1; + *off = -1; return mv; } mv = vi_read(); switch (mv) { - case ' ': - for (i = 0; i < cnt; i++) - if (lbuf_lnnext(xb, row, col, 1)) - break; - break; case 'f': if (!(cs = vi_char())) return -1; - if (lbuf_findchar(xb, row, col, cs, mv, cnt)) + if (vi_findchar(xb, cs, mv, cnt, row, off)) return -1; break; case 'F': if (!(cs = vi_char())) return -1; - if (lbuf_findchar(xb, row, col, cs, mv, cnt)) + if (vi_findchar(xb, cs, mv, cnt, row, off)) return -1; break; case ';': if (!vi_charlast[0]) return -1; - if (lbuf_findchar(xb, row, col, vi_charlast, vi_charcmd, cnt)) + if (vi_findchar(xb, vi_charlast, vi_charcmd, cnt, row, off)) return -1; break; case ',': if (!vi_charlast[0]) return -1; - if (lbuf_findchar(xb, row, col, vi_charlast, vi_charcmd, -cnt)) + if (vi_findchar(xb, vi_charlast, vi_charcmd, -cnt, row, off)) return -1; break; case 'h': for (i = 0; i < cnt; i++) - if (lbuf_lnnext(xb, row, col, -1 * dir)) + if (vi_nextcol(xb, -1 * dir, row, off)) break; break; case 'l': for (i = 0; i < cnt; i++) - if (lbuf_lnnext(xb, row, col, +1 * dir)) + if (vi_nextcol(xb, +1 * dir, row, off)) break; break; case 't': if (!(cs = vi_char())) return -1; - if (lbuf_findchar(xb, row, col, cs, mv, cnt)) + if (vi_findchar(xb, cs, mv, cnt, row, off)) return -1; break; case 'T': if (!(cs = vi_char())) return -1; - if (lbuf_findchar(xb, row, col, cs, mv, cnt)) + if (vi_findchar(xb, cs, mv, cnt, row, off)) return -1; break; case 'B': for (i = 0; i < cnt; i++) - if (lbuf_wordend(xb, row, col, 1, -1)) + if (lbuf_wordend(xb, 1, -1, row, off)) break; break; case 'E': for (i = 0; i < cnt; i++) - if (lbuf_wordend(xb, row, col, 1, +1)) + if (lbuf_wordend(xb, 1, +1, row, off)) break; break; case 'W': for (i = 0; i < cnt; i++) - if (lbuf_wordbeg(xb, row, col, 1, +1)) + if (lbuf_wordbeg(xb, 1, +1, row, off)) break; break; case 'b': for (i = 0; i < cnt; i++) - if (lbuf_wordend(xb, row, col, 0, -1)) + if (lbuf_wordend(xb, 0, -1, row, off)) break; break; case 'e': for (i = 0; i < cnt; i++) - if (lbuf_wordend(xb, row, col, 0, +1)) + if (lbuf_wordend(xb, 0, +1, row, off)) break; break; case 'w': for (i = 0; i < cnt; i++) - if (lbuf_wordbeg(xb, row, col, 0, +1)) + if (lbuf_wordbeg(xb, 0, +1, row, off)) break; break; case '{': for (i = 0; i < cnt; i++) - if (lbuf_paragraphbeg(xb, row, col, -1)) + if (lbuf_paragraphbeg(xb, -1, row, off)) break; break; case '}': for (i = 0; i < cnt; i++) - if (lbuf_paragraphbeg(xb, row, col, +1)) + if (lbuf_paragraphbeg(xb, +1, row, off)) break; break; case '[': if (vi_read() != '[') return -1; for (i = 0; i < cnt; i++) - if (lbuf_sectionbeg(xb, row, col, -1)) + if (lbuf_sectionbeg(xb, -1, row, off)) break; break; case ']': if (vi_read() != ']') return -1; for (i = 0; i < cnt; i++) - if (lbuf_sectionbeg(xb, row, col, +1)) + if (lbuf_sectionbeg(xb, +1, row, off)) break; break; case '0': - lbuf_eol(xb, row, col, -1); + *off = 0; break; case '^': - lbuf_postindents(xb, row, col); + *off = lbuf_indents(xb, *row); break; case '$': - *col = 1024; + *off = lbuf_eol(xb, *row); break; case '|': - *col = cnt - 1; + *off = vi_col2off(xb, *row, cnt - 1); + vi_pcol = cnt - 1; break; case '/': - if (vi_search(mv, cnt, row, col)) + if (vi_search(mv, cnt, row, off)) return -1; break; case '?': - if (vi_search(mv, cnt, row, col)) + if (vi_search(mv, cnt, row, off)) return -1; break; case 'n': - if (vi_search(mv, cnt, row, col)) + if (vi_search(mv, cnt, row, off)) return -1; break; case 'N': - if (vi_search(mv, cnt, row, col)) + if (vi_search(mv, cnt, row, off)) return -1; break; case TK_CTL('a'): - if (!(cs = lbuf_curword(xb, *row, *col))) + if (!(cs = vi_curword(xb, *row, *off))) return -1; strcpy(vi_findlast, cs); free(cs); vi_finddir = +1; - if (vi_search('n', cnt, row, col)) + if (vi_search('n', cnt, row, off)) return -1; break; + case ' ': + for (i = 0; i < cnt; i++) + if (vi_nextoff(xb, +1, row, off)) + break; + break; case 127: case TK_CTL('h'): for (i = 0; i < cnt; i++) - if (lbuf_lnnext(xb, row, col, -1)) + if (vi_nextoff(xb, -1, row, off)) break; break; default: @@ -597,15 +475,15 @@ static void swap(int *a, int *b) *b = t; } -static char *lbuf_region(struct lbuf *lb, int r1, int l1, int r2, int l2) +static char *lbuf_region(struct lbuf *lb, int r1, int o1, int r2, int o2) { struct sbuf *sb; char *s1, *s2, *s3; if (r1 == r2) - return uc_sub(lbuf_get(lb, r1), l1, l2); + return uc_sub(lbuf_get(lb, r1), o1, o2); sb = sbuf_make(); - s1 = uc_sub(lbuf_get(lb, r1), l1, -1); - s3 = uc_sub(lbuf_get(lb, r2), 0, l2); + s1 = uc_sub(lbuf_get(lb, r1), o1, -1); + s3 = uc_sub(lbuf_get(lb, r2), 0, o2); s2 = lbuf_cp(lb, r1 + 1, r2); sbuf_str(sb, s1); sbuf_str(sb, s2); @@ -616,53 +494,25 @@ static char *lbuf_region(struct lbuf *lb, int r1, int l1, int r2, int l2) return sbuf_done(sb); } -/* insertion offset before or after the given visual position */ -static int vi_insertionoffset(char *s, int c1, int before) -{ - int l; - if (!s || !*s) - return 0; - l = ren_off(s, c1); - return before || s[l] == '\n' ? l : l + 1; -} - -static void vi_commandregion(int *r1, int *r2, int *c1, int *c2, int *l1, int *l2, int closed) -{ - if (*r2 < *r1 || (*r2 == *r1 && *c2 < *c1)) { - swap(r1, r2); - swap(c1, c2); - } - *l1 = vi_insertionoffset(lbuf_get(xb, *r1), *c1, 1); - *l2 = vi_insertionoffset(lbuf_get(xb, *r2), *c2, !closed); - if (*r1 == *r2 && lbuf_get(xb, *r1)) - ren_region(lbuf_get(xb, *r1), *c1, *c2, l1, l2, closed); - if (*r1 == *r2 && *l2 < *l1) - swap(l1, l2); -} - -static void vi_yank(int r1, int c1, int r2, int c2, int lnmode, int closed) +static void vi_yank(int r1, int o1, int r2, int o2, int lnmode) { char *region; - int l1, l2; - vi_commandregion(&r1, &r2, &c1, &c2, &l1, &l2, closed); - region = lbuf_region(xb, r1, lnmode ? 0 : l1, r2, lnmode ? -1 : l2); + region = lbuf_region(xb, r1, lnmode ? 0 : o1, r2, lnmode ? -1 : o2); reg_put(vi_ybuf, region, lnmode); free(region); xrow = r1; - xcol = lnmode ? xcol : c1; + xoff = lnmode ? xoff : o1; } -static void vi_delete(int r1, int c1, int r2, int c2, int lnmode, int closed) +static void vi_delete(int r1, int o1, int r2, int o2, int lnmode) { char *pref, *post; char *region; - int l1, l2; - vi_commandregion(&r1, &r2, &c1, &c2, &l1, &l2, closed); - region = lbuf_region(xb, r1, lnmode ? 0 : l1, r2, lnmode ? -1 : l2); + region = lbuf_region(xb, r1, lnmode ? 0 : o1, r2, lnmode ? -1 : o2); reg_put(vi_ybuf, region, lnmode); free(region); - pref = lnmode ? uc_dup("") : uc_sub(lbuf_get(xb, r1), 0, l1); - post = lnmode ? uc_dup("\n") : uc_sub(lbuf_get(xb, r2), l2, -1); + pref = lnmode ? uc_dup("") : uc_sub(lbuf_get(xb, r1), 0, o1); + post = lnmode ? uc_dup("\n") : uc_sub(lbuf_get(xb, r2), o2, -1); lbuf_rm(xb, r1, r2 + 1); if (!lnmode) { struct sbuf *sb = sbuf_make(); @@ -672,9 +522,7 @@ static void vi_delete(int r1, int c1, int r2, int c2, int lnmode, int closed) sbuf_free(sb); } xrow = r1; - xcol = c1; - if (lnmode) - lbuf_postindents(xb, &xrow, &xcol); + xoff = lnmode ? lbuf_indents(xb, xrow) : o1; free(pref); free(post); } @@ -697,12 +545,12 @@ static int indentscopy(char *d, char *s, int len) return i; } -static char *vi_input(char *pref, char *post, int *row, int *col) +static char *vi_input(char *pref, char *post, int *row, int *off) { char ai[64] = ""; char *rep, *s; struct sbuf *sb; - int last, off; + int last; if (xai) pref += indentscopy(ai, pref, sizeof(ai)); rep = led_input(pref, post, ai, xai ? sizeof(ai) - 1 : 0, &vi_kmap); @@ -714,13 +562,12 @@ static char *vi_input(char *pref, char *post, int *row, int *col) sbuf_str(sb, rep); s = sbuf_buf(sb); last = uc_lastline(s) - s; - off = uc_slen(sbuf_buf(sb) + last); + *off = MAX(0, uc_slen(sbuf_buf(sb) + last) - 1); if (last) while (xai && (post[0] == ' ' || post[0] == '\t')) post++; sbuf_str(sb, post); *row = linecount(sbuf_buf(sb)) - 1; - *col = ren_pos(sbuf_buf(sb) + last, MAX(0, off - 1)); free(rep); return sbuf_done(sb); } @@ -733,25 +580,23 @@ static char *vi_indents(char *ln) return sbuf_done(sb); } -static void vi_change(int r1, int c1, int r2, int c2, int lnmode, int closed) +static void vi_change(int r1, int o1, int r2, int o2, int lnmode) { char *region; - int l1, l2; - int row, col; + int row, off; char *rep; char *pref, *post; - vi_commandregion(&r1, &r2, &c1, &c2, &l1, &l2, closed); - region = lbuf_region(xb, r1, lnmode ? 0 : l1, r2, lnmode ? -1 : l2); + region = lbuf_region(xb, r1, lnmode ? 0 : o1, r2, lnmode ? -1 : o2); reg_put(vi_ybuf, region, lnmode); free(region); - pref = lnmode ? vi_indents(lbuf_get(xb, r1)) : uc_sub(lbuf_get(xb, r1), 0, l1); - post = lnmode ? uc_dup("\n") : uc_sub(lbuf_get(xb, r2), l2, -1); - rep = vi_input(pref, post, &row, &col); + pref = lnmode ? vi_indents(lbuf_get(xb, r1)) : uc_sub(lbuf_get(xb, r1), 0, o1); + post = lnmode ? uc_dup("\n") : uc_sub(lbuf_get(xb, r2), o2, -1); + rep = vi_input(pref, post, &row, &off); if (rep) { lbuf_rm(xb, r1, r2 + 1); lbuf_put(xb, r1, rep); xrow = r1 + row - 1; - xcol = col; + xoff = off; free(rep); } free(pref); @@ -766,8 +611,6 @@ static void vi_pipe(int r1, int r2) char *cmd = vi_prompt("!", &kmap); if (!cmd) return; - if (r2 < r1) - swap(&r1, &r2); text = lbuf_cp(xb, r1, r2 + 1); rep = cmd_pipe(cmd, text); if (rep) { @@ -784,8 +627,6 @@ static void vi_shift(int r1, int r2, int dir) struct sbuf *sb; char *ln; int i; - if (r2 < r1) - swap(&r1, &r2); for (i = r1; i <= r2; i++) { if (!(ln = lbuf_get(xb, i))) continue; @@ -800,42 +641,49 @@ static void vi_shift(int r1, int r2, int dir) sbuf_free(sb); } xrow = r1; - lbuf_postindents(xb, &xrow, &xcol); + xoff = lbuf_indents(xb, xrow); } static int vc_motion(int cmd) { int r1 = xrow, r2 = xrow; /* region rows */ - int c1 = xcol, c2 = xcol; /* visual region columns */ + int o1 = xoff, o2 = xoff; /* visual region columns */ int lnmode = 0; /* line-based region */ - int closed = 1; /* include the last character */ int mv; vi_arg2 = vi_prefix(); if (vi_arg2 < 0) return 1; - c1 = ren_noeol(lbuf_get(xb, r1), xcol); - c2 = c1; + o1 = ren_noeol(lbuf_get(xb, r1), o1); + o2 = o1; if ((mv = vi_motionln(&r2, cmd))) { - c2 = -1; - } else if (!(mv = vi_motion(&r2, &c2))) { + o2 = -1; + } else if (!(mv = vi_motion(&r2, &o2))) { vi_read(); return 1; } if (mv < 0) return 1; - if (!strchr("fFtTeE", mv)) - closed = 0; - lnmode = c2 < 0; + lnmode = o2 < 0; if (lnmode) { - lbuf_eol(xb, &r1, &c1, -1); - lbuf_eol(xb, &r2, &c2, +1); + o1 = 0; + o2 = lbuf_eol(xb, r2); } + if (r1 > r2) { + swap(&r1, &r2); + swap(&o1, &o2); + } + if (r1 == r2 && o1 > o2) + swap(&o1, &o2); + o1 = ren_noeol(lbuf_get(xb, r1), o1); + if (!lnmode && strchr("fFtTeE", mv)) + if (o2 < lbuf_eol(xb, r2)) + o2 = ren_noeol(lbuf_get(xb, r2), o2) + 1; if (cmd == 'y') - vi_yank(r1, c1, r2, c2, lnmode, closed); + vi_yank(r1, o1, r2, o2, lnmode); if (cmd == 'd') - vi_delete(r1, c1, r2, c2, lnmode, closed); + vi_delete(r1, o1, r2, o2, lnmode); if (cmd == 'c') - vi_change(r1, c1, r2, c2, lnmode, closed); + vi_change(r1, o1, r2, o2, lnmode); if (cmd == '!') vi_pipe(r1, r2); if (cmd == '>' || cmd == '<') @@ -847,24 +695,22 @@ static int vc_insert(int cmd) { char *pref, *post; char *ln = lbuf_get(xb, xrow); - int row, col, off = 0; + int row, off = 0; char *rep; if (cmd == 'I') - lbuf_postindents(xb, &xrow, &xcol); - if (cmd == 'A') { - lbuf_eol(xb, &xrow, &xcol, +1); - lbuf_lnnext(xb, &xrow, &xcol, -1); - } - xcol = ren_noeol(ln, xcol); + xoff = lbuf_indents(xb, xrow); + if (cmd == 'A') + xoff = lbuf_eol(xb, xrow); + xoff = ren_noeol(ln, xoff); if (cmd == 'o') xrow += 1; if (cmd == 'i' || cmd == 'I') - off = vi_insertionoffset(ln, xcol, 1); + off = xoff; if (cmd == 'a' || cmd == 'A') - off = vi_insertionoffset(ln, xcol, 0); + off = xoff + 1; pref = ln && cmd != 'o' && cmd != 'O' ? uc_sub(ln, 0, off) : vi_indents(ln); post = ln && cmd != 'o' && cmd != 'O' ? uc_sub(ln, off, -1) : uc_dup("\n"); - rep = vi_input(pref, post, &row, &col); + rep = vi_input(pref, post, &row, &off); if ((cmd == 'o' || cmd == 'O') && !lbuf_len(xb)) lbuf_put(xb, 0, "\n"); if (rep) { @@ -872,7 +718,7 @@ static int vc_insert(int cmd) lbuf_rm(xb, xrow, xrow + 1); lbuf_put(xb, xrow, rep); xrow += row - 1; - xcol = col; + xoff = off; free(rep); } free(pref); @@ -892,7 +738,7 @@ static int vc_put(int cmd) if (!buf) return 1; ln = lnmode ? NULL : lbuf_get(xb, xrow); - off = vi_insertionoffset(ln, ren_noeol(ln, xcol), cmd == 'P'); + off = ren_noeol(ln, xoff) + (cmd == 'p'); if (cmd == 'p' && !ln) xrow++; sb = sbuf_make(); @@ -914,9 +760,9 @@ static int vc_put(int cmd) lbuf_rm(xb, xrow, xrow + 1); lbuf_put(xb, xrow, sbuf_buf(sb)); if (ln) - xcol = ren_pos(lbuf_get(xb, xrow), off + uc_slen(buf) * cnt - 1); + xoff = off + uc_slen(buf) * cnt - 1; else - lbuf_postindents(xb, &xrow, &xcol); + xoff = lbuf_indents(xb, xrow); sbuf_free(sb); return 0; } @@ -958,7 +804,7 @@ static int vc_join(void) sbuf_chr(sb, '\n'); lbuf_rm(xb, beg, end); lbuf_put(xb, beg, sbuf_buf(sb)); - xcol = ren_pos(sbuf_buf(sb), off); + xoff = off; sbuf_free(sb); return 0; } @@ -983,10 +829,10 @@ static int vi_scrollbackward(int cnt) static void vc_status(void) { - int pos = ren_noeol(lbuf_get(xb, xrow), xcol); + int col = vi_off2col(xb, xrow, xoff); snprintf(vi_msg, sizeof(vi_msg), "\"%s\" line %d of %d, col %d\n", xpath[0] ? xpath : "unnamed", xrow + 1, lbuf_len(xb), - ren_cursor(lbuf_get(xb, xrow), pos) + 1); + ren_cursor(lbuf_get(xb, xrow), col) + 1); } static int vc_replace(void) @@ -1000,7 +846,7 @@ static int vc_replace(void) int off, i; if (!ln || !cs) return 1; - off = ren_off(ln, ren_noeol(ln, xcol)); + off = ren_noeol(ln, xoff); s = uc_chr(ln, off); for (i = 0; s[0] != '\n' && i < cnt; i++) s = uc_next(s); @@ -1016,7 +862,7 @@ static int vc_replace(void) lbuf_rm(xb, xrow, xrow + 1); lbuf_put(xb, xrow, sbuf_buf(sb)); off += cnt - 1; - xcol = ren_pos(sbuf_buf(sb), off); + xoff = off; sbuf_free(sb); free(pref); free(post); @@ -1025,19 +871,21 @@ static int vc_replace(void) static void vi(void) { + int xcol; int mark; char *ln; char *kmap = NULL; term_init(); xtop = 0; xrow = 0; - lbuf_eol(xb, &xrow, &xcol, -1); - vi_draw(); + xoff = 0; + xcol = vi_off2col(xb, xrow, xoff); + vi_draw(xcol); term_pos(xrow, led_pos(lbuf_get(xb, xrow), xcol)); while (!xquit) { int redraw = 0; int nrow = xrow; - int ncol = ren_noeol(lbuf_get(xb, xrow), xcol); + int noff = ren_noeol(lbuf_get(xb, xrow), xoff); int otop = xtop; int mv, n; vi_arg2 = 0; @@ -1045,20 +893,20 @@ static void vi(void) vi_arg1 = vi_prefix(); if (!vi_ybuf) vi_ybuf = vi_yankbuf(); - mv = vi_motion(&nrow, &ncol); + mv = vi_motion(&nrow, &noff); if (mv > 0) { - if (strchr("\'GHML/?{}[]", mv)) + if (strchr("\'GHML/?{}[]nN", mv)) lbuf_mark(xb, '\'', xrow); xrow = nrow; - if (ncol < 0) { - if (!strchr("jk", mv)) - lbuf_postindents(xb, &xrow, &xcol); - } else { - if (strchr("|$", mv)) - xcol = ncol; - else - xcol = ren_noeol(lbuf_get(xb, xrow), ncol); - } + if (noff < 0 && !strchr("jk", mv)) + noff = lbuf_indents(xb, xrow); + if (strchr("jk", mv)) + noff = vi_col2off(xb, xrow, xcol); + xoff = noff; + if (!strchr("|jk", mv)) + xcol = vi_off2col(xb, xrow, noff); + if (mv == '|') + xcol = vi_pcol; } else if (mv == 0) { int c = vi_read(); int z; @@ -1068,13 +916,13 @@ static void vi(void) case TK_CTL('b'): if (vi_scrollbackward(MAX(1, vi_arg1) * (xrows - 1))) break; - lbuf_postindents(xb, &xrow, &xcol); + xoff = lbuf_indents(xb, xrow); redraw = 1; break; case TK_CTL('f'): if (vi_scrollforeward(MAX(1, vi_arg1) * (xrows - 1))) break; - lbuf_postindents(xb, &xrow, &xcol); + xoff = lbuf_indents(xb, xrow); redraw = 1; break; case TK_CTL('e'): @@ -1219,8 +1067,11 @@ static void vi(void) if (xtop + xrows <= xrow) xtop = xtop + xrows + xrows / 2 <= xrow ? xrow - xrows / 2 : xrow - xrows + 1; + xoff = ren_noeol(lbuf_get(xb, xrow), xoff); + if (redraw) + xcol = vi_off2col(xb, xrow, xoff); if (redraw || xtop != otop) - vi_draw(); + vi_draw(xcol); if (vi_msg[0]) vi_drawmsg(); term_pos(xrow - xtop, led_pos(lbuf_get(xb, xrow), diff --git a/vi.h b/vi.h index aef4552..cd938f1 100644 --- a/vi.h +++ b/vi.h @@ -21,6 +21,15 @@ void lbuf_undo(struct lbuf *lbuf); void 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); +int lbuf_eol(struct lbuf *lb, int r); +/* motions */ +int lbuf_findchar(struct lbuf *lb, char *cs, int cmd, int n, int *r, int *o); +int lbuf_search(struct lbuf *lb, char *kw, int dir, int *r, int *o, int *len); +int lbuf_paragraphbeg(struct lbuf *lb, int dir, int *row, int *off); +int lbuf_sectionbeg(struct lbuf *lb, int dir, int *row, int *off); +int lbuf_wordbeg(struct lbuf *lb, int big, int dir, int *row, int *off); +int lbuf_wordend(struct lbuf *lb, int big, int dir, int *row, int *off); /* string buffer, variable-sized string */ struct sbuf *sbuf_make(void); @@ -83,8 +92,9 @@ int uc_isalpha(char *s); int uc_kind(char *c); char **uc_chop(char *s, int *n); char *uc_next(char *s); +char *uc_prev(char *beg, char *s); char *uc_beg(char *beg, char *s); -char *uc_end(char *beg, char *s); +char *uc_end(char *s); char *uc_shape(char *beg, char *s); char *uc_lastline(char *s); @@ -130,7 +140,7 @@ char *cmd_pipe(char *cmd, char *s); #define SYN_BD 0x100 #define SYN_IT 0x200 #define SYN_RV 0x400 -#define SYN_ATTR(f, b) (((b) << 16) | (f)) +#define SYN_BGMK(b) ((b) << 16) #define SYN_FG(a) ((a) & 0xffff) #define SYN_BG(a) ((a) >> 16) @@ -153,7 +163,7 @@ int conf_filetype(int idx, char **ft, char **pat); extern int xvis; extern struct lbuf *xb; extern int xrow; -extern int xcol; +extern int xoff; extern int xtop; extern int xled; extern int xrow_alt; -- 2.11.4.GIT