tTERM set to xterm by default (which broke a lot of stuff), better escape handl… | |
git clone git://src.adamsgaard.dk/st | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 0981437524b64579cc656f60b0108abdcdf8a0cd | |
parent f2dff29a16ef0eb1a0b680cdd753471ba406e4f5 | |
Author: Aurélien Aptel <[email protected]> | |
Date: Wed, 3 Feb 2010 03:25:35 +0100 | |
TERM set to xterm by default (which broke a lot of stuff), better escape handli… | |
Diffstat: | |
M st.c | 389 +++++++++++++++--------------… | |
1 file changed, 190 insertions(+), 199 deletions(-) | |
--- | |
diff --git a/st.c b/st.c | |
t@@ -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) | |
t@@ -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; | |
t@@ -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 { | |
t@@ -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 */ | |
t@@ -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); | |
t@@ -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; | |
t@@ -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"); | |
} | |
t@@ -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; | |
t@@ -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'/*, noa… | |
- } | |
- 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; | |
} | |
} | |
t@@ -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-… | |
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, t… | |
- 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, t… | |
- 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)); | |
} | |
t@@ -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; | |
t@@ -811,6 +793,15 @@ tputc(char c) { | |
case '\a': | |
xbell(); | |
break; | |
+ case '\033': | |
+ csireset(); | |
+ term.esc = ESCin; | |
+ break; | |
+ default: | |
+ tsetchar(c); | |
+ tcursor(CSright); | |
+ break; | |
+ } | |
} | |
} | |