tMerge remote-tracking branch 'upstream/master' - st - [fork] customized build of st, the simple terminal
 (HTM) git clone git://src.adamsgaard.dk/st
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 8d971068c60f64dee3e8751b54548d86f6fecd6f
 (DIR) parent 643585f3d771e48023ce469a5cd4e1a848c84e18
 (HTM) Author: Anders Damsgaard <anders@adamsgaard.dk>
       Date:   Fri, 19 Jun 2020 13:47:33 +0200
       
       Merge remote-tracking branch 'upstream/master'
       
       Diffstat:
         M FAQ                                 |      59 ++++++++++++++++++++++++++++---
         M LICENSE                             |       2 +-
         M config.def.h                        |       4 ++++
         M config.mk                           |       6 +++---
         M st.c                                |      42 +++++++++++++------------------
         M st.h                                |       1 +
         M st.info                             |       2 ++
         M x.c                                 |       9 ++++-----
       
       8 files changed, 86 insertions(+), 39 deletions(-)
       ---
 (DIR) diff --git a/FAQ b/FAQ
       t@@ -2,12 +2,14 @@
        
        Use the excellent tool of [utmp](https://git.suckless.org/utmp/) for this task.
        
       +
        ## Some _random program_ complains that st is unknown/not recognised/unsupported/whatever!
        
        It means that st doesn’t have any terminfo entry on your system. Chances are
        you did not `make install`. If you just want to test it without installing it,
        you can manually run `tic -sx st.info`.
        
       +
        ## Nothing works, and nothing is said about an unknown terminal!
        
        * Some programs just assume they’re running in xterm i.e. they don’t rely on
       t@@ -15,6 +17,7 @@ you can manually run `tic -sx st.info`.
        * Some programs don’t complain about the lacking st description and default to
          another terminal. In that case see the question about terminfo.
        
       +
        ## How do I scroll back up?
        
        * Using a terminal multiplexer.
       t@@ -23,11 +26,13 @@ you can manually run `tic -sx st.info`.
        * Using the excellent tool of [scroll](https://git.suckless.org/scroll/).
        * Using the scrollback [patch](https://st.suckless.org/patches/scrollback/).
        
       +
        ## I would like to have utmp and/or scroll functionality by default
        
        You can add the absolute patch of both programs in your config.h
        file. You only have to modify the value of utmp and scroll variables.
        
       +
        ## Why doesn't the Del key work in some programs?
        
        Taken from the terminfo manpage:
       t@@ -83,12 +88,14 @@ If you are using zsh, then read the zsh FAQ
        
        Putting these lines into your .zshrc will fix the problems.
        
       +
        ## How can I use meta in 8bit mode?
        
        St supports meta in 8bit mode, but the default terminfo entry doesn't
        use this capability. If you want it, you have to use the 'st-meta' value
        in TERM.
        
       +
        ## I cannot compile st in OpenBSD
        
        OpenBSD lacks librt, despite it being mandatory in POSIX
       t@@ -97,6 +104,7 @@ If you want to compile st for OpenBSD you have to remove -lrt from config.mk, an
        st will compile without any loss of functionality, because all the functions are
        included in libc on this platform.
        
       +
        ## The Backspace Case
        
        St is emulating the Linux way of handling backspace being delete and delete being
       t@@ -158,19 +166,60 @@ terminal users wants its backspace to be how he feels it:
                [1] http://www.ibb.net/~anne/keyboard.html
                [2] http://www.tldp.org/HOWTO/Keyboard-and-Console-HOWTO-5.html
        
       +
        ## But I really want the old grumpy behaviour of my terminal
        
        Apply [1].
        
        [1] https://st.suckless.org/patches/delkey
        
       -## Why do images not work in st (in programs such as w3m)?
        
       -This is a terrible hack that overdraws an image on top of the terminal emulator
       -window. It also relies on a very specific way the terminal draws it's contents.
       +## Why do images not work in st using the w3m image hack?
       +
       +w3mimg uses a hack that draws an image on top of the terminal emulator Drawable
       +window. The hack relies on the terminal to use a single buffer to draw its
       +contents directly.
       +
       +st uses double-buffered drawing so the image is quickly replaced and may show a
       +short flicker effect.
       +
       +Below is a patch example to change st double-buffering to a single Drawable
       +buffer.
       +
       +diff --git a/x.c b/x.c
       +--- a/x.c
       ++++ b/x.c
       +@@ -732,10 +732,6 @@ xresize(int col, int row)
       +         win.tw = col * win.cw;
       +         win.th = row * win.ch;
       + 
       +-        XFreePixmap(xw.dpy, xw.buf);
       +-        xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
       +-                        DefaultDepth(xw.dpy, xw.scr));
       +-        XftDrawChange(xw.draw, xw.buf);
       +         xclear(0, 0, win.w, win.h);
       + 
       +         /* resize to new width */
       +@@ -1148,8 +1144,7 @@ xinit(int cols, int rows)
       +         gcvalues.graphics_exposures = False;
       +         dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
       +                         &gcvalues);
       +-        xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
       +-                        DefaultDepth(xw.dpy, xw.scr));
       ++        xw.buf = xw.win;
       +         XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
       +         XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
       + 
       +@@ -1632,8 +1627,6 @@ xdrawline(Line line, int x1, int y1, int x2)
       + void
       + xfinishdraw(void)
       + {
       +-        XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w,
       +-                        win.h, 0, 0);
       +         XSetForeground(xw.dpy, dc.gc,
       +                         dc.col[IS_SET(MODE_REVERSE)?
       +                                 defaultfg : defaultbg].pixel);
        
       -A more proper (but limited way) would be using sixels. Which st doesn't
       -support.
        
        ## BadLength X error in Xft when trying to render emoji
        
 (DIR) diff --git a/LICENSE b/LICENSE
       t@@ -1,7 +1,7 @@
        MIT/X Consortium License
        
        © 2019-2020 Anders Damsgaard <anders at adamsgaard dot dk>
       -© 2014-2018 Hiltjo Posthuma <hiltjo at codemadness dot org>
       +© 2014-2020 Hiltjo Posthuma <hiltjo at codemadness dot org>
        © 2018 Devin J. Pohly <djpohly at gmail dot com>
        © 2014-2017 Quentin Rameau <quinq at fifth dot space>
        © 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com>
 (DIR) diff --git a/config.def.h b/config.def.h
       t@@ -43,6 +43,10 @@ static unsigned int tripleclicktimeout = 600;
        /* alt screens */
        int allowaltscreen = 1;
        
       +/* allow certain non-interactive (insecure) window operations such as:
       +   setting the clipboard text */
       +int allowwindowops = 0;
       +
        /*
         * draw latency range in ms - from new content/keypress/etc until drawing.
         * within this range, st draws when content stops arriving (idle). mostly it's
 (DIR) diff --git a/config.mk b/config.mk
       t@@ -1,5 +1,5 @@
        # st version
       -VERSION = 0.8.3
       +VERSION = 0.8.4
        
        # Customize below to fit your system
        
       t@@ -28,8 +28,8 @@ STLDFLAGS = $(LIBS) $(LDFLAGS)
        # OpenBSD:
        CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE
        LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \
       -       `pkg-config --libs fontconfig` \
       -       `pkg-config --libs freetype2`
       +       `$(PKG_CONFIG) --libs fontconfig` \
       +       `$(PKG_CONFIG) --libs freetype2`
        
        # compiler and linker
        # CC = c99
 (DIR) diff --git a/st.c b/st.c
       t@@ -51,7 +51,6 @@ enum term_mode {
                MODE_ECHO        = 1 << 4,
                MODE_PRINT       = 1 << 5,
                MODE_UTF8        = 1 << 6,
       -        MODE_SIXEL       = 1 << 7,
        };
        
        enum cursor_movement {
       t@@ -78,12 +77,11 @@ enum charset {
        enum escape_state {
                ESC_START      = 1,
                ESC_CSI        = 2,
       -        ESC_STR        = 4,  /* OSC, PM, APC */
       +        ESC_STR        = 4,  /* DCS, OSC, PM, APC */
                ESC_ALTCHARSET = 8,
                ESC_STR_END    = 16, /* a final string was encountered */
                ESC_TEST       = 32, /* Enter in test mode */
                ESC_UTF8       = 64,
       -        ESC_DCS        =128,
        };
        
        typedef struct {
       t@@ -129,6 +127,7 @@ typedef struct {
                int charset;  /* current charset */
                int icharset; /* selected charset for sequence */
                int *tabs;
       +        Rune lastc;   /* last printed char outside of sequence, 0 if control */
        } Term;
        
        /* CSI Escape sequence structs */
       t@@ -842,7 +841,6 @@ ttyread(void)
                        if (buflen > 0)
                                memmove(buf, buf + written, buflen);
                        return ret;
       -
                }
        }
        
       t@@ -1648,6 +1646,12 @@ csihandle(void)
                        if (csiescseq.arg[0] == 0)
                                ttywrite(vtiden, strlen(vtiden), 0);
                        break;
       +        case 'b': /* REP -- if last char is printable print it <n> more times */
       +                DEFAULT(csiescseq.arg[0], 1);
       +                if (term.lastc)
       +                        while (csiescseq.arg[0]-- > 0)
       +                                tputc(term.lastc);
       +                break;
                case 'C': /* CUF -- Cursor <n> Forward */
                case 'a': /* HPR -- Cursor <n> Forward */
                        DEFAULT(csiescseq.arg[0], 1);
       t@@ -1771,7 +1775,7 @@ csihandle(void)
                        break;
                case 'n': /* DSR – Device Status Report (cursor position) */
                        if (csiescseq.arg[0] == 6) {
       -                        len = snprintf(buf, sizeof(buf),"\033[%i;%iR",
       +                        len = snprintf(buf, sizeof(buf), "\033[%i;%iR",
                                                term.c.y+1, term.c.x+1);
                                ttywrite(buf, len, 0);
                        }
       t@@ -1855,7 +1859,7 @@ strhandle(void)
                                        xsettitle(strescseq.args[1]);
                                return;
                        case 52:
       -                        if (narg > 2) {
       +                        if (narg > 2 && allowwindowops) {
                                        dec = base64dec(strescseq.args[2]);
                                        if (dec) {
                                                xsetsel(dec);
       t@@ -1891,7 +1895,6 @@ strhandle(void)
                        xsettitle(strescseq.args[0]);
                        return;
                case 'P': /* DCS -- Device Control String */
       -                term.mode |= ESC_DCS;
                case '_': /* APC -- Application Program Command */
                case '^': /* PM -- Privacy Message */
                        return;
       t@@ -2085,12 +2088,9 @@ tdectest(char c)
        void
        tstrsequence(uchar c)
        {
       -        strreset();
       -
                switch (c) {
                case 0x90:   /* DCS -- Device Control String */
                        c = 'P';
       -                term.esc |= ESC_DCS;
                        break;
                case 0x9f:   /* APC -- Application Program Command */
                        c = '_';
       t@@ -2102,6 +2102,7 @@ tstrsequence(uchar c)
                        c = ']';
                        break;
                }
       +        strreset();
                strescseq.type = c;
                term.esc |= ESC_STR;
        }
       t@@ -2299,7 +2300,7 @@ tputc(Rune u)
                Glyph *gp;
        
                control = ISCONTROL(u);
       -        if (u < 127 || !IS_SET(MODE_UTF8 | MODE_SIXEL)) {
       +        if (u < 127 || !IS_SET(MODE_UTF8)) {
                        c[0] = u;
                        width = len = 1;
                } else {
       t@@ -2320,23 +2321,11 @@ tputc(Rune u)
                if (term.esc & ESC_STR) {
                        if (u == '\a' || u == 030 || u == 032 || u == 033 ||
                           ISCONTROLC1(u)) {
       -                        term.esc &= ~(ESC_START|ESC_STR|ESC_DCS);
       -                        if (IS_SET(MODE_SIXEL)) {
       -                                /* TODO: render sixel */;
       -                                term.mode &= ~MODE_SIXEL;
       -                                return;
       -                        }
       +                        term.esc &= ~(ESC_START|ESC_STR);
                                term.esc |= ESC_STR_END;
                                goto check_control_code;
                        }
        
       -                if (IS_SET(MODE_SIXEL)) {
       -                        /* TODO: implement sixel mode */
       -                        return;
       -                }
       -                if (term.esc&ESC_DCS && strescseq.len == 0 && u == 'q')
       -                        term.mode |= MODE_SIXEL;
       -
                        if (strescseq.len+len >= strescseq.siz) {
                                /*
                                 * Here is a bug in terminals. If the user never sends
       t@@ -2373,6 +2362,8 @@ check_control_code:
                        /*
                         * control codes are not shown ever
                         */
       +                if (!term.esc)
       +                        term.lastc = 0;
                        return;
                } else if (term.esc & ESC_START) {
                        if (term.esc & ESC_CSI) {
       t@@ -2422,6 +2413,7 @@ check_control_code:
                }
        
                tsetchar(u, &term.c.attr, term.c.x, term.c.y);
       +        term.lastc = u;
        
                if (width == 2) {
                        gp->mode |= ATTR_WIDE;
       t@@ -2445,7 +2437,7 @@ twrite(const char *buf, int buflen, int show_ctrl)
                int n;
        
                for (n = 0; n < buflen; n += charsize) {
       -                if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
       +                if (IS_SET(MODE_UTF8)) {
                                /* process a complete utf8 char */
                                charsize = utf8decode(buf + n, &u, buflen - n);
                                if (charsize == 0)
 (DIR) diff --git a/st.h b/st.h
       t@@ -118,6 +118,7 @@ extern char *stty_args;
        extern char *vtiden;
        extern wchar_t *worddelimiters;
        extern int allowaltscreen;
       +extern int allowwindowops;
        extern char *termname;
        extern unsigned int tabspaces;
        extern unsigned int defaultfg;
 (DIR) diff --git a/st.info b/st.info
       t@@ -184,6 +184,8 @@ st-mono| simpleterm monocolor,
        # XTerm extensions
                rmxx=\E[29m,
                smxx=\E[9m,
       +# disabled rep for now: causes some issues with older ncurses versions.
       +#        rep=%p1%c\E[%p2%{1}%-%db,
        # tmux extensions, see TERMINFO EXTENSIONS in tmux(1)
                Tc,
                Ms=\E]52;%p1%s;%p2%s\007,
 (DIR) diff --git a/x.c b/x.c
       t@@ -1566,8 +1566,8 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
                /* draw the new one */
                if (IS_SET(MODE_FOCUSED)) {
                        switch (win.cursor) {
       -                case 7: /* st extension: snowman (U+2603) */
       -                        g.u = 0x2603;
       +                case 7: /* st extension */
       +                        g.u = 0x2603; /* snowman (U+2603) */
                                /* FALLTHROUGH */
                        case 0: /* Blinking Block */
                        case 1: /* Blinking Block (Default) */
       t@@ -1730,8 +1730,7 @@ xsetmode(int set, unsigned int flags)
        int
        xsetcursor(int cursor)
        {
       -        DEFAULT(cursor, 1);
       -        if (!BETWEEN(cursor, 0, 6))
       +        if (!BETWEEN(cursor, 0, 7)) /* 7: st extension */
                        return 1;
                win.cursor = cursor;
                return 0;
       t@@ -2023,7 +2022,7 @@ main(int argc, char *argv[])
        {
                xw.l = xw.t = 0;
                xw.isfixed = False;
       -        win.cursor = cursorshape;
       +        xsetcursor(cursorshape);
        
                ARGBEGIN {
                case 'a':