On Tue, Mar 20, 2018 at 07:14:48PM +0800, Pickfire wrote:
> "Devin J. Pohly" <[email protected]> wrote:
> >
> > This won't work - the Term instance is now internal to st.c, and IS_SET
> > in x.c refers to win.mode (on the TermWindow instance) which doesn't
> > contain MODE_ALTSCREEN.
> >
> > How about checking it in kscrollup/kscrolldown, over on the st.c side of
> > things?  (To be honest, the ^E/^Y behavior already seems like kind of a
> > compatibility hack for programs that lack actual mouse reporting.)
> >
> > *dp
> >
> >
> > -- 
> > <><
> 
> Ah, thanks a lot for the suggestion. That brings benefit as well which
> does not break other mouse keys.
> 
> But this patched I was already using it fine though, no issues here.
> 

The patch will apply fine but will simply not work as intended.  It
checks bit 2 of win.mode, which is MODE_APPKEYPAD, not MODE_ALTSCREEN.
Moving the enumeration into st.c after dividing up the mode bits helped
prevent mistaken use of the wrong ones by turning the mistake into a
compile error.

(I do like the way that scrollback implements mouse shortcuts though; it
feels more consistent and general.  I could possibly see that making it
into mainline.)

I've revised the scrollback patches to work well with the new code and
attached the result.  Not proposing these for mainline, but as an update
to the wiki patch.

*dp


-- 
<><
>From 02bedeff299cca383d81969850ee3054a53daa43 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <[email protected]>
Date: Mon, 19 Mar 2018 16:13:55 -0500
Subject: [PATCH 1/3] st-scrollback-0.8-2

---
 config.def.h |   2 ++
 st.c         | 105 ++++++++++++++++++++++++++++++++++++++++++++---------------
 st.h         |   8 +++++
 3 files changed, 89 insertions(+), 26 deletions(-)

diff --git a/config.def.h b/config.def.h
index 82b1b09..283fa5e 100644
--- a/config.def.h
+++ b/config.def.h
@@ -178,6 +178,8 @@ static Shortcut shortcuts[] = {
        { TERMMOD,              XK_Y,           selpaste,       {.i =  0} },
        { TERMMOD,              XK_Num_Lock,    numlock,        {.i =  0} },
        { TERMMOD,              XK_I,           iso14755,       {.i =  0} },
+       { ShiftMask,            XK_Page_Up,     kscrollpage,    {.i =  1} },
+       { ShiftMask,            XK_Page_Down,   kscrollpage,    {.i = -1} },
 };
 
 /*
diff --git a/st.c b/st.c
index 46c954b..78f3343 100644
--- a/st.c
+++ b/st.c
@@ -121,6 +121,9 @@ typedef struct {
        int col;      /* nb col */
        Line *line;   /* screen */
        Line *alt;    /* alternate screen */
+       Line hist[HISTSIZE]; /* history buffer */
+       int histi;    /* history index */
+       int scr;      /* scroll back */
        int *dirty;   /* dirtyness of lines */
        TCursor c;    /* cursor */
        int ocx;      /* old cursor col */
@@ -188,8 +191,8 @@ static void tnewline(int);
 static void tputtab(int);
 static void tputc(Rune);
 static void treset(void);
-static void tscrollup(int, int);
-static void tscrolldown(int, int);
+static void tscrollup(int, int, int);
+static void tscrolldown(int, int, int);
 static void tsetattr(int *, int);
 static void tsetchar(Rune, Glyph *, int, int);
 static void tsetdirt(int, int);
@@ -431,10 +434,10 @@ tlinelen(int y)
 {
        int i = term.col;
 
-       if (term.line[y][i - 1].mode & ATTR_WRAP)
+       if (TLINE(y)[i - 1].mode & ATTR_WRAP)
                return i;
 
-       while (i > 0 && term.line[y][i - 1].u == ' ')
+       while (i > 0 && TLINE(y)[i - 1].u == ' ')
                --i;
 
        return i;
@@ -543,7 +546,7 @@ selsnap(int *x, int *y, int direction)
                 * Snap around if the word wraps around at the end or
                 * beginning of a line.
                 */
-               prevgp = &term.line[*y][*x];
+               prevgp = &TLINE(*y)[*x];
                prevdelim = ISDELIM(prevgp->u);
                for (;;) {
                        newx = *x + direction;
@@ -558,14 +561,14 @@ selsnap(int *x, int *y, int direction)
                                        yt = *y, xt = *x;
                                else
                                        yt = newy, xt = newx;
-                               if (!(term.line[yt][xt].mode & ATTR_WRAP))
+                               if (!(TLINE(yt)[xt].mode & ATTR_WRAP))
                                        break;
                        }
 
                        if (newx >= tlinelen(newy))
                                break;
 
-                       gp = &term.line[newy][newx];
+                       gp = &TLINE(newy)[newx];
                        delim = ISDELIM(gp->u);
                        if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
                                        || (delim && gp->u != prevgp->u)))
@@ -586,14 +589,14 @@ selsnap(int *x, int *y, int direction)
                *x = (direction < 0) ? 0 : term.col - 1;
                if (direction < 0) {
                        for (; *y > 0; *y += direction) {
-                               if (!(term.line[*y-1][term.col-1].mode
+                               if (!(TLINE(*y-1)[term.col-1].mode
                                                & ATTR_WRAP)) {
                                        break;
                                }
                        }
                } else if (direction > 0) {
                        for (; *y < term.row-1; *y += direction) {
-                               if (!(term.line[*y][term.col-1].mode
+                               if (!(TLINE(*y)[term.col-1].mode
                                                & ATTR_WRAP)) {
                                        break;
                                }
@@ -624,13 +627,13 @@ getsel(void)
                }
 
                if (sel.type == SEL_RECTANGULAR) {
-                       gp = &term.line[y][sel.nb.x];
+                       gp = &TLINE(y)[sel.nb.x];
                        lastx = sel.ne.x;
                } else {
-                       gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0];
+                       gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0];
                        lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
                }
-               last = &term.line[y][MIN(lastx, linelen-1)];
+               last = &TLINE(y)[MIN(lastx, linelen-1)];
                while (last >= gp && last->u == ' ')
                        --last;
 
@@ -835,6 +838,9 @@ ttyread(void)
        if (buflen > 0)
                memmove(buf, buf + written, buflen);
 
+       if (term.scr > 0 && term.scr < HISTSIZE-1)
+               term.scr++;
+
        return ret;
 }
 
@@ -842,6 +848,9 @@ void
 ttywrite(const char *s, size_t n, int may_echo)
 {
        const char *next;
+       Arg arg = (Arg) { .i = -term.scr };
+
+       kscroll(&arg);
 
        if (may_echo && IS_SET(MODE_ECHO))
                twrite(s, n, 1);
@@ -1053,13 +1062,40 @@ tswapscreen(void)
 }
 
 void
-tscrolldown(int orig, int n)
+kscroll(const Arg* a)
+{
+       int oldscr = term.scr;
+       term.scr += a->i;
+       LIMIT(term.scr, 0, HISTSIZE);
+       if (term.scr == oldscr)
+               return;
+       selscroll(0, term.scr - oldscr);
+       tfulldirt();
+}
+
+void
+kscrollpage(const Arg* a)
+{
+       Arg arg = (Arg) { .i = a->i * term.row - 1 };
+       kscroll(&arg);
+}
+
+
+void
+tscrolldown(int orig, int n, int copyhist)
 {
        int i;
        Line temp;
 
        LIMIT(n, 0, term.bot-orig+1);
 
+       if (copyhist) {
+               term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE;
+               temp = term.hist[term.histi];
+               term.hist[term.histi] = term.line[term.bot];
+               term.line[term.bot] = temp;
+       }
+
        tsetdirt(orig, term.bot-n);
        tclearregion(0, term.bot-n+1, term.col-1, term.bot);
 
@@ -1073,13 +1109,20 @@ tscrolldown(int orig, int n)
 }
 
 void
-tscrollup(int orig, int n)
+tscrollup(int orig, int n, int copyhist)
 {
        int i;
        Line temp;
 
        LIMIT(n, 0, term.bot-orig+1);
 
+       if (copyhist) {
+               term.histi = (term.histi + 1) % HISTSIZE;
+               temp = term.hist[term.histi];
+               term.hist[term.histi] = term.line[orig];
+               term.line[orig] = temp;
+       }
+
        tclearregion(0, orig, term.col-1, orig+n-1);
        tsetdirt(orig+n, term.bot);
 
@@ -1128,7 +1171,7 @@ tnewline(int first_col)
        int y = term.c.y;
 
        if (y == term.bot) {
-               tscrollup(term.top, 1);
+               tscrollup(term.top, 1, 1);
        } else {
                y++;
        }
@@ -1293,14 +1336,14 @@ void
 tinsertblankline(int n)
 {
        if (BETWEEN(term.c.y, term.top, term.bot))
-               tscrolldown(term.c.y, n);
+               tscrolldown(term.c.y, n, 0);
 }
 
 void
 tdeleteline(int n)
 {
        if (BETWEEN(term.c.y, term.top, term.bot))
-               tscrollup(term.c.y, n);
+               tscrollup(term.c.y, n, 0);
 }
 
 int32_t
@@ -1729,11 +1772,11 @@ csihandle(void)
                break;
        case 'S': /* SU -- Scroll <n> line up */
                DEFAULT(csiescseq.arg[0], 1);
-               tscrollup(term.top, csiescseq.arg[0]);
+               tscrollup(term.top, csiescseq.arg[0], 0);
                break;
        case 'T': /* SD -- Scroll <n> line down */
                DEFAULT(csiescseq.arg[0], 1);
-               tscrolldown(term.top, csiescseq.arg[0]);
+               tscrolldown(term.top, csiescseq.arg[0], 0);
                break;
        case 'L': /* IL -- Insert <n> blank lines */
                DEFAULT(csiescseq.arg[0], 1);
@@ -2257,7 +2300,7 @@ eschandle(uchar ascii)
                return 0;
        case 'D': /* IND -- Linefeed */
                if (term.c.y == term.bot) {
-                       tscrollup(term.top, 1);
+                       tscrollup(term.top, 1, 1);
                } else {
                        tmoveto(term.c.x, term.c.y+1);
                }
@@ -2270,7 +2313,7 @@ eschandle(uchar ascii)
                break;
        case 'M': /* RI -- Reverse index */
                if (term.c.y == term.top) {
-                       tscrolldown(term.top, 1);
+                       tscrolldown(term.top, 1, 1);
                } else {
                        tmoveto(term.c.x, term.c.y-1);
                }
@@ -2489,7 +2532,7 @@ twrite(const char *buf, int buflen, int show_ctrl)
 void
 tresize(int col, int row)
 {
-       int i;
+       int i, j;
        int minrow = MIN(row, term.row);
        int mincol = MIN(col, term.col);
        int *bp;
@@ -2526,7 +2569,15 @@ tresize(int col, int row)
        term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
        term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
 
-       /* resize each row to new width, zero-pad if needed */
+       for (i = 0; i < HISTSIZE; i++) {
+               term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph));
+               for (j = mincol; j < col; j++) {
+                       term.hist[i][j] = term.c.attr;
+                       term.hist[i][j].u = ' ';
+               }
+       }
+
+       /* resize each r w to new width, zero-pad if needed */
        for (i = 0; i < minrow; i++) {
                term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
                term.alt[i]  = xrealloc(term.alt[i],  col * sizeof(Glyph));
@@ -2583,7 +2634,7 @@ drawregion(int x1, int y1, int x2, int y2)
                        continue;
 
                term.dirty[y] = 0;
-               xdrawline(term.line[y], x1, y, x2);
+               xdrawline(TLINE(y), x1, y, x2);
        }
 }
 
@@ -2604,8 +2655,10 @@ draw(void)
                cx--;
 
        drawregion(0, 0, term.col, term.row);
-       xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
-                       term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
+       if (term.scr == 0) {
+               xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
+                               term.ocx, term.ocy, 
term.line[term.ocy][term.ocx]);
+       }
        term.ocx = cx, term.ocy = term.c.y;
        xfinishdraw();
 }
diff --git a/st.h b/st.h
index dac64d8..6e974a6 100644
--- a/st.h
+++ b/st.h
@@ -3,6 +3,9 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+/* Arbitrary size */
+#define HISTSIZE      2000
+
 /* macros */
 #define MIN(a, b)              ((a) < (b) ? (a) : (b))
 #define MAX(a, b)              ((a) < (b) ? (b) : (a))
@@ -19,6 +22,8 @@
 
 #define TRUECOLOR(r,g,b)       (1 << 24 | (r) << 16 | (g) << 8 | (b))
 #define IS_TRUECOL(x)          (1 << 24 & (x))
+#define TLINE(y)       ((y) < term.scr ? term.hist[((y) + term.histi - 
term.scr \
+               + HISTSIZE + 1) % HISTSIZE] : term.line[(y) - term.scr])
 
 enum glyph_attribute {
        ATTR_NULL       = 0,
@@ -111,6 +116,9 @@ void *xmalloc(size_t);
 void *xrealloc(void *, size_t);
 char *xstrdup(char *);
 
+void kscroll(const Arg *);
+void kscrollpage(const Arg *);
+
 /* config.h globals */
 extern char *utmp;
 extern char *stty_args;
-- 
2.16.2

>From f2a2bf2cf319a59c528f52a5750e41e1c5443906 Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <[email protected]>
Date: Mon, 19 Mar 2018 16:14:13 -0500
Subject: [PATCH 2/3] st-scrollback-mouse-0.8-2

---
 config.def.h | 10 ++++++++--
 st.h         |  8 ++++++++
 x.c          |  9 +++++++++
 3 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/config.def.h b/config.def.h
index 283fa5e..2a100d5 100644
--- a/config.def.h
+++ b/config.def.h
@@ -156,8 +156,14 @@ static unsigned int defaultattr = 11;
  */
 static MouseShortcut mshortcuts[] = {
        /* button               mask            string */
-       { Button4,              XK_ANY_MOD,     "\031" },
-       { Button5,              XK_ANY_MOD,     "\005" },
+       { Button4,              XK_NO_MOD,      "\031" },
+       { Button5,              XK_NO_MOD,      "\005" },
+};
+
+MouseKey mkeys[] = {
+       /* button               mask            function        argument */
+       { Button4,              ShiftMask,      kscroll,        {.i =  1} },
+       { Button5,              ShiftMask,      kscroll,        {.i = -1} },
 };
 
 /* Internal keyboard shortcuts. */
diff --git a/st.h b/st.h
index 6e974a6..bd69c95 100644
--- a/st.h
+++ b/st.h
@@ -81,6 +81,13 @@ typedef union {
        const void *v;
 } Arg;
 
+typedef struct {
+       uint b;
+       uint mask;
+       void (*func)(const Arg *);
+       const Arg arg;
+} MouseKey;
+
 void die(const char *, ...);
 void redraw(void);
 void draw(void);
@@ -129,3 +136,4 @@ extern char *termname;
 extern unsigned int tabspaces;
 extern unsigned int defaultfg;
 extern unsigned int defaultbg;
+extern MouseKey mkeys[];
diff --git a/x.c b/x.c
index 12bc86b..6cc2d4e 100644
--- a/x.c
+++ b/x.c
@@ -409,6 +409,7 @@ bpress(XEvent *e)
 {
        struct timespec now;
        MouseShortcut *ms;
+       MouseKey *mk;
        int snap;
 
        if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
@@ -424,6 +425,14 @@ bpress(XEvent *e)
                }
        }
 
+       for (mk = mkeys; mk < mkeys + LEN(mkeys); mk++) {
+               if (e->xbutton.button == mk->b
+                               && match(mk->mask, e->xbutton.state)) {
+                       mk->func(&mk->arg);
+                       return;
+               }
+       }
+
        if (e->xbutton.button == Button1) {
                /*
                 * If the user clicks below predefined timeouts specific
-- 
2.16.2

>From 76df6a93dacd5af6ed30e33b28d490afe36337dc Mon Sep 17 00:00:00 2001
From: "Devin J. Pohly" <[email protected]>
Date: Mon, 19 Mar 2018 16:15:02 -0500
Subject: [PATCH 3/3] st-scrollback-mouse-altscreen-0.8-2

---
 config.def.h | 10 ++--------
 st.c         | 10 +++++++++-
 st.h         |  8 --------
 x.c          | 14 +++-----------
 4 files changed, 14 insertions(+), 28 deletions(-)

diff --git a/config.def.h b/config.def.h
index 2a100d5..7a6eb21 100644
--- a/config.def.h
+++ b/config.def.h
@@ -155,15 +155,9 @@ static unsigned int defaultattr = 11;
  * Beware that overloading Button1 will disable the selection.
  */
 static MouseShortcut mshortcuts[] = {
-       /* button               mask            string */
-       { Button4,              XK_NO_MOD,      "\031" },
-       { Button5,              XK_NO_MOD,      "\005" },
-};
-
-MouseKey mkeys[] = {
        /* button               mask            function        argument */
-       { Button4,              ShiftMask,      kscroll,        {.i =  1} },
-       { Button5,              ShiftMask,      kscroll,        {.i = -1} },
+       { Button4,              XK_NO_MOD,      kscroll,        {.i =  1} },
+       { Button5,              XK_NO_MOD,      kscroll,        {.i = -1} },
 };
 
 /* Internal keyboard shortcuts. */
diff --git a/st.c b/st.c
index 78f3343..c7982c2 100644
--- a/st.c
+++ b/st.c
@@ -1064,8 +1064,16 @@ tswapscreen(void)
 void
 kscroll(const Arg* a)
 {
+       int n = a->i;
+       if (IS_SET(MODE_ALTSCREEN)) {
+               for (/* n */; n < 0; n++)
+                       ttywrite("\031", 1, 1);
+               for (/* n */; n > 0; n--)
+                       ttywrite("\005", 1, 1);
+               return;
+       }
        int oldscr = term.scr;
-       term.scr += a->i;
+       term.scr += n;
        LIMIT(term.scr, 0, HISTSIZE);
        if (term.scr == oldscr)
                return;
diff --git a/st.h b/st.h
index bd69c95..6e974a6 100644
--- a/st.h
+++ b/st.h
@@ -81,13 +81,6 @@ typedef union {
        const void *v;
 } Arg;
 
-typedef struct {
-       uint b;
-       uint mask;
-       void (*func)(const Arg *);
-       const Arg arg;
-} MouseKey;
-
 void die(const char *, ...);
 void redraw(void);
 void draw(void);
@@ -136,4 +129,3 @@ extern char *termname;
 extern unsigned int tabspaces;
 extern unsigned int defaultfg;
 extern unsigned int defaultbg;
-extern MouseKey mkeys[];
diff --git a/x.c b/x.c
index 6cc2d4e..9cd6a3b 100644
--- a/x.c
+++ b/x.c
@@ -31,7 +31,8 @@ typedef struct {
 typedef struct {
        uint b;
        uint mask;
-       char *s;
+       void (*func)(const Arg *);
+       const Arg arg;
 } MouseShortcut;
 
 typedef struct {
@@ -409,7 +410,6 @@ bpress(XEvent *e)
 {
        struct timespec now;
        MouseShortcut *ms;
-       MouseKey *mk;
        int snap;
 
        if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
@@ -420,15 +420,7 @@ bpress(XEvent *e)
        for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
                if (e->xbutton.button == ms->b
                                && match(ms->mask, e->xbutton.state)) {
-                       ttywrite(ms->s, strlen(ms->s), 1);
-                       return;
-               }
-       }
-
-       for (mk = mkeys; mk < mkeys + LEN(mkeys); mk++) {
-               if (e->xbutton.button == mk->b
-                               && match(mk->mask, e->xbutton.state)) {
-                       mk->func(&mk->arg);
+                       ms->func(&ms->arg);
                        return;
                }
        }
-- 
2.16.2

Reply via email to