st

fork of suckless's simple terminal
Index Commits Files Refs README LICENSE
commit 0981437524b64579cc656f60b0108abdcdf8a0cd
parent f2dff29a16ef0eb1a0b680cdd753471ba406e4f5
Author: Aurélien Aptel <aurelien.aptel@gmail.com>
Date:   Wed,  3 Feb 2010 03:25:35 +0100

TERM set to xterm by default (which broke a lot of stuff), better escape handling (title), and a little clean up.

Diffstat:
Mst.c | 389+++++++++++++++++++++++++++++++++++++++----------------------------------------
1 file changed, 190 insertions(+), 199 deletions(-)
diff --git a/st.c b/st.c
@@ -20,11 +20,12 @@
 #include <X11/keysym.h>
 #include <X11/Xutil.h>
 
-#define TNAME "st"
+#define TNAME "xterm"
 
 /* Arbitrary sizes */
+#define TITLESIZ 256
 #define ESCSIZ 256
-#define ESCARG 16
+#define ESCARGSIZ 16
 #define MAXDRAWBUF 1024
 
 #define SERRNO strerror(errno)
@@ -40,7 +41,8 @@
 enum { ATnone=0 , ATreverse=1 , ATunderline=2, ATbold=4 };
 enum { CSup, CSdown, CSright, CSleft, CShide, CSdraw, CSwrap, CSsave, CSload };
 enum { CRset=1, CRupdate=2 };
-enum { TMwrap=1, TMinsert=2 };
+enum { TMwrap=1, TMinsert=2, TMtitle=4 };
+enum { ESCin = 1, ESCcsi = 2, ESCosc = 4, ESCtitle = 8 };
 enum { SCupdate, SCredraw };
 
 typedef int Color;
@@ -62,17 +64,16 @@ typedef struct {
     int y;
 } TCursor;
 
-/* Escape sequence structs */
-/* ESC <pre> [[ [<priv>] <arg> [;]] <mode>] */
+/* CSI Escape sequence structs */
+/* ESC '[' [[ [<priv>] <arg> [;]] <mode>] */
 typedef struct {
-    char buf[ESCSIZ+1]; /* raw string */
+    char buf[ESCSIZ]; /* raw string */
     int len;            /* raw string length */
-    char pre;           
     char priv;
-    int arg[ESCARG+1];
+    int arg[ESCARGSIZ];
     int narg;           /* nb of args */
     char mode;
-} Escseq;
+} CSIEscape;
 
 /* Internal representation of the screen */
 typedef struct {
@@ -83,6 +84,9 @@ typedef struct {
     int top;    /* top    scroll limit */
     int bot;    /* bottom scroll limit */
     int mode;   /* terminal mode */
+    int esc;
+    char title[TITLESIZ];
+    int titlelen;
 } Term;
 
 /* Purely graphic info */
@@ -116,12 +120,10 @@ static void execsh(void);
 static void sigchld(int);
 static void run(void);
 
-static int escaddc(char);
-static int escfinal(char);
-static void escdump(void);
-static void eschandle(void);
-static void escparse(void);
-static void escreset(void);
+static void csidump(void);
+static void csihandle(void);
+static void csiparse(void);
+static void csireset(void);
 
 static void tclearregion(int, int, int, int);
 static void tcpos(int);
@@ -168,7 +170,7 @@ static void (*handler[LASTEvent])(XEvent *) = {
 static DC dc;
 static XWindow xw;
 static Term term;
-static Escseq escseq;
+static CSIEscape escseq;
 static int cmdfd;
 static pid_t pid;
 static int running;
@@ -269,7 +271,7 @@ ttynew(void) {
 void
 dump(char c) {
     static int col;
-    fprintf(stderr, " %02x %c ", c, isprint(c)?c:'.');
+    fprintf(stderr, " %02x '%c' ", c, isprint(c)?c:'.');
     if(++col % 10 == 0)
         fprintf(stderr, "\n");
 }
@@ -305,24 +307,6 @@ ttyresize(int x, int y) {
         fprintf(stderr, "Couldn't set window size: %s\n", SERRNO);
 }
 
-int
-escfinal(char c) {
-    if(escseq.len == 1)
-        switch(c) {
-        case '[':
-        case ']':
-        case '(':
-            return 0;
-        case '=':
-        case '>':
-        default:
-            return 1;
-        }
-    else if(BETWEEN(c, 0x40, 0x7E))
-        return 1;
-    return 0;      
-}
-
 void
 tcpos(int mode) {
     static int x = 0;
@@ -372,44 +356,27 @@ tnewline(void) {
     tmoveto(0, y);
 }
 
-int
-escaddc(char c) {
-    escseq.buf[escseq.len++] = c;
-    if(escfinal(c) || escseq.len >= ESCSIZ) {
-        escparse(), eschandle();
-        return 0;
-    }
-    return 1;
-}
-
 void
-escparse(void) {
+csiparse(void) {
     /* int noarg = 1; */
     char *p = escseq.buf;
 
     escseq.narg = 0;
-    switch(escseq.pre = *p++) {
-    case '[': /* CSI */
-        if(*p == '?')
-            escseq.priv = 1, p++;
-
-        while(p < escseq.buf+escseq.len) {
-            while(isdigit(*p)) {
-                escseq.arg[escseq.narg] *= 10;
-                escseq.arg[escseq.narg] += *(p++) - '0'/*, noarg = 0 */;
-            }
-            if(*p == ';')
-                escseq.narg++, p++;
-            else {
-                escseq.mode = *p;
-                escseq.narg++;
-                return;
-            }
+    if(*p == '?')
+        escseq.priv = 1, p++;
+    
+    while(p < escseq.buf+escseq.len) {
+        while(isdigit(*p)) {
+            escseq.arg[escseq.narg] *= 10;
+            escseq.arg[escseq.narg] += *p++ - '0'/*, noarg = 0 */;
+        }
+        if(*p == ';' && escseq.narg+1 < ESCARGSIZ)
+            escseq.narg++, p++;
+        else {
+            escseq.mode = *p;
+            escseq.narg++;
+            return;
         }
-        break;
-    case '(':
-        /* XXX: graphic character set */
-        break;
     }
 }
 
@@ -625,146 +592,141 @@ tsetscroll(int t, int b) {
 }
 
 void
-eschandle(void) {
-    switch(escseq.pre) {
+csihandle(void) {
+    switch(escseq.mode) {
     default:
-        goto unknown_seq;
-    case '[':
-        switch(escseq.mode) {
-        default:
-        unknown_seq:
-            fprintf(stderr, "erresc: unknown sequence\n");
-            escdump();
-            break;
-        case '@': /* Insert <n> blank char */
-            DEFAULT(escseq.arg[0], 1);
-            tinsertblank(escseq.arg[0]);
-            break;
-        case 'A': /* Cursor <n> Up */
-        case 'e':
-            DEFAULT(escseq.arg[0], 1);
-            tmoveto(term.c.x, term.c.y-escseq.arg[0]);
-            break;
-        case 'B': /* Cursor <n> Down */
-            DEFAULT(escseq.arg[0], 1);
-            tmoveto(term.c.x, term.c.y+escseq.arg[0]);
-            break;
-        case 'C': /* Cursor <n> Forward */
-        case 'a':
-            DEFAULT(escseq.arg[0], 1);
-            tmoveto(term.c.x+escseq.arg[0], term.c.y);
-            break;
-        case 'D': /* Cursor <n> Backward */
-            DEFAULT(escseq.arg[0], 1);
-            tmoveto(term.c.x-escseq.arg[0], term.c.y);
-            break;
-        case 'E': /* Cursor <n> Down and first col */
-            DEFAULT(escseq.arg[0], 1);
-            tmoveto(0, term.c.y+escseq.arg[0]);
-            break;
-        case 'F': /* Cursor <n> Up and first col */
-            DEFAULT(escseq.arg[0], 1);
-            tmoveto(0, term.c.y-escseq.arg[0]);
-            break;
-        case 'G': /* Move to <col> */
-        case '`':
-            DEFAULT(escseq.arg[0], 1);
-            tmoveto(escseq.arg[0]-1, term.c.y);
+        fprintf(stderr, "erresc: unknown sequence\n");
+        csidump();
+        /* die(""); */
+        break;
+    case '@': /* Insert <n> blank char */
+        DEFAULT(escseq.arg[0], 1);
+        tinsertblank(escseq.arg[0]);
+        break;
+    case 'A': /* Cursor <n> Up */
+    case 'e':
+        DEFAULT(escseq.arg[0], 1);
+        tmoveto(term.c.x, term.c.y-escseq.arg[0]);
+        break;
+    case 'B': /* Cursor <n> Down */
+        DEFAULT(escseq.arg[0], 1);
+        tmoveto(term.c.x, term.c.y+escseq.arg[0]);
+        break;
+    case 'C': /* Cursor <n> Forward */
+    case 'a':
+        DEFAULT(escseq.arg[0], 1);
+        tmoveto(term.c.x+escseq.arg[0], term.c.y);
+        break;
+    case 'D': /* Cursor <n> Backward */
+        DEFAULT(escseq.arg[0], 1);
+        tmoveto(term.c.x-escseq.arg[0], term.c.y);
+        break;
+    case 'E': /* Cursor <n> Down and first col */
+        DEFAULT(escseq.arg[0], 1);
+        tmoveto(0, term.c.y+escseq.arg[0]);
+        break;
+    case 'F': /* Cursor <n> Up and first col */
+        DEFAULT(escseq.arg[0], 1);
+        tmoveto(0, term.c.y-escseq.arg[0]);
+        break;
+    case 'G': /* Move to <col> */
+    case '`':
+        DEFAULT(escseq.arg[0], 1);
+         tmoveto(escseq.arg[0]-1, term.c.y);
+        break;
+    case 'H': /* Move to <row> <col> */
+    case 'f':
+        DEFAULT(escseq.arg[0], 1);
+        DEFAULT(escseq.arg[1], 1);
+        tmoveto(escseq.arg[1]-1, escseq.arg[0]-1);
+        break;
+    case 'J': /* Clear screen */
+        switch(escseq.arg[0]) {
+        case 0: /* below */
+            tclearregion(term.c.x, term.c.y, term.col-1, term.row-1);
             break;
-        case 'H': /* Move to <row> <col> */
-        case 'f':
-            DEFAULT(escseq.arg[0], 1);
-            DEFAULT(escseq.arg[1], 1);
-            tmoveto(escseq.arg[1]-1, escseq.arg[0]-1);
+        case 1: /* above */
+            tclearregion(0, 0, term.c.x, term.c.y);
             break;
-        case 'J': /* Clear screen */
-            switch(escseq.arg[0]) {
-            case 0: /* below */
-                tclearregion(term.c.x, term.c.y, term.col-1, term.row-1);
-                break;
-            case 1: /* above */
-                tclearregion(0, 0, term.c.x, term.c.y);
-                break;
-            case 2: /* all */
-                tclearregion(0, 0, term.col-1, term.row-1);
-                break;                  
-            }
+        case 2: /* all */
+            tclearregion(0, 0, term.col-1, term.row-1);
+            break;                  
+        }
+        break;
+    case 'K': /* Clear line */
+        switch(escseq.arg[0]) {
+        case 0: /* right */
+            tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
             break;
-        case 'K': /* Clear line */
-            switch(escseq.arg[0]) {
-            case 0: /* right */
-                tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
-                break;
-            case 1: /* left */
-                tclearregion(0, term.c.y, term.c.x, term.c.y);
-                break;
-            case 2: /* all */
-                tclearregion(0, term.c.y, term.col-1, term.c.y);
-                break;
-            }
+        case 1: /* left */
+            tclearregion(0, term.c.y, term.c.x, term.c.y);
             break;
-        case 'L': /* Insert <n> blank lines */
-            DEFAULT(escseq.arg[0], 1);
-            tinsertblankline(escseq.arg[0]);
+        case 2: /* all */
+            tclearregion(0, term.c.y, term.col-1, term.c.y);
             break;
-        case 'l':
-            if(escseq.priv && escseq.arg[0] == 25)
+        }
+        break;
+    case 'S':
+    case 'L': /* Insert <n> blank lines */
+        DEFAULT(escseq.arg[0], 1);
+        tinsertblankline(escseq.arg[0]);
+        break;
+    case 'l':
+        if(escseq.priv && escseq.arg[0] == 25)
                 term.c.hidden = 1;
-            break;
-        case 'M': /* Delete <n> lines */
-            DEFAULT(escseq.arg[0], 1);
-            tdeleteline(escseq.arg[0]);
-            break;
-        case 'P': /* Delete <n> char */
-            DEFAULT(escseq.arg[0], 1);
-            tdeletechar(escseq.arg[0]);
-            break;
-        case 'd': /* Move to <row> */
+        break;
+    case 'M': /* Delete <n> lines */
+        DEFAULT(escseq.arg[0], 1);
+        tdeleteline(escseq.arg[0]);
+        break;
+    case 'X':
+    case 'P': /* Delete <n> char */
+        DEFAULT(escseq.arg[0], 1);
+        tdeletechar(escseq.arg[0]);
+        break;
+    case 'd': /* Move to <row> */
+        DEFAULT(escseq.arg[0], 1);
+        tmoveto(term.c.x, escseq.arg[0]-1);
+        break;
+    case 'h': /* Set terminal mode */
+        if(escseq.priv && escseq.arg[0] == 25)
+            term.c.hidden = 0;
+        break;
+    case 'm': /* Terminal attribute (color) */
+        tsetattr(escseq.arg, escseq.narg);
+        break;
+    case 'r':
+        if(escseq.priv)
+            ;
+        else {
             DEFAULT(escseq.arg[0], 1);
-            tmoveto(term.c.x, escseq.arg[0]-1);
-            break;
-        case 'h': /* Set terminal mode */
-            if(escseq.priv && escseq.arg[0] == 25)
-                term.c.hidden = 0;
-            break;
-        case 'm': /* Terminal attribute (color) */
-            tsetattr(escseq.arg, escseq.narg);
-            break;
-        case 'r':
-            if(escseq.priv)
-                ;
-            else {
-                DEFAULT(escseq.arg[0], 1);
-                DEFAULT(escseq.arg[1], term.row);
-                tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1);
-            }
-            break;
-        case 's': /* Save cursor position */
-            tcpos(CSsave);
-            break;
-        case 'u': /* Load cursor position */
-            tcpos(CSload);
-            break;
+            DEFAULT(escseq.arg[1], term.row);
+            tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1);
         }
         break;
+    case 's': /* Save cursor position */
+        tcpos(CSsave);
+        break;
+    case 'u': /* Load cursor position */
+        tcpos(CSload);
+        break;
     }
 }
 
 void
-escdump(void) { 
+csidump(void) { 
     int i;
-    printf("rawbuf    : %s\n", escseq.buf);
-    printf("prechar : %c\n", escseq.pre);
-    printf("private : %c\n", escseq.priv ? '?' : ' ');
-    printf("narg    : %d\n", escseq.narg);
+    printf("ESC [ %s", escseq.priv ? "? " : "");
     if(escseq.narg)
         for(i = 0; i < escseq.narg; i++)
-            printf("\targ %d = %d\n", i, escseq.arg[i]);
-    printf("mode    : %c\n", escseq.mode);
+            printf("%d ", escseq.arg[i]);
+    if(escseq.mode)
+        putchar(escseq.mode);
+    putchar('\n');
 }
 
 void
-escreset(void) {
+csireset(void) {
     memset(&escseq, 0, sizeof(escseq));
 }
 
@@ -781,21 +743,41 @@ tputtab(void) {
 
 void
 tputc(char c) {
-    static int inesc = 0;
 #if 0
     dump(c);
 #endif    
-    /* start of escseq */
-    if(c == '\033')
-        escreset(), inesc = 1;
-    else if(inesc) {
-        inesc = escaddc(c);
-    } /* normal char */ 
-    else switch(c) { 
-        default:
-            tsetchar(c);
-            tcursor(CSright);
-            break;
+    if(term.esc & ESCin) {
+        if(term.esc & ESCcsi) {
+            escseq.buf[escseq.len++] = c;
+            if(BETWEEN(c, 0x40, 0x7E) || escseq.len >= ESCSIZ) {
+                term.esc = 0;
+                csiparse(), csihandle();
+            }
+        } else if (term.esc & ESCosc) {
+            if(c == ';') {
+                term.titlelen = 0;
+                term.esc = ESCin | ESCtitle;
+            }
+        } else if(term.esc & ESCtitle) {
+            if(c == '\a' || term.titlelen+1 >= TITLESIZ) {
+                term.esc = 0;
+                term.title[term.titlelen] = '\0';
+                XStoreName(xw.dis, xw.win, term.title);
+            } else {
+                term.title[term.titlelen++] = c;
+            }
+        } else {        
+            switch(c) {
+            case '[':
+                term.esc |= ESCcsi;
+                break;
+            case ']':
+                term.esc |= ESCosc;
+                break;
+            }
+        }
+    } else {
+        switch(c) {
         case '\t':
             tputtab();
             break;
@@ -811,6 +793,15 @@ tputc(char c) {
         case '\a':
             xbell();
             break;
+        case '\033':
+            csireset();
+            term.esc = ESCin;
+            break;
+        default:
+            tsetchar(c);
+            tcursor(CSright);
+            break;
+        }
     }
 }