]> git.armaanb.net Git - st.git/blobdiff - st.c
Add parsing of DCS q sequences
[st.git] / st.c
diff --git a/st.c b/st.c
index ca126d7448962d2a4bd175715aa6a184c0522341..6c1638651fe372e829ec57dd47e3e4a0fbb9f920 100644 (file)
--- a/st.c
+++ b/st.c
@@ -137,6 +137,8 @@ enum term_mode {
        MODE_MOUSEMANY   = 1 << 18,
        MODE_BRCKTPASTE  = 1 << 19,
        MODE_PRINT       = 1 << 20,
+       MODE_UTF8        = 1 << 21,
+       MODE_SIXEL       = 1 << 22,
        MODE_MOUSE       = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
                          |MODE_MOUSEMANY,
 };
@@ -154,10 +156,12 @@ enum charset {
 enum escape_state {
        ESC_START      = 1,
        ESC_CSI        = 2,
-       ESC_STR        = 4,  /* DCS, OSC, PM, APC */
+       ESC_STR        = 4,  /* OSC, PM, APC */
        ESC_ALTCHARSET = 8,
        ESC_STR_END    = 16, /* a final string was encountered */
        ESC_TEST       = 32, /* Enter in test mode */
+       ESC_UTF8       = 64,
+       ESC_DCS        =128,
 };
 
 enum window_state {
@@ -412,6 +416,7 @@ static void tfulldirt(void);
 static void techo(Rune);
 static void tcontrolcode(uchar );
 static void tdectest(char );
+static void tdefutf8(char);
 static int32_t tdefcolor(int *, int *, int);
 static void tdeftran(char);
 static inline int match(uint, uint);
@@ -1151,8 +1156,7 @@ selnotify(XEvent *e)
         * Deleting the property again tells the selection owner to send the
         * next data chunk in the property.
         */
-       if (e->type == PropertyNotify)
-               XDeleteProperty(xw.dpy, xw.win, (int)property);
+       XDeleteProperty(xw.dpy, xw.win, (int)property);
 }
 
 void
@@ -1404,9 +1408,9 @@ stty(void)
                if ((n = strlen(s)) > siz-1)
                        die("stty parameter length too long\n");
                *q++ = ' ';
-               q = memcpy(q, s, n);
+               memcpy(q, s, n);
                q += n;
-               siz-= n + 1;
+               siz -= n + 1;
        }
        *q = '\0';
        if (system(cmd) != 0)
@@ -1479,17 +1483,29 @@ ttyread(void)
        if ((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0)
                die("Couldn't read from shell: %s\n", strerror(errno));
 
-       /* process every complete utf8 char */
        buflen += ret;
        ptr = buf;
-       while ((charsize = utf8decode(ptr, &unicodep, buflen))) {
-               tputc(unicodep);
-               ptr += charsize;
-               buflen -= charsize;
-       }
 
+       for (;;) {
+               if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
+                       /* process a complete utf8 char */
+                       charsize = utf8decode(ptr, &unicodep, buflen);
+                       if (charsize == 0)
+                               break;
+                       tputc(unicodep);
+                       ptr += charsize;
+                       buflen -= charsize;
+
+               } else {
+                       if (buflen <= 0)
+                               break;
+                       tputc(*ptr++ & 0xFF);
+                       buflen--;
+               }
+       }
        /* keep any uncomplete utf8 char for the next call */
-       memmove(buf, ptr, buflen);
+       if (buflen > 0)
+               memmove(buf, ptr, buflen);
 
        return ret;
 }
@@ -1555,15 +1571,26 @@ void
 ttysend(char *s, size_t n)
 {
        int len;
+       char *t, *lim;
        Rune u;
 
        ttywrite(s, n);
-       if (IS_SET(MODE_ECHO))
-               while ((len = utf8decode(s, &u, n)) > 0) {
-                       techo(u);
-                       n -= len;
-                       s += len;
+       if (!IS_SET(MODE_ECHO))
+               return;
+
+       lim = &s[n];
+       for (t = s; t < lim; t += len) {
+               if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
+                       len = utf8decode(t, &u, n);
+               } else {
+                       u = *t & 0xFF;
+                       len = 1;
                }
+               if (len <= 0)
+                       break;
+               techo(u);
+               n -= len;
+       }
 }
 
 void
@@ -1657,7 +1684,7 @@ treset(void)
                term.tabs[i] = 1;
        term.top = 0;
        term.bot = term.row - 1;
-       term.mode = MODE_WRAP;
+       term.mode = MODE_WRAP|MODE_UTF8;
        memset(term.trantbl, CS_USA, sizeof(term.trantbl));
        term.charset = 0;
 
@@ -2523,6 +2550,7 @@ strhandle(void)
                xsettitle(strescseq.args[0]);
                return;
        case 'P': /* DCS -- Device Control String */
+               term.mode |= ESC_DCS;
        case '_': /* APC -- Application Program Command */
        case '^': /* PM -- Privacy Message */
                return;
@@ -2690,6 +2718,15 @@ techo(Rune u)
        tputc(u);
 }
 
+void
+tdefutf8(char ascii)
+{
+       if (ascii == 'G')
+               term.mode |= MODE_UTF8;
+       else if (ascii == '@')
+               term.mode &= ~MODE_UTF8;
+}
+
 void
 tdeftran(char ascii)
 {
@@ -2720,9 +2757,12 @@ tdectest(char c)
 void
 tstrsequence(uchar c)
 {
+       strreset();
+
        switch (c) {
        case 0x90:   /* DCS -- Device Control String */
                c = 'P';
+               term.esc |= ESC_DCS;
                break;
        case 0x9f:   /* APC -- Application Program Command */
                c = '_';
@@ -2734,7 +2774,6 @@ tstrsequence(uchar c)
                c = ']';
                break;
        }
-       strreset();
        strescseq.type = c;
        term.esc |= ESC_STR;
 }
@@ -2852,6 +2891,9 @@ eschandle(uchar ascii)
        case '#':
                term.esc |= ESC_TEST;
                return 0;
+       case '%':
+               term.esc |= ESC_UTF8;
+               return 0;
        case 'P': /* DCS -- Device Control String */
        case '_': /* APC -- Application Program Command */
        case '^': /* PM -- Privacy Message */
@@ -2931,10 +2973,15 @@ tputc(Rune u)
        Glyph *gp;
 
        control = ISCONTROL(u);
-       len = utf8encode(u, c);
-       if (!control && (width = wcwidth(u)) == -1) {
-               memcpy(c, "\357\277\275", 4); /* UTF_INVALID */
-               width = 1;
+       if (!IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
+               c[0] = u;
+               width = len = 1;
+       } else {
+               len = utf8encode(u, c);
+               if (!control && (width = wcwidth(u)) == -1) {
+                       memcpy(c, "\357\277\275", 4); /* UTF_INVALID */
+                       width = 1;
+               }
        }
 
        if (IS_SET(MODE_PRINT))
@@ -2949,30 +2996,47 @@ tputc(Rune u)
        if (term.esc & ESC_STR) {
                if (u == '\a' || u == 030 || u == 032 || u == 033 ||
                   ISCONTROLC1(u)) {
-                       term.esc &= ~(ESC_START|ESC_STR);
+                       term.esc &= ~(ESC_START|ESC_STR|ESC_DCS);
+                       if (IS_SET(MODE_SIXEL)) {
+                               /* TODO: render sixel */;
+                               term.mode &= ~MODE_SIXEL;
+                               return;
+                       }
                        term.esc |= ESC_STR_END;
-               } else if (strescseq.len + len < sizeof(strescseq.buf) - 1) {
-                       memmove(&strescseq.buf[strescseq.len], c, len);
-                       strescseq.len += len;
+                       goto check_control_code;
+               }
+
+
+               if (IS_SET(MODE_SIXEL)) {
+                       /* TODO: implement sixel mode */
                        return;
-               } else {
-               /*
-                * Here is a bug in terminals. If the user never sends
-                * some code to stop the str or esc command, then st
-                * will stop responding. But this is better than
-                * silently failing with unknown characters. At least
-                * then users will report back.
-                *
-                * In the case users ever get fixed, here is the code:
-                */
-               /*
-                * term.esc = 0;
-                * strhandle();
-                */
+               }
+               if (term.esc&ESC_DCS && strescseq.len == 0 && u == 'q')
+                       term.mode |= MODE_SIXEL;
+
+               if (strescseq.len+len >= sizeof(strescseq.buf)-1) {
+                       /*
+                        * Here is a bug in terminals. If the user never sends
+                        * some code to stop the str or esc command, then st
+                        * will stop responding. But this is better than
+                        * silently failing with unknown characters. At least
+                        * then users will report back.
+                        *
+                        * In the case users ever get fixed, here is the code:
+                        */
+                       /*
+                        * term.esc = 0;
+                        * strhandle();
+                        */
                        return;
                }
+
+               memmove(&strescseq.buf[strescseq.len], c, len);
+               strescseq.len += len;
+               return;
        }
 
+check_control_code:
        /*
         * Actions of control codes must be performed as soon they arrive
         * because they can be embedded inside a control sequence, and
@@ -2995,6 +3059,8 @@ tputc(Rune u)
                                csihandle();
                        }
                        return;
+               } else if (term.esc & ESC_UTF8) {
+                       tdefutf8(u);
                } else if (term.esc & ESC_ALTCHARSET) {
                        tdeftran(u);
                } else if (term.esc & ESC_TEST) {
@@ -3280,7 +3346,7 @@ xloadfont(Font *f, FcPattern *pattern)
        FcResult result;
        XGlyphInfo extents;
 
-       match = FcFontMatch(NULL, pattern, &result);
+       match = XftFontMatch(xw.dpy, xw.scr, pattern, &result);
        if (!match)
                return 1;
 
@@ -3291,7 +3357,7 @@ xloadfont(Font *f, FcPattern *pattern)
 
        XftTextExtentsUtf8(xw.dpy, f->match,
                (const FcChar8 *) ascii_printable,
-               LEN(ascii_printable), &extents);
+               strlen(ascii_printable), &extents);
 
        f->set = NULL;
        f->pattern = FcPatternDuplicate(pattern);
@@ -3302,7 +3368,7 @@ xloadfont(Font *f, FcPattern *pattern)
        f->rbearing = f->match->max_advance_width;
 
        f->height = f->ascent + f->descent;
-       f->width = DIVCEIL(extents.xOff, LEN(ascii_printable));
+       f->width = DIVCEIL(extents.xOff, strlen(ascii_printable));
 
        return 0;
 }
@@ -3346,9 +3412,6 @@ xloadfonts(char *fontstr, double fontsize)
                defaultfontsize = usedfontsize;
        }
 
-       FcConfigSubstitute(0, pattern, FcMatchPattern);
-       FcDefaultSubstitute(pattern);
-
        if (xloadfont(&dc.font, pattern))
                die("st: can't open font %s\n", fontstr);
 
@@ -3671,7 +3734,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
                specs[numspecs].font = frc[f].font;
                specs[numspecs].glyph = glyphidx;
                specs[numspecs].x = (short)xp;
-               specs[numspecs].y = (short)(winy + frc[f].font->ascent);
+               specs[numspecs].y = (short)yp;
                xp += runewidth;
                numspecs++;
        }