JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
Add support for multiple charset definitions
[st.git] / st.c
diff --git a/st.c b/st.c
index 4a91073..77ea0c8 100644 (file)
--- a/st.c
+++ b/st.c
@@ -132,10 +132,21 @@ enum term_mode {
        MODE_FOCUS       = 65536,
        MODE_MOUSEX10    = 131072,
        MODE_MOUSEMANY   = 262144,
+       MODE_BRCKTPASTE  = 524288,
        MODE_MOUSE       = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
                          |MODE_MOUSEMANY,
 };
 
+enum charset {
+       CS_GRAPHIC0,
+       CS_GRAPHIC1,
+       CS_UK,
+       CS_USA,
+       CS_MULTI,
+       CS_GER,
+       CS_FIN
+};
+
 enum escape_state {
        ESC_START      = 1,
        ESC_CSI        = 2,
@@ -215,6 +226,9 @@ typedef struct {
        int bot;      /* bottom scroll limit */
        int mode;     /* terminal mode flags */
        int esc;      /* escape state flags */
+       char trantbl[4]; /* charset table translation */
+       int charset;  /* current charset */
+       int icharset; /* selected charset for sequence */
        bool numlock; /* lock numbers in keyboard */
        bool *tabs;
 } Term;
@@ -366,6 +380,8 @@ static void tsetmode(bool, bool, int *, int);
 static void tfulldirt(void);
 static void techo(char *, int);
 static long tdefcolor(int *, int *, int);
+static void tselcs(void);
+static void tdeftran(char);
 static inline bool match(uint, uint);
 static void ttynew(void);
 static void ttyread(void);
@@ -823,18 +839,23 @@ mousereport(XEvent *e) {
                button = oldbutton + 32;
                ox = x;
                oy = y;
-       } else if(!IS_SET(MODE_MOUSESGR)
-                       && (e->xbutton.type == ButtonRelease
-                               || button == AnyButton)) {
-               button = 3;
        } else {
-               button -= Button1;
-               if(button >= 3)
-                       button += 64 - 3;
+               if(!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) {
+                       button = 3;
+               } else {
+                       button -= Button1;
+                       if(button >= 3)
+                               button += 64 - 3;
+               }
                if(e->xbutton.type == ButtonPress) {
                        oldbutton = button;
                        ox = x;
                        oy = y;
+               } else if(e->xbutton.type == ButtonRelease) {
+                       oldbutton = 3;
+                       /* MODE_MOUSEX10: no button release reporting */
+                       if(IS_SET(MODE_MOUSEX10))
+                               return;
                }
        }
 
@@ -851,8 +872,7 @@ mousereport(XEvent *e) {
                                e->xbutton.type == ButtonRelease ? 'm' : 'M');
        } else if(x < 223 && y < 223) {
                len = snprintf(buf, sizeof(buf), "\033[M%c%c%c",
-                               IS_SET(MODE_MOUSEX10)? button-1 : 32+button,
-                               32+x+1, 32+y+1);
+                               32+button, 32+x+1, 32+y+1);
        } else {
                return;
        }
@@ -957,7 +977,7 @@ selcopy(void) {
                         * st.
                         * FIXME: Fix the computer world.
                         */
-                       if(y < sel.ne.y && !((gp-1)->mode & ATTR_WRAP))
+                       if(y < sel.ne.y && x > 0 && !((gp-1)->mode & ATTR_WRAP))
                                *ptr++ = '\n';
 
                        /*
@@ -1009,7 +1029,11 @@ selnotify(XEvent *e) {
                        *repl++ = '\r';
                }
 
+               if(IS_SET(MODE_BRCKTPASTE))
+                       ttywrite("\033[200~", 6);
                ttywrite((const char *)data, nitems * format / 8);
+               if(IS_SET(MODE_BRCKTPASTE))
+                       ttywrite("\033[201~", 6);
                XFree(data);
                /* number of 32-bit chunks returned */
                ofs += nitems * format / 32;
@@ -1333,13 +1357,14 @@ tfulldirt(void) {
 
 void
 tcursor(int mode) {
-       static TCursor c;
+       static TCursor c[2];
+       bool alt = IS_SET(MODE_ALTSCREEN);
 
        if(mode == CURSOR_SAVE) {
-               c = term.c;
+               c[alt] = term.c;
        } else if(mode == CURSOR_LOAD) {
-               term.c = c;
-               tmoveto(c.x, c.y);
+               term.c = c[alt];
+               tmoveto(c[alt].x, c[alt].y);
        }
 }
 
@@ -1359,6 +1384,8 @@ treset(void) {
        term.top = 0;
        term.bot = term.row - 1;
        term.mode = MODE_WRAP;
+       memset(term.trantbl, sizeof(term.trantbl), CS_USA);
+       term.charset = 0;
 
        tclearregion(0, 0, term.col-1, term.row-1);
        tmoveto(0, 0);
@@ -1845,12 +1872,12 @@ tsetmode(bool priv, bool set, int *args, int narg) {
                        case 1034:
                                MODBIT(term.mode, set, MODE_8BIT);
                                break;
-                       case 1049: /* = 1047 and 1048 */
-                       case 47:
+                       case 1049: /* swap screen & set/restore cursor as xterm */
+                               tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
+                       case 47: /* swap screen */
                        case 1047:
                                if (!allowaltscreen)
                                        break;
-
                                alt = IS_SET(MODE_ALTSCREEN);
                                if(alt) {
                                        tclearregion(0, 0, term.col-1,
@@ -1864,6 +1891,9 @@ tsetmode(bool priv, bool set, int *args, int narg) {
                        case 1048:
                                tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
                                break;
+                       case 2004: /* 2004: bracketed paste mode */
+                               MODBIT(term.mode, set, MODE_BRCKTPASTE);
+                               break;
                        /* Not implemented mouse modes. See comments there. */
                        case 1001: /* mouse highlight mode; can hang the
                                      terminal by design when implemented. */
@@ -1907,6 +1937,9 @@ tsetmode(bool priv, bool set, int *args, int narg) {
 
 void
 csihandle(void) {
+       char buf[40];
+       int len;
+
        switch(csiescseq.mode) {
        default:
        unknown:
@@ -2055,6 +2088,13 @@ csihandle(void) {
        case 'm': /* SGR -- Terminal attribute (color) */
                tsetattr(csiescseq.arg, csiescseq.narg);
                break;
+       case 'n': /* DSR – Device Status Report (cursor position) */
+               if (csiescseq.arg[0] == 6) {
+                       len = snprintf(buf, sizeof(buf),"\033[%i;%iR",
+                                       term.c.y+1, term.c.x+1);
+                       ttywrite(buf, len);
+                       break;
+               }
        case 'r': /* DECSTBM -- Set Scrolling Region */
                if(csiescseq.priv) {
                        goto unknown;
@@ -2237,6 +2277,33 @@ techo(char *buf, int len) {
 }
 
 void
+tdeftran(char ascii) {
+       char c, (*bp)[2];
+       static char tbl[][2] = {
+               {'0', CS_GRAPHIC0}, {'1', CS_GRAPHIC1}, {'A', CS_UK},
+               {'B', CS_USA},      {'<', CS_MULTI},    {'K', CS_GER},
+               {'5', CS_FIN},      {'C', CS_FIN},
+               {0, 0}
+       };
+
+       for (bp = &tbl[0]; (c = (*bp)[0]) && c != ascii; ++bp)
+               /* nothing */;
+
+       if (c == 0)
+               fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii);
+       else
+               term.trantbl[term.icharset] = (*bp)[1];
+}
+
+void
+tselcs(void) {
+       if (term.trantbl[term.charset] == CS_GRAPHIC0)
+               term.c.attr.mode |= ATTR_GFX;
+       else
+               term.c.attr.mode &= ~ATTR_GFX;
+}
+
+void
 tputc(char *c, int len) {
        uchar ascii = *c;
        bool control = ascii < '\x20' || ascii == 0177;
@@ -2328,13 +2395,12 @@ tputc(char *c, int len) {
                        term.esc = ESC_START;
                        return;
                case '\016': /* SO */
+                       term.charset = 0;
+                       tselcs();
+                       return;
                case '\017': /* SI */
-                       /*
-                        * Different charsets are hard to handle. Applications
-                        * should use the right alt charset escapes for the
-                        * only reason they still exist: line drawing. The
-                        * rest is incompatible history st should not support.
-                        */
+                       term.charset = 1;
+                       tselcs();
                        return;
                case '\032': /* SUB */
                case '\030': /* CAN */
@@ -2362,22 +2428,8 @@ tputc(char *c, int len) {
                        if(ascii == '\\')
                                strhandle();
                } else if(term.esc & ESC_ALTCHARSET) {
-                       switch(ascii) {
-                       case '0': /* Line drawing set */
-                               term.c.attr.mode |= ATTR_GFX;
-                               break;
-                       case 'B': /* USASCII */
-                               term.c.attr.mode &= ~ATTR_GFX;
-                               break;
-                       case 'A': /* UK (IGNORED) */
-                       case '<': /* multinational charset (IGNORED) */
-                       case '5': /* Finnish (IGNORED) */
-                       case 'C': /* Finnish (IGNORED) */
-                       case 'K': /* German (IGNORED) */
-                               break;
-                       default:
-                               fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii);
-                       }
+                       tdeftran(ascii);
+                       tselcs();
                        term.esc = 0;
                } else if(term.esc & ESC_TEST) {
                        if(ascii == '8') { /* DEC screen alignment test. */
@@ -2408,13 +2460,12 @@ tputc(char *c, int len) {
                                term.esc |= ESC_STR;
                                break;
                        case '(': /* set primary charset G0 */
+                       case ')': /* set secondary charset G1 */
+                       case '*': /* set tertiary charset G2 */
+                       case '+': /* set quaternary charset G3 */
+                               term.icharset = ascii - '(';
                                term.esc |= ESC_ALTCHARSET;
                                break;
-                       case ')': /* set secondary charset G1 (IGNORED) */
-                       case '*': /* set tertiary charset G2 (IGNORED) */
-                       case '+': /* set quaternary charset G3 (IGNORED) */
-                               term.esc = 0;
-                               break;
                        case 'D': /* IND -- Linefeed */
                                if(term.c.y == term.bot) {
                                        tscrollup(term.top, 1);