tren: return placeholder characters from ren_translate() - 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 0c2fb9f33f08de99cfc4e5b61e14259bbbe2c468
 (DIR) parent a183ae6d1a2a745051c1f2a45f1b4de5fcaa4d5d
 (HTM) Author: Ali Gholami Rudi <ali@rudi.ir>
       Date:   Sun, 17 May 2015 10:10:27 +0430
       
       ren: return placeholder characters from ren_translate()
       
       Placeholders are useful especially for zerowidth characters.
       
       Diffstat:
         M dir.c                               |       2 +-
         M led.c                               |      45 ++++++++++++++++++++-----------
         M ren.c                               |      64 +++++++++++++++++++++----------
         M uc.c                                |       6 ++----
         M vi.h                                |       3 ++-
       
       5 files changed, 77 insertions(+), 43 deletions(-)
       ---
 (DIR) diff --git a/dir.c b/dir.c
       t@@ -3,7 +3,7 @@
        #include <string.h>
        #include "vi.h"
        
       -#define CR2L                "ءآأؤإئابةتثجحخدذرزسشصضطظعغـفقكلمنهوىييپچژکگی‌‍؛،»«؟"
       +#define CR2L                "ءآأؤإئابةتثجحخدذرزسشصضطظعغـفقكلمنهوىييپچژکگی‌‍؛،»«؟ًٌٍَُِّْ"
        #define CNEUT                "-!\"#$%&'()*+,./:;<=>?@^_`{|}~ "
        
        /* direction context patterns */
 (DIR) diff --git a/led.c b/led.c
       t@@ -31,33 +31,45 @@ static char *led_render(char *s0)
                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);
       +        int i, j;
       +        chrs = uc_chop(s0, &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;
       +                int curpos = pos[i];
       +                int curwid = ren_cwid(chrs[i], curpos);
       +                if (curpos >= 0 && curpos + curwid < xcols) {
       +                        for (j = 0; j < curwid; j++) {
       +                                off[led_pos(s0, curpos + j)] = i;
       +                                if (led_pos(s0, curpos + j) > maxcol)
       +                                        maxcol = led_pos(s0, curpos + j);
       +                        }
                        }
                }
                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
       +        i = 0;
       +        while (i <= maxcol) {
       +                int o = off[i];
       +                if (o >= 0) {
       +                        if (ren_translate(chrs[o], s0))
       +                                sbuf_str(out, ren_translate(chrs[o], s0));
       +                        else if (uc_isprint(chrs[o]))
       +                                sbuf_mem(out, chrs[o], uc_len(chrs[o]));
       +                        else
       +                                for (j = i; j <= maxcol && off[j] == o; j++)
       +                                        sbuf_chr(out, ' ');
       +                        while (i <= maxcol && off[i] == o)
       +                                i++;
       +                } else {
                                sbuf_chr(out, ' ');
       +                        i++;
       +                }
                }
                free(pos);
                free(off);
                free(chrs);
       -        free(s1);
                return sbuf_done(out);
        }
        
       t@@ -99,15 +111,16 @@ static void led_printparts(char *ai, char *pref, char *main, char *post)
                sbuf_str(ln, pref);
                sbuf_str(ln, main);
                off = uc_slen(sbuf_buf(ln));
       -        sbuf_str(ln, post);
                /* cursor position for inserting the next character */
       -        if (post[0]) {
       +        if (post[0] && post[0] != '\n') {
       +                sbuf_str(ln, post);
                        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_cursor(sbuf_buf(ln), ren_pos(sbuf_buf(ln), off));
                        sbuf_cut(ln, len);
       +                sbuf_str(ln, post);
                }
                led_print(sbuf_buf(ln), -1);
                term_pos(-1, led_pos(sbuf_buf(ln), pos));
 (DIR) diff --git a/ren.c b/ren.c
       t@@ -11,7 +11,7 @@ int *ren_position(char *s)
                int i, n;
                char **chrs = uc_chop(s, &n);
                int *off, *pos;
       -        int diff = 0;
       +        int cpos = 0;
                pos = malloc((n + 1) * sizeof(pos[0]));
                for (i = 0; i < n; i++)
                        pos[i] = i;
       t@@ -20,11 +20,10 @@ int *ren_position(char *s)
                for (i = 0; i < n; i++)
                        off[pos[i]] = i;
                for (i = 0; i < n; i++) {
       -                pos[off[i]] += diff;
       -                if (*chrs[i] == '\t')
       -                        diff += 8 - (pos[off[i]] & 7) - 1;
       +                pos[off[i]] = cpos;
       +                cpos += ren_cwid(chrs[off[i]], cpos);
                }
       -        pos[n] = n + diff;
       +        pos[n] = cpos;
                free(chrs);
                free(off);
                return pos;
       t@@ -39,22 +38,6 @@ int ren_wid(char *s)
                return ret;
        }
        
       -char *ren_translate(char *s)
       -{
       -        struct sbuf *sb = sbuf_make();
       -        char *r = s;
       -        while (*r) {
       -                char *c = uc_shape(s, r);
       -                if (!strcmp(c, "‌"))
       -                        c = "-";
       -                if (!strcmp(c, "‍"))
       -                        c = "-";
       -                sbuf_str(sb, c);
       -                r = uc_next(r);
       -        }
       -        return sbuf_done(sb);
       -}
       -
        /* 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)
        {
       t@@ -175,3 +158,42 @@ int ren_region(char *s, int c1, int c2, int *l1, int *l2, int closed)
                free(ord);
                return 0;
        }
       +
       +static struct placeholder {
       +        char *s;        /* the source character */
       +        char *d;        /* the placeholder */
       +} placeholders[] = {
       +        {"‌", "-"},
       +        {"‍", "-"},
       +        {"ْ", "ـْ"},
       +        {"ٌ", "ـٌ"},
       +        {"ٍ", "ـٍ"},
       +        {"ً", "ـً"},
       +        {"ُ", "ـُ"},
       +        {"ِ", "ـِ"},
       +        {"َ", "ـَ"},
       +        {"ّ", "ـّ"},
       +};
       +
       +static char *ren_placeholder(char *s)
       +{
       +        int i = 0;
       +        int c = uc_code(s);
       +        for (i = 0; i < LEN(placeholders); i++)
       +                if (uc_code(placeholders[i].s) == c)
       +                        return placeholders[i].d;
       +        return NULL;
       +}
       +
       +int ren_cwid(char *s, int pos)
       +{
       +        if (s[0] == '\t')
       +                return 8 - (pos & 7);
       +        return 1;
       +}
       +
       +char *ren_translate(char *s, char *ln)
       +{
       +        char *p = ren_placeholder(s);
       +        return p ? p : uc_shape(ln, s);
       +}
 (DIR) diff --git a/uc.c b/uc.c
       t@@ -323,10 +323,8 @@ char *uc_shape(char *beg, char *s)
                int prev = 0;
                int next = 0;
                int curr = uc_code(s);
       -        if (!curr || !UC_R2L(curr)) {
       -                uc_cput(out, curr);
       -                return out;
       -        }
       +        if (!curr || !UC_R2L(curr))
       +                return NULL;
                r = s;
                while (r > beg) {
                        r = uc_beg(beg, r - 1);
 (DIR) diff --git a/vi.h b/vi.h
       t@@ -45,7 +45,6 @@ void rset_free(struct rset *re);
        
        /* rendering lines */
        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);
       t@@ -53,6 +52,8 @@ int ren_pos(char *s, int off);
        int ren_off(char *s, int pos);
        int ren_wid(char *s);
        int ren_region(char *s, int c1, int c2, int *l1, int *l2, int closed);
       +char *ren_translate(char *s, char *ln);
       +int ren_cwid(char *s, int pos);
        
        /* text direction */
        int dir_context(char *s);