| tAdd OSC, DSC, PM, APC and settitle. - st - [fork] customized build of st, the … | |
| git clone git://src.adamsgaard.dk/st | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| commit 6696ef8563a58ee07e4de5b3a74b52b91934f6a9 | |
| parent ff040e9894f62fe28bf100488211d0a407740668 | |
| Author: Christoph Lohmann <[email protected]> | |
| Date: Wed, 29 Aug 2012 23:14:20 +0200 | |
| Add OSC, DSC, PM, APC and settitle. | |
| Diffstat: | |
| M TODO | 1 + | |
| M st.c | 279 +++++++++++++++++++++--------… | |
| 2 files changed, 191 insertions(+), 89 deletions(-) | |
| --- | |
| diff --git a/TODO b/TODO | |
| t@@ -20,6 +20,7 @@ bugs | |
| * fix shift up/down (shift selection in emacs) | |
| * fix selection click | |
| * fix selection paste for xatom STRING | |
| +* fix umlaut handling in settitle | |
| misc | |
| ---- | |
| diff --git a/st.c b/st.c | |
| t@@ -43,9 +43,10 @@ | |
| #define XEMBED_FOCUS_OUT 5 | |
| /* Arbitrary sizes */ | |
| -#define ESC_TITLE_SIZ 256 | |
| #define ESC_BUF_SIZ 256 | |
| #define ESC_ARG_SIZ 16 | |
| +#define STR_BUF_SIZ 256 | |
| +#define STR_ARG_SIZ 16 | |
| #define DRAW_BUF_SIZ 1024 | |
| #define UTF_SIZ 4 | |
| #define XK_NO_MOD UINT_MAX | |
| t@@ -110,9 +111,9 @@ enum term_mode { | |
| enum escape_state { | |
| ESC_START = 1, | |
| ESC_CSI = 2, | |
| - ESC_OSC = 4, | |
| - ESC_TITLE = 8, | |
| - ESC_ALTCHARSET = 16 | |
| + ESC_STR = 4, /* DSC, OSC, PM, APC */ | |
| + ESC_ALTCHARSET = 8, | |
| + ESC_STR_END = 16, /* a final string was encountered */ | |
| }; | |
| enum window_state { | |
| t@@ -158,6 +159,16 @@ typedef struct { | |
| char mode; | |
| } CSIEscape; | |
| +/* STR Escape sequence structs */ | |
| +/* ESC type [[ [<priv>] <arg> [;]] <mode>] ESC '\' */ | |
| +typedef struct { | |
| + char type; /* ESC type ... */ | |
| + char buf[STR_BUF_SIZ]; /* raw string */ | |
| + int len; /* raw string length */ | |
| + char *args[STR_ARG_SIZ]; | |
| + int narg; /* nb of args */ | |
| +} STREscape; | |
| + | |
| /* Internal representation of the screen */ | |
| typedef struct { | |
| int row; /* nb row */ | |
| t@@ -170,8 +181,6 @@ typedef struct { | |
| int bot; /* bottom scroll limit */ | |
| int mode; /* terminal mode flags */ | |
| int esc; /* escape state flags */ | |
| - char title[ESC_TITLE_SIZ]; | |
| - int titlelen; | |
| bool *tabs; | |
| } Term; | |
| t@@ -239,6 +248,10 @@ static void csidump(void); | |
| static void csihandle(void); | |
| static void csiparse(void); | |
| static void csireset(void); | |
| +static void strdump(void); | |
| +static void strhandle(void); | |
| +static void strparse(void); | |
| +static void strreset(void); | |
| static void tclearregion(int, int, int, int); | |
| static void tcursor(int); | |
| t@@ -323,7 +336,8 @@ static void (*handler[LASTEvent])(XEvent *) = { | |
| static DC dc; | |
| static XWindow xw; | |
| static Term term; | |
| -static CSIEscape escseq; | |
| +static CSIEscape csiescseq; | |
| +static STREscape strescseq; | |
| static int cmdfd; | |
| static pid_t pid; | |
| static Selection sel; | |
| t@@ -968,22 +982,22 @@ tnewline(int first_col) { | |
| void | |
| csiparse(void) { | |
| /* int noarg = 1; */ | |
| - char *p = escseq.buf; | |
| + char *p = csiescseq.buf; | |
| - escseq.narg = 0; | |
| + csiescseq.narg = 0; | |
| if(*p == '?') | |
| - escseq.priv = 1, p++; | |
| + csiescseq.priv = 1, p++; | |
| - while(p < escseq.buf+escseq.len) { | |
| + while(p < csiescseq.buf+csiescseq.len) { | |
| while(isdigit(*p)) { | |
| - escseq.arg[escseq.narg] *= 10; | |
| - escseq.arg[escseq.narg] += *p++ - '0'/*, noarg = 0 */; | |
| + csiescseq.arg[csiescseq.narg] *= 10; | |
| + csiescseq.arg[csiescseq.narg] += *p++ - '0'/*, noarg =… | |
| } | |
| - if(*p == ';' && escseq.narg+1 < ESC_ARG_SIZ) | |
| - escseq.narg++, p++; | |
| + if(*p == ';' && csiescseq.narg+1 < ESC_ARG_SIZ) | |
| + csiescseq.narg++, p++; | |
| else { | |
| - escseq.mode = *p; | |
| - escseq.narg++; | |
| + csiescseq.mode = *p; | |
| + csiescseq.narg++; | |
| return; | |
| } | |
| } | |
| t@@ -1166,7 +1180,7 @@ tsetscroll(int t, int b) { | |
| void | |
| csihandle(void) { | |
| - switch(escseq.mode) { | |
| + switch(csiescseq.mode) { | |
| default: | |
| unknown: | |
| fprintf(stderr, "erresc: unknown csi "); | |
| t@@ -1174,37 +1188,37 @@ csihandle(void) { | |
| /* die(""); */ | |
| break; | |
| case '@': /* ICH -- Insert <n> blank char */ | |
| - DEFAULT(escseq.arg[0], 1); | |
| - tinsertblank(escseq.arg[0]); | |
| + DEFAULT(csiescseq.arg[0], 1); | |
| + tinsertblank(csiescseq.arg[0]); | |
| break; | |
| case 'A': /* CUU -- Cursor <n> Up */ | |
| case 'e': | |
| - DEFAULT(escseq.arg[0], 1); | |
| - tmoveto(term.c.x, term.c.y-escseq.arg[0]); | |
| + DEFAULT(csiescseq.arg[0], 1); | |
| + tmoveto(term.c.x, term.c.y-csiescseq.arg[0]); | |
| break; | |
| case 'B': /* CUD -- Cursor <n> Down */ | |
| - DEFAULT(escseq.arg[0], 1); | |
| - tmoveto(term.c.x, term.c.y+escseq.arg[0]); | |
| + DEFAULT(csiescseq.arg[0], 1); | |
| + tmoveto(term.c.x, term.c.y+csiescseq.arg[0]); | |
| break; | |
| case 'C': /* CUF -- Cursor <n> Forward */ | |
| case 'a': | |
| - DEFAULT(escseq.arg[0], 1); | |
| - tmoveto(term.c.x+escseq.arg[0], term.c.y); | |
| + DEFAULT(csiescseq.arg[0], 1); | |
| + tmoveto(term.c.x+csiescseq.arg[0], term.c.y); | |
| break; | |
| case 'D': /* CUB -- Cursor <n> Backward */ | |
| - DEFAULT(escseq.arg[0], 1); | |
| - tmoveto(term.c.x-escseq.arg[0], term.c.y); | |
| + DEFAULT(csiescseq.arg[0], 1); | |
| + tmoveto(term.c.x-csiescseq.arg[0], term.c.y); | |
| break; | |
| case 'E': /* CNL -- Cursor <n> Down and first col */ | |
| - DEFAULT(escseq.arg[0], 1); | |
| - tmoveto(0, term.c.y+escseq.arg[0]); | |
| + DEFAULT(csiescseq.arg[0], 1); | |
| + tmoveto(0, term.c.y+csiescseq.arg[0]); | |
| break; | |
| case 'F': /* CPL -- Cursor <n> Up and first col */ | |
| - DEFAULT(escseq.arg[0], 1); | |
| - tmoveto(0, term.c.y-escseq.arg[0]); | |
| + DEFAULT(csiescseq.arg[0], 1); | |
| + tmoveto(0, term.c.y-csiescseq.arg[0]); | |
| break; | |
| case 'g': /* TBC -- Tabulation clear */ | |
| - switch (escseq.arg[0]) { | |
| + switch (csiescseq.arg[0]) { | |
| case 0: /* clear current tab stop */ | |
| term.tabs[term.c.x] = 0; | |
| break; | |
| t@@ -1217,23 +1231,23 @@ csihandle(void) { | |
| break; | |
| case 'G': /* CHA -- Move to <col> */ | |
| case '`': /* XXX: HPA -- same? */ | |
| - DEFAULT(escseq.arg[0], 1); | |
| - tmoveto(escseq.arg[0]-1, term.c.y); | |
| + DEFAULT(csiescseq.arg[0], 1); | |
| + tmoveto(csiescseq.arg[0]-1, term.c.y); | |
| break; | |
| case 'H': /* CUP -- Move to <row> <col> */ | |
| case 'f': /* XXX: HVP -- same? */ | |
| - DEFAULT(escseq.arg[0], 1); | |
| - DEFAULT(escseq.arg[1], 1); | |
| - tmoveto(escseq.arg[1]-1, escseq.arg[0]-1); | |
| + DEFAULT(csiescseq.arg[0], 1); | |
| + DEFAULT(csiescseq.arg[1], 1); | |
| + tmoveto(csiescseq.arg[1]-1, csiescseq.arg[0]-1); | |
| break; | |
| case 'I': /* CHT -- Cursor Forward Tabulation <n> tab stops */ | |
| - DEFAULT(escseq.arg[0], 1); | |
| - while (escseq.arg[0]--) | |
| + DEFAULT(csiescseq.arg[0], 1); | |
| + while (csiescseq.arg[0]--) | |
| tputtab(); | |
| break; | |
| case 'J': /* ED -- Clear screen */ | |
| sel.bx = -1; | |
| - switch(escseq.arg[0]) { | |
| + switch(csiescseq.arg[0]) { | |
| case 0: /* below */ | |
| tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); | |
| if(term.c.y < term.row-1) | |
| t@@ -1252,7 +1266,7 @@ csihandle(void) { | |
| } | |
| break; | |
| case 'K': /* EL -- Clear line */ | |
| - switch(escseq.arg[0]) { | |
| + switch(csiescseq.arg[0]) { | |
| case 0: /* right */ | |
| tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); | |
| break; | |
| t@@ -1265,20 +1279,20 @@ csihandle(void) { | |
| } | |
| break; | |
| case 'S': /* SU -- Scroll <n> line up */ | |
| - DEFAULT(escseq.arg[0], 1); | |
| - tscrollup(term.top, escseq.arg[0]); | |
| + DEFAULT(csiescseq.arg[0], 1); | |
| + tscrollup(term.top, csiescseq.arg[0]); | |
| break; | |
| case 'T': /* SD -- Scroll <n> line down */ | |
| - DEFAULT(escseq.arg[0], 1); | |
| - tscrolldown(term.top, escseq.arg[0]); | |
| + DEFAULT(csiescseq.arg[0], 1); | |
| + tscrolldown(term.top, csiescseq.arg[0]); | |
| break; | |
| case 'L': /* IL -- Insert <n> blank lines */ | |
| - DEFAULT(escseq.arg[0], 1); | |
| - tinsertblankline(escseq.arg[0]); | |
| + DEFAULT(csiescseq.arg[0], 1); | |
| + tinsertblankline(csiescseq.arg[0]); | |
| break; | |
| case 'l': /* RM -- Reset Mode */ | |
| - if(escseq.priv) { | |
| - switch(escseq.arg[0]) { | |
| + if(csiescseq.priv) { | |
| + switch(csiescseq.arg[0]) { | |
| case 1: | |
| term.mode &= ~MODE_APPKEYPAD; | |
| break; | |
| t@@ -1312,7 +1326,7 @@ csihandle(void) { | |
| tclearregion(0, 0, term.col-1, term.ro… | |
| tswapscreen(); | |
| } | |
| - if(escseq.arg[0] != 1049) | |
| + if(csiescseq.arg[0] != 1049) | |
| break; | |
| case 1048: | |
| tcursor(CURSOR_LOAD); | |
| t@@ -1321,7 +1335,7 @@ csihandle(void) { | |
| goto unknown; | |
| } | |
| } else { | |
| - switch(escseq.arg[0]) { | |
| + switch(csiescseq.arg[0]) { | |
| case 4: | |
| term.mode &= ~MODE_INSERT; | |
| break; | |
| t@@ -1331,25 +1345,25 @@ csihandle(void) { | |
| } | |
| break; | |
| case 'M': /* DL -- Delete <n> lines */ | |
| - DEFAULT(escseq.arg[0], 1); | |
| - tdeleteline(escseq.arg[0]); | |
| + DEFAULT(csiescseq.arg[0], 1); | |
| + tdeleteline(csiescseq.arg[0]); | |
| break; | |
| case 'X': /* ECH -- Erase <n> char */ | |
| - DEFAULT(escseq.arg[0], 1); | |
| - tclearregion(term.c.x, term.c.y, term.c.x + escseq.arg[0], ter… | |
| + DEFAULT(csiescseq.arg[0], 1); | |
| + tclearregion(term.c.x, term.c.y, term.c.x + csiescseq.arg[0], … | |
| break; | |
| case 'P': /* DCH -- Delete <n> char */ | |
| - DEFAULT(escseq.arg[0], 1); | |
| - tdeletechar(escseq.arg[0]); | |
| + DEFAULT(csiescseq.arg[0], 1); | |
| + tdeletechar(csiescseq.arg[0]); | |
| break; | |
| /* XXX: (CSI n Z) CBT -- Cursor Backward Tabulation <n> tab stops */ | |
| case 'd': /* VPA -- Move to <row> */ | |
| - DEFAULT(escseq.arg[0], 1); | |
| - tmoveto(term.c.x, escseq.arg[0]-1); | |
| + DEFAULT(csiescseq.arg[0], 1); | |
| + tmoveto(term.c.x, csiescseq.arg[0]-1); | |
| break; | |
| case 'h': /* SM -- Set terminal mode */ | |
| - if(escseq.priv) { | |
| - switch(escseq.arg[0]) { | |
| + if(csiescseq.priv) { | |
| + switch(csiescseq.arg[0]) { | |
| case 1: | |
| term.mode |= MODE_APPKEYPAD; | |
| break; | |
| t@@ -1367,7 +1381,7 @@ csihandle(void) { | |
| break; | |
| case 12: /* att610 -- Start blinking cursor (IGNORED) … | |
| /* fallthrough for xterm cvvis = CSI [ ? 12 ;… | |
| - if(escseq.narg > 1 && escseq.arg[1] != 25) | |
| + if(csiescseq.narg > 1 && csiescseq.arg[1] != 2… | |
| break; | |
| case 25: | |
| term.c.state &= ~CURSOR_HIDE; | |
| t@@ -1385,7 +1399,7 @@ csihandle(void) { | |
| tclearregion(0, 0, term.col-1, term.ro… | |
| else | |
| tswapscreen(); | |
| - if(escseq.arg[0] != 1049) | |
| + if(csiescseq.arg[0] != 1049) | |
| break; | |
| case 1048: | |
| tcursor(CURSOR_SAVE); | |
| t@@ -1393,7 +1407,7 @@ csihandle(void) { | |
| default: goto unknown; | |
| } | |
| } else { | |
| - switch(escseq.arg[0]) { | |
| + switch(csiescseq.arg[0]) { | |
| case 4: | |
| term.mode |= MODE_INSERT; | |
| break; | |
| t@@ -1402,15 +1416,15 @@ csihandle(void) { | |
| }; | |
| break; | |
| case 'm': /* SGR -- Terminal attribute (color) */ | |
| - tsetattr(escseq.arg, escseq.narg); | |
| + tsetattr(csiescseq.arg, csiescseq.narg); | |
| break; | |
| case 'r': /* DECSTBM -- Set Scrolling Region */ | |
| - if(escseq.priv) | |
| + if(csiescseq.priv) | |
| goto unknown; | |
| else { | |
| - DEFAULT(escseq.arg[0], 1); | |
| - DEFAULT(escseq.arg[1], term.row); | |
| - tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1); | |
| + DEFAULT(csiescseq.arg[0], 1); | |
| + DEFAULT(csiescseq.arg[1], term.row); | |
| + tsetscroll(csiescseq.arg[0]-1, csiescseq.arg[1]-1); | |
| tmoveto(0, 0); | |
| } | |
| break; | |
| t@@ -1427,8 +1441,8 @@ void | |
| csidump(void) { | |
| int i; | |
| printf("ESC["); | |
| - for(i = 0; i < escseq.len; i++) { | |
| - uint c = escseq.buf[i] & 0xff; | |
| + for(i = 0; i < csiescseq.len; i++) { | |
| + uint c = csiescseq.buf[i] & 0xff; | |
| if(isprint(c)) putchar(c); | |
| else if(c == '\n') printf("(\\n)"); | |
| else if(c == '\r') printf("(\\r)"); | |
| t@@ -1440,7 +1454,80 @@ csidump(void) { | |
| void | |
| csireset(void) { | |
| - memset(&escseq, 0, sizeof(escseq)); | |
| + memset(&csiescseq, 0, sizeof(csiescseq)); | |
| +} | |
| + | |
| +void | |
| +strhandle(void) { | |
| + char *p; | |
| + | |
| + p = strescseq.buf; | |
| + | |
| + switch(strescseq.type) { | |
| + case ']': /* OSC -- Operating System Command */ | |
| + switch(p[0]) { | |
| + case '0': | |
| + case '2': | |
| + /* | |
| + * TODO: Handle special chars in string, like umlauts. | |
| + */ | |
| + if(p[1] == ';') { | |
| + if(!strncmp(strescseq.buf, "settitle ", 9)) { | |
| + XStoreName(xw.dpy, xw.win, strescseq.b… | |
| + } else { | |
| + XStoreName(xw.dpy, xw.win, strescseq.b… | |
| + } | |
| + } | |
| + break; | |
| + case ';': | |
| + XStoreName(xw.dpy, xw.win, strescseq.buf+1); | |
| + break; | |
| + case '4': /* TODO: Set color (arg0) to "rgb:%hexr/$hexg/$hexb"… | |
| + break; | |
| + default: | |
| + fprintf(stderr, "erresc: unknown str "); | |
| + strdump(); | |
| + break; | |
| + } | |
| + break; | |
| + case 'P': /* DSC -- Device Control String */ | |
| + case '_': /* APC -- Application Program Command */ | |
| + case '^': /* PM -- Privacy Message */ | |
| + default: | |
| + fprintf(stderr, "erresc: unknown str "); | |
| + strdump(); | |
| + /* die(""); */ | |
| + break; | |
| + } | |
| +} | |
| + | |
| +void | |
| +strparse(void) { | |
| + /* | |
| + * TODO: Implement parsing like for CSI when required. | |
| + * Format: ESC type cmd ';' arg0 [';' argn] ESC \ | |
| + */ | |
| + return; | |
| +} | |
| + | |
| +void | |
| +strdump(void) { | |
| + int i; | |
| + printf("ESC%c", strescseq.type); | |
| + for(i = 0; i < strescseq.len; i++) { | |
| + uint c = strescseq.buf[i] & 0xff; | |
| + if(isprint(c)) putchar(c); | |
| + else if(c == '\n') printf("(\\n)"); | |
| + else if(c == '\r') printf("(\\r)"); | |
| + else if(c == 0x1b) printf("(\\e)"); | |
| + else printf("(%02x)", c); | |
| + } | |
| + printf("ESC\\\n"); | |
| +} | |
| + | |
| +void | |
| +strreset(void) { | |
| + memset(&strescseq, 0, sizeof(strescseq)); | |
| } | |
| void | |
| t@@ -1457,25 +1544,31 @@ tputc(char *c) { | |
| char ascii = *c; | |
| if(term.esc & ESC_START) { | |
| if(term.esc & ESC_CSI) { | |
| - escseq.buf[escseq.len++] = ascii; | |
| - if(BETWEEN(ascii, 0x40, 0x7E) || escseq.len >= ESC_BUF… | |
| + csiescseq.buf[csiescseq.len++] = ascii; | |
| + if(BETWEEN(ascii, 0x40, 0x7E) || csiescseq.len >= ESC_… | |
| term.esc = 0; | |
| csiparse(), csihandle(); | |
| } | |
| - /* TODO: handle other OSC */ | |
| - } else if(term.esc & ESC_OSC) { | |
| - if(ascii == ';') { | |
| - term.titlelen = 0; | |
| - term.esc = ESC_START | ESC_TITLE; | |
| - } | |
| - } else if(term.esc & ESC_TITLE) { | |
| - if(ascii == '\a' || term.titlelen+1 >= ESC_TITLE_SIZ) { | |
| + } else if(term.esc & ESC_STR) { | |
| + switch(ascii) { | |
| + case '\033': | |
| + term.esc = ESC_START | ESC_STR_END; | |
| + break; | |
| + case '\a': /* backwards compatibility to xterm */ | |
| term.esc = 0; | |
| - term.title[term.titlelen] = '\0'; | |
| - XStoreName(xw.dpy, xw.win, term.title); | |
| - } else { | |
| - term.title[term.titlelen++] = ascii; | |
| + strhandle(); | |
| + break; | |
| + default: | |
| + strescseq.buf[strescseq.len++] = ascii; | |
| + if (strescseq.len+1 >= STR_BUF_SIZ) { | |
| + term.esc = 0; | |
| + strhandle(); | |
| + } | |
| } | |
| + } else if(term.esc & ESC_STR_END) { | |
| + term.esc = 0; | |
| + if(ascii == '\\') | |
| + strhandle(); | |
| } else if(term.esc & ESC_ALTCHARSET) { | |
| switch(ascii) { | |
| case '0': /* Line drawing crap */ | |
| t@@ -1493,8 +1586,13 @@ tputc(char *c) { | |
| case '[': | |
| term.esc |= ESC_CSI; | |
| break; | |
| - case ']': | |
| - term.esc |= ESC_OSC; | |
| + case 'P': /* DCS -- Device Control String */ | |
| + case '_': /* APC -- Application Program Command */ | |
| + case '^': /* PM -- Privacy Message */ | |
| + case ']': /* OSC -- Operating System Command */ | |
| + strreset(); | |
| + strescseq.type = ascii; | |
| + term.esc |= ESC_STR; | |
| break; | |
| case '(': | |
| term.esc |= ESC_ALTCHARSET; | |
| t@@ -1541,6 +1639,9 @@ tputc(char *c) { | |
| tcursor(CURSOR_LOAD); | |
| term.esc = 0; | |
| break; | |
| + case '\\': /* ST -- Stop */ | |
| + term.esc = 0; | |
| + break; | |
| default: | |
| fprintf(stderr, "erresc: unknown sequence ESC … | |
| (uchar) ascii, isprint(ascii)?ascii:'.'); |