tvi: yank and put - 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 01c3c8a62f1daee16d343488699f804c72dbca91
 (DIR) parent f80a244199b5d2735fcdd0abd4664346ba51dd32
 (HTM) Author: Ali Gholami Rudi <ali@rudi.ir>
       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(-)
       ---
 (DIR) 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
 (DIR) 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);
       +}
 (DIR) 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;
 (DIR) 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 pre2)
                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 position */
       +                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 : l2);
       +                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;
        }
 (DIR) 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);