tvi: find cursor position after insertion in vi_input() - neatvi - [fork] simple vi-type editor with UTF-8 support
git clone git://src.adamsgaard.dk/neatvi
Log
Files
Refs
README
---
commit 674db133b8d6995f54c4cb682d7193dbda7ca62a
parent 7344f210fcb3b51fa46f90f0ace3bbe126cb47b8
Author: Ali Gholami Rudi 
Date:   Tue, 12 May 2015 22:45:59 +0430

vi: find cursor position after insertion in vi_input()

Diffstat:
  M led.c                               |      36 +++++++++++--------------------
  M ren.c                               |       9 ---------
  M uc.c                                |      14 --------------
  M vi.c                                |      51 ++++++++++++++++++++++++++++---
  M vi.h                                |       4 +---

5 files changed, 60 insertions(+), 54 deletions(-)
---
diff --git a/led.c b/led.c
t@@ -90,30 +90,26 @@ static int led_lastword(char *s)
         return r - s;
 }
 
-/* the position of the cursor for inserting another character */
-static int led_insertionpos(struct sbuf *sb)
-{
-        int len = sbuf_len(sb);
-        char *chr = keymap(led_kmap, 'a');
-        int col;
-        sbuf_str(sb, chr);
-        col = ren_cursor(sbuf_buf(sb),
-                ren_pos(sbuf_buf(sb), uc_slen(sbuf_buf(sb)) - 1));
-        sbuf_cut(sb, len);
-        return col;
-}
-
 static void led_printparts(char *pref, char *main, char *post)
 {
         struct sbuf *ln;
-        int col;
+        int off, pos;
         ln = sbuf_make();
         sbuf_str(ln, pref);
         sbuf_str(ln, main);
-        col = led_insertionpos(ln);
+        off = uc_slen(sbuf_buf(ln));
         sbuf_str(ln, post);
+        /* cursor position for inserting the next character */
+        if (post[0]) {
+                pos = ren_cursor(sbuf_buf(ln), ren_pos(sbuf_buf(ln), off));
+        } else {
+                int len = sbuf_len(ln);
+                sbuf_str(ln, keymap(led_kmap, 'a'));
+                pos = ren_pos(sbuf_buf(ln), off);
+                sbuf_cut(ln, len);
+        }
         led_print(sbuf_buf(ln), -1);
-        term_pos(-1, led_pos(sbuf_buf(ln), col));
+        term_pos(-1, led_pos(sbuf_buf(ln), ren_cursor(sbuf_buf(ln), pos)));
         sbuf_free(ln);
 }
 
t@@ -177,19 +173,15 @@ char *led_prompt(char *pref, char *post)
 }
 
 /* read visual command input */
-char *led_input(char *pref, char *post, int *row, int *col)
+char *led_input(char *pref, char *post)
 {
         struct sbuf *sb = sbuf_make();
         int key;
-        *row = 0;
         while (1) {
                 char *ln = led_line(pref, post, &key, &led_kmap);
-                if (pref)
-                        sbuf_str(sb, pref);
                 sbuf_str(sb, ln);
                 if (key == '\n')
                         sbuf_chr(sb, '\n');
-                *col = ren_last(pref ? sbuf_buf(sb) : ln);
                 led_printparts(pref ? pref : "", ln, key == '\n' ? "" : post);
                 if (key == '\n')
                         term_chr('\n');
t@@ -198,9 +190,7 @@ char *led_input(char *pref, char *post, int *row, int *col)
                 free(ln);
                 if (key != '\n')
                         break;
-                (*row)++;
         }
-        sbuf_str(sb, post);
         if (key == TERMESC)
                 return sbuf_done(sb);
         sbuf_free(sb);
diff --git a/ren.c b/ren.c
t@@ -55,15 +55,6 @@ char *ren_translate(char *s)
         return sbuf_done(sb);
 }
 
-int ren_last(char *s)
-{
-        int n = uc_slen(s);
-        int *pos = ren_position(s);
-        int ret = n ? pos[n - 1] : 0;
-        free(pos);
-        return ret;
-}
-
 /* find the next character after visual position p; if cur start from p itself */
 static int pos_next(int *pos, int n, int p, int cur)
 {
diff --git a/uc.c b/uc.c
t@@ -285,20 +285,6 @@ static int uc_comb(int c)
                 c == 0x0670;                                /* superscript alef */
 }
 
-/* the direction of the given utf-8 character */
-int uc_dir(char *s)
-{
-        int u, c = (unsigned char) s[0];
-        if (c < 128 && (ispunct(c) || isspace(c)))
-                return 0;
-        if (c < 128 && isalnum(c))
-                return 1;
-        u = uc_code(s);
-        if (UC_R2L(u))
-                return -1;
-        return 1;
-}
-
 static void uc_cput(char *d, int c)
 {
         int l = 0;
diff --git a/vi.c b/vi.c
t@@ -398,7 +398,12 @@ static int vi_insertionoffset(char *s, int c1, int before)
                         return l2 < l1 ? l1 + 1 : l1;
         }
         ren_region(s, c1, c2, &l1, &l2, 0);
-        return l1 < l2 ? l2 : l1;
+        c1 = ren_pos(s, l1);
+        c2 = ren_pos(s, l2);
+        if (c1 < c2)
+                return l1 < l2 ? l2 : l1;
+        else
+                return l1 < l2 ? l1 : l2;
 }
 
 static void vi_commandregion(int *r1, int *r2, int *c1, int *c2, int *l1, int *l2, int closed)
t@@ -454,6 +459,42 @@ static void vi_delete(int r1, int c1, int r2, int c2, int lnmode, int closed)
         free(post);
 }
 
+static int lastline(char *str)
+{
+        char *s = str;
+        char *r = s;
+        while (s && s[0]) {
+                r = s;
+                s = strchr(s == str ? s : s + 1, '\n');
+        }
+        return r - str;
+}
+
+static int linecount(char *s)
+{
+        int n;
+        for (n = 0; s; n++)
+                if ((s = strchr(s, '\n')))
+                        s++;
+        return n;
+}
+
+static char *vi_input(char *pref, char *post, int *row, int *col)
+{
+        char *rep = led_input(pref, post);
+        struct sbuf *sb = sbuf_make();
+        int last, off;
+        sbuf_str(sb, pref);
+        sbuf_str(sb, rep);
+        last = lastline(sbuf_buf(sb));
+        off = uc_slen(sbuf_buf(sb) + last);
+        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);
+}
+
 static void vi_change(int r1, int c1, int r2, int c2, int lnmode, int closed)
 {
         char *region;
t@@ -467,11 +508,11 @@ static void vi_change(int r1, int c1, int r2, int c2, int lnmode, int closed)
         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);
-        rep = led_input(pref, post, &row, &col);
+        rep = vi_input(pref, post, &row, &col);
         if (rep) {
                 lbuf_rm(xb, r1, r2 + 1);
                 lbuf_put(xb, r1, rep);
-                xrow = r1 + row;
+                xrow = r1 + row - 1;
                 xcol = col;
                 free(rep);
         }
t@@ -529,14 +570,14 @@ static void vc_insert(int cmd)
                 off = ln ? vi_insertionoffset(ln, xcol, 0) : 0;
         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);
+        rep = vi_input(pref, post, &row, &col);
         if ((cmd == 'o' || cmd == 'O') && !lbuf_len(xb))
                 lbuf_put(xb, 0, "\n");
         if (rep) {
                 if (cmd != 'o' && cmd != 'O')
                         lbuf_rm(xb, xrow, xrow + 1);
                 lbuf_put(xb, xrow, rep);
-                xrow += row;
+                xrow += row - 1;
                 xcol = col;
                 free(rep);
         }
diff --git a/vi.h b/vi.h
t@@ -49,7 +49,6 @@ int ren_next(char *s, int p, int dir);
 int ren_eol(char *s, int dir);
 int ren_pos(char *s, int off);
 int ren_off(char *s, int pos);
-int ren_last(char *s);
 int ren_wid(char *s);
 int ren_region(char *s, int c1, int c2, int *l1, int *l2, int closed);
 
t@@ -66,7 +65,6 @@ 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);
t@@ -106,7 +104,7 @@ void term_commit(void);
 
 /* line-oriented input and output */
 char *led_prompt(char *pref, char *post);
-char *led_input(char *pref, char *post, int *row, int *col);
+char *led_input(char *pref, char *post);
 void led_print(char *msg, int row);
 char *led_keymap(int c);
 int led_pos(char *s, int pos);