JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
reset the alt screen in treset
[st.git] / st.c
diff --git a/st.c b/st.c
index 3aa8539..0e228a7 100644 (file)
--- a/st.c
+++ b/st.c
@@ -86,22 +86,19 @@ char *argv0;
 #define TRUEBLUE(x)      (((x) & 0xff) << 8)
 
 
-#define VT102ID "\033[?6c"
-
 enum glyph_attribute {
-        ATTR_NULL      = 0,
+       ATTR_NULL      = 0,
        ATTR_BOLD      = 1,
        ATTR_FAINT     = 2,
        ATTR_ITALIC    = 4,
        ATTR_UNDERLINE = 8,
        ATTR_BLINK     = 16,
-       ATTR_FASTBLINK = 32,
-       ATTR_REVERSE   = 64,
-       ATTR_INVISIBLE = 128,
-       ATTR_STRUCK    = 256,
-       ATTR_WRAP      = 512,
-       ATTR_WIDE      = 1024,
-       ATTR_WDUMMY    = 2048,
+       ATTR_REVERSE   = 32,
+       ATTR_INVISIBLE = 64,
+       ATTR_STRUCK    = 128,
+       ATTR_WRAP      = 256,
+       ATTR_WIDE      = 512,
+       ATTR_WDUMMY    = 1024,
 };
 
 enum cursor_movement {
@@ -375,6 +372,7 @@ static void tdeletechar(int);
 static void tdeleteline(int);
 static void tinsertblank(int);
 static void tinsertblankline(int);
+static int tlinelen(int);
 static void tmoveto(int, int);
 static void tmoveato(int, int);
 static void tnew(int, int);
@@ -382,7 +380,7 @@ static void tnewline(int);
 static void tputtab(int);
 static void tputc(char *, int);
 static void treset(void);
-static int tresize(int, int);
+static void tresize(int, int);
 static void tscrollup(int, int);
 static void tscrolldown(int, int);
 static void tsetattr(int *, int);
@@ -404,6 +402,7 @@ static void ttyread(void);
 static void ttyresize(void);
 static void ttysend(char *, size_t);
 static void ttywrite(const char *, size_t);
+static void tstrsequence(uchar c);
 
 static void xdraws(char *, Glyph, int, int, int, int);
 static void xhints(void);
@@ -920,7 +919,7 @@ bpress(XEvent *e) {
 char *
 getsel(void) {
        char *str, *ptr;
-       int x, y, bufsize, size, ex;
+       int y, bufsize, size, lastx, linelen;
        Glyph *gp, *last;
 
        if(sel.ob.x == -1)
@@ -931,16 +930,19 @@ getsel(void) {
 
        /* append every set & selected glyph to the selection */
        for(y = sel.nb.y; y < sel.ne.y + 1; y++) {
-               gp = &term.line[y][0];
-               last = &gp[term.col-1];
+               linelen = tlinelen(y);
 
-               while(last >= gp && !(selected(last - gp, y) &&
-                                     strcmp(last->c, " ") != 0)) {
-                       --last;
+               if(sel.type == SEL_RECTANGULAR) {
+                       gp = &term.line[y][sel.nb.x];
+                       lastx = sel.ne.x;
+               } else {
+                       gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0];
+                       lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
                }
+               last = &term.line[y][MIN(lastx, linelen-1)];
 
-               for(x = 0; gp <= last; x++, ++gp) {
-                       if(!selected(x, y) || (gp->mode & ATTR_WDUMMY))
+               for( ; gp <= last; ++gp) {
+                       if(gp->mode & ATTR_WDUMMY)
                                continue;
 
                        size = utf8len(gp->c);
@@ -957,20 +959,8 @@ getsel(void) {
                 * st.
                 * FIXME: Fix the computer world.
                 */
-               if(y < sel.ne.y && !(x > 0 && (gp-1)->mode & ATTR_WRAP))
+               if(sel.ne.y > y || lastx >= linelen)
                        *ptr++ = '\n';
-
-               /*
-                * If the last selected line expands in the selection
-                * after the visible text '\n' is appended.
-                */
-               if(y == sel.ne.y) {
-                       ex = sel.ne.x;
-                       if(sel.nb.y == sel.ne.y && sel.ne.x < sel.nb.x)
-                               ex = sel.nb.x;
-                       if(tlinelen(y) < ex)
-                               *ptr++ = '\n';
-               }
        }
        *ptr = 0;
        return str;
@@ -1184,16 +1174,15 @@ execsh(void) {
 
 void
 sigchld(int a) {
-       int stat = 0;
+       int stat, ret;
 
        if(waitpid(pid, &stat, 0) < 0)
                die("Waiting for pid %hd failed: %s\n", pid, strerror(errno));
 
-       if(WIFEXITED(stat)) {
-               exit(WEXITSTATUS(stat));
-       } else {
-               exit(EXIT_FAILURE);
-       }
+       ret = WIFEXITED(stat) ? WEXITSTATUS(stat) : EXIT_FAILURE;
+       if (ret != EXIT_SUCCESS)
+               die("child finished with error '%d'\n", stat);
+       exit(EXIT_SUCCESS);
 }
 
 void
@@ -1367,9 +1356,12 @@ treset(void) {
        memset(term.trantbl, sizeof(term.trantbl), CS_USA);
        term.charset = 0;
 
-       tclearregion(0, 0, term.col-1, term.row-1);
-       tmoveto(0, 0);
-       tcursor(CURSOR_SAVE);
+       for(i = 0; i < 2; i++) {
+               tmoveto(0, 0);
+               tcursor(CURSOR_SAVE);
+               tclearregion(0, 0, term.col-1, term.row-1);
+               tswapscreen();
+       }
 }
 
 void
@@ -1562,6 +1554,7 @@ tsetchar(char *c, Glyph *attr, int x, int y) {
 void
 tclearregion(int x1, int y1, int x2, int y2) {
        int x, y, temp;
+       Glyph *gp;
 
        if(x1 > x2)
                temp = x1, x1 = x2, x2 = temp;
@@ -1576,10 +1569,13 @@ tclearregion(int x1, int y1, int x2, int y2) {
        for(y = y1; y <= y2; y++) {
                term.dirty[y] = 1;
                for(x = x1; x <= x2; x++) {
+                       gp = &term.line[y][x];
                        if(selected(x, y))
                                selclear(NULL);
-                       term.line[y][x] = term.c.attr;
-                       memcpy(term.line[y][x].c, " ", 2);
+                       gp->fg = term.c.attr.fg;
+                       gp->bg = term.c.attr.bg;
+                       gp->mode = 0;
+                       memcpy(gp->c, " ", 2);
                }
        }
 }
@@ -1691,7 +1687,6 @@ tsetattr(int *attr, int l) {
                                ATTR_ITALIC     |
                                ATTR_UNDERLINE  |
                                ATTR_BLINK      |
-                               ATTR_FASTBLINK  |
                                ATTR_REVERSE    |
                                ATTR_INVISIBLE  |
                                ATTR_STRUCK     );
@@ -1711,10 +1706,9 @@ tsetattr(int *attr, int l) {
                        term.c.attr.mode |= ATTR_UNDERLINE;
                        break;
                case 5: /* slow blink */
-                       term.c.attr.mode |= ATTR_BLINK;
-                       break;
+                       /* FALLTHROUGH */
                case 6: /* rapid blink */
-                       term.c.attr.mode |= ATTR_FASTBLINK;
+                       term.c.attr.mode |= ATTR_BLINK;
                        break;
                case 7:
                        term.c.attr.mode |= ATTR_REVERSE;
@@ -1725,11 +1719,8 @@ tsetattr(int *attr, int l) {
                case 9:
                        term.c.attr.mode |= ATTR_STRUCK;
                        break;
-               case 21:
-                       term.c.attr.mode &= ~ATTR_BOLD;
-                       break;
                case 22:
-                       term.c.attr.mode &= ~ATTR_FAINT;
+                       term.c.attr.mode &= ~(ATTR_BOLD | ATTR_FAINT);
                        break;
                case 23:
                        term.c.attr.mode &= ~ATTR_ITALIC;
@@ -1740,9 +1731,6 @@ tsetattr(int *attr, int l) {
                case 25:
                        term.c.attr.mode &= ~ATTR_BLINK;
                        break;
-               case 26:
-                       term.c.attr.mode &= ~ATTR_FASTBLINK;
-                       break;
                case 27:
                        term.c.attr.mode &= ~ATTR_REVERSE;
                        break;
@@ -1978,7 +1966,7 @@ csihandle(void) {
                break;
        case 'c': /* DA -- Device Attributes */
                if(csiescseq.arg[0] == 0)
-                       ttywrite(VT102ID, sizeof(VT102ID) - 1);
+                       ttywrite(vtiden, sizeof(vtiden) - 1);
                break;
        case 'C': /* CUF -- Cursor <n> Forward */
        case 'a': /* HPR -- Cursor <n> Forward */
@@ -2287,12 +2275,10 @@ tdumpline(int n) {
        Glyph *bp, *end;
 
        bp = &term.line[n][0];
-       end = &bp[term.col-1];
-       while(end > bp && !strcmp(" ", end->c))
-               --end;
-       if(bp != end || strcmp(bp->c, " ")) {
+       end = &bp[MIN(tlinelen(n), term.col) - 1];
+       if(bp != end || bp->c[0] != ' ') {
                for( ;bp <= end; ++bp)
-                       tprinter(bp->c, strlen(bp->c));
+                       tprinter(bp->c, utf8len(bp->c));
        }
        tprinter("\n", 1);
 }
@@ -2326,13 +2312,13 @@ techo(char *buf, int len) {
        for(; len > 0; buf++, len--) {
                char c = *buf;
 
-               if(ISCONTROL(c)) { /* control code */
+               if(ISCONTROL((uchar) c)) { /* control code */
                        if(c & 0x80) {
                                c &= 0x7f;
                                tputc("^", 1);
                                tputc("[", 1);
                        } else if(c != '\n' && c != '\r' && c != '\t') {
-                               c ^= '\x40';
+                               c ^= 0x40;
                                tputc("^", 1);
                        }
                        tputc(&c, 1);
@@ -2358,6 +2344,30 @@ tdeftran(char ascii) {
 }
 
 void
+tstrsequence(uchar c) {
+       if (c & 0x80) {
+               switch (c) {
+               case 0x90:   /* DCS -- Device Control String */
+                       c = 'P';
+                       break;
+               case 0x9f:   /* APC -- Application Program Command */
+                       c = '_';
+                       break;
+               case 0x9e:   /* PM -- Privacy Message */
+                       c = '^';
+                       break;
+               case 0x9d:   /* OSC -- Operating System Command */
+                       c = ']';
+                       break;
+               }
+       }
+       strreset();
+       strescseq.type = c;
+       term.esc |= ESC_STR;
+       return;
+}
+
+void
 tcontrolcode(uchar ascii) {
        static char question[UTF_SIZ] = "?";
 
@@ -2411,20 +2421,30 @@ tcontrolcode(uchar ascii) {
        case 0177:   /* DEL (IGNORED) */
                return;
        case 0x84:   /* TODO: IND */
-       case 0x85:   /* TODO: NEL */
-       case 0x88:   /* TODO: HTS */
+               break;
+       case 0x85:   /* NEL -- Next line */
+               tnewline(1); /* always go to first col */
+               break;
+       case 0x88:   /* HTS -- Horizontal tab stop */
+               term.tabs[term.c.x] = 1;
+               break;
        case 0x8d:   /* TODO: RI */
        case 0x8e:   /* TODO: SS2 */
        case 0x8f:   /* TODO: SS3 */
-       case 0x90:   /* TODO: DCS */
        case 0x98:   /* TODO: SOS */
-       case 0x9a:   /* TODO: DECID */
+               break;
+       case 0x9a:   /* DECID -- Identify Terminal */
+               ttywrite(vtiden, sizeof(vtiden) - 1);
+               break;
        case 0x9b:   /* TODO: CSI */
        case 0x9c:   /* TODO: ST */
-       case 0x9d:   /* TODO: OSC */
-       case 0x9e:   /* TODO: PM */
-       case 0x9f:   /* TODO: APC */
                break;
+       case 0x90:   /* DCS -- Device Control String */
+       case 0x9f:   /* APC -- Application Program Command */
+       case 0x9e:   /* PM -- Privacy Message */
+       case 0x9d:   /* OSC -- Operating System Command */
+               tstrsequence(ascii);
+               return;
        }
        /* only CAN, SUB, \a and C1 chars interrupt a sequence */
        term.esc &= ~(ESC_STR_END|ESC_STR);
@@ -2540,9 +2560,7 @@ tputc(char *c, int len) {
                        case '^': /* PM -- Privacy Message */
                        case ']': /* OSC -- Operating System Command */
                        case 'k': /* old title set compatibility */
-                               strreset();
-                               strescseq.type = ascii;
-                               term.esc |= ESC_STR;
+                               tstrsequence(ascii);
                                return;
                        case '(': /* set primary charset G0 */
                        case ')': /* set secondary charset G1 */
@@ -2572,7 +2590,7 @@ tputc(char *c, int len) {
                                }
                                break;
                        case 'Z': /* DECID -- Identify Terminal */
-                               ttywrite(VT102ID, sizeof(VT102ID) - 1);
+                               ttywrite(vtiden, sizeof(vtiden) - 1);
                                break;
                        case 'c': /* RIS -- Reset to inital state */
                                treset();
@@ -2639,18 +2657,20 @@ tputc(char *c, int len) {
        }
 }
 
-int
+void
 tresize(int col, int row) {
        int i;
        int minrow = MIN(row, term.row);
        int mincol = MIN(col, term.col);
        int slide = term.c.y - row + 1;
        bool *bp;
-       Line *orig;
        TCursor c;
 
-       if(col < 1 || row < 1)
-               return 0;
+       if(col < 1 || row < 1) {
+               fprintf(stderr,
+                       "tresize: error resizing to %dx%d\n", col, row);
+               return;
+       }
 
        /* free unneeded rows */
        i = 0;
@@ -2680,14 +2700,12 @@ tresize(int col, int row) {
 
        /* resize each row to new width, zero-pad if needed */
        for(i = 0; i < minrow; i++) {
-               term.dirty[i] = 1;
                term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
                term.alt[i]  = xrealloc(term.alt[i],  col * sizeof(Glyph));
        }
 
        /* allocate any new rows */
        for(/* i == minrow */; i < row; i++) {
-               term.dirty[i] = 1;
                term.line[i] = xmalloc(col * sizeof(Glyph));
                term.alt[i] = xmalloc(col * sizeof(Glyph));
        }
@@ -2707,10 +2725,9 @@ tresize(int col, int row) {
        tsetscroll(0, row-1);
        /* make use of the LIMIT in tmoveto */
        tmoveto(term.c.x, term.c.y);
-       /* Clearing both screens */
-       orig = term.line;
+       /* Clearing both screens (it makes dirty all lines) */
        c = term.c;
-       do {
+       for(i = 0; i < 2; i++) {
                if(mincol < col && 0 < minrow) {
                        tclearregion(mincol, 0, col - 1, minrow - 1);
                }
@@ -2719,10 +2736,8 @@ tresize(int col, int row) {
                }
                tswapscreen();
                tcursor(CURSOR_LOAD);
-       } while(orig != term.line);
+       }
        term.c = c;
-
-       return (slide > 0);
 }
 
 void
@@ -3189,7 +3204,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
                 * change basic system colors [0-7]
                 * to bright system colors [8-15]
                 */
-               if(BETWEEN(base.fg, 0, 7))
+               if(BETWEEN(base.fg, 0, 7) && !(base.mode & ATTR_FAINT))
                        fg = &dc.col[base.fg + 8];
 
                if(base.mode & ATTR_ITALIC) {
@@ -3233,6 +3248,14 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
                bg = temp;
        }
 
+       if(base.mode & ATTR_FAINT && !(base.mode & ATTR_BOLD)) {
+               colfg.red = fg->color.red / 2;
+               colfg.green = fg->color.green / 2;
+               colfg.blue = fg->color.blue / 2;
+               XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &revfg);
+               fg = &revfg;
+       }
+
        if(base.mode & ATTR_BLINK && term.mode & MODE_BLINK)
                fg = bg;
 
@@ -3755,6 +3778,8 @@ run(void) {
        /* Waiting for window mapping */
        while(1) {
                XNextEvent(xw.dpy, &ev);
+               if(XFilterEvent(&ev, None))
+                       continue;
                if(ev.type == ConfigureNotify) {
                        w = ev.xconfigure.width;
                        h = ev.xconfigure.height;
@@ -3846,8 +3871,8 @@ run(void) {
 void
 usage(void) {
        die("%s " VERSION " (c) 2010-2014 st engineers\n" \
-       "usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]" \
-       " [-t title] [-w windowid] [-e command ...]\n", argv0);
+       "usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
+       "          [-i] [-t title] [-w windowid] [-e command ...]\n", argv0);
 }
 
 int