]> git.neil.brown.name Git - edlib.git/commitdiff
lib-renderline: expect control chars instead of <> for attributes.
authorNeilBrown <neil@brown.name>
Wed, 21 Jun 2023 07:48:57 +0000 (17:48 +1000)
committerNeilBrown <neil@brown.name>
Wed, 28 Jun 2023 07:51:41 +0000 (17:51 +1000)
Using <> to distinguish attributes is clumsy as it requires that '<' be
quoted.

We already quote control characters, making them <red>^X</red> so use
control characters for distinguishing attributes.
SOH (\1) marks start of attrs
STX (\2) marks end of attrs, start of text
ETX (\3) marks end of the text for those attrs.
ACK (\6) is used as a filler when needed.

A string that start \6 or \1 is assumed not to contain meaningful <>
Otherwise we translate to remain compatible with old code.

Signed-off-by: NeilBrown <neil@brown.name>
DOC/TODO.md
lib-renderline.c
misc.h
tests.d/02-grep

index 9350457493205dff3e17047e8d7598f6ff1bb19b..5e305a887e870089f8fa01fc673afb9eede67036 100644 (file)
@@ -58,7 +58,7 @@ Requirements for a v1.0 release
       Maybe a pencil in a window pane
 - [ ] configuration
 - [ ] vi mode
-- [ ] office mode
+- [ ] CUA mode
 - [ ] nano mode(?)
 - [ ] multiple front ends: elvi, elma, elnm, eled?
 - [ ] introspection
@@ -803,7 +803,7 @@ Module features
 New Modules
 -----------
 
-- [ ] separate out from mode-emacs:
+- [ ] separate out CUA-base from mode-emacs:
 
      - selection management
      - mouse management
@@ -823,7 +823,10 @@ New Modules
     - numeric prefix
     - much more
 
-- [ ] "office" mode
+- [ ] "CUA" mode
+
+    - "extra" on CUA-base which might conflict with emacs/vi, including
+      control-letter and function keys.
 
     - C-c for copy, C-x for cut, C-v for paste,
     - C-a select all
index b14fc8c0a9470a3ecc44df79a5058264b8da6d38..d238bf0f3ca514eb5519b5e68e1b12e51528ae78 100644 (file)
@@ -367,11 +367,8 @@ static void update_line_height(struct pane *p safe, struct pane *focus safe,
        while (*line) {
                char c = *line++;
                const char *st = line;
-               if (c == '<' && *line == '<') {
-                       line += 1;
-                       continue;
-               }
-               if (c != '<')
+
+               if (c != soh && c != etx && c != ack)
                        continue;
 
                if (line - 1 > segstart) {
@@ -381,14 +378,16 @@ static void update_line_height(struct pane *p safe, struct pane *focus safe,
                                                buf_final(&attr), l, scale);
                        free(l);
                }
-               while (*line && line[-1] != '>')
-                       line += 1;
-               segstart = line;
-               if (st[0] != '/') {
+               if (c == soh) {
                        char *c2;
                        char *b;
                        const char *aend;
 
+                       /* move 'line' over the attrs */
+                       while (*line && line[-1] != stx)
+                               line += 1;
+                       segstart = line;
+
                        /* attrs must not contain ",," */
                        aend = strstr(st, ",,");
                        if (aend)
@@ -397,9 +396,9 @@ static void update_line_height(struct pane *p safe, struct pane *focus safe,
                                aend = line;
 
                        buf_concat_len(&attr, st, aend-st);
-                       /* Replace trailing '>' with ',', and append ','
+                       /* Replace trailing 'stx' with ',', and append ','
                         * so ",," marks where to strip back to when we
-                        * find </>.
+                        * find etx
                         */
                        attr.b[attr.len-1] = ',';
                        buf_append(&attr, ',');
@@ -419,7 +418,8 @@ static void update_line_height(struct pane *p safe, struct pane *focus safe,
                        attr_found = 1;
                        update_line_height_attr(p, focus, h, a, w, b, "",
                                                scale);
-               } else {
+               } else if (c == etx) {
+                       segstart = line;
                        /* strip back to ",," */
                        if (attr.len >= 2)
                                attr.len -= 2;
@@ -427,6 +427,8 @@ static void update_line_height(struct pane *p safe, struct pane *focus safe,
                               (attr.b[attr.len] != ',' ||
                                attr.b[attr.len+1] != ','))
                                attr.len -= 1;
+               } else if (c == ack) {
+                       segstart = line;
                }
        }
        if (line > segstart && line[-1] == '\n')
@@ -495,11 +497,11 @@ static int render_image(struct pane *p safe, struct pane *focus safe,
        width = p->parent->w/2;
        height = p->parent->h/2;
 
-       while (*line == '<')
+       while (*line == soh)
                line += 1;
 
-       while (*line && *line != '>') {
-               int len = strcspn(line, ",>");
+       while (*line && *line != stx && *line != etx) {
+               int len = strcspn(line, "," STX ETX);
 
                if (strstarts(line, "image:")) {
                        fname = strndup(line+6, len-6);
@@ -689,7 +691,7 @@ DEF_CMD(renderline)
        if (dodraw)
                home_call(focus, "Draw:clear", p);
 
-       if (strstarts(line, "<image:"))
+       if (strstarts(line, SOH "image:"))
                /* For now an <image> must be on a line by itself.
                 * Maybe this can be changed later if I decide on
                 * something that makes sense.
@@ -792,7 +794,7 @@ DEF_CMD(renderline)
                }
 
                if ((ret == WRAP || x >= p->w - mwidth) &&
-                   (line[0] != '<' || line[1] == '<')) {
+                   line[0] != soh && line[0] != ack) {
                        /* No room for more text */
                        if (wrap && *line && *line != '\n') {
                                int wrap_prefix_size;
@@ -830,7 +832,7 @@ DEF_CMD(renderline)
                ch = *line;
                if (line == line_start + offset)
                        rd->curs_width = mwidth;
-               if (ch >= ' ' && ch != '<') {
+               if (ch >= ' ') {
                        bool was_in_lws = in_lws;
                        line += 1;
                        /* Only flush out if string is getting a bit long.
@@ -885,70 +887,63 @@ DEF_CMD(renderline)
                start = line;
                if (ret != OK || !ch)
                        continue;
-               if (ch == '<') {
-                       line += 1;
-                       if (*line == '<') {
-                               in_lws = False;
-                               ret = draw_some(p, focus, &rlst, &x, start, &line,
-                                               buf_final(&attr), in_lws,
-                                               wrap ? mwidth : 0,
-                                               in_tab ?:offset - (start - line_start),
-                                               posx, scale);
-                               if (ret != OK)
-                                       continue;
-                               start += 2;
-                               line = start;
-                       } else {
-                               const char *a = line;
-
-                               while (*line && line[-1] != '>')
-                                       line += 1;
-
-                               if (a[0] != '/') {
-                                       int ln = attr.len;
-                                       char *tb;
-                                       const char *aend;
-
-                                       /* attrs must not contain ",," */
-                                       aend = strstr(a, ",,");
-                                       if (aend)
-                                               aend += 1;
-                                       if (!aend || line < aend)
-                                               aend = line;
-
-                                       buf_concat_len(&attr, a, aend-a);
-                                       /* Replace trailing '>' with ',', and
-                                        * append ',' so ",," marks where to
-                                        * strip back to when we find </>.
-                                        */
-                                       attr.b[attr.len-1] = ',';
-                                       buf_append(&attr, ',');
-                                       tb = strstr(buf_final(&attr)+ln,
-                                                   "tab:");
-                                       if (tb)
-                                               x = margin +
-                                                       atoi(tb+4) * scale / 1000;
-                               } else {
-                                       /* strip back to ",," */
-                                       if (attr.len > 0)
-                                               attr.len -= 2;
-                                       while (attr.len >=2 &&
-                                              (attr.b[attr.len-1] != ',' ||
-                                               attr.b[attr.len-2] != ','))
-                                               attr.len -= 1;
-                                       if (attr.len == 1)
-                                               attr.len = 0;
-                               }
-                               if (offset == start - line_start)
-                                       offset += line-start;
-                               start = line;
-                               mwidth = -1;
-                       }
-                       continue;
-               }
-
                line += 1;
-               if (ch == '\n') {
+               switch (ch) {
+               case soh: {
+                       const char *a = line;
+                       char *tb;
+                       const char *aend;
+                       int ln;
+
+                       while (*line && line[-1] != stx)
+                               line += 1;
+
+                       ln = attr.len;
+
+                       /* attrs must not contain ",," */
+                       aend = strstr(a, ",,");
+                       if (aend)
+                               aend += 1;
+                       if (!aend || line < aend)
+                               aend = line;
+
+                       buf_concat_len(&attr, a, aend-a);
+                       /* Replace trailing stx with ',', and
+                        * append ',' so ",," marks where to
+                        * strip back to when we find etx.
+                        */
+                       attr.b[attr.len-1] = ',';
+                       buf_append(&attr, ',');
+                       tb = strstr(buf_final(&attr)+ln,
+                                   "tab:");
+                       if (tb)
+                               x = margin +
+                                       atoi(tb+4) * scale / 1000;
+                       if (offset == start - line_start)
+                               offset += line-start;
+                       start = line;
+                       mwidth = -1;
+                       break;
+                       }
+               case etx:
+                       /* strip back to ",," */
+                       if (attr.len > 0)
+                               attr.len -= 2;
+                       while (attr.len >=2 &&
+                              (attr.b[attr.len-1] != ',' ||
+                               attr.b[attr.len-2] != ','))
+                               attr.len -= 1;
+                       if (attr.len == 1)
+                               attr.len = 0;
+                       if (offset == start - line_start)
+                               offset += line-start;
+                       start = line;
+                       mwidth = -1;
+                       break;
+               case ack:
+                       start = line;
+                       break;
+               case '\n':
                        xypos = line-1;
                        flush_line(p, focus, dodraw, &rlst, y+ascent, scale, 0,
                                   &wrap_margin, NULL, &xypos, &xyattr, &cursattr);
@@ -956,12 +951,14 @@ DEF_CMD(renderline)
                        x = 0;
                        wrap_offset = 0;
                        start = line;
-               } else if (ch == '\f') {
+                       break;
+               case '\f':
                        x = 0;
                        start = line;
                        wrap_offset = 0;
                        end_of_page = 1;
-               } else if (ch == '\t') {
+                       break;
+               case '\t': {
                        int xc = (wrap_offset + x) / mwidth;
                        /* Note xc might be negative, so "xc % 8" won't work here */
                        int w = 8 - (xc & 7);
@@ -981,7 +978,9 @@ DEF_CMD(renderline)
                        } else
                                in_tab = 0;
                        start = line;
-               } else {
+                       break;
+                       }
+               default:{
                        char buf[4];
                        const char *b;
                        int l = attr.len;
@@ -998,6 +997,8 @@ DEF_CMD(renderline)
                                        posx, scale);
                        attr.len = l;
                        start = line;
+                       break;
+                       }
                }
        }
        if (!*line && (line > start || offset == start - line_start)) {
@@ -1089,6 +1090,39 @@ DEF_CMD(renderline_get)
        return 1;
 }
 
+static char *cvt(char *str safe)
+{
+       /* Convert:
+        *    << to < ack  (ack is a no-op)
+        *    < stuff > to soh stuff stx
+        *    </> to ack ack etx
+        */
+       char *c;
+       for (c = str; *c; c += 1) {
+               if (c[0] == soh || c[0] == ack)
+                       break;
+               if (c[0] == '<' && c[1] == '<') {
+                       c[1] = ack;
+                       c++;
+                       continue;
+               }
+               if (c[0] != '<')
+                       continue;
+               if (c[1] == '/') {
+                       c[0] = ack;
+                       c[1] = ack;
+                       c[2] = etx;
+                       c += 2;
+                       continue;
+               }
+               c[0] = soh;
+               while (c[0] && c[1] != '>')
+                       c++;
+               c[1] = stx;
+       }
+       return str;
+}
+
 DEF_CMD(renderline_set)
 {
        struct rline_data *rd = ci->home->data;
@@ -1096,7 +1130,7 @@ DEF_CMD(renderline_set)
        struct xy xyscale = pane_scale(ci->focus);
 
        if (ci->str)
-               rd->line = strdup(ci->str);
+               rd->line = cvt(strdup(ci->str));
        else
                rd->line = NULL;
        if (strcmp(rd->line ?:"", old ?:"") != 0 ||
diff --git a/misc.h b/misc.h
index 9d861f85c7ac0ed8722d63c95426921dde00f4f8..b0490df6b720cc09d6e2ab6fb389dd72da544cb8 100644 (file)
--- a/misc.h
+++ b/misc.h
@@ -60,6 +60,24 @@ static inline void buf_reinit(struct buf *b safe)
        b->len = 0;
 }
 
+/* Formatting can be embedded in text strings in some places using
+ * SOH STX ETX.
+ * SOH format-attributes STX the text ETX
+ * "the text" can contain nested SOH/STX/ETX sequences.
+ * The same can be done with
+ *  < format-attributes> the text </a>
+ * but that is being phased out.
+ */
+#define SOH "\001"
+#define STX "\002"
+#define ETX "\003"
+#define soh '\001'
+#define stx '\002'
+#define etx '\003'
+/* ACK is used as a no-op. */
+#define ack '\006'
+#define ACK "\006"
+
 /* Performance measurements.
  * 1/ timers.
  */
index cae82b3057017ee70f0c2e4d40129877d38da8e7..e662c6921af027ae2795feceb00308c46eb66732 100644 (file)
@@ -222,7 +222,7 @@ Display 80,30 DD0B850460093327B7F2F877E46EA378 1,7
 Key "-`"
 Display 80,30 9BFCD6FB7DDEEB9FF736EEE48A983DF2 1,6
 Key "-`"
-Display 80,30 5BC5B368B3E25A73BE8F8D595D61AEE6 1,6
+Display 80,30 CAEBB71698ADA0E51D9B5E710B1B0969 1,6
 Key "-`"
 Display 80,30 3A381382535261F222BA0E5DC190CC2A 1,6
 Key ":A-0"