tled: map cursor position to terminal column number with led_pos() - 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 9eea97a38d9862f405e00ab6a5b830a19a0df101
 (DIR) parent 7feca5e3a5de42c3ee1d3a0a0b13dc27c93280ed
 (HTM) Author: Ali Gholami Rudi <ali@rudi.ir>
       Date:   Mon, 11 May 2015 18:19:30 +0430
       
       led: map cursor position to terminal column number with led_pos()
       
       Diffstat:
         M led.c                               |      46 +++++++++++++++++++++++++++++--
         M ren.c                               |     114 +++++++------------------------
         M term.c                              |       4 ++++
         M vi.c                                |      13 +++++++------
         M vi.h                                |       6 ++++--
       
       5 files changed, 84 insertions(+), 99 deletions(-)
       ---
 (DIR) diff --git a/led.c b/led.c
       t@@ -14,14 +14,56 @@ static char *keymap(char **kmap, int c)
                return kmap[c] ? kmap[c] : cs;
        }
        
       +/* map cursor horizontal position to terminal column number */
       +int led_pos(char *s, int pos)
       +{
       +        return dir_context(s) >= 0 ? pos : xcols - pos - 1;
       +}
       +
        char *led_keymap(int c)
        {
                return c >= 0 ? keymap(led_kmap, c) : NULL;
        }
        
       +static char *led_render(char *s0)
       +{
       +        int n, maxcol = 0;
       +        int *pos;        /* pos[i]: the screen position of the i-th character */
       +        int *off;        /* off[i]: the character at screen position i */
       +        char **chrs;        /* chrs[i]: the i-th character in s1 */
       +        char *s1;
       +        struct sbuf *out;
       +        int i;
       +        s1 = ren_translate(s0 ? s0 : "");
       +        chrs = uc_chop(s1, &n);
       +        pos = ren_position(s0);
       +        off = malloc(xcols * sizeof(off[0]));
       +        memset(off, 0xff, xcols * sizeof(off[0]));
       +        for (i = 0; i < n; i++) {
       +                int curpos = led_pos(s0, pos[i]);
       +                if (curpos >= 0 && curpos < xcols) {
       +                        off[curpos] = i;
       +                        if (curpos > maxcol)
       +                                maxcol = curpos;
       +                }
       +        }
       +        out = sbuf_make();
       +        for (i = 0; i <= maxcol; i++) {
       +                if (off[i] >= 0 && uc_isprint(chrs[off[i]]))
       +                        sbuf_mem(out, chrs[off[i]], uc_len(chrs[off[i]]));
       +                else
       +                        sbuf_chr(out, ' ');
       +        }
       +        free(pos);
       +        free(off);
       +        free(chrs);
       +        free(s1);
       +        return sbuf_done(out);
       +}
       +
        void led_print(char *s, int row)
        {
       -        char *r = ren_all(s, -1);
       +        char *r = led_render(s);
                term_pos(row, 0);
                term_kill();
                term_str(r);
       t@@ -71,7 +113,7 @@ static void led_printparts(char *pref, char *main, char *post)
                col = led_insertionpos(ln);
                sbuf_str(ln, post);
                led_print(sbuf_buf(ln), -1);
       -        term_pos(-1, col);
       +        term_pos(-1, led_pos(sbuf_buf(ln), col));
                sbuf_free(ln);
        }
        
 (DIR) diff --git a/ren.c b/ren.c
       t@@ -6,14 +6,13 @@
        #include "vi.h"
        
        /* specify the screen position of the characters in s */
       -static int *ren_position(char *s, int *beg, int *end)
       +int *ren_position(char *s)
        {
                int i, n;
                char **chrs = uc_chop(s, &n);
                int *off, *pos;
                int diff = 0;
       -        int dir = dir_context(s);
       -        pos = malloc(n * sizeof(pos[0]));
       +        pos = malloc((n + 1) * sizeof(pos[0]));
                for (i = 0; i < n; i++)
                        pos[i] = i;
                dir_reorder(s, pos);
       t@@ -25,24 +24,22 @@ static int *ren_position(char *s, int *beg, int *end)
                        if (*chrs[i] == '\t')
                                diff += 8 - (pos[off[i]] & 7);
                }
       -        if (beg)
       -                *beg = 0;
       -        if (end)
       -                *end = n + diff;
       -        if (dir < 0) {
       -                if (beg)
       -                        *beg = xcols - *end - 1;
       -                if (end)
       -                        *end = xcols - 1;
       -                for (i = 0; i < n; i++)
       -                        pos[i] = xcols - pos[i] - 1;
       -        }
       +        pos[n] = n + diff;
                free(chrs);
                free(off);
                return pos;
        }
        
       -static char *ren_translate(char *s)
       +int ren_wid(char *s)
       +{
       +        int *pos = ren_position(s);
       +        int n = uc_slen(s);
       +        int ret = pos[n];
       +        free(pos);
       +        return ret;
       +}
       +
       +char *ren_translate(char *s)
        {
                struct sbuf *sb = sbuf_make();
                char *r = s;
       t@@ -58,43 +55,10 @@ static char *ren_translate(char *s)
                return sbuf_done(sb);
        }
        
       -char *ren_all(char *s0, int wid)
       -{
       -        int n, w = 0;
       -        int *pos;        /* pos[i]: the screen position of the i-th character */
       -        int *off;        /* off[i]: the character at screen position i */
       -        char **chrs;        /* chrs[i]: the i-th character in s1 */
       -        char *s1;
       -        struct sbuf *out;
       -        int i;
       -        s1 = ren_translate(s0 ? s0 : "");
       -        chrs = uc_chop(s1, &n);
       -        pos = ren_position(s0, NULL, NULL);
       -        for (i = 0; i < n; i++)
       -                if (w <= pos[i])
       -                        w = pos[i] + 1;
       -        off = malloc(w * sizeof(off[0]));
       -        memset(off, 0xff, w * sizeof(off[0]));
       -        for (i = 0; i < n; i++)
       -                off[pos[i]] = i;
       -        out = sbuf_make();
       -        for (i = 0; i < w; i++) {
       -                if (off[i] >= 0 && uc_isprint(chrs[off[i]]))
       -                        sbuf_mem(out, chrs[off[i]], uc_len(chrs[off[i]]));
       -                else
       -                        sbuf_chr(out, ' ');
       -        }
       -        free(pos);
       -        free(off);
       -        free(chrs);
       -        free(s1);
       -        return sbuf_done(out);
       -}
       -
        int ren_last(char *s)
        {
                int n = uc_slen(s);
       -        int *pos = ren_position(s, NULL, NULL);
       +        int *pos = ren_position(s);
                int ret = n ? pos[n - 1] : 0;
                free(pos);
                return ret;
       t@@ -124,7 +88,7 @@ static int pos_prev(int *pos, int n, int p, int cur)
        int ren_pos(char *s, int off)
        {
                int n = uc_slen(s);
       -        int *pos = ren_position(s, NULL, NULL);
       +        int *pos = ren_position(s);
                int ret = off < n ? pos[off] : 0;
                free(pos);
                return ret;
       t@@ -135,12 +99,9 @@ int ren_off(char *s, int p)
        {
                int off = -1;
                int n = uc_slen(s);
       -        int *pos = ren_position(s, NULL, NULL);
       +        int *pos = ren_position(s);
                int i;
       -        if (dir_context(s) >= 0)
       -                p = pos_prev(pos, n, p, 1);
       -        else
       -                p = pos_next(pos, n, p, 1);
       +        p = pos_prev(pos, n, p, 1);
                for (i = 0; i < n; i++)
                        if (pos[i] == p)
                                off = i;
       t@@ -151,23 +112,15 @@ int ren_off(char *s, int p)
        /* adjust cursor position */
        int ren_cursor(char *s, int p)
        {
       -        int dir = dir_context(s ? s : "");
                int n, next;
       -        int beg, end;
                int *pos;
                if (!s)
                        return 0;
                n = uc_slen(s);
       -        pos = ren_position(s, &beg, &end);
       -        if (dir >= 0)
       -                p = pos_prev(pos, n, p, 1);
       -        else
       -                p = pos_next(pos, n, p, 1);
       -        if (dir >= 0)
       -                next = pos_next(pos, n, p, 0);
       -        else
       -                next = pos_prev(pos, n, p, 0);
       -        p = (next >= 0 ? next : (dir >= 0 ? end : beg)) - dir;
       +        pos = ren_position(s);
       +        p = pos_prev(pos, n, p, 1);
       +        next = pos_next(pos, n, p, 0);
       +        p = (next >= 0 ? next : pos[n]) - 1;
                free(pos);
                return p >= 0 ? p : 0;
        }
       t@@ -176,12 +129,9 @@ int ren_cursor(char *s, int p)
        int ren_next(char *s, int p, int dir)
        {
                int n = uc_slen(s);
       -        int *pos = ren_position(s, NULL, NULL);
       -        if (dir_context(s ? s : "") >= 0)
       -                p = pos_prev(pos, n, p, 1);
       -        else
       -                p = pos_next(pos, n, p, 1);
       -        if (dir * dir_context(s ? s : "") >= 0)
       +        int *pos = ren_position(s);
       +        p = pos_prev(pos, n, p, 1);
       +        if (dir >= 0)
                        p = pos_next(pos, n, p, 0);
                else
                        p = pos_prev(pos, n, p, 0);
       t@@ -189,20 +139,6 @@ int ren_next(char *s, int p, int dir)
                return p;
        }
        
       -int ren_eol(char *s, int dir)
       -{
       -        int beg, end;
       -        int *pos = ren_position(s, &beg, &end);
       -        free(pos);
       -        return dir * dir_context(s) >= 0 ? end : beg;
       -}
       -
       -/* compare two visual positions */
       -int ren_cmp(char *s, int pos1, int pos2)
       -{
       -        return dir_context(s ? s : "") >= 0 ? pos1 - pos2 : pos2 - pos1;
       -}
       -
        static void swap(int *i1, int *i2)
        {
                int t = *i1;
       t@@ -228,7 +164,7 @@ int ren_region(char *s, int c1, int c2, int *l1, int *l2, int closed)
                        ord[i] = i;
                dir_reorder(s, ord);
        
       -        if (ren_cmp(s, c1, c2) > 0)
       +        if (c2 < c1)
                        swap(&c1, &c2);
                if (!closed)
                        c2 = ren_next(s, c2, -1);
 (DIR) diff --git a/term.c b/term.c
       t@@ -80,6 +80,10 @@ void term_kill(void)
        void term_pos(int r, int c)
        {
                char buf[32] = "\r";
       +        if (c < 0)
       +                c = 0;
       +        if (c >= xcols)
       +                c = cols - 1;
                if (r < 0)
                        sprintf(buf, "\r\33[%d%c", abs(c), c > 0 ? 'C' : 'D');
                else
 (DIR) diff --git a/vi.c b/vi.c
       t@@ -27,7 +27,7 @@ static void vi_draw(void)
                        char *s = lbuf_get(xb, i);
                        led_print(s ? s : "~", i - xtop);
                }
       -        term_pos(xrow, xcol);
       +        term_pos(xrow, led_pos(lbuf_get(xb, i), xcol));
                term_commit();
        }
        
       t@@ -77,7 +77,7 @@ static int lbuf_lnnext(struct lbuf *lb, int *r, int *c, int dir)
        static void lbuf_eol(struct lbuf *lb, int *r, int *c, int dir)
        {
                char *ln = lbuf_get(lb, *r);
       -        *c = ren_eol(ln ? ln : "", dir);
       +        *c = dir < 0 ? 0 : MAX(0, ren_wid(ln ? ln : "") - 1);
        }
        
        static int lbuf_next(struct lbuf *lb, int *r, int *c, int dir)
       t@@ -394,7 +394,7 @@ static int vi_insertionoffset(char *s, int c1, int before)
        
        static void vi_commandregion(int *r1, int *r2, int *c1, int *c2, int *l1, int *l2, int closed)
        {
       -        if (*r2 < *r1 || (*r2 == *r1 && ren_cmp(lbuf_get(xb, *r1), *c1, *c2) > 0)) {
       +        if (*r2 < *r1 || (*r2 == *r1 && *c2 < *c1)) {
                        swap(r1, r2);
                        swap(c1, c2);
                }
       t@@ -618,7 +618,7 @@ static void vi(void)
                xrow = 0;
                lbuf_eol(xb, &xrow, &xcol, -1);
                vi_draw();
       -        term_pos(xrow, xcol);
       +        term_pos(xrow, led_pos(lbuf_get(xb, xrow), xcol));
                while (!xquit) {
                        int redraw = 0;
                        int orow = xrow;
       t@@ -660,7 +660,7 @@ static void vi(void)
                                        redraw = 1;
                                        break;
                                case ':':
       -                                term_pos(xrows, 0);
       +                                term_pos(xrows, led_pos(":", 0));
                                        term_kill();
                                        ex_command(NULL);
                                        if (xquit)
       t@@ -763,7 +763,8 @@ static void vi(void)
                        }
                        if (redraw)
                                vi_draw();
       -                term_pos(xrow - xtop, ren_cursor(lbuf_get(xb, xrow), xcol));
       +                term_pos(xrow - xtop, led_pos(lbuf_get(xb, xrow),
       +                                ren_cursor(lbuf_get(xb, xrow), xcol)));
                        lbuf_undomark(xb);
                }
                term_pos(xrows, 0);
 (DIR) diff --git a/vi.h b/vi.h
       t@@ -42,14 +42,15 @@ int reset_find(struct reset *re, char *s, int n, int *grps, int flg);
        void reset_free(struct reset *re);
        
        /* rendering lines */
       -char *ren_all(char *s, int wid);
       +int *ren_position(char *s);
       +char *ren_translate(char *s);
        int ren_cursor(char *s, int pos);
        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_cmp(char *s, int pos1, int pos2);
       +int ren_wid(char *s);
        int ren_region(char *s, int c1, int c2, int *l1, int *l2, int closed);
        
        /* text direction */
       t@@ -108,6 +109,7 @@ char *led_prompt(char *pref, char *post);
        char *led_input(char *pref, char *post, int *row, int *col);
        void led_print(char *msg, int row);
        char *led_keymap(int c);
       +int led_pos(char *s, int pos);
        
        /* ex commands */
        void ex(void);