| tvi: yank and put - neatvi - [fork] simple vi-type editor with UTF-8 support | |
| git clone git://src.adamsgaard.dk/neatvi | |
| Log | |
| Files | |
| Refs | |
| README | |
| --- | |
| commit 01c3c8a62f1daee16d343488699f804c72dbca91 | |
| parent f80a244199b5d2735fcdd0abd4664346ba51dd32 | |
| Author: Ali Gholami Rudi <[email protected]> | |
| Date: Tue, 5 May 2015 12:17:59 +0430 | |
| vi: yank and put | |
| Diffstat: | |
| M Makefile | 2 +- | |
| A reg.c | 26 ++++++++++++++++++++++++++ | |
| M uc.c | 28 ++++++++++++++++++++++++++++ | |
| M vi.c | 134 ++++++++++++++++++++---------… | |
| M vi.h | 8 ++++++++ | |
| 5 files changed, 148 insertions(+), 50 deletions(-) | |
| --- | |
| diff --git a/Makefile b/Makefile | |
| t@@ -2,7 +2,7 @@ CC = cc | |
| CFLAGS = -Wall -O2 | |
| LDFLAGS = | |
| -OBJS = vi.o ex.o lbuf.o sbuf.o ren.o led.o uc.o term.o | |
| +OBJS = vi.o ex.o lbuf.o sbuf.o ren.o reg.o led.o uc.o term.o | |
| all: vi | |
| %.o: %.c | |
| diff --git a/reg.c b/reg.c | |
| t@@ -0,0 +1,26 @@ | |
| +#include <stdlib.h> | |
| +#include <string.h> | |
| +#include "vi.h" | |
| + | |
| +static char *reg; | |
| +static int lnmode; | |
| + | |
| +char *reg_get(int c, int *ln) | |
| +{ | |
| + *ln = lnmode; | |
| + return reg; | |
| +} | |
| + | |
| +void reg_put(int c, char *s, int ln) | |
| +{ | |
| + char *nreg = malloc(strlen(s) + 1); | |
| + strcpy(nreg, s); | |
| + free(reg); | |
| + reg = nreg; | |
| + lnmode = ln; | |
| +} | |
| + | |
| +void reg_done(void) | |
| +{ | |
| + free(reg); | |
| +} | |
| diff --git a/uc.c b/uc.c | |
| t@@ -94,6 +94,34 @@ char **uc_chop(char *s, int *n) | |
| return chrs; | |
| } | |
| +char *uc_chr(char *s, int off) | |
| +{ | |
| + int i = 0; | |
| + while (s && *s) { | |
| + if (i++ == off) | |
| + return s; | |
| + s = uc_next(s); | |
| + } | |
| + return s && (off < 0 || i == off) ? s : ""; | |
| +} | |
| + | |
| +char *uc_sub(char *s, int beg, int end) | |
| +{ | |
| + char *sbeg = uc_chr(s, beg); | |
| + char *send = uc_chr(s, end); | |
| + int len = sbeg && send && sbeg <= send ? send - sbeg : 0; | |
| + char *r = malloc(len + 1); | |
| + memcpy(r, sbeg, len); | |
| + r[len] = '\0'; | |
| + return r; | |
| +} | |
| + | |
| +char *uc_dup(char *s) | |
| +{ | |
| + char *r = malloc(strlen(s) + 1); | |
| + return r ? strcpy(r, s) : NULL; | |
| +} | |
| + | |
| int uc_isspace(char *s) | |
| { | |
| int c = s ? (unsigned char) *s : 0; | |
| diff --git a/vi.c b/vi.c | |
| t@@ -98,17 +98,14 @@ static char *lbuf_chr(struct lbuf *lb, int r, int c) | |
| { | |
| static char chr[8]; | |
| char *ln = lbuf_get(lb, r); | |
| - int n; | |
| if (ln) { | |
| - char **chrs = uc_chop(ln, &n); | |
| int off = ren_off(ln, c); | |
| - if (off >= 0 && off < n) { | |
| - memcpy(chr, chrs[off], uc_len(chrs[off])); | |
| - chr[uc_len(chr)] = '\0'; | |
| - free(chrs); | |
| + char *s = uc_chr(ln, off); | |
| + if (s) { | |
| + memcpy(chr, s, uc_len(s)); | |
| + chr[uc_len(s)] = '\0'; | |
| return chr; | |
| } | |
| - free(chrs); | |
| } | |
| return ""; | |
| } | |
| t@@ -364,30 +361,6 @@ static int vi_motion(int *row, int *col, int pre1, int pr… | |
| return c; | |
| } | |
| -static char *vi_strprefix(char *s, int off) | |
| -{ | |
| - struct sbuf *sb = sbuf_make(); | |
| - int n; | |
| - char **chrs = uc_chop(s ? s : "", &n); | |
| - if (n > 0) | |
| - sbuf_mem(sb, s, chrs[MIN(n - 1, off)] - s); | |
| - free(chrs); | |
| - return sbuf_done(sb); | |
| -} | |
| - | |
| -static char *vi_strpostfix(char *s, int off) | |
| -{ | |
| - struct sbuf *sb = sbuf_make(); | |
| - int n; | |
| - char **chrs = uc_chop(s ? s : "", &n); | |
| - if (n >= 0 && off < n) | |
| - sbuf_str(sb, chrs[off]); | |
| - free(chrs); | |
| - if (!sbuf_len(sb)) | |
| - sbuf_chr(sb, '\n'); | |
| - return sbuf_done(sb); | |
| -} | |
| - | |
| static void swap(int *a, int *b) | |
| { | |
| int t = *a; | |
| t@@ -395,10 +368,23 @@ static void swap(int *a, int *b) | |
| *b = t; | |
| } | |
| -static char *sdup(char *s) /* strdup() */ | |
| +static char *lbuf_region(struct lbuf *lb, int r1, int l1, int r2, int l2) | |
| { | |
| - char *r = malloc(strlen(s) + 1); | |
| - return r ? strcpy(r, s) : NULL; | |
| + struct sbuf *sb; | |
| + char *s1, *s2, *s3; | |
| + if (r1 == r2) | |
| + return uc_sub(lbuf_get(lb, r1), l1, l2); | |
| + sb = sbuf_make(); | |
| + s1 = uc_sub(lbuf_get(lb, r1), l1, -1); | |
| + s3 = uc_sub(lbuf_get(lb, r2), 0, l2); | |
| + s2 = lbuf_cp(lb, r1 + 1, r2); | |
| + sbuf_str(sb, s1); | |
| + sbuf_str(sb, s2); | |
| + sbuf_str(sb, s3); | |
| + free(s1); | |
| + free(s2); | |
| + free(s3); | |
| + return sbuf_done(sb); | |
| } | |
| static void vc_motion(int c, int pre1) | |
| t@@ -429,14 +415,34 @@ static void vc_motion(int c, int pre1) | |
| swap(&r1, &r2); | |
| swap(&c1, &c2); | |
| } | |
| + if (c == 'y') { /* adjusting cursor pos… | |
| + xrow = r1; | |
| + xcol = ln ? xcol : c1; | |
| + } | |
| for (i = 0; i < 2; i++) { | |
| l1 = ren_insertionoffset(lbuf_get(xb, r1), c1, 1); | |
| l2 = ren_insertionoffset(lbuf_get(xb, r2), c2, !closed); | |
| if (r1 == r2 && l2 < l1) /* offsets out of order */ | |
| swap(&l1, &l2); | |
| } | |
| - pref = ln ? sdup("") : vi_strprefix(lbuf_get(xb, r1), l1); | |
| - post = ln ? sdup("\n") : vi_strpostfix(lbuf_get(xb, r2), l2); | |
| + pref = ln ? uc_dup("") : uc_sub(lbuf_get(xb, r1), 0, l1); | |
| + post = ln ? uc_dup("\n") : uc_sub(lbuf_get(xb, r2), l2, -1); | |
| + if (c == 'c' || c == 'd' || c == 'y') { | |
| + char *region = lbuf_region(xb, r1, ln ? 0 : l1, r2, ln ? -1 : … | |
| + reg_put(0, region, ln); | |
| + free(region); | |
| + } | |
| + if (c == 'c') { | |
| + int row, col; | |
| + char *rep = led_input(pref, post, &row, &col); | |
| + if (rep) { | |
| + lbuf_rm(xb, r1, r2 + 1); | |
| + lbuf_put(xb, r1, rep); | |
| + xrow = r1 + row; | |
| + xcol = col; | |
| + free(rep); | |
| + } | |
| + } | |
| if (c == 'd') { | |
| lbuf_rm(xb, r1, r2 + 1); | |
| if (!ln) { | |
| t@@ -451,17 +457,6 @@ static void vc_motion(int c, int pre1) | |
| if (ln) | |
| lbuf_postindents(xb, &xrow, &xcol); | |
| } | |
| - if (c == 'c') { | |
| - int row, col; | |
| - char *rep = led_input(pref, post, &row, &col); | |
| - if (rep) { | |
| - lbuf_rm(xb, r1, r2 + 1); | |
| - lbuf_put(xb, r1, rep); | |
| - xrow = r1 + row; | |
| - xcol = col; | |
| - free(rep); | |
| - } | |
| - } | |
| free(pref); | |
| free(post); | |
| } | |
| t@@ -486,8 +481,8 @@ static void vc_insert(int cmd) | |
| off = ln ? ren_insertionoffset(ln, xcol, 1) : 0; | |
| if (cmd == 'a' || cmd == 'A') | |
| off = ln ? ren_insertionoffset(ln, xcol, 0) : 0; | |
| - pref = ln ? vi_strprefix(ln, off) : sdup(""); | |
| - post = ln ? vi_strpostfix(ln, off) : sdup("\n"); | |
| + pref = ln ? uc_sub(ln, 0, off) : uc_dup(""); | |
| + post = ln ? uc_sub(ln, off, -1) : uc_dup("\n"); | |
| rep = led_input(pref, post, &row, &col); | |
| if (rep) { | |
| if (cmd != 'o' && cmd != 'O') | |
| t@@ -501,6 +496,40 @@ static void vc_insert(int cmd) | |
| free(post); | |
| } | |
| +static void vc_put(int cmd, int cnt) | |
| +{ | |
| + int lnmode; | |
| + char *ln; | |
| + char *buf = reg_get(0, &lnmode); | |
| + struct sbuf *sb; | |
| + int off; | |
| + int i; | |
| + if (!buf) | |
| + return; | |
| + ln = lnmode ? NULL : lbuf_get(xb, xrow); | |
| + off = ln ? ren_insertionoffset(ln, xcol, cmd == 'P') : 0; | |
| + if (cmd == 'p' && !ln) | |
| + xrow++; | |
| + sb = sbuf_make(); | |
| + if (ln) { | |
| + char *s = uc_sub(ln, 0, off); | |
| + sbuf_str(sb, s); | |
| + free(s); | |
| + } | |
| + for (i = 0; i < MAX(cnt, 1); i++) | |
| + sbuf_str(sb, buf); | |
| + if (ln) { | |
| + char *s = uc_sub(ln, off, -1); | |
| + sbuf_str(sb, s); | |
| + free(s); | |
| + } | |
| + if (ln) | |
| + lbuf_rm(xb, xrow, xrow + 1); | |
| + lbuf_put(xb, xrow, sbuf_buf(sb)); | |
| + sbuf_free(sb); | |
| + | |
| +} | |
| + | |
| static void vi(void) | |
| { | |
| int mark; | |
| t@@ -559,6 +588,7 @@ static void vi(void) | |
| break; | |
| case 'c': | |
| case 'd': | |
| + case 'y': | |
| vc_motion(c, pre1); | |
| redraw = 1; | |
| break; | |
| t@@ -575,6 +605,11 @@ static void vi(void) | |
| if ((mark = vi_read()) > 0 && isalpha(mark)) | |
| lbuf_mark(xb, mark, xrow); | |
| break; | |
| + case 'p': | |
| + case 'P': | |
| + vc_put(c, pre1); | |
| + redraw = 1; | |
| + break; | |
| default: | |
| continue; | |
| } | |
| t@@ -618,5 +653,6 @@ int main(int argc, char *argv[]) | |
| else | |
| ex(); | |
| lbuf_free(xb); | |
| + reg_done(); | |
| return 0; | |
| } | |
| diff --git a/vi.h b/vi.h | |
| t@@ -48,12 +48,20 @@ int ren_last(char *s); | |
| int ren_cmp(char *s, int pos1, int pos2); | |
| int ren_insertionoffset(char *s, int pos, int pre); | |
| +/* string registers */ | |
| +char *reg_get(int c, int *lnmode); | |
| +void reg_put(int c, char *s, int lnmode); | |
| +void reg_done(void); | |
| + | |
| /* utf-8 helper functions */ | |
| int uc_len(char *s); | |
| int uc_dir(char *s); | |
| int uc_wid(char *s); | |
| int uc_slen(char *s); | |
| int uc_code(char *s); | |
| +char *uc_chr(char *s, int off); | |
| +char *uc_sub(char *s, int beg, int end); | |
| +char *uc_dup(char *s); | |
| int uc_isspace(char *s); | |
| int uc_isprint(char *s); | |
| int uc_isdigit(char *s); |