commit 5016961ef88fa9b77fcb98d241539cf5e419cd7e
parent 343dfc629dde00bade3a35716ef14552699322c1
Author: mjkloeckner <martin.cachari@gmail.com>
Date: Tue, 1 Nov 2022 23:55:45 -0300
Update
Diffstat:
12 files changed, 4094 insertions(+), 107 deletions(-)
diff --git a/config.def.h b/config.def.h
@@ -6,9 +6,9 @@
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
*/
/* static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; */
-static char *font = "JetBrains Mono NL:size=10:antialias=true:autohint=true";
-static int borderpx = 2;
-
+/* static char *font = "JetBrainsMono Nerd Font Mono:style=Regular:size=10:antialias=true:autohint=true"; */
+static char *font = "Victor Mono:style=Regular:size=10:antialias=true:autohint=true";
+static int borderpx = 0;
/*
* What program is execed by st depends of these precedence rules:
* 1: program passed with -e
@@ -20,7 +20,7 @@ static int borderpx = 2;
static char *shell = "/bin/sh";
char *utmp = NULL;
/* scroll program: to enable use a string like "scroll" */
-char *scroll = "scroll";
+char *scroll = NULL;
char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";
/* identification sequence returned in DA and DECID */
@@ -97,53 +97,128 @@ unsigned int tabspaces = 8;
/* bg opacity */
float alpha = 0.92;
-/* #1d2021 */
-/* Terminal colors (16 first used in escape sequence) */
-static const char *colorname[] = {
+typedef struct {
+ const char* const colors[258]; /* terminal colors */
+ unsigned int fg; /* foreground */
+ unsigned int bg; /* background */
+ unsigned int cs; /* cursor */
+ unsigned int rcs; /* reverse cursor */
+} ColorScheme;
+/*
+ * Terminal colors (16 first used in escape sequence,
+ * 2 last for custom cursor color),
+ * foreground, background, cursor, reverse cursor
+ */
+static const ColorScheme schemes[] = {
+ /* // st (dark) */
+ /* {{"black", "red3", "green3", "yellow3", */
+ /* "blue2", "magenta3", "cyan3", "gray90", */
+ /* "gray50", "red", "green", "yellow", */
+ /* "#5c5cff", "magenta", "cyan", "white", */
+ /* [256]="#cccccc", "#555555"}, 7, 0, 256, 257}, */
+
/* 8 normal colors */
- [0] = "#0c1010", /* hard contrast: #1d2021 / soft contrast: #32302f */
- [1] = "#cc241d", /* red */
- [2] = "#98971a", /* green */
- [3] = "#d79921", /* yellow */
- [4] = "#458588", /* blue */
- [5] = "#b16286", /* magenta */
- [6] = "#689d6a", /* cyan */
- [7] = "#a89984", /* white */
-
- /* 8 bright colors */
- [8] = "#928374", /* black */
- [9] = "#fb4934", /* red */
- [10] = "#b8bb26", /* green */
- [11] = "#fabd2f", /* yellow */
- [12] = "#83a598", /* blue */
- [13] = "#d3869b", /* magenta */
- [14] = "#8ec07c", /* cyan */
- [15] = "#ebdbb2", /* white */
+ {{ "#040505", /* hard contrast: #1d2021 / soft contrast: #32302f */
+ "#cc241d", /* red */
+ "#98971a", /* green */
+ "#d79921", /* yellow */
+ "#458588", /* blue */
+ "#b16286", /* magenta */
+ "#689d6a", /* cyan */
+ "#a89984", /* white */
+
+ /* 8 bright colors */
+ "#928374", /* black */
+ "#fb4934", /* red */
+ "#b8bb26", /* green */
+ "#fabd2f", /* yellow */
+ "#83a598", /* blue */
+ "#d3869b", /* magenta */
+ "#8ec07c", /* cyan */
+ "#ebdbb2", /* white */
+ [256]="#a89984", "#040505"}, 15, 0, 256, 257},
+
+ // Alacritty (dark)
+ {{"#1d1f21", "#cc6666", "#b5bd68", "#f0c674",
+ "#81a2be", "#b294bb", "#8abeb7", "#c5c8c6",
+ "#666666", "#d54e53", "#b9ca4a", "#e7c547",
+ "#7aa6da", "#c397d8", "#70c0b1", "#eaeaea",
+ [256]="#cccccc", "#555555"}, 7, 0, 256, 257},
+
+ // One Half dark
+ {{"#282c34", "#e06c75", "#98c379", "#e5c07b",
+ "#61afef", "#c678dd", "#56b6c2", "#dcdfe4",
+ "#282c34", "#e06c75", "#98c379", "#e5c07b",
+ "#61afef", "#c678dd", "#56b6c2", "#dcdfe4",
+ [256]="#cccccc", "#555555"}, 7, 0, 256, 257},
+
+ // One Half light
+ {{"#fafafa", "#e45649", "#50a14f", "#c18401",
+ "#0184bc", "#a626a4", "#0997b3", "#383a42",
+ "#fafafa", "#e45649", "#50a14f", "#c18401",
+ "#0184bc", "#a626a4", "#0997b3", "#383a42",
+ [256]="#cccccc", "#555555"}, 7, 0, 256, 257},
+
+ // Solarized dark
+ {{"#073642", "#dc322f", "#859900", "#b58900",
+ "#268bd2", "#d33682", "#2aa198", "#eee8d5",
+ "#002b36", "#cb4b16", "#586e75", "#657b83",
+ "#839496", "#6c71c4", "#93a1a1", "#fdf6e3",
+ [256]="#93a1a1", "#fdf6e3"}, 12, 8, 256, 257},
+
+ // Solarized light
+ {{"#eee8d5", "#dc322f", "#859900", "#b58900",
+ "#268bd2", "#d33682", "#2aa198", "#073642",
+ "#fdf6e3", "#cb4b16", "#93a1a1", "#839496",
+ "#657b83", "#6c71c4", "#586e75", "#002b36",
+ [256]="#586e75", "#002b36"}, 12, 8, 256, 257},
+
+ // Gruvbox dark
+ {{"#282828", "#cc241d", "#98971a", "#d79921",
+ "#458588", "#b16286", "#689d6a", "#a89984",
+ "#928374", "#fb4934", "#b8bb26", "#fabd2f",
+ "#83a598", "#d3869b", "#8ec07c", "#ebdbb2",
+ [256]="#ebdbb2", "#555555"}, 15, 0, 256, 257},
+
+ // Gruvbox light
+ {{"#fbf1c7", "#cc241d", "#98971a", "#d79921",
+ "#458588", "#b16286", "#689d6a", "#7c6f64",
+ "#928374", "#9d0006", "#79740e", "#b57614",
+ "#076678", "#8f3f71", "#427b58", "#3c3836",
+ [256]="#3c3836", "#555555"}, 15, 0, 256, 257},
};
+static const char * const * colorname;
+int colorscheme = 0;
/*
* Default colors (colorname index)
* foreground, background, cursor, reverse cursor
*/
-unsigned int defaultfg = 15;
-unsigned int defaultbg = 0;
-unsigned int defaultcs = 15;
-static unsigned int defaultrcs = 257;
+unsigned int defaultfg;
+unsigned int defaultbg;
+unsigned int defaultcs;
+static unsigned int defaultrcs;
/*
- * Default shape of cursor
- * 2: Block ("█")
- * 4: Underline ("_")
- * 6: Bar ("|")
- * 7: Snowman ("☃")
+ * https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps-SP-q.1D81
+ * Default style of cursor
+ * 0: blinking block
+ * 1: blinking block (default)
+ * 2: steady block ("█")
+ * 3: blinking underline
+ * 4: steady underline ("_")
+ * 5: blinking bar
+ * 6: steady bar ("|")
+ * 7: blinking st cursor
+ * 8: steady st cursor
*/
-static unsigned int cursorshape = 2;
+static unsigned int cursorstyle = 1;
+static Rune stcursor = 0x2603; /* snowman ("☃") */
/*
* Default columns and rows numbers
*/
-
static unsigned int cols = 80;
static unsigned int rows = 24;
@@ -173,17 +248,26 @@ static uint forcemousemod = ShiftMask;
*/
static MouseShortcut mshortcuts[] = {
/* mask button function argument release */
- { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
- { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
- { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
- { ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} },
- { XK_ANY_MOD, Button5, ttysend, {.s = "\005"} },
+ { ShiftMask, Button4, kscrollup, {.i = 1} },
+ { ShiftMask, Button5, kscrolldown, {.i = 1} },
+ /* mask button function argument release alt */
+ { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
+ { XK_ANY_MOD, Button4, ttysend, {.s = "\033[5;2~"}, 0, -1 },
+ { XK_ANY_MOD, Button4, ttysend, {.s = "\033[5;2~"} },
+ { XK_ANY_MOD, Button5, ttysend, {.s = "\033[6;2~"}, 0, -1 },
+ { XK_ANY_MOD, Button5, ttysend, {.s = "\033[6:2~"} },
};
/* Internal keyboard shortcuts. */
#define MODKEY Mod1Mask
#define TERMMOD (ControlMask|ShiftMask)
+static unsigned char scheme = 0;
+static void togglescheme() {
+ Arg s = {.i = (scheme = (scheme ? 0 : 7))};
+ selectscheme(&s);
+}
+
static Shortcut shortcuts[] = {
/* mask keysym function argument */
{ XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} },
@@ -198,6 +282,18 @@ static Shortcut shortcuts[] = {
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
+ { MODKEY, XK_1, selectscheme, {.i = 0} },
+ { MODKEY, XK_2, selectscheme, {.i = 1} },
+ { MODKEY, XK_3, selectscheme, {.i = 2} },
+ { MODKEY, XK_4, selectscheme, {.i = 3} },
+ { MODKEY, XK_5, selectscheme, {.i = 4} },
+ { MODKEY, XK_6, selectscheme, {.i = 5} },
+ { MODKEY, XK_7, selectscheme, {.i = 6} },
+ { MODKEY, XK_8, selectscheme, {.i = 7} },
+ { MODKEY, XK_9, selectscheme, {.i = 8} },
+ { MODKEY, XK_0, togglescheme, {.i = -1} },
+ { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
+ { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
};
/*
diff --git a/patches/st-blinking_cursor-20211116-2f6e597.diff b/patches/st-blinking_cursor-20211116-2f6e597.diff
@@ -0,0 +1,153 @@
+From a3cdd0753bf578cd4e6db7c6507481f3b5c38aea Mon Sep 17 00:00:00 2001
+From: Steve Ward <planet36@gmail.com>
+Date: Tue, 16 Nov 2021 14:15:06 -0500
+Subject: [PATCH] Allow blinking cursor
+
+---
+ config.def.h | 19 +++++++++++++------
+ x.c | 47 +++++++++++++++++++++++++++++++++++------------
+ 2 files changed, 48 insertions(+), 18 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 6f05dce..1a5fed0 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -133,13 +133,20 @@ static unsigned int defaultcs = 256;
+ static unsigned int defaultrcs = 257;
+
+ /*
+- * Default shape of cursor
+- * 2: Block ("█")
+- * 4: Underline ("_")
+- * 6: Bar ("|")
+- * 7: Snowman ("☃")
++ * https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps-SP-q.1D81
++ * Default style of cursor
++ * 0: blinking block
++ * 1: blinking block (default)
++ * 2: steady block ("█")
++ * 3: blinking underline
++ * 4: steady underline ("_")
++ * 5: blinking bar
++ * 6: steady bar ("|")
++ * 7: blinking st cursor
++ * 8: steady st cursor
+ */
+-static unsigned int cursorshape = 2;
++static unsigned int cursorstyle = 1;
++static Rune stcursor = 0x2603; /* snowman ("☃") */
+
+ /*
+ * Default columns and rows numbers
+diff --git a/x.c b/x.c
+index 89786b8..7d2447d 100644
+--- a/x.c
++++ b/x.c
+@@ -253,6 +253,7 @@ static char *opt_name = NULL;
+ static char *opt_title = NULL;
+
+ static int oldbutton = 3; /* button event on startup: 3 = release */
++static int cursorblinks = 0;
+
+ void
+ clipcopy(const Arg *dummy)
+@@ -1529,29 +1530,44 @@ 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 */
+- g.u = 0x2603; /* snowman (U+2603) */
++ default:
++ case 0: /* blinking block */
++ case 1: /* blinking block (default) */
++ if (IS_SET(MODE_BLINK))
++ break;
+ /* FALLTHROUGH */
+- case 0: /* Blinking Block */
+- case 1: /* Blinking Block (Default) */
+- case 2: /* Steady Block */
++ case 2: /* steady block */
+ xdrawglyph(g, cx, cy);
+ break;
+- case 3: /* Blinking Underline */
+- case 4: /* Steady Underline */
++ case 3: /* blinking underline */
++ if (IS_SET(MODE_BLINK))
++ break;
++ /* FALLTHROUGH */
++ case 4: /* steady underline */
+ XftDrawRect(xw.draw, &drawcol,
+ borderpx + cx * win.cw,
+ borderpx + (cy + 1) * win.ch - \
+ cursorthickness,
+ win.cw, cursorthickness);
+ break;
+- case 5: /* Blinking bar */
+- case 6: /* Steady bar */
++ case 5: /* blinking bar */
++ if (IS_SET(MODE_BLINK))
++ break;
++ /* FALLTHROUGH */
++ case 6: /* steady bar */
+ XftDrawRect(xw.draw, &drawcol,
+ borderpx + cx * win.cw,
+ borderpx + cy * win.ch,
+ cursorthickness, win.ch);
+ break;
++ case 7: /* blinking st cursor */
++ if (IS_SET(MODE_BLINK))
++ break;
++ /* FALLTHROUGH */
++ case 8: /* steady st cursor */
++ g.u = stcursor;
++ xdrawglyph(g, cx, cy);
++ break;
+ }
+ } else {
+ XftDrawRect(xw.draw, &drawcol,
+@@ -1708,9 +1724,12 @@ xsetmode(int set, unsigned int flags)
+ int
+ xsetcursor(int cursor)
+ {
+- if (!BETWEEN(cursor, 0, 7)) /* 7: st extension */
++ if (!BETWEEN(cursor, 0, 8)) /* 7-8: st extensions */
+ return 1;
+ win.cursor = cursor;
++ cursorblinks = win.cursor == 0 || win.cursor == 1 ||
++ win.cursor == 3 || win.cursor == 5 ||
++ win.cursor == 7;
+ return 0;
+ }
+
+@@ -1954,6 +1973,10 @@ run(void)
+ if (FD_ISSET(ttyfd, &rfd) || xev) {
+ if (!drawing) {
+ trigger = now;
++ if (IS_SET(MODE_BLINK)) {
++ win.mode ^= MODE_BLINK;
++ }
++ lastblink = now;
+ drawing = 1;
+ }
+ timeout = (maxlatency - TIMEDIFF(now, trigger)) \
+@@ -1964,7 +1987,7 @@ run(void)
+
+ /* idle detected or maxlatency exhausted -> draw */
+ timeout = -1;
+- if (blinktimeout && tattrset(ATTR_BLINK)) {
++ if (blinktimeout && (cursorblinks || tattrset(ATTR_BLINK))) {
+ timeout = blinktimeout - TIMEDIFF(now, lastblink);
+ if (timeout <= 0) {
+ if (-timeout > blinktimeout) /* start visible */
+@@ -2000,7 +2023,7 @@ main(int argc, char *argv[])
+ {
+ xw.l = xw.t = 0;
+ xw.isfixed = False;
+- xsetcursor(cursorshape);
++ xsetcursor(cursorstyle);
+
+ ARGBEGIN {
+ case 'a':
+--
+2.34.0
+
diff --git a/patches/st-colorschemes-0.8.5.diff b/patches/st-colorschemes-0.8.5.diff
@@ -0,0 +1,306 @@
+From 9bfbafa1e98c13c039bea4790941e51b3a8054b4 Mon Sep 17 00:00:00 2001
+From: Max Schillinger <maxschillinger@web.de>
+Date: Thu, 23 Jun 2022 21:58:37 +0200
+Subject: [PATCH] Add multiple color schemes and key bindings to change them
+
+This commits adds these color schemes:
+
+- the default (dark) st color scheme
+- the default (dark) alacritty color scheme
+- One Half (dark & light)
+- Solarized (dark & light)
+- Gruvbox (dark & light)
+
+Select one with Alt+1..8.
+Select the next one with Alt+0.
+Select the previous one with Ctrl+Alt+0.
+---
+ config.def.h | 118 +++++++++++++++++++++++++++++++++++++--------------
+ st.c | 22 ++++++++++
+ st.h | 2 +
+ x.c | 52 ++++++++++++++++++++++-
+ 4 files changed, 160 insertions(+), 34 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 91ab8ca..38777fe 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -93,46 +93,87 @@ char *termname = "st-256color";
+ */
+ unsigned int tabspaces = 8;
+
+-/* Terminal colors (16 first used in escape sequence) */
+-static const char *colorname[] = {
+- /* 8 normal colors */
+- "black",
+- "red3",
+- "green3",
+- "yellow3",
+- "blue2",
+- "magenta3",
+- "cyan3",
+- "gray90",
+-
+- /* 8 bright colors */
+- "gray50",
+- "red",
+- "green",
+- "yellow",
+- "#5c5cff",
+- "magenta",
+- "cyan",
+- "white",
+-
+- [255] = 0,
+-
+- /* more colors can be added after 255 to use with DefaultXX */
+- "#cccccc",
+- "#555555",
+- "gray90", /* default foreground colour */
+- "black", /* default background colour */
++typedef struct {
++ const char* const colors[258]; /* terminal colors */
++ unsigned int fg; /* foreground */
++ unsigned int bg; /* background */
++ unsigned int cs; /* cursor */
++ unsigned int rcs; /* reverse cursor */
++} ColorScheme;
++/*
++ * Terminal colors (16 first used in escape sequence,
++ * 2 last for custom cursor color),
++ * foreground, background, cursor, reverse cursor
++ */
++static const ColorScheme schemes[] = {
++ // st (dark)
++ {{"black", "red3", "green3", "yellow3",
++ "blue2", "magenta3", "cyan3", "gray90",
++ "gray50", "red", "green", "yellow",
++ "#5c5cff", "magenta", "cyan", "white",
++ [256]="#cccccc", "#555555"}, 7, 0, 256, 257},
++
++ // Alacritty (dark)
++ {{"#1d1f21", "#cc6666", "#b5bd68", "#f0c674",
++ "#81a2be", "#b294bb", "#8abeb7", "#c5c8c6",
++ "#666666", "#d54e53", "#b9ca4a", "#e7c547",
++ "#7aa6da", "#c397d8", "#70c0b1", "#eaeaea",
++ [256]="#cccccc", "#555555"}, 7, 0, 256, 257},
++
++ // One Half dark
++ {{"#282c34", "#e06c75", "#98c379", "#e5c07b",
++ "#61afef", "#c678dd", "#56b6c2", "#dcdfe4",
++ "#282c34", "#e06c75", "#98c379", "#e5c07b",
++ "#61afef", "#c678dd", "#56b6c2", "#dcdfe4",
++ [256]="#cccccc", "#555555"}, 7, 0, 256, 257},
++
++ // One Half light
++ {{"#fafafa", "#e45649", "#50a14f", "#c18401",
++ "#0184bc", "#a626a4", "#0997b3", "#383a42",
++ "#fafafa", "#e45649", "#50a14f", "#c18401",
++ "#0184bc", "#a626a4", "#0997b3", "#383a42",
++ [256]="#cccccc", "#555555"}, 7, 0, 256, 257},
++
++ // Solarized dark
++ {{"#073642", "#dc322f", "#859900", "#b58900",
++ "#268bd2", "#d33682", "#2aa198", "#eee8d5",
++ "#002b36", "#cb4b16", "#586e75", "#657b83",
++ "#839496", "#6c71c4", "#93a1a1", "#fdf6e3",
++ [256]="#93a1a1", "#fdf6e3"}, 12, 8, 256, 257},
++
++ // Solarized light
++ {{"#eee8d5", "#dc322f", "#859900", "#b58900",
++ "#268bd2", "#d33682", "#2aa198", "#073642",
++ "#fdf6e3", "#cb4b16", "#93a1a1", "#839496",
++ "#657b83", "#6c71c4", "#586e75", "#002b36",
++ [256]="#586e75", "#002b36"}, 12, 8, 256, 257},
++
++ // Gruvbox dark
++ {{"#282828", "#cc241d", "#98971a", "#d79921",
++ "#458588", "#b16286", "#689d6a", "#a89984",
++ "#928374", "#fb4934", "#b8bb26", "#fabd2f",
++ "#83a598", "#d3869b", "#8ec07c", "#ebdbb2",
++ [256]="#ebdbb2", "#555555"}, 15, 0, 256, 257},
++
++ // Gruvbox light
++ {{"#fbf1c7", "#cc241d", "#98971a", "#d79921",
++ "#458588", "#b16286", "#689d6a", "#7c6f64",
++ "#928374", "#9d0006", "#79740e", "#b57614",
++ "#076678", "#8f3f71", "#427b58", "#3c3836",
++ [256]="#3c3836", "#555555"}, 15, 0, 256, 257},
+ };
+
++static const char * const * colorname;
++int colorscheme = 0;
+
+ /*
+ * Default colors (colorname index)
+ * foreground, background, cursor, reverse cursor
+ */
+-unsigned int defaultfg = 258;
+-unsigned int defaultbg = 259;
+-unsigned int defaultcs = 256;
+-static unsigned int defaultrcs = 257;
++unsigned int defaultfg;
++unsigned int defaultbg;
++unsigned int defaultcs;
++static unsigned int defaultrcs;
+
+ /*
+ * Default shape of cursor
+@@ -201,6 +242,17 @@ static Shortcut shortcuts[] = {
+ { TERMMOD, XK_Y, selpaste, {.i = 0} },
+ { ShiftMask, XK_Insert, selpaste, {.i = 0} },
+ { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
++ { MODKEY, XK_1, selectscheme, {.i = 0} },
++ { MODKEY, XK_2, selectscheme, {.i = 1} },
++ { MODKEY, XK_3, selectscheme, {.i = 2} },
++ { MODKEY, XK_4, selectscheme, {.i = 3} },
++ { MODKEY, XK_5, selectscheme, {.i = 4} },
++ { MODKEY, XK_6, selectscheme, {.i = 5} },
++ { MODKEY, XK_7, selectscheme, {.i = 6} },
++ { MODKEY, XK_8, selectscheme, {.i = 7} },
++ { MODKEY, XK_9, selectscheme, {.i = 8} },
++ { MODKEY, XK_0, nextscheme, {.i = +1} },
++ { MODKEY|ControlMask, XK_0, nextscheme, {.i = -1} },
+ };
+
+ /*
+diff --git a/st.c b/st.c
+index 51049ba..3ffe333 100644
+--- a/st.c
++++ b/st.c
+@@ -2196,6 +2196,28 @@ tstrsequence(uchar c)
+ term.esc |= ESC_STR;
+ }
+
++void
++tupdatebgcolor(int oldbg, int newbg)
++{
++ for (int y = 0; y < term.row; y++) {
++ for (int x = 0; x < term.col; x++) {
++ if (term.line[y][x].bg == oldbg)
++ term.line[y][x].bg = newbg;
++ }
++ }
++}
++
++void
++tupdatefgcolor(int oldfg, int newfg)
++{
++ for (int y = 0; y < term.row; y++) {
++ for (int x = 0; x < term.col; x++) {
++ if (term.line[y][x].fg == oldfg)
++ term.line[y][x].fg = newfg;
++ }
++ }
++}
++
+ void
+ tcontrolcode(uchar ascii)
+ {
+diff --git a/st.h b/st.h
+index 519b9bd..2700de5 100644
+--- a/st.h
++++ b/st.h
+@@ -90,6 +90,8 @@ int tattrset(int);
+ void tnew(int, int);
+ void tresize(int, int);
+ void tsetdirtattr(int);
++void tupdatebgcolor(int, int);
++void tupdatefgcolor(int, int);
+ void ttyhangup(void);
+ int ttynew(const char *, char *, const char *, char **);
+ size_t ttyread(void);
+diff --git a/x.c b/x.c
+index 8a16faa..bc0a48c 100644
+--- a/x.c
++++ b/x.c
+@@ -59,6 +59,8 @@ static void zoom(const Arg *);
+ static void zoomabs(const Arg *);
+ static void zoomreset(const Arg *);
+ static void ttysend(const Arg *);
++static void nextscheme(const Arg *);
++static void selectscheme(const Arg *);
+
+ /* config.h for applying patches and the configuration. */
+ #include "config.h"
+@@ -185,6 +187,7 @@ static void mousesel(XEvent *, int);
+ static void mousereport(XEvent *);
+ static char *kmap(KeySym, uint);
+ static int match(uint, uint);
++static void updatescheme(void);
+
+ static void run(void);
+ static void usage(void);
+@@ -785,7 +788,7 @@ xloadcols(void)
+ for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp)
+ XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
+ } else {
+- dc.collen = MAX(LEN(colorname), 256);
++ dc.collen = 258;
+ dc.col = xmalloc(dc.collen * sizeof(Color));
+ }
+
+@@ -2008,6 +2011,47 @@ usage(void)
+ " [stty_args ...]\n", argv0, argv0);
+ }
+
++void
++nextscheme(const Arg *arg)
++{
++ colorscheme += arg->i;
++ if (colorscheme >= (int)LEN(schemes))
++ colorscheme = 0;
++ else if (colorscheme < 0)
++ colorscheme = LEN(schemes) - 1;
++ updatescheme();
++}
++
++void
++selectscheme(const Arg *arg)
++{
++ if (BETWEEN(arg->i, 0, LEN(schemes)-1)) {
++ colorscheme = arg->i;
++ updatescheme();
++ }
++}
++
++void
++updatescheme(void)
++{
++ int oldbg, oldfg;
++
++ oldbg = defaultbg;
++ oldfg = defaultfg;
++ colorname = schemes[colorscheme].colors;
++ defaultbg = schemes[colorscheme].bg;
++ defaultfg = schemes[colorscheme].fg;
++ defaultcs = schemes[colorscheme].cs;
++ defaultrcs = schemes[colorscheme].rcs;
++ xloadcols();
++ if (defaultbg != oldbg)
++ tupdatebgcolor(oldbg, defaultbg);
++ if (defaultfg != oldfg)
++ tupdatefgcolor(oldfg, defaultfg);
++ cresize(win.w, win.h);
++ redraw();
++}
++
+ int
+ main(int argc, char *argv[])
+ {
+@@ -2060,6 +2104,12 @@ main(int argc, char *argv[])
+ } ARGEND;
+
+ run:
++ colorname = schemes[colorscheme].colors;
++ defaultbg = schemes[colorscheme].bg;
++ defaultfg = schemes[colorscheme].fg;
++ defaultcs = schemes[colorscheme].cs;
++ defaultrcs = schemes[colorscheme].rcs;
++
+ if (argc > 0) /* eat all remaining arguments */
+ opt_cmd = argv;
+
+--
+2.36.1
+
diff --git a/patches/st-scrollback-20210507-4536f46.diff b/patches/st-scrollback-20210507-4536f46.diff
@@ -0,0 +1,351 @@
+diff --git a/config.def.h b/config.def.h
+index 6f05dce..93cbcc0 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -199,6 +199,8 @@ static Shortcut shortcuts[] = {
+ { TERMMOD, XK_Y, selpaste, {.i = 0} },
+ { ShiftMask, XK_Insert, selpaste, {.i = 0} },
+ { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
++ { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
++ { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
+ };
+
+ /*
+diff --git a/st.c b/st.c
+index ebdf360..817cc47 100644
+--- a/st.c
++++ b/st.c
+@@ -35,6 +35,7 @@
+ #define ESC_ARG_SIZ 16
+ #define STR_BUF_SIZ ESC_BUF_SIZ
+ #define STR_ARG_SIZ ESC_ARG_SIZ
++#define HISTSIZE 2000
+
+ /* macros */
+ #define IS_SET(flag) ((term.mode & (flag)) != 0)
+@@ -42,6 +43,9 @@
+ #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
+ #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
+ #define ISDELIM(u) (u && wcschr(worddelimiters, u))
++#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \
++ term.scr + HISTSIZE + 1) % HISTSIZE] : \
++ term.line[(y) - term.scr])
+
+ enum term_mode {
+ MODE_WRAP = 1 << 0,
+@@ -115,6 +119,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 */
+@@ -184,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(const int *, int);
+ static void tsetchar(Rune, const Glyph *, int, int);
+ static void tsetdirt(int, int);
+@@ -416,10 +423,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;
+@@ -528,7 +535,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;
+@@ -543,14 +550,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)))
+@@ -571,14 +578,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;
+ }
+@@ -609,13 +616,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;
+
+@@ -850,6 +857,9 @@ void
+ ttywrite(const char *s, size_t n, int may_echo)
+ {
+ const char *next;
++ Arg arg = (Arg) { .i = term.scr };
++
++ kscrolldown(&arg);
+
+ if (may_echo && IS_SET(MODE_ECHO))
+ twrite(s, n, 1);
+@@ -1061,13 +1071,53 @@ tswapscreen(void)
+ }
+
+ void
+-tscrolldown(int orig, int n)
++kscrolldown(const Arg* a)
++{
++ int n = a->i;
++
++ if (n < 0)
++ n = term.row + n;
++
++ if (n > term.scr)
++ n = term.scr;
++
++ if (term.scr > 0) {
++ term.scr -= n;
++ selscroll(0, -n);
++ tfulldirt();
++ }
++}
++
++void
++kscrollup(const Arg* a)
++{
++ int n = a->i;
++
++ if (n < 0)
++ n = term.row + n;
++
++ if (term.scr <= HISTSIZE-n) {
++ term.scr += n;
++ selscroll(0, n);
++ tfulldirt();
++ }
++}
++
++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);
+
+@@ -1077,17 +1127,28 @@ tscrolldown(int orig, int n)
+ term.line[i-n] = temp;
+ }
+
+- selscroll(orig, n);
++ if (term.scr == 0)
++ selscroll(orig, 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;
++ }
++
++ if (term.scr > 0 && term.scr < HISTSIZE)
++ term.scr = MIN(term.scr + n, HISTSIZE-1);
++
+ tclearregion(0, orig, term.col-1, orig+n-1);
+ tsetdirt(orig+n, term.bot);
+
+@@ -1097,7 +1158,8 @@ tscrollup(int orig, int n)
+ term.line[i+n] = temp;
+ }
+
+- selscroll(orig, -n);
++ if (term.scr == 0)
++ selscroll(orig, -n);
+ }
+
+ void
+@@ -1126,7 +1188,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++;
+ }
+@@ -1291,14 +1353,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
+@@ -1735,11 +1797,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);
+@@ -2251,7 +2313,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);
+ }
+@@ -2264,7 +2326,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);
+ }
+@@ -2474,7 +2536,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;
+@@ -2511,6 +2573,14 @@ tresize(int col, int row)
+ term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
+ term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
+
++ 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 row to new width, zero-pad if needed */
+ for (i = 0; i < minrow; i++) {
+ term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
+@@ -2569,7 +2639,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);
+ }
+ }
+
+@@ -2590,8 +2660,9 @@ 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 fa2eddf..adda2db 100644
+--- a/st.h
++++ b/st.h
+@@ -81,6 +81,8 @@ void die(const char *, ...);
+ void redraw(void);
+ void draw(void);
+
++void kscrolldown(const Arg *);
++void kscrollup(const Arg *);
+ void printscreen(const Arg *);
+ void printsel(const Arg *);
+ void sendbreak(const Arg *);
diff --git a/patches/st-scrollback-mouse-20220127-2c5edf2.diff b/patches/st-scrollback-mouse-20220127-2c5edf2.diff
@@ -0,0 +1,25 @@
+From b5d3351a21442a842e01e8c0317603b6890b379c Mon Sep 17 00:00:00 2001
+From: asparagii <michele.lambertucci1@gmail.com>
+Date: Thu, 27 Jan 2022 15:44:02 +0100
+Subject: [PATCH] st-scrollback-mouse
+
+---
+ config.def.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/config.def.h b/config.def.h
+index e3b469b..c217315 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -176,6 +176,8 @@ static uint forcemousemod = ShiftMask;
+ */
+ static MouseShortcut mshortcuts[] = {
+ /* mask button function argument release */
++ { ShiftMask, Button4, kscrollup, {.i = 1} },
++ { ShiftMask, Button5, kscrolldown, {.i = 1} },
+ { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
+ { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
+ { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
+--
+2.34.1
+
diff --git a/patches/st-scrollback-reflow-0.8.5.diff b/patches/st-scrollback-reflow-0.8.5.diff
@@ -0,0 +1,1478 @@
+diff --git a/st.c b/st.c
+index 91e7077..a76d983 100644
+--- a/st.c
++++ b/st.c
+@@ -36,6 +36,7 @@
+ #define STR_BUF_SIZ ESC_BUF_SIZ
+ #define STR_ARG_SIZ ESC_ARG_SIZ
+ #define HISTSIZE 2000
++#define RESIZEBUFFER 1000
+
+ /* macros */
+ #define IS_SET(flag) ((term.mode & (flag)) != 0)
+@@ -43,9 +44,22 @@
+ #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
+ #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
+ #define ISDELIM(u) (u && wcschr(worddelimiters, u))
+-#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \
+- term.scr + HISTSIZE + 1) % HISTSIZE] : \
+- term.line[(y) - term.scr])
++
++#define TLINE(y) ( \
++ (y) < term.scr ? term.hist[(term.histi + (y) - term.scr + 1 + HISTSIZE) % HISTSIZE] \
++ : term.line[(y) - term.scr] \
++)
++
++#define TLINEABS(y) ( \
++ (y) < 0 ? term.hist[(term.histi + (y) + 1 + HISTSIZE) % HISTSIZE] : term.line[(y)] \
++)
++
++#define UPDATEWRAPNEXT(alt, col) do { \
++ if ((term.c.state & CURSOR_WRAPNEXT) && term.c.x + term.wrapcwidth[alt] < col) { \
++ term.c.x += term.wrapcwidth[alt]; \
++ term.c.state &= ~CURSOR_WRAPNEXT; \
++ } \
++} while (0);
+
+ enum term_mode {
+ MODE_WRAP = 1 << 0,
+@@ -57,6 +71,12 @@ enum term_mode {
+ MODE_UTF8 = 1 << 6,
+ };
+
++enum scroll_mode {
++ SCROLL_RESIZE = -1,
++ SCROLL_NOSAVEHIST = 0,
++ SCROLL_SAVEHIST = 1
++};
++
+ enum cursor_movement {
+ CURSOR_SAVE,
+ CURSOR_LOAD
+@@ -118,10 +138,11 @@ typedef struct {
+ int row; /* nb row */
+ 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 histi; /* history index */
++ int histf; /* nb history available */
++ int scr; /* scroll back */
++ int wrapcwidth[2]; /* used in updating WRAPNEXT when resizing */
+ int *dirty; /* dirtyness of lines */
+ TCursor c; /* cursor */
+ int ocx; /* old cursor col */
+@@ -179,26 +200,37 @@ static void tprinter(char *, size_t);
+ static void tdumpsel(void);
+ static void tdumpline(int);
+ static void tdump(void);
+-static void tclearregion(int, int, int, int);
++static void tclearregion(int, int, int, int, int);
+ static void tcursor(int);
++static void tclearglyph(Glyph *, int);
++static void tresetcursor(void);
+ static void tdeletechar(int);
+ static void tdeleteline(int);
+ static void tinsertblank(int);
+ static void tinsertblankline(int);
+-static int tlinelen(int);
++static int tlinelen(Line len);
++static int tiswrapped(Line line);
++static char *tgetglyphs(char *, const Glyph *, const Glyph *);
++static size_t tgetline(char *, const Glyph *);
+ static void tmoveto(int, int);
+ static void tmoveato(int, int);
+ static void tnewline(int);
+ static void tputtab(int);
+ static void tputc(Rune);
+ static void treset(void);
+-static void tscrollup(int, int, int);
+-static void tscrolldown(int, int, int);
++static void tscrollup(int, int, int, int);
++static void tscrolldown(int, int);
++static void treflow(int, int);
++static void rscrolldown(int);
++static void tresizedef(int, int);
++static void tresizealt(int, int);
+ static void tsetattr(const int *, int);
+ static void tsetchar(Rune, const Glyph *, int, int);
+ static void tsetdirt(int, int);
+ static void tsetscroll(int, int);
+ static void tswapscreen(void);
++static void tloaddefscreen(int, int);
++static void tloadaltscreen(int, int);
+ static void tsetmode(int, int, const int *, int);
+ static int twrite(const char *, int, int);
+ static void tfulldirt(void);
+@@ -212,7 +244,10 @@ static void tstrsequence(uchar);
+ static void drawregion(int, int, int, int);
+
+ static void selnormalize(void);
+-static void selscroll(int, int);
++static void selscroll(int, int, int);
++static void selmove(int);
++static void selremove(void);
++static int regionselected(int, int, int, int);
+ static void selsnap(int *, int *, int);
+
+ static size_t utf8decode(const char *, Rune *, size_t);
+@@ -412,17 +447,46 @@ selinit(void)
+ }
+
+ int
+-tlinelen(int y)
++tlinelen(Line line)
+ {
+- int i = term.col;
++ int i = term.col - 1;
++
++ for (; i >= 0 && !(line[i].mode & (ATTR_SET | ATTR_WRAP)); i--);
++ return i + 1;
++}
+
+- if (TLINE(y)[i - 1].mode & ATTR_WRAP)
+- return i;
++int
++tiswrapped(Line line)
++{
++ int len = tlinelen(line);
+
+- while (i > 0 && TLINE(y)[i - 1].u == ' ')
+- --i;
++ return len > 0 && (line[len - 1].mode & ATTR_WRAP);
++}
+
+- return i;
++char *
++tgetglyphs(char *buf, const Glyph *gp, const Glyph *lgp)
++{
++ while (gp <= lgp)
++ if (gp->mode & ATTR_WDUMMY) {
++ gp++;
++ } else {
++ buf += utf8encode((gp++)->u, buf);
++ }
++ return buf;
++}
++
++size_t
++tgetline(char *buf, const Glyph *fgp)
++{
++ char *ptr;
++ const Glyph *lgp = &fgp[term.col - 1];
++
++ while (lgp > fgp && !(lgp->mode & (ATTR_SET | ATTR_WRAP)))
++ lgp--;
++ ptr = tgetglyphs(buf, fgp, lgp);
++ if (!(lgp->mode & ATTR_WRAP))
++ *(ptr++) = '\n';
++ return ptr - buf;
+ }
+
+ void
+@@ -462,10 +526,11 @@ selextend(int col, int row, int type, int done)
+
+ sel.oe.x = col;
+ sel.oe.y = row;
+- selnormalize();
+ sel.type = type;
++ selnormalize();
+
+- if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type || sel.mode == SEL_EMPTY)
++ if (oldey != sel.oe.y || oldex != sel.oe.x ||
++ oldtype != sel.type || sel.mode == SEL_EMPTY)
+ tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
+
+ sel.mode = done ? SEL_IDLE : SEL_READY;
+@@ -492,36 +557,43 @@ selnormalize(void)
+ /* expand selection over line breaks */
+ if (sel.type == SEL_RECTANGULAR)
+ return;
+- i = tlinelen(sel.nb.y);
+- if (i < sel.nb.x)
++
++ i = tlinelen(TLINE(sel.nb.y));
++ if (sel.nb.x > i)
+ sel.nb.x = i;
+- if (tlinelen(sel.ne.y) <= sel.ne.x)
+- sel.ne.x = term.col - 1;
++ if (sel.ne.x >= tlinelen(TLINE(sel.ne.y)))
++ sel.ne.x = term.col - 1;
+ }
+
+ int
+-selected(int x, int y)
++regionselected(int x1, int y1, int x2, int y2)
+ {
+- if (sel.mode == SEL_EMPTY || sel.ob.x == -1 ||
+- sel.alt != IS_SET(MODE_ALTSCREEN))
++ if (sel.ob.x == -1 || sel.mode == SEL_EMPTY ||
++ sel.alt != IS_SET(MODE_ALTSCREEN) || sel.nb.y > y2 || sel.ne.y < y1)
+ return 0;
+
+- if (sel.type == SEL_RECTANGULAR)
+- return BETWEEN(y, sel.nb.y, sel.ne.y)
+- && BETWEEN(x, sel.nb.x, sel.ne.x);
++ return (sel.type == SEL_RECTANGULAR) ? sel.nb.x <= x2 && sel.ne.x >= x1
++ : (sel.nb.y != y2 || sel.nb.x <= x2) &&
++ (sel.ne.y != y1 || sel.ne.x >= x1);
++}
+
+- return BETWEEN(y, sel.nb.y, sel.ne.y)
+- && (y != sel.nb.y || x >= sel.nb.x)
+- && (y != sel.ne.y || x <= sel.ne.x);
++int
++selected(int x, int y)
++{
++ return regionselected(x, y, x, y);
+ }
+
+ void
+ selsnap(int *x, int *y, int direction)
+ {
+ int newx, newy, xt, yt;
++ int rtop = 0, rbot = term.row - 1;
+ int delim, prevdelim;
+ const Glyph *gp, *prevgp;
+
++ if (!IS_SET(MODE_ALTSCREEN))
++ rtop += -term.histf + term.scr, rbot += term.scr;
++
+ switch (sel.snap) {
+ case SNAP_WORD:
+ /*
+@@ -536,7 +608,7 @@ selsnap(int *x, int *y, int direction)
+ if (!BETWEEN(newx, 0, term.col - 1)) {
+ newy += direction;
+ newx = (newx + term.col) % term.col;
+- if (!BETWEEN(newy, 0, term.row - 1))
++ if (!BETWEEN(newy, rtop, rbot))
+ break;
+
+ if (direction > 0)
+@@ -547,13 +619,13 @@ selsnap(int *x, int *y, int direction)
+ break;
+ }
+
+- if (newx >= tlinelen(newy))
++ if (newx >= tlinelen(TLINE(newy)))
+ break;
+
+ gp = &TLINE(newy)[newx];
+ delim = ISDELIM(gp->u);
+- if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
+- || (delim && gp->u != prevgp->u)))
++ if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim ||
++ (delim && !(gp->u == ' ' && prevgp->u == ' '))))
+ break;
+
+ *x = newx;
+@@ -570,18 +642,14 @@ selsnap(int *x, int *y, int direction)
+ */
+ *x = (direction < 0) ? 0 : term.col - 1;
+ if (direction < 0) {
+- for (; *y > 0; *y += direction) {
+- if (!(TLINE(*y-1)[term.col-1].mode
+- & ATTR_WRAP)) {
++ for (; *y > rtop; *y -= 1) {
++ if (!tiswrapped(TLINE(*y-1)))
+ break;
+- }
+ }
+ } else if (direction > 0) {
+- for (; *y < term.row-1; *y += direction) {
+- if (!(TLINE(*y)[term.col-1].mode
+- & ATTR_WRAP)) {
++ for (; *y < rbot; *y += 1) {
++ if (!tiswrapped(TLINE(*y)))
+ break;
+- }
+ }
+ }
+ break;
+@@ -592,40 +660,34 @@ char *
+ getsel(void)
+ {
+ char *str, *ptr;
+- int y, bufsize, lastx, linelen;
+- const Glyph *gp, *last;
++ int y, lastx, linelen;
++ const Glyph *gp, *lgp;
+
+- if (sel.ob.x == -1)
++ if (sel.ob.x == -1 || sel.alt != IS_SET(MODE_ALTSCREEN))
+ return NULL;
+
+- bufsize = (term.col+1) * (sel.ne.y-sel.nb.y+1) * UTF_SIZ;
+- ptr = str = xmalloc(bufsize);
++ str = xmalloc((term.col + 1) * (sel.ne.y - sel.nb.y + 1) * UTF_SIZ);
++ ptr = str;
+
+ /* append every set & selected glyph to the selection */
+ for (y = sel.nb.y; y <= sel.ne.y; y++) {
+- if ((linelen = tlinelen(y)) == 0) {
++ Line line = TLINE(y);
++
++ if ((linelen = tlinelen(line)) == 0) {
+ *ptr++ = '\n';
+ continue;
+ }
+
+ if (sel.type == SEL_RECTANGULAR) {
+- gp = &TLINE(y)[sel.nb.x];
++ gp = &line[sel.nb.x];
+ lastx = sel.ne.x;
+ } else {
+- gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0];
++ gp = &line[sel.nb.y == y ? sel.nb.x : 0];
+ lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
+ }
+- last = &TLINE(y)[MIN(lastx, linelen-1)];
+- while (last >= gp && last->u == ' ')
+- --last;
+-
+- for ( ; gp <= last; ++gp) {
+- if (gp->mode & ATTR_WDUMMY)
+- continue;
+-
+- ptr += utf8encode(gp->u, ptr);
+- }
++ lgp = &line[MIN(lastx, linelen-1)];
+
++ ptr = tgetglyphs(ptr, gp, lgp);
+ /*
+ * Copy and pasting of line endings is inconsistent
+ * in the inconsistent terminal and GUI world.
+@@ -636,10 +698,10 @@ getsel(void)
+ * FIXME: Fix the computer world.
+ */
+ if ((y < sel.ne.y || lastx >= linelen) &&
+- (!(last->mode & ATTR_WRAP) || sel.type == SEL_RECTANGULAR))
++ (!(lgp->mode & ATTR_WRAP) || sel.type == SEL_RECTANGULAR))
+ *ptr++ = '\n';
+ }
+- *ptr = 0;
++ *ptr = '\0';
+ return str;
+ }
+
+@@ -648,9 +710,15 @@ selclear(void)
+ {
+ if (sel.ob.x == -1)
+ return;
++ selremove();
++ tsetdirt(sel.nb.y, sel.ne.y);
++}
++
++void
++selremove(void)
++{
+ sel.mode = SEL_IDLE;
+ sel.ob.x = -1;
+- tsetdirt(sel.nb.y, sel.ne.y);
+ }
+
+ void
+@@ -851,10 +919,8 @@ void
+ ttywrite(const char *s, size_t n, int may_echo)
+ {
+ const char *next;
+- Arg arg = (Arg) { .i = term.scr };
+-
+- kscrolldown(&arg);
+
++ kscrolldown(&((Arg){ .i = term.scr }));
+ if (may_echo && IS_SET(MODE_ECHO))
+ twrite(s, n, 1);
+
+@@ -990,7 +1056,7 @@ tsetdirtattr(int attr)
+ for (i = 0; i < term.row-1; i++) {
+ for (j = 0; j < term.col-1; j++) {
+ if (term.line[i][j].mode & attr) {
+- tsetdirt(i, i);
++ term.dirty[i] = 1;
+ break;
+ }
+ }
+@@ -1000,7 +1066,8 @@ tsetdirtattr(int attr)
+ void
+ tfulldirt(void)
+ {
+- tsetdirt(0, term.row-1);
++ for (int i = 0; i < term.row; i++)
++ term.dirty[i] = 1;
+ }
+
+ void
+@@ -1017,51 +1084,116 @@ tcursor(int mode)
+ }
+ }
+
++void
++tresetcursor(void)
++{
++ term.c = (TCursor){ { .mode = ATTR_NULL, .fg = defaultfg, .bg = defaultbg },
++ .x = 0, .y = 0, .state = CURSOR_DEFAULT };
++}
++
+ void
+ treset(void)
+ {
+ uint i;
++ int x, y;
+
+- term.c = (TCursor){{
+- .mode = ATTR_NULL,
+- .fg = defaultfg,
+- .bg = defaultbg
+- }, .x = 0, .y = 0, .state = CURSOR_DEFAULT};
++ tresetcursor();
+
+ memset(term.tabs, 0, term.col * sizeof(*term.tabs));
+ for (i = tabspaces; i < term.col; i += tabspaces)
+ term.tabs[i] = 1;
+ term.top = 0;
++ term.histf = 0;
++ term.scr = 0;
+ term.bot = term.row - 1;
+ term.mode = MODE_WRAP|MODE_UTF8;
+ memset(term.trantbl, CS_USA, sizeof(term.trantbl));
+ term.charset = 0;
+
++ selremove();
+ for (i = 0; i < 2; i++) {
+- tmoveto(0, 0);
+- tcursor(CURSOR_SAVE);
+- tclearregion(0, 0, term.col-1, term.row-1);
++ tcursor(CURSOR_SAVE); /* reset saved cursor */
++ for (y = 0; y < term.row; y++)
++ for (x = 0; x < term.col; x++)
++ tclearglyph(&term.line[y][x], 0);
+ tswapscreen();
+ }
++ tfulldirt();
+ }
+
+ void
+ tnew(int col, int row)
+ {
+- term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } };
+- tresize(col, row);
+- treset();
++ int i, j;
++
++ for (i = 0; i < 2; i++) {
++ term.line = xmalloc(row * sizeof(Line));
++ for (j = 0; j < row; j++)
++ term.line[j] = xmalloc(col * sizeof(Glyph));
++ term.col = col, term.row = row;
++ tswapscreen();
++ }
++ term.dirty = xmalloc(row * sizeof(*term.dirty));
++ term.tabs = xmalloc(col * sizeof(*term.tabs));
++ for (i = 0; i < HISTSIZE; i++)
++ term.hist[i] = xmalloc(col * sizeof(Glyph));
++ treset();
+ }
+
++/* handle it with care */
+ void
+ tswapscreen(void)
+ {
+- Line *tmp = term.line;
++ static Line *altline;
++ static int altcol, altrow;
++ Line *tmpline = term.line;
++ int tmpcol = term.col, tmprow = term.row;
+
+- term.line = term.alt;
+- term.alt = tmp;
++ term.line = altline;
++ term.col = altcol, term.row = altrow;
++ altline = tmpline;
++ altcol = tmpcol, altrow = tmprow;
+ term.mode ^= MODE_ALTSCREEN;
+- tfulldirt();
++}
++
++void
++tloaddefscreen(int clear, int loadcursor)
++{
++ int col, row, alt = IS_SET(MODE_ALTSCREEN);
++
++ if (alt) {
++ if (clear)
++ tclearregion(0, 0, term.col-1, term.row-1, 1);
++ col = term.col, row = term.row;
++ tswapscreen();
++ }
++ if (loadcursor)
++ tcursor(CURSOR_LOAD);
++ if (alt)
++ tresizedef(col, row);
++}
++
++void
++tloadaltscreen(int clear, int savecursor)
++{
++ int col, row, def = !IS_SET(MODE_ALTSCREEN);
++
++ if (savecursor)
++ tcursor(CURSOR_SAVE);
++ if (def) {
++ col = term.col, row = term.row;
++ tswapscreen();
++ term.scr = 0;
++ tresizealt(col, row);
++ }
++ if (clear)
++ tclearregion(0, 0, term.col-1, term.row-1, 1);
++}
++
++int
++tisaltscreen(void)
++{
++ return IS_SET(MODE_ALTSCREEN);
+ }
+
+ void
+@@ -1069,17 +1201,22 @@ kscrolldown(const Arg* a)
+ {
+ int n = a->i;
+
+- if (n < 0)
+- n = term.row + n;
++ if (!term.scr || IS_SET(MODE_ALTSCREEN))
++ return;
+
+- if (n > term.scr)
+- n = term.scr;
++ if (n < 0)
++ n = MAX(term.row / -n, 1);
+
+- if (term.scr > 0) {
++ if (n <= term.scr) {
+ term.scr -= n;
+- selscroll(0, -n);
+- tfulldirt();
++ } else {
++ n = term.scr;
++ term.scr = 0;
+ }
++
++ if (sel.ob.x != -1 && !sel.alt)
++ selmove(-n); /* negate change in term.scr */
++ tfulldirt();
+ }
+
+ void
+@@ -1087,92 +1224,118 @@ kscrollup(const Arg* a)
+ {
+ int n = a->i;
+
++ if (!term.histf || IS_SET(MODE_ALTSCREEN))
++ return;
++
+ if (n < 0)
+- n = term.row + n;
++ n = MAX(term.row / -n, 1);
+
+- if (term.scr <= HISTSIZE-n) {
++ if (term.scr + n <= term.histf) {
+ term.scr += n;
+- selscroll(0, n);
+- tfulldirt();
++ } else {
++ n = term.histf - term.scr;
++ term.scr = term.histf;
+ }
++
++ if (sel.ob.x != -1 && !sel.alt)
++ selmove(n); /* negate change in term.scr */
++ tfulldirt();
+ }
+
+ void
+-tscrolldown(int orig, int n, int copyhist)
++tscrolldown(int top, int n)
+ {
+- int i;
++ int i, bot = term.bot;
+ 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;
+- }
+-
++ if (n <= 0)
++ return;
++ n = MIN(n, bot-top+1);
+
+- tsetdirt(orig, term.bot-n);
+- tclearregion(0, term.bot-n+1, term.col-1, term.bot);
++ tsetdirt(top, bot-n);
++ tclearregion(0, bot-n+1, term.col-1, bot, 1);
+
+- for (i = term.bot; i >= orig+n; i--) {
++ for (i = bot; i >= top+n; i--) {
+ temp = term.line[i];
+ term.line[i] = term.line[i-n];
+ term.line[i-n] = temp;
+ }
+
+- if (term.scr == 0)
+- selscroll(orig, n);
++ if (sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN))
++ selscroll(top, bot, n);
+ }
+
+ void
+-tscrollup(int orig, int n, int copyhist)
++tscrollup(int top, int bot, int n, int mode)
+ {
+- int i;
++ int i, j, s;
++ int alt = IS_SET(MODE_ALTSCREEN);
++ int savehist = !alt && top == 0 && mode != SCROLL_NOSAVEHIST;
+ 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;
++ if (n <= 0)
++ return;
++ n = MIN(n, bot-top+1);
++
++ if (savehist) {
++ for (i = 0; i < n; i++) {
++ term.histi = (term.histi + 1) % HISTSIZE;
++ temp = term.hist[term.histi];
++ for (j = 0; j < term.col; j++)
++ tclearglyph(&temp[j], 1);
++ term.hist[term.histi] = term.line[i];
++ term.line[i] = temp;
++ }
++ term.histf = MIN(term.histf + n, HISTSIZE);
++ s = n;
++ if (term.scr) {
++ j = term.scr;
++ term.scr = MIN(j + n, HISTSIZE);
++ s = j + n - term.scr;
++ }
++ if (mode != SCROLL_RESIZE)
++ tfulldirt();
++ } else {
++ tclearregion(0, top, term.col-1, top+n-1, 1);
++ tsetdirt(top+n, bot);
+ }
+
+- if (term.scr > 0 && term.scr < HISTSIZE)
+- term.scr = MIN(term.scr + n, HISTSIZE-1);
+-
+- tclearregion(0, orig, term.col-1, orig+n-1);
+- tsetdirt(orig+n, term.bot);
+-
+- for (i = orig; i <= term.bot-n; i++) {
++ for (i = top; i <= bot-n; i++) {
+ temp = term.line[i];
+ term.line[i] = term.line[i+n];
+ term.line[i+n] = temp;
+ }
+
+- if (term.scr == 0)
+- selscroll(orig, -n);
++ if (sel.ob.x != -1 && sel.alt == alt) {
++ if (!savehist) {
++ selscroll(top, bot, -n);
++ } else if (s > 0) {
++ selmove(-s);
++ if (-term.scr + sel.nb.y < -term.histf)
++ selremove();
++ }
++ }
+ }
+
+ void
+-selscroll(int orig, int n)
++selmove(int n)
+ {
+- if (sel.ob.x == -1)
+- return;
++ sel.ob.y += n, sel.nb.y += n;
++ sel.oe.y += n, sel.ne.y += n;
++}
++
++void
++selscroll(int top, int bot, int n)
++{
++ /* turn absolute coordinates into relative */
++ top += term.scr, bot += term.scr;
+
+- if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig, term.bot)) {
++ if (BETWEEN(sel.nb.y, top, bot) != BETWEEN(sel.ne.y, top, bot)) {
+ selclear();
+- } else if (BETWEEN(sel.nb.y, orig, term.bot)) {
+- sel.ob.y += n;
+- sel.oe.y += n;
+- if (sel.ob.y < term.top || sel.ob.y > term.bot ||
+- sel.oe.y < term.top || sel.oe.y > term.bot) {
++ } else if (BETWEEN(sel.nb.y, top, bot)) {
++ selmove(n);
++ if (sel.nb.y < top || sel.ne.y > bot)
+ selclear();
+- } else {
+- selnormalize();
+- }
+ }
+ }
+
+@@ -1182,7 +1345,7 @@ tnewline(int first_col)
+ int y = term.c.y;
+
+ if (y == term.bot) {
+- tscrollup(term.top, 1, 1);
++ tscrollup(term.top, term.bot, 1, SCROLL_SAVEHIST);
+ } else {
+ y++;
+ }
+@@ -1272,89 +1435,93 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
+ } else if (term.line[y][x].mode & ATTR_WDUMMY) {
+ term.line[y][x-1].u = ' ';
+ term.line[y][x-1].mode &= ~ATTR_WIDE;
+- }
++ }
+
+ term.dirty[y] = 1;
+ term.line[y][x] = *attr;
+ term.line[y][x].u = u;
++ term.line[y][x].mode |= ATTR_SET;
+ }
+
+ void
+-tclearregion(int x1, int y1, int x2, int y2)
++tclearglyph(Glyph *gp, int usecurattr)
+ {
+- int x, y, temp;
+- Glyph *gp;
++ if (usecurattr) {
++ gp->fg = term.c.attr.fg;
++ gp->bg = term.c.attr.bg;
++ } else {
++ gp->fg = defaultfg;
++ gp->bg = defaultbg;
++ }
++ gp->mode = ATTR_NULL;
++ gp->u = ' ';
++}
+
+- if (x1 > x2)
+- temp = x1, x1 = x2, x2 = temp;
+- if (y1 > y2)
+- temp = y1, y1 = y2, y2 = temp;
++void
++tclearregion(int x1, int y1, int x2, int y2, int usecurattr)
++{
++ int x, y;
+
+- LIMIT(x1, 0, term.col-1);
+- LIMIT(x2, 0, term.col-1);
+- LIMIT(y1, 0, term.row-1);
+- LIMIT(y2, 0, term.row-1);
++ /* regionselected() takes relative coordinates */
++ if (regionselected(x1+term.scr, y1+term.scr, x2+term.scr, y2+term.scr))
++ selremove();
+
+ for (y = y1; y <= y2; y++) {
+ term.dirty[y] = 1;
+- for (x = x1; x <= x2; x++) {
+- gp = &term.line[y][x];
+- if (selected(x, y))
+- selclear();
+- gp->fg = term.c.attr.fg;
+- gp->bg = term.c.attr.bg;
+- gp->mode = 0;
+- gp->u = ' ';
+- }
++ for (x = x1; x <= x2; x++)
++ tclearglyph(&term.line[y][x], usecurattr);
+ }
+ }
+
+ void
+ tdeletechar(int n)
+ {
+- int dst, src, size;
+- Glyph *line;
+-
+- LIMIT(n, 0, term.col - term.c.x);
++ int src, dst, size;
++ Line line;
+
++ if (n <= 0)
++ return;
+ dst = term.c.x;
+- src = term.c.x + n;
++ src = MIN(term.c.x + n, term.col);
+ size = term.col - src;
+- line = term.line[term.c.y];
+-
+- memmove(&line[dst], &line[src], size * sizeof(Glyph));
+- tclearregion(term.col-n, term.c.y, term.col-1, term.c.y);
++ if (size > 0) { /* otherwise src would point beyond the array
++ https://stackoverflow.com/questions/29844298 */
++ line = term.line[term.c.y];
++ memmove(&line[dst], &line[src], size * sizeof(Glyph));
++ }
++ tclearregion(dst + size, term.c.y, term.col - 1, term.c.y, 1);
+ }
+
+ void
+ tinsertblank(int n)
+ {
+- int dst, src, size;
+- Glyph *line;
++ int src, dst, size;
++ Line line;
+
+- LIMIT(n, 0, term.col - term.c.x);
+-
+- dst = term.c.x + n;
++ if (n <= 0)
++ return;
++ dst = MIN(term.c.x + n, term.col);
+ src = term.c.x;
+ size = term.col - dst;
+- line = term.line[term.c.y];
+-
+- memmove(&line[dst], &line[src], size * sizeof(Glyph));
+- tclearregion(src, term.c.y, dst - 1, term.c.y);
++ if (size > 0) { /* otherwise dst would point beyond the array */
++ line = term.line[term.c.y];
++ memmove(&line[dst], &line[src], size * sizeof(Glyph));
++ }
++ tclearregion(src, term.c.y, dst - 1, term.c.y, 1);
+ }
+
+ void
+ tinsertblankline(int n)
+ {
+ if (BETWEEN(term.c.y, term.top, term.bot))
+- tscrolldown(term.c.y, n, 0);
++ tscrolldown(term.c.y, n);
+ }
+
+ void
+ tdeleteline(int n)
+ {
+ if (BETWEEN(term.c.y, term.top, term.bot))
+- tscrollup(term.c.y, n, 0);
++ tscrollup(term.c.y, term.bot, n, SCROLL_NOSAVEHIST);
+ }
+
+ int32_t
+@@ -1528,7 +1695,7 @@ tsetscroll(int t, int b)
+ void
+ tsetmode(int priv, int set, const int *args, int narg)
+ {
+- int alt; const int *lim;
++ const int *lim;
+
+ for (lim = args + narg; args < lim; ++args) {
+ if (priv) {
+@@ -1589,25 +1756,18 @@ tsetmode(int priv, int set, const int *args, int narg)
+ xsetmode(set, MODE_8BIT);
+ break;
+ case 1049: /* swap screen & set/restore cursor as xterm */
+- if (!allowaltscreen)
+- break;
+- tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
+- /* FALLTHROUGH */
+ case 47: /* swap screen */
+- case 1047:
++ case 1047: /* swap screen, clearing alternate screen */
+ if (!allowaltscreen)
+ break;
+- alt = IS_SET(MODE_ALTSCREEN);
+- if (alt) {
+- tclearregion(0, 0, term.col-1,
+- term.row-1);
+- }
+- if (set ^ alt) /* set is always 1 or 0 */
+- tswapscreen();
+- if (*args != 1049)
+- break;
+- /* FALLTHROUGH */
++ if (set)
++ tloadaltscreen(*args == 1049, *args == 1049);
++ else
++ tloaddefscreen(*args == 1047, *args == 1049);
++ break;
+ case 1048:
++ if (!allowaltscreen)
++ break;
+ tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
+ break;
+ case 2004: /* 2004: bracketed paste mode */
+@@ -1659,7 +1819,7 @@ void
+ csihandle(void)
+ {
+ char buf[40];
+- int len;
++ int n, x;
+
+ switch (csiescseq.mode[0]) {
+ default:
+@@ -1757,20 +1917,30 @@ csihandle(void)
+ case 'J': /* ED -- Clear screen */
+ switch (csiescseq.arg[0]) {
+ case 0: /* below */
+- tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
++ tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 1);
+ if (term.c.y < term.row-1) {
+- tclearregion(0, term.c.y+1, term.col-1,
+- term.row-1);
++ tclearregion(0, term.c.y+1, term.col-1, term.row-1, 1);
+ }
+ break;
+ case 1: /* above */
+- if (term.c.y > 1)
+- tclearregion(0, 0, term.col-1, term.c.y-1);
+- tclearregion(0, term.c.y, term.c.x, term.c.y);
++ if (term.c.y >= 1)
++ tclearregion(0, 0, term.col-1, term.c.y-1, 1);
++ tclearregion(0, term.c.y, term.c.x, term.c.y, 1);
+ break;
+ case 2: /* all */
+- tclearregion(0, 0, term.col-1, term.row-1);
+- break;
++ if (IS_SET(MODE_ALTSCREEN)) {
++ tclearregion(0, 0, term.col-1, term.row-1, 1);
++ break;
++ }
++ /* vte does this:
++ tscrollup(0, term.row-1, term.row, SCROLL_SAVEHIST); */
++
++ /* alacritty does this: */
++ for (n = term.row-1; n >= 0 && tlinelen(term.line[n]) == 0; n--);
++ if (n >= 0)
++ tscrollup(0, term.row-1, n+1, SCROLL_SAVEHIST);
++ tscrollup(0, term.row-1, term.row-n-1, SCROLL_NOSAVEHIST);
++ break;
+ default:
+ goto unknown;
+ }
+@@ -1778,24 +1948,24 @@ csihandle(void)
+ case 'K': /* EL -- Clear line */
+ switch (csiescseq.arg[0]) {
+ case 0: /* right */
+- tclearregion(term.c.x, term.c.y, term.col-1,
+- term.c.y);
++ tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 1);
+ break;
+ case 1: /* left */
+- tclearregion(0, term.c.y, term.c.x, term.c.y);
++ tclearregion(0, term.c.y, term.c.x, term.c.y, 1);
+ break;
+ case 2: /* all */
+- tclearregion(0, term.c.y, term.col-1, term.c.y);
++ tclearregion(0, term.c.y, term.col-1, term.c.y, 1);
+ break;
+ }
+ break;
+ case 'S': /* SU -- Scroll <n> line up */
+ DEFAULT(csiescseq.arg[0], 1);
+- tscrollup(term.top, csiescseq.arg[0], 0);
++ /* xterm, urxvt, alacritty save this in history */
++ tscrollup(term.top, term.bot, csiescseq.arg[0], SCROLL_SAVEHIST);
+ break;
+ case 'T': /* SD -- Scroll <n> line down */
+ DEFAULT(csiescseq.arg[0], 1);
+- tscrolldown(term.top, csiescseq.arg[0], 0);
++ tscrolldown(term.top, csiescseq.arg[0]);
+ break;
+ case 'L': /* IL -- Insert <n> blank lines */
+ DEFAULT(csiescseq.arg[0], 1);
+@@ -1809,9 +1979,11 @@ csihandle(void)
+ tdeleteline(csiescseq.arg[0]);
+ break;
+ case 'X': /* ECH -- Erase <n> char */
++ if (csiescseq.arg[0] < 0)
++ return;
+ DEFAULT(csiescseq.arg[0], 1);
+- tclearregion(term.c.x, term.c.y,
+- term.c.x + csiescseq.arg[0] - 1, term.c.y);
++ x = MIN(term.c.x + csiescseq.arg[0], term.col) - 1;
++ tclearregion(term.c.x, term.c.y, x, term.c.y, 1);
+ break;
+ case 'P': /* DCH -- Delete <n> char */
+ DEFAULT(csiescseq.arg[0], 1);
+@@ -1833,9 +2005,9 @@ csihandle(void)
+ break;
+ case 'n': /* DSR – Device Status Report (cursor position) */
+ if (csiescseq.arg[0] == 6) {
+- len = snprintf(buf, sizeof(buf), "\033[%i;%iR",
++ n = snprintf(buf, sizeof(buf), "\033[%i;%iR",
+ term.c.y+1, term.c.x+1);
+- ttywrite(buf, len, 0);
++ ttywrite(buf, n, 0);
+ }
+ break;
+ case 'r': /* DECSTBM -- Set Scrolling Region */
+@@ -2128,16 +2300,8 @@ tdumpsel(void)
+ void
+ tdumpline(int n)
+ {
+- char buf[UTF_SIZ];
+- const Glyph *bp, *end;
+-
+- bp = &term.line[n][0];
+- end = &bp[MIN(tlinelen(n), term.col) - 1];
+- if (bp != end || bp->u != ' ') {
+- for ( ; bp <= end; ++bp)
+- tprinter(buf, utf8encode(bp->u, buf));
+- }
+- tprinter("\n", 1);
++ char str[(term.col + 1) * UTF_SIZ];
++ tprinter(str, tgetline(str, &term.line[n][0]));
+ }
+
+ void
+@@ -2358,7 +2522,7 @@ eschandle(uchar ascii)
+ return 0;
+ case 'D': /* IND -- Linefeed */
+ if (term.c.y == term.bot) {
+- tscrollup(term.top, 1, 1);
++ tscrollup(term.top, term.bot, 1, SCROLL_SAVEHIST);
+ } else {
+ tmoveto(term.c.x, term.c.y+1);
+ }
+@@ -2371,7 +2535,7 @@ eschandle(uchar ascii)
+ break;
+ case 'M': /* RI -- Reverse index */
+ if (term.c.y == term.top) {
+- tscrolldown(term.top, 1, 1);
++ tscrolldown(term.top, 1);
+ } else {
+ tmoveto(term.c.x, term.c.y-1);
+ }
+@@ -2511,7 +2675,8 @@ check_control_code:
+ */
+ return;
+ }
+- if (selected(term.c.x, term.c.y))
++ /* selected() takes relative coordinates */
++ if (selected(term.c.x + term.scr, term.c.y + term.scr))
+ selclear();
+
+ gp = &term.line[term.c.y][term.c.x];
+@@ -2546,6 +2711,7 @@ check_control_code:
+ if (term.c.x+width < term.col) {
+ tmoveto(term.c.x+width, term.c.y);
+ } else {
++ term.wrapcwidth[IS_SET(MODE_ALTSCREEN)] = width;
+ term.c.state |= CURSOR_WRAPNEXT;
+ }
+ }
+@@ -2583,93 +2749,275 @@ twrite(const char *buf, int buflen, int show_ctrl)
+ }
+
+ void
+-tresize(int col, int row)
++treflow(int col, int row)
+ {
+ int i, j;
+- int minrow = MIN(row, term.row);
+- int mincol = MIN(col, term.col);
+- int *bp;
+- TCursor c;
+-
+- if (col < 1 || row < 1) {
+- fprintf(stderr,
+- "tresize: error resizing to %dx%d\n", col, row);
+- return;
++ int oce, nce, bot, scr;
++ int ox = 0, oy = -term.histf, nx = 0, ny = -1, len;
++ int cy = -1; /* proxy for new y coordinate of cursor */
++ int nlines;
++ Line *buf, line;
++
++ /* y coordinate of cursor line end */
++ for (oce = term.c.y; oce < term.row - 1 &&
++ tiswrapped(term.line[oce]); oce++);
++
++ nlines = term.histf + oce + 1;
++ if (col < term.col) {
++ /* each line can take this many lines after reflow */
++ j = (term.col + col - 1) / col;
++ nlines = j * nlines;
++ if (nlines > HISTSIZE + RESIZEBUFFER + row) {
++ nlines = HISTSIZE + RESIZEBUFFER + row;
++ oy = -(nlines / j - oce - 1);
++ }
+ }
++ buf = xmalloc(nlines * sizeof(Line));
++ do {
++ if (!nx)
++ buf[++ny] = xmalloc(col * sizeof(Glyph));
++ if (!ox) {
++ line = TLINEABS(oy);
++ len = tlinelen(line);
++ }
++ if (oy == term.c.y) {
++ if (!ox)
++ len = MAX(len, term.c.x + 1);
++ /* update cursor */
++ if (cy < 0 && term.c.x - ox < col - nx) {
++ term.c.x = nx + term.c.x - ox, cy = ny;
++ UPDATEWRAPNEXT(0, col);
++ }
++ }
++ /* get reflowed lines in buf */
++ if (col - nx > len - ox) {
++ memcpy(&buf[ny][nx], &line[ox], (len-ox) * sizeof(Glyph));
++ nx += len - ox;
++ if (len == 0 || !(line[len - 1].mode & ATTR_WRAP)) {
++ for (j = nx; j < col; j++)
++ tclearglyph(&buf[ny][j], 0);
++ nx = 0;
++ } else if (nx > 0) {
++ buf[ny][nx - 1].mode &= ~ATTR_WRAP;
++ }
++ ox = 0, oy++;
++ } else if (col - nx == len - ox) {
++ memcpy(&buf[ny][nx], &line[ox], (col-nx) * sizeof(Glyph));
++ ox = 0, oy++, nx = 0;
++ } else/* if (col - nx < len - ox) */ {
++ memcpy(&buf[ny][nx], &line[ox], (col-nx) * sizeof(Glyph));
++ ox += col - nx;
++ buf[ny][col - 1].mode |= ATTR_WRAP;
++ nx = 0;
++ }
++ } while (oy <= oce);
++ if (nx)
++ for (j = nx; j < col; j++)
++ tclearglyph(&buf[ny][j], 0);
+
+- /*
+- * slide screen to keep cursor where we expect it -
+- * tscrollup would work here, but we can optimize to
+- * memmove because we're freeing the earlier lines
+- */
+- for (i = 0; i <= term.c.y - row; i++) {
++ /* free extra lines */
++ for (i = row; i < term.row; i++)
+ free(term.line[i]);
+- free(term.alt[i]);
++ /* resize to new height */
++ term.line = xrealloc(term.line, row * sizeof(Line));
++
++ bot = MIN(ny, row - 1);
++ scr = MAX(row - term.row, 0);
++ /* update y coordinate of cursor line end */
++ nce = MIN(oce + scr, bot);
++ /* update cursor y coordinate */
++ term.c.y = nce - (ny - cy);
++ if (term.c.y < 0) {
++ j = nce, nce = MIN(nce + -term.c.y, bot);
++ term.c.y += nce - j;
++ while (term.c.y < 0) {
++ free(buf[ny--]);
++ term.c.y++;
++ }
+ }
+- /* ensure that both src and dst are not NULL */
+- if (i > 0) {
+- memmove(term.line, term.line + i, row * sizeof(Line));
+- memmove(term.alt, term.alt + i, row * sizeof(Line));
++ /* allocate new rows */
++ for (i = row - 1; i > nce; i--) {
++ term.line[i] = xmalloc(col * sizeof(Glyph));
++ for (j = 0; j < col; j++)
++ tclearglyph(&term.line[i][j], 0);
+ }
+- for (i += row; i < term.row; i++) {
++ /* fill visible area */
++ for (/*i = nce */; i >= term.row; i--, ny--)
++ term.line[i] = buf[ny];
++ for (/*i = term.row - 1 */; i >= 0; i--, ny--) {
+ free(term.line[i]);
+- free(term.alt[i]);
++ term.line[i] = buf[ny];
++ }
++ /* fill lines in history buffer and update term.histf */
++ for (/*i = -1 */; ny >= 0 && i >= -HISTSIZE; i--, ny--) {
++ j = (term.histi + i + 1 + HISTSIZE) % HISTSIZE;
++ free(term.hist[j]);
++ term.hist[j] = buf[ny];
+ }
++ term.histf = -i - 1;
++ term.scr = MIN(term.scr, term.histf);
++ /* resize rest of the history lines */
++ for (/*i = -term.histf - 1 */; i >= -HISTSIZE; i--) {
++ j = (term.histi + i + 1 + HISTSIZE) % HISTSIZE;
++ term.hist[j] = xrealloc(term.hist[j], col * sizeof(Glyph));
++ }
++ free(buf);
++}
+
+- /* resize to new height */
+- term.line = xrealloc(term.line, row * sizeof(Line));
+- term.alt = xrealloc(term.alt, row * sizeof(Line));
+- term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
+- term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
++void
++rscrolldown(int n)
++{
++ int i;
++ Line temp;
+
+- 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 = ' ';
+- }
+- }
++ /* can never be true as of now
++ if (IS_SET(MODE_ALTSCREEN))
++ return; */
+
+- /* resize each row 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));
+- }
++ if ((n = MIN(n, term.histf)) <= 0)
++ return;
+
+- /* allocate any new rows */
+- for (/* i = minrow */; i < row; i++) {
+- term.line[i] = xmalloc(col * sizeof(Glyph));
+- term.alt[i] = xmalloc(col * sizeof(Glyph));
++ for (i = term.c.y + n; i >= n; i--) {
++ temp = term.line[i];
++ term.line[i] = term.line[i-n];
++ term.line[i-n] = temp;
+ }
++ for (/*i = n - 1 */; i >= 0; i--) {
++ temp = term.line[i];
++ term.line[i] = term.hist[term.histi];
++ term.hist[term.histi] = temp;
++ term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE;
++ }
++ term.c.y += n;
++ term.histf -= n;
++ if ((i = term.scr - n) >= 0) {
++ term.scr = i;
++ } else {
++ term.scr = 0;
++ if (sel.ob.x != -1 && !sel.alt)
++ selmove(-i);
++ }
++}
++
++void
++tresize(int col, int row)
++{
++ int *bp;
++
++ /* col and row are always MAX(_, 1)
++ if (col < 1 || row < 1) {
++ fprintf(stderr, "tresize: error resizing to %dx%d\n", col, row);
++ return;
++ } */
++
++ term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
++ term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
+ if (col > term.col) {
+ bp = term.tabs + term.col;
+-
+ memset(bp, 0, sizeof(*term.tabs) * (col - term.col));
+ while (--bp > term.tabs && !*bp)
+ /* nothing */ ;
+ for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces)
+ *bp = 1;
+ }
+- /* update terminal size */
+- term.col = col;
+- term.row = row;
+- /* reset scrolling region */
+- tsetscroll(0, row-1);
+- /* make use of the LIMIT in tmoveto */
+- tmoveto(term.c.x, term.c.y);
+- /* Clearing both screens (it makes dirty all lines) */
+- c = term.c;
+- for (i = 0; i < 2; i++) {
+- if (mincol < col && 0 < minrow) {
+- tclearregion(mincol, 0, col - 1, minrow - 1);
++
++ if (IS_SET(MODE_ALTSCREEN))
++ tresizealt(col, row);
++ else
++ tresizedef(col, row);
++}
++
++void
++tresizedef(int col, int row)
++{
++ int i, j;
++
++ /* return if dimensions haven't changed */
++ if (term.col == col && term.row == row) {
++ tfulldirt();
++ return;
++ }
++ if (col != term.col) {
++ if (!sel.alt)
++ selremove();
++ treflow(col, row);
++ } else {
++ /* slide screen up if otherwise cursor would get out of the screen */
++ if (term.c.y >= row) {
++ tscrollup(0, term.row - 1, term.c.y - row + 1, SCROLL_RESIZE);
++ term.c.y = row - 1;
+ }
+- if (0 < col && minrow < row) {
+- tclearregion(0, minrow, col - 1, row - 1);
++ for (i = row; i < term.row; i++)
++ free(term.line[i]);
++
++ /* resize to new height */
++ term.line = xrealloc(term.line, row * sizeof(Line));
++ /* allocate any new rows */
++ for (i = term.row; i < row; i++) {
++ term.line[i] = xmalloc(col * sizeof(Glyph));
++ for (j = 0; j < col; j++)
++ tclearglyph(&term.line[i][j], 0);
+ }
+- tswapscreen();
+- tcursor(CURSOR_LOAD);
++ /* scroll down as much as height has increased */
++ rscrolldown(row - term.row);
++ }
++ /* update terminal size */
++ term.col = col, term.row = row;
++ /* reset scrolling region */
++ term.top = 0, term.bot = row - 1;
++ /* dirty all lines */
++ tfulldirt();
++}
++
++void
++tresizealt(int col, int row)
++{
++ int i, j;
++
++ /* return if dimensions haven't changed */
++ if (term.col == col && term.row == row) {
++ tfulldirt();
++ return;
+ }
+- term.c = c;
++ if (sel.alt)
++ selremove();
++ /* slide screen up if otherwise cursor would get out of the screen */
++ for (i = 0; i <= term.c.y - row; i++)
++ free(term.line[i]);
++ if (i > 0) {
++ /* ensure that both src and dst are not NULL */
++ memmove(term.line, term.line + i, row * sizeof(Line));
++ term.c.y = row - 1;
++ }
++ for (i += row; i < term.row; i++)
++ free(term.line[i]);
++ /* resize to new height */
++ term.line = xrealloc(term.line, row * sizeof(Line));
++ /* resize to new width */
++ for (i = 0; i < MIN(row, term.row); i++) {
++ term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
++ for (j = term.col; j < col; j++)
++ tclearglyph(&term.line[i][j], 0);
++ }
++ /* allocate any new rows */
++ for (/*i = MIN(row, term.row) */; i < row; i++) {
++ term.line[i] = xmalloc(col * sizeof(Glyph));
++ for (j = 0; j < col; j++)
++ tclearglyph(&term.line[i][j], 0);
++ }
++ /* update cursor */
++ if (term.c.x >= col) {
++ term.c.state &= ~CURSOR_WRAPNEXT;
++ term.c.x = col - 1;
++ } else {
++ UPDATEWRAPNEXT(1, col);
++ }
++ /* update terminal size */
++ term.col = col, term.row = row;
++ /* reset scrolling region */
++ term.top = 0, term.bot = row - 1;
++ /* dirty all lines */
++ tfulldirt();
+ }
+
+ void
+@@ -2709,9 +3057,8 @@ draw(void)
+ cx--;
+
+ drawregion(0, 0, term.col, term.row);
+- 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]);
++ 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 818a6f8..514ec08 100644
+--- a/st.h
++++ b/st.h
+@@ -22,17 +22,19 @@
+
+ enum glyph_attribute {
+ ATTR_NULL = 0,
+- ATTR_BOLD = 1 << 0,
+- ATTR_FAINT = 1 << 1,
+- ATTR_ITALIC = 1 << 2,
+- ATTR_UNDERLINE = 1 << 3,
+- ATTR_BLINK = 1 << 4,
+- ATTR_REVERSE = 1 << 5,
+- ATTR_INVISIBLE = 1 << 6,
+- ATTR_STRUCK = 1 << 7,
+- ATTR_WRAP = 1 << 8,
+- ATTR_WIDE = 1 << 9,
+- ATTR_WDUMMY = 1 << 10,
++ ATTR_SET = 1 << 0,
++ ATTR_BOLD = 1 << 1,
++ ATTR_FAINT = 1 << 2,
++ ATTR_ITALIC = 1 << 3,
++ ATTR_UNDERLINE = 1 << 4,
++ ATTR_BLINK = 1 << 5,
++ ATTR_REVERSE = 1 << 6,
++ ATTR_INVISIBLE = 1 << 7,
++ ATTR_STRUCK = 1 << 8,
++ ATTR_WRAP = 1 << 9,
++ ATTR_WIDE = 1 << 10,
++ ATTR_WDUMMY = 1 << 11,
++ ATTR_SELECTED = 1 << 12,
+ ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
+ };
+
+@@ -90,6 +92,7 @@ void toggleprinter(const Arg *);
+
+ int tattrset(int);
+ void tnew(int, int);
++int tisaltscreen(void);
+ void tresize(int, int);
+ void tsetdirtattr(int);
+ void ttyhangup(void);
diff --git a/patches/st-scrollback-ringbuffer-0.8.5.diff b/patches/st-scrollback-ringbuffer-0.8.5.diff
@@ -0,0 +1,730 @@
+commit 0663bdf11a409961da5b1120741a69814da8ce65
+Author: Timo Röhling <timo@gaussglocke.de>
+Date: Tue Nov 23 19:45:33 2021 +0100
+
+ Terminal scrollback with ring buffer
+
+ This patch adds a ring buffer for scrollback to the terminal. The
+ advantage of using a ring buffer is that the common case, scrolling with
+ no static screen content, can be achieved very efficiently by
+ incrementing and decrementing the starting line (modulo buffer size).
+
+ The scrollback buffer is limited to HISTSIZE lines in order to bound
+ memory usage. As the lines are allocated on demand, it is possible to
+ implement unlimited scrollback with few changes. If the terminal is
+ reset, the scroll back buffer is reset, too.
+
+diff --git a/config.def.h b/config.def.h
+index 91ab8ca..e3b469b 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -201,6 +201,8 @@ static Shortcut shortcuts[] = {
+ { TERMMOD, XK_Y, selpaste, {.i = 0} },
+ { ShiftMask, XK_Insert, selpaste, {.i = 0} },
+ { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
++ { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
++ { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
+ };
+
+ /*
+diff --git a/st.c b/st.c
+index 51049ba..f9e24ba 100644
+--- a/st.c
++++ b/st.c
+@@ -43,6 +43,10 @@
+ #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
+ #define ISDELIM(u) (u && wcschr(worddelimiters, u))
+
++#define TSCREEN term.screen[IS_SET(MODE_ALTSCREEN)]
++#define TLINEOFFSET(y) (((y) + TSCREEN.cur - TSCREEN.off + TSCREEN.size) % TSCREEN.size)
++#define TLINE(y) (TSCREEN.buffer[TLINEOFFSET(y)])
++
+ enum term_mode {
+ MODE_WRAP = 1 << 0,
+ MODE_INSERT = 1 << 1,
+@@ -109,12 +113,21 @@ typedef struct {
+ int alt;
+ } Selection;
+
++/* Screen lines */
++typedef struct {
++ Line* buffer; /* ring buffer */
++ int size; /* size of buffer */
++ int cur; /* start of active screen */
++ int off; /* scrollback line offset */
++ TCursor sc; /* saved cursor */
++} LineBuffer;
++
+ /* Internal representation of the screen */
+ typedef struct {
+ int row; /* nb row */
+ int col; /* nb col */
+- Line *line; /* screen */
+- Line *alt; /* alternate screen */
++ LineBuffer screen[2]; /* screen and alternate screen */
++ int linelen; /* allocated line length */
+ int *dirty; /* dirtyness of lines */
+ TCursor c; /* cursor */
+ int ocx; /* old cursor col */
+@@ -202,6 +215,8 @@ static void tdeftran(char);
+ static void tstrsequence(uchar);
+
+ static void drawregion(int, int, int, int);
++static void clearline(Line, Glyph, int, int);
++static Line ensureline(Line);
+
+ static void selnormalize(void);
+ static void selscroll(int, int);
+@@ -415,11 +430,12 @@ int
+ tlinelen(int y)
+ {
+ int i = term.col;
++ Line line = TLINE(y);
+
+- if (term.line[y][i - 1].mode & ATTR_WRAP)
++ if (line[i - 1].mode & ATTR_WRAP)
+ return i;
+
+- while (i > 0 && term.line[y][i - 1].u == ' ')
++ while (i > 0 && line[i - 1].u == ' ')
+ --i;
+
+ return i;
+@@ -528,7 +544,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;
+@@ -543,14 +559,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)))
+@@ -571,14 +587,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;
+ }
+@@ -609,13 +625,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;
+
+@@ -956,12 +972,15 @@ int
+ tattrset(int attr)
+ {
+ int i, j;
++ int y = TLINEOFFSET(0);
+
+ for (i = 0; i < term.row-1; i++) {
++ Line line = TSCREEN.buffer[y];
+ for (j = 0; j < term.col-1; j++) {
+- if (term.line[i][j].mode & attr)
++ if (line[j].mode & attr)
+ return 1;
+ }
++ y = (y+1) % TSCREEN.size;
+ }
+
+ return 0;
+@@ -983,14 +1002,17 @@ void
+ tsetdirtattr(int attr)
+ {
+ int i, j;
++ int y = TLINEOFFSET(0);
+
+ for (i = 0; i < term.row-1; i++) {
++ Line line = TSCREEN.buffer[y];
+ for (j = 0; j < term.col-1; j++) {
+- if (term.line[i][j].mode & attr) {
++ if (line[j].mode & attr) {
+ tsetdirt(i, i);
+ break;
+ }
+ }
++ y = (y+1) % TSCREEN.size;
+ }
+ }
+
+@@ -1003,27 +1025,19 @@ tfulldirt(void)
+ void
+ tcursor(int mode)
+ {
+- static TCursor c[2];
+- int alt = IS_SET(MODE_ALTSCREEN);
+-
+ if (mode == CURSOR_SAVE) {
+- c[alt] = term.c;
++ TSCREEN.sc = term.c;
+ } else if (mode == CURSOR_LOAD) {
+- term.c = c[alt];
+- tmoveto(c[alt].x, c[alt].y);
++ term.c = TSCREEN.sc;
++ tmoveto(term.c.x, term.c.y);
+ }
+ }
+
+ void
+ treset(void)
+ {
+- uint i;
+-
+- term.c = (TCursor){{
+- .mode = ATTR_NULL,
+- .fg = defaultfg,
+- .bg = defaultbg
+- }, .x = 0, .y = 0, .state = CURSOR_DEFAULT};
++ int i, j;
++ Glyph g = (Glyph){ .fg = defaultfg, .bg = defaultbg};
+
+ memset(term.tabs, 0, term.col * sizeof(*term.tabs));
+ for (i = tabspaces; i < term.col; i += tabspaces)
+@@ -1035,17 +1049,37 @@ treset(void)
+ term.charset = 0;
+
+ for (i = 0; i < 2; i++) {
+- tmoveto(0, 0);
+- tcursor(CURSOR_SAVE);
+- tclearregion(0, 0, term.col-1, term.row-1);
+- tswapscreen();
++ term.screen[i].sc = (TCursor){{
++ .fg = defaultfg,
++ .bg = defaultbg
++ }};
++ term.screen[i].cur = 0;
++ term.screen[i].off = 0;
++ for (j = 0; j < term.row; ++j) {
++ if (term.col != term.linelen)
++ term.screen[i].buffer[j] = xrealloc(term.screen[i].buffer[j], term.col * sizeof(Glyph));
++ clearline(term.screen[i].buffer[j], g, 0, term.col);
++ }
++ for (j = term.row; j < term.screen[i].size; ++j) {
++ free(term.screen[i].buffer[j]);
++ term.screen[i].buffer[j] = NULL;
++ }
+ }
++ tcursor(CURSOR_LOAD);
++ term.linelen = term.col;
++ tfulldirt();
+ }
+
+ void
+ tnew(int col, int row)
+ {
+- term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } };
++ int i;
++ term = (Term){};
++ term.screen[0].buffer = xmalloc(HISTSIZE * sizeof(Line));
++ term.screen[0].size = HISTSIZE;
++ term.screen[1].buffer = NULL;
++ for (i = 0; i < HISTSIZE; ++i) term.screen[0].buffer[i] = NULL;
++
+ tresize(col, row);
+ treset();
+ }
+@@ -1053,14 +1087,42 @@ tnew(int col, int row)
+ void
+ tswapscreen(void)
+ {
+- Line *tmp = term.line;
+-
+- term.line = term.alt;
+- term.alt = tmp;
+ term.mode ^= MODE_ALTSCREEN;
+ tfulldirt();
+ }
+
++void
++kscrollup(const Arg *a)
++{
++ int n = a->i;
++
++ if (IS_SET(MODE_ALTSCREEN))
++ return;
++
++ if (n < 0) n = (-n) * term.row;
++ if (n > TSCREEN.size - term.row - TSCREEN.off) n = TSCREEN.size - term.row - TSCREEN.off;
++ while (!TLINE(-n)) --n;
++ TSCREEN.off += n;
++ selscroll(0, n);
++ tfulldirt();
++}
++
++void
++kscrolldown(const Arg *a)
++{
++
++ int n = a->i;
++
++ if (IS_SET(MODE_ALTSCREEN))
++ return;
++
++ if (n < 0) n = (-n) * term.row;
++ if (n > TSCREEN.off) n = TSCREEN.off;
++ TSCREEN.off -= n;
++ selscroll(0, -n);
++ tfulldirt();
++}
++
+ void
+ tscrolldown(int orig, int n)
+ {
+@@ -1069,15 +1131,29 @@ tscrolldown(int orig, int n)
+
+ LIMIT(n, 0, term.bot-orig+1);
+
+- tsetdirt(orig, term.bot-n);
+- tclearregion(0, term.bot-n+1, term.col-1, term.bot);
++ /* Ensure that lines are allocated */
++ for (i = -n; i < 0; i++) {
++ TLINE(i) = ensureline(TLINE(i));
++ }
+
+- for (i = term.bot; i >= orig+n; i--) {
+- temp = term.line[i];
+- term.line[i] = term.line[i-n];
+- term.line[i-n] = temp;
++ /* Shift non-scrolling areas in ring buffer */
++ for (i = term.bot+1; i < term.row; i++) {
++ temp = TLINE(i);
++ TLINE(i) = TLINE(i-n);
++ TLINE(i-n) = temp;
++ }
++ for (i = 0; i < orig; i++) {
++ temp = TLINE(i);
++ TLINE(i) = TLINE(i-n);
++ TLINE(i-n) = temp;
+ }
+
++ /* Scroll buffer */
++ TSCREEN.cur = (TSCREEN.cur + TSCREEN.size - n) % TSCREEN.size;
++ /* Clear lines that have entered the view */
++ tclearregion(0, orig, term.linelen-1, orig+n-1);
++ /* Redraw portion of the screen that has scrolled */
++ tsetdirt(orig+n-1, term.bot);
+ selscroll(orig, n);
+ }
+
+@@ -1089,15 +1165,29 @@ tscrollup(int orig, int n)
+
+ LIMIT(n, 0, term.bot-orig+1);
+
+- tclearregion(0, orig, term.col-1, orig+n-1);
+- tsetdirt(orig+n, term.bot);
++ /* Ensure that lines are allocated */
++ for (i = term.row; i < term.row + n; i++) {
++ TLINE(i) = ensureline(TLINE(i));
++ }
+
+- for (i = orig; i <= term.bot-n; i++) {
+- temp = term.line[i];
+- term.line[i] = term.line[i+n];
+- term.line[i+n] = temp;
++ /* Shift non-scrolling areas in ring buffer */
++ for (i = orig-1; i >= 0; i--) {
++ temp = TLINE(i);
++ TLINE(i) = TLINE(i+n);
++ TLINE(i+n) = temp;
++ }
++ for (i = term.row-1; i >term.bot; i--) {
++ temp = TLINE(i);
++ TLINE(i) = TLINE(i+n);
++ TLINE(i+n) = temp;
+ }
+
++ /* Scroll buffer */
++ TSCREEN.cur = (TSCREEN.cur + n) % TSCREEN.size;
++ /* Clear lines that have entered the view */
++ tclearregion(0, term.bot-n+1, term.linelen-1, term.bot);
++ /* Redraw portion of the screen that has scrolled */
++ tsetdirt(orig, term.bot-n+1);
+ selscroll(orig, -n);
+ }
+
+@@ -1201,6 +1291,7 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
+ "⎻", "─", "⎼", "⎽", "├", "┤", "┴", "┬", /* p - w */
+ "│", "≤", "≥", "π", "≠", "£", "·", /* x - ~ */
+ };
++ Line line = TLINE(y);
+
+ /*
+ * The table is proudly stolen from rxvt.
+@@ -1209,25 +1300,25 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
+ BETWEEN(u, 0x41, 0x7e) && vt100_0[u - 0x41])
+ utf8decode(vt100_0[u - 0x41], &u, UTF_SIZ);
+
+- if (term.line[y][x].mode & ATTR_WIDE) {
++ if (line[x].mode & ATTR_WIDE) {
+ if (x+1 < term.col) {
+- term.line[y][x+1].u = ' ';
+- term.line[y][x+1].mode &= ~ATTR_WDUMMY;
++ line[x+1].u = ' ';
++ line[x+1].mode &= ~ATTR_WDUMMY;
+ }
+- } else if (term.line[y][x].mode & ATTR_WDUMMY) {
+- term.line[y][x-1].u = ' ';
+- term.line[y][x-1].mode &= ~ATTR_WIDE;
++ } else if (line[x].mode & ATTR_WDUMMY) {
++ line[x-1].u = ' ';
++ line[x-1].mode &= ~ATTR_WIDE;
+ }
+
+ term.dirty[y] = 1;
+- term.line[y][x] = *attr;
+- term.line[y][x].u = u;
++ line[x] = *attr;
++ line[x].u = u;
+ }
+
+ void
+ tclearregion(int x1, int y1, int x2, int y2)
+ {
+- int x, y, temp;
++ int x, y, L, S, temp;
+ Glyph *gp;
+
+ if (x1 > x2)
+@@ -1235,15 +1326,16 @@ tclearregion(int x1, int y1, int x2, int y2)
+ if (y1 > y2)
+ temp = y1, y1 = y2, y2 = temp;
+
+- LIMIT(x1, 0, term.col-1);
+- LIMIT(x2, 0, term.col-1);
++ LIMIT(x1, 0, term.linelen-1);
++ LIMIT(x2, 0, term.linelen-1);
+ LIMIT(y1, 0, term.row-1);
+ LIMIT(y2, 0, term.row-1);
+
++ L = TLINEOFFSET(y1);
+ for (y = y1; y <= y2; y++) {
+ term.dirty[y] = 1;
+ for (x = x1; x <= x2; x++) {
+- gp = &term.line[y][x];
++ gp = &TSCREEN.buffer[L][x];
+ if (selected(x, y))
+ selclear();
+ gp->fg = term.c.attr.fg;
+@@ -1251,6 +1343,7 @@ tclearregion(int x1, int y1, int x2, int y2)
+ gp->mode = 0;
+ gp->u = ' ';
+ }
++ L = (L + 1) % TSCREEN.size;
+ }
+ }
+
+@@ -1265,7 +1358,7 @@ tdeletechar(int n)
+ dst = term.c.x;
+ src = term.c.x + n;
+ size = term.col - src;
+- line = term.line[term.c.y];
++ line = TLINE(term.c.y);
+
+ memmove(&line[dst], &line[src], size * sizeof(Glyph));
+ tclearregion(term.col-n, term.c.y, term.col-1, term.c.y);
+@@ -1282,7 +1375,7 @@ tinsertblank(int n)
+ dst = term.c.x + n;
+ src = term.c.x;
+ size = term.col - dst;
+- line = term.line[term.c.y];
++ line = TLINE(term.c.y);
+
+ memmove(&line[dst], &line[src], size * sizeof(Glyph));
+ tclearregion(src, term.c.y, dst - 1, term.c.y);
+@@ -2103,7 +2196,7 @@ tdumpline(int n)
+ char buf[UTF_SIZ];
+ const Glyph *bp, *end;
+
+- bp = &term.line[n][0];
++ bp = &TLINE(n)[0];
+ end = &bp[MIN(tlinelen(n), term.col) - 1];
+ if (bp != end || bp->u != ' ') {
+ for ( ; bp <= end; ++bp)
+@@ -2486,11 +2579,11 @@ check_control_code:
+ if (selected(term.c.x, term.c.y))
+ selclear();
+
+- gp = &term.line[term.c.y][term.c.x];
++ gp = &TLINE(term.c.y)[term.c.x];
+ if (IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) {
+ gp->mode |= ATTR_WRAP;
+ tnewline(1);
+- gp = &term.line[term.c.y][term.c.x];
++ gp = &TLINE(term.c.y)[term.c.x];
+ }
+
+ if (IS_SET(MODE_INSERT) && term.c.x+width < term.col)
+@@ -2498,7 +2591,7 @@ check_control_code:
+
+ if (term.c.x+width > term.col) {
+ tnewline(1);
+- gp = &term.line[term.c.y][term.c.x];
++ gp = &TLINE(term.c.y)[term.c.x];
+ }
+
+ tsetchar(u, &term.c.attr, term.c.x, term.c.y);
+@@ -2529,6 +2622,11 @@ twrite(const char *buf, int buflen, int show_ctrl)
+ Rune u;
+ int n;
+
++ if (TSCREEN.off) {
++ TSCREEN.off = 0;
++ tfulldirt();
++ }
++
+ for (n = 0; n < buflen; n += charsize) {
+ if (IS_SET(MODE_UTF8)) {
+ /* process a complete utf8 char */
+@@ -2555,56 +2653,85 @@ twrite(const char *buf, int buflen, int show_ctrl)
+ }
+
+ void
+-tresize(int col, int row)
++clearline(Line line, Glyph g, int x, int xend)
+ {
+ int i;
++ g.mode = 0;
++ g.u = ' ';
++ for (i = x; i < xend; ++i) {
++ line[i] = g;
++ }
++}
++
++Line
++ensureline(Line line)
++{
++ if (!line) {
++ line = xmalloc(term.linelen * sizeof(Glyph));
++ }
++ return line;
++}
++
++void
++tresize(int col, int row)
++{
++ int i, j;
+ int minrow = MIN(row, term.row);
+ int mincol = MIN(col, term.col);
++ int linelen = MAX(col, term.linelen);
+ int *bp;
+- TCursor c;
+
+- if (col < 1 || row < 1) {
++ if (col < 1 || row < 1 || row > HISTSIZE) {
+ fprintf(stderr,
+ "tresize: error resizing to %dx%d\n", col, row);
+ return;
+ }
+
+- /*
+- * slide screen to keep cursor where we expect it -
+- * tscrollup would work here, but we can optimize to
+- * memmove because we're freeing the earlier lines
+- */
+- for (i = 0; i <= term.c.y - row; i++) {
+- free(term.line[i]);
+- free(term.alt[i]);
++ /* Shift buffer to keep the cursor where we expect it */
++ if (row <= term.c.y) {
++ term.screen[0].cur = (term.screen[0].cur - row + term.c.y + 1) % term.screen[0].size;
++ }
++
++ /* Resize and clear line buffers as needed */
++ if (linelen > term.linelen) {
++ for (i = 0; i < term.screen[0].size; ++i) {
++ if (term.screen[0].buffer[i]) {
++ term.screen[0].buffer[i] = xrealloc(term.screen[0].buffer[i], linelen * sizeof(Glyph));
++ clearline(term.screen[0].buffer[i], term.c.attr, term.linelen, linelen);
++ }
++ }
++ for (i = 0; i < minrow; ++i) {
++ term.screen[1].buffer[i] = xrealloc(term.screen[1].buffer[i], linelen * sizeof(Glyph));
++ clearline(term.screen[1].buffer[i], term.c.attr, term.linelen, linelen);
++ }
+ }
+- /* ensure that both src and dst are not NULL */
+- if (i > 0) {
+- memmove(term.line, term.line + i, row * sizeof(Line));
+- memmove(term.alt, term.alt + i, row * sizeof(Line));
++ /* Allocate all visible lines for regular line buffer */
++ for (j = term.screen[0].cur, i = 0; i < row; ++i, j = (j + 1) % term.screen[0].size)
++ {
++ if (!term.screen[0].buffer[j]) {
++ term.screen[0].buffer[j] = xmalloc(linelen * sizeof(Glyph));
++ }
++ if (i >= term.row) {
++ clearline(term.screen[0].buffer[j], term.c.attr, 0, linelen);
++ }
+ }
+- for (i += row; i < term.row; i++) {
+- free(term.line[i]);
+- free(term.alt[i]);
++ /* Resize alt screen */
++ term.screen[1].cur = 0;
++ term.screen[1].size = row;
++ for (i = row; i < term.row; ++i) {
++ free(term.screen[1].buffer[i]);
++ }
++ term.screen[1].buffer = xrealloc(term.screen[1].buffer, row * sizeof(Line));
++ for (i = term.row; i < row; ++i) {
++ term.screen[1].buffer[i] = xmalloc(linelen * sizeof(Glyph));
++ clearline(term.screen[1].buffer[i], term.c.attr, 0, linelen);
+ }
+
+ /* resize to new height */
+- term.line = xrealloc(term.line, row * sizeof(Line));
+- term.alt = xrealloc(term.alt, row * sizeof(Line));
+ 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 < minrow; i++) {
+- term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
+- term.alt[i] = xrealloc(term.alt[i], col * sizeof(Glyph));
+- }
+-
+- /* allocate any new rows */
+- for (/* i = minrow */; i < row; i++) {
+- term.line[i] = xmalloc(col * sizeof(Glyph));
+- term.alt[i] = xmalloc(col * sizeof(Glyph));
+- }
++ /* fix tabstops */
+ if (col > term.col) {
+ bp = term.tabs + term.col;
+
+@@ -2614,26 +2741,16 @@ tresize(int col, int row)
+ for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces)
+ *bp = 1;
+ }
++
+ /* update terminal size */
+ term.col = col;
+ term.row = row;
++ term.linelen = linelen;
+ /* reset scrolling region */
+ tsetscroll(0, row-1);
+ /* make use of the LIMIT in tmoveto */
+ tmoveto(term.c.x, term.c.y);
+- /* Clearing both screens (it makes dirty all lines) */
+- c = term.c;
+- for (i = 0; i < 2; i++) {
+- if (mincol < col && 0 < minrow) {
+- tclearregion(mincol, 0, col - 1, minrow - 1);
+- }
+- if (0 < col && minrow < row) {
+- tclearregion(0, minrow, col - 1, row - 1);
+- }
+- tswapscreen();
+- tcursor(CURSOR_LOAD);
+- }
+- term.c = c;
++ tfulldirt();
+ }
+
+ void
+@@ -2645,14 +2762,15 @@ resettitle(void)
+ void
+ drawregion(int x1, int y1, int x2, int y2)
+ {
+- int y;
++ int y, L;
+
++ L = TLINEOFFSET(y1);
+ for (y = y1; y < y2; y++) {
+- if (!term.dirty[y])
+- continue;
+-
+- term.dirty[y] = 0;
+- xdrawline(term.line[y], x1, y, x2);
++ if (term.dirty[y]) {
++ term.dirty[y] = 0;
++ xdrawline(TSCREEN.buffer[L], x1, y, x2);
++ }
++ L = (L + 1) % TSCREEN.size;
+ }
+ }
+
+@@ -2667,14 +2785,15 @@ draw(void)
+ /* adjust cursor position */
+ LIMIT(term.ocx, 0, term.col-1);
+ LIMIT(term.ocy, 0, term.row-1);
+- if (term.line[term.ocy][term.ocx].mode & ATTR_WDUMMY)
++ if (TLINE(term.ocy)[term.ocx].mode & ATTR_WDUMMY)
+ term.ocx--;
+- if (term.line[term.c.y][cx].mode & ATTR_WDUMMY)
++ if (TLINE(term.c.y)[cx].mode & ATTR_WDUMMY)
+ 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 (TSCREEN.off == 0)
++ xdrawcursor(cx, term.c.y, TLINE(term.c.y)[cx],
++ term.ocx, term.ocy, TLINE(term.ocy)[term.ocx]);
+ term.ocx = cx;
+ term.ocy = term.c.y;
+ xfinishdraw();
+diff --git a/st.h b/st.h
+index 519b9bd..b48e810 100644
+--- a/st.h
++++ b/st.h
+@@ -19,6 +19,7 @@
+
+ #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
+ #define IS_TRUECOL(x) (1 << 24 & (x))
++#define HISTSIZE 2000
+
+ enum glyph_attribute {
+ ATTR_NULL = 0,
+diff --git a/x.c b/x.c
+index 8a16faa..1bb5853 100644
+--- a/x.c
++++ b/x.c
+@@ -59,6 +59,8 @@ static void zoom(const Arg *);
+ static void zoomabs(const Arg *);
+ static void zoomreset(const Arg *);
+ static void ttysend(const Arg *);
++void kscrollup(const Arg *);
++void kscrolldown(const Arg *);
+
+ /* config.h for applying patches and the configuration. */
+ #include "config.h"
diff --git a/patches/st-universcroll-0.8.4.diff b/patches/st-universcroll-0.8.4.diff
@@ -0,0 +1,90 @@
+From 9726b1e58352126252412e101432e64d46fc51ca Mon Sep 17 00:00:00 2001
+From: Dennis Lee <dennis@dennislee.xyz>
+Date: Sun, 28 Jun 2020 23:01:03 -0700
+Subject: [PATCH] universcroll: mouse wheel only scroll in all modes
+
+Scroll normally via scroll(1), without Shift, when outside of
+`MODE_ALTSCREEN`. Inside an alt screen, continue to scroll normally
+without Shift; in this mode, your scrolling is automatically translated
+into ^Y and ^E. It just werks!
+
+Based on the existing mouse-altscreen patch
+https://st.suckless.org/patches/scrollback/
+adapted for st(1) 0.8.4 and scroll(1).
+---
+ config.def.h | 10 +++++-----
+ st.c | 5 +++++
+ st.h | 1 +
+ x.c | 2 ++
+ 4 files changed, 13 insertions(+), 5 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 6f05dce..62e87da 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -173,11 +173,11 @@ static uint forcemousemod = ShiftMask;
+ * Beware that overloading Button1 will disable the selection.
+ */
+ static MouseShortcut mshortcuts[] = {
+- /* mask button function argument release */
+- { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
+- { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
++ /* mask button function argument release alt */
++ { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
++ { XK_ANY_MOD, Button4, ttysend, {.s = "\033[5;2~"}, 0, -1 },
+ { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
+- { ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} },
++ { XK_ANY_MOD, Button5, ttysend, {.s = "\033[6;2~"}, 0, -1 },
+ { XK_ANY_MOD, Button5, ttysend, {.s = "\005"} },
+ };
+
+diff --git a/st.c b/st.c
+index 76b7e0d..1f65453 100644
+--- a/st.c
++++ b/st.c
+@@ -1047,6 +1047,11 @@ tnew(int col, int row)
+ treset();
+ }
+
++int tisaltscr(void)
++{
++ return IS_SET(MODE_ALTSCREEN);
++}
++
+ void
+ tswapscreen(void)
+ {
+diff --git a/st.h b/st.h
+index 3d351b6..39cc054 100644
+--- a/st.h
++++ b/st.h
+@@ -87,6 +87,7 @@ void sendbreak(const Arg *);
+ void toggleprinter(const Arg *);
+
+ int tattrset(int);
++int tisaltscr(void);
+ void tnew(int, int);
+ void tresize(int, int);
+ void tsetdirtattr(int);
+diff --git a/x.c b/x.c
+index 210f184..210dde9 100644
+--- a/x.c
++++ b/x.c
+@@ -34,6 +34,7 @@ typedef struct {
+ void (*func)(const Arg *);
+ const Arg arg;
+ uint release;
++ int altscrn; /* 0: don't care, -1: not alt screen, 1: alt screen */
+ } MouseShortcut;
+
+ typedef struct {
+@@ -446,6 +447,7 @@ mouseaction(XEvent *e, uint release)
+ for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
+ if (ms->release == release &&
+ ms->button == e->xbutton.button &&
++ (!ms->altscrn || (ms->altscrn == (tisaltscr() ? 1 : -1))) &&
+ (match(ms->mod, state) || /* exact or forced */
+ match(ms->mod, state & ~forcemousemod))) {
+ ms->func(&(ms->arg));
+--
+2.27.0
diff --git a/st.c b/st.c
@@ -35,6 +35,7 @@
#define ESC_ARG_SIZ 16
#define STR_BUF_SIZ ESC_BUF_SIZ
#define STR_ARG_SIZ ESC_ARG_SIZ
+#define HISTSIZE 2000
/* macros */
#define IS_SET(flag) ((term.mode & (flag)) != 0)
@@ -42,6 +43,9 @@
#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
#define ISDELIM(u) (u && wcschr(worddelimiters, u))
+#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \
+ term.scr + HISTSIZE + 1) % HISTSIZE] : \
+ term.line[(y) - term.scr])
enum term_mode {
MODE_WRAP = 1 << 0,
@@ -115,6 +119,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 */
@@ -185,8 +192,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(const int *, int);
static void tsetchar(Rune, const Glyph *, int, int);
static void tsetdirt(int, int);
@@ -409,10 +416,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;
@@ -521,7 +528,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;
@@ -536,14 +543,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)))
@@ -564,14 +571,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;
}
@@ -602,13 +609,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;
@@ -844,6 +851,9 @@ void
ttywrite(const char *s, size_t n, int may_echo)
{
const char *next;
+ Arg arg = (Arg) { .i = term.scr };
+
+ kscrolldown(&arg);
if (may_echo && IS_SET(MODE_ECHO))
twrite(s, n, 1);
@@ -1043,6 +1053,11 @@ tnew(int col, int row)
treset();
}
+int tisaltscr(void)
+{
+ return IS_SET(MODE_ALTSCREEN);
+}
+
void
tswapscreen(void)
{
@@ -1055,13 +1070,53 @@ tswapscreen(void)
}
void
-tscrolldown(int orig, int n)
+kscrolldown(const Arg* a)
+{
+ int n = a->i;
+
+ if (n < 0)
+ n = term.row + n;
+
+ if (n > term.scr)
+ n = term.scr;
+
+ if (term.scr > 0) {
+ term.scr -= n;
+ selscroll(0, -n);
+ tfulldirt();
+ }
+}
+
+void
+kscrollup(const Arg* a)
+{
+ int n = a->i;
+
+ if (n < 0)
+ n = term.row + n;
+
+ if (term.scr <= HISTSIZE-n) {
+ term.scr += n;
+ selscroll(0, n);
+ tfulldirt();
+ }
+}
+
+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);
@@ -1071,17 +1126,28 @@ tscrolldown(int orig, int n)
term.line[i-n] = temp;
}
- selscroll(orig, n);
+ if (term.scr == 0)
+ selscroll(orig, 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;
+ }
+
+ if (term.scr > 0 && term.scr < HISTSIZE)
+ term.scr = MIN(term.scr + n, HISTSIZE-1);
+
tclearregion(0, orig, term.col-1, orig+n-1);
tsetdirt(orig+n, term.bot);
@@ -1091,7 +1157,8 @@ tscrollup(int orig, int n)
term.line[i+n] = temp;
}
- selscroll(orig, -n);
+ if (term.scr == 0)
+ selscroll(orig, -n);
}
void
@@ -1120,7 +1187,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++;
}
@@ -1285,14 +1352,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 +1796,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);
@@ -2163,6 +2230,28 @@ tstrsequence(uchar c)
}
void
+tupdatebgcolor(int oldbg, int newbg)
+{
+ for (int y = 0; y < term.row; y++) {
+ for (int x = 0; x < term.col; x++) {
+ if (term.line[y][x].bg == oldbg)
+ term.line[y][x].bg = newbg;
+ }
+ }
+}
+
+void
+tupdatefgcolor(int oldfg, int newfg)
+{
+ for (int y = 0; y < term.row; y++) {
+ for (int x = 0; x < term.col; x++) {
+ if (term.line[y][x].fg == oldfg)
+ term.line[y][x].fg = newfg;
+ }
+ }
+}
+
+void
tcontrolcode(uchar ascii)
{
switch (ascii) {
@@ -2296,7 +2385,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);
}
@@ -2309,7 +2398,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);
}
@@ -2523,7 +2612,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;
@@ -2560,6 +2649,14 @@ tresize(int col, int row)
term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
+ 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 row to new width, zero-pad if needed */
for (i = 0; i < minrow; i++) {
term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
@@ -2618,7 +2715,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);
}
}
@@ -2639,8 +2736,9 @@ 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
@@ -81,15 +81,20 @@ void die(const char *, ...);
void redraw(void);
void draw(void);
+void kscrolldown(const Arg *);
+void kscrollup(const Arg *);
void printscreen(const Arg *);
void printsel(const Arg *);
void sendbreak(const Arg *);
void toggleprinter(const Arg *);
int tattrset(int);
+int tisaltscr(void);
void tnew(int, int);
void tresize(int, int);
void tsetdirtattr(int);
+void tupdatebgcolor(int, int);
+void tupdatefgcolor(int, int);
void ttyhangup(void);
int ttynew(const char *, char *, const char *, char **);
size_t ttyread(void);
diff --git a/tags b/tags
@@ -0,0 +1,577 @@
+$(OBJ) Makefile /^$(OBJ): config.h config.mk$/;" t
+-1000,7 +1066,8 patches/st-scrollback-reflow-0.8.5.diff /^@@ -1000,7 +1066,8 @@ tsetdirtattr(int attr)$/;" h modifiedFile:a/st.c
+-1003,27 +1025,19 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -1003,27 +1025,19 @@ tfulldirt(void)$/;" h modifiedFile:a/st.c
+-1017,51 +1084,116 patches/st-scrollback-reflow-0.8.5.diff /^@@ -1017,51 +1084,116 @@ tcursor(int mode)$/;" h modifiedFile:a/st.c
+-1035,17 +1049,37 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -1035,17 +1049,37 @@ treset(void)$/;" h modifiedFile:a/st.c
+-1047,6 +1047,11 patches/st-universcroll-0.8.4.diff /^@@ -1047,6 +1047,11 @@ tnew(int col, int row)$/;" h modifiedFile:a/st.c
+-105,6 +105,7 patches/st-alpha-20220206-0.8.5.diff /^@@ -105,6 +105,7 @@ typedef struct {$/;" h modifiedFile:a/x.c
+-1053,14 +1087,42 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -1053,14 +1087,42 @@ tnew(int col, int row)$/;" h modifiedFile:a/st.c
+-1061,13 +1071,53 patches/st-scrollback-20210507-4536f46.diff /^@@ -1061,13 +1071,53 @@ tswapscreen(void)$/;" h modifiedFile:a/st.c
+-1069,15 +1131,29 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -1069,15 +1131,29 @@ tscrolldown(int orig, int n)$/;" h modifiedFile:a/st.c
+-1069,17 +1201,22 patches/st-scrollback-reflow-0.8.5.diff /^@@ -1069,17 +1201,22 @@ kscrolldown(const Arg* a)$/;" h modifiedFile:a/st.c
+-1077,17 +1127,28 patches/st-scrollback-20210507-4536f46.diff /^@@ -1077,17 +1127,28 @@ tscrolldown(int orig, int n)$/;" h modifiedFile:a/st.c
+-1087,92 +1224,118 patches/st-scrollback-reflow-0.8.5.diff /^@@ -1087,92 +1224,118 @@ kscrollup(const Arg* a)$/;" h modifiedFile:a/st.c
+-1089,15 +1165,29 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -1089,15 +1165,29 @@ tscrollup(int orig, int n)$/;" h modifiedFile:a/st.c
+-109,12 +113,21 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -109,12 +113,21 @@ typedef struct {$/;" h modifiedFile:a/st.c
+-1097,7 +1158,8 patches/st-scrollback-20210507-4536f46.diff /^@@ -1097,7 +1158,8 @@ tscrollup(int orig, int n)$/;" h modifiedFile:a/st.c
+-1118,11 +1127,23 patches/st-alpha-20220206-0.8.5.diff /^@@ -1118,11 +1127,23 @@ xinit(int cols, int rows)$/;" h modifiedFile:a/x.c
+-1126,7 +1188,7 patches/st-scrollback-20210507-4536f46.diff /^@@ -1126,7 +1188,7 @@ tnewline(int first_col)$/;" h modifiedFile:a/st.c
+-1132,7 +1153,7 patches/st-alpha-20220206-0.8.5.diff /^@@ -1132,7 +1153,7 @@ xinit(int cols, int rows)$/;" h modifiedFile:a/x.c
+-115,6 +119,9 patches/st-scrollback-20210507-4536f46.diff /^@@ -115,6 +119,9 @@ typedef struct {$/;" h modifiedFile:a/st.c
+-1152,19 +1173,15 patches/st-alpha-20220206-0.8.5.diff /^@@ -1152,19 +1173,15 @@ xinit(int cols, int rows)$/;" h modifiedFile:a/x.c
+-1152,8 +1156,8 patches/st-anysize-20220718-baa9357.diff /^@@ -1152,8 +1156,8 @@ xinit(int cols, int rows)$/;" h modifiedFile:a/x.c
+-118,10 +138,11 patches/st-scrollback-reflow-0.8.5.diff /^@@ -118,10 +138,11 @@ typedef struct {$/;" h modifiedFile:a/st.c
+-1182,7 +1345,7 patches/st-scrollback-reflow-0.8.5.diff /^@@ -1182,7 +1345,7 @@ tnewline(int first_col)$/;" h modifiedFile:a/st.c
+-1201,6 +1291,7 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -1201,6 +1291,7 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)$/;" h modifiedFile:a/st.c
+-1209,25 +1300,25 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -1209,25 +1300,25 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)$/;" h modifiedFile:a/st.c
+-1235,15 +1326,16 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -1235,15 +1326,16 @@ tclearregion(int x1, int y1, int x2, int y2)$/;" h modifiedFile:a/st.c
+-1242,7 +1246,7 patches/st-anysize-20220718-baa9357.diff /^@@ -1242,7 +1246,7 @@ xinit(int cols, int rows)$/;" h modifiedFile:a/x.c
+-1251,6 +1343,7 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -1251,6 +1343,7 @@ tclearregion(int x1, int y1, int x2, int y2)$/;" h modifiedFile:a/st.c
+-126,3 +126,4 patches/st-alpha-20220206-0.8.5.diff /^@@ -126,3 +126,4 @@ extern unsigned int tabspaces;$/;" h modifiedFile:a/st.h
+-1265,7 +1358,7 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -1265,7 +1358,7 @@ tdeletechar(int n)$/;" h modifiedFile:a/st.c
+-1272,89 +1435,93 patches/st-scrollback-reflow-0.8.5.diff /^@@ -1272,89 +1435,93 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)$/;" h modifiedFile:a/st.c
+-1282,7 +1375,7 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -1282,7 +1375,7 @@ tinsertblank(int n)$/;" h modifiedFile:a/st.c
+-129,9 +121,9 patches/st-gruvbox-dark-0.8.5.diff /^@@ -129,9 +121,9 @@ static const char *colorname[] = {$/;" h modifiedFile:a/config.def.h
+-1291,14 +1353,14 patches/st-scrollback-20210507-4536f46.diff /^@@ -1291,14 +1353,14 @@ void$/;" h modifiedFile:a/st.c
+-133,13 +133,20 patches/st-blinking_cursor-20211116-2f6e597.diff /^@@ -133,13 +133,20 @@ static unsigned int defaultcs = 256;$/;" h modifiedFile:a/config.def.h
+-1375,7 +1379,7 patches/st-anysize-20220718-baa9357.diff /^@@ -1375,7 +1379,7 @@ void$/;" h modifiedFile:a/x.c
+-1465,17 +1469,17 patches/st-anysize-20220718-baa9357.diff /^@@ -1465,17 +1469,17 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, /;" h modifiedFile:a/x.c
+-1528,7 +1695,7 patches/st-scrollback-reflow-0.8.5.diff /^@@ -1528,7 +1695,7 @@ tsetscroll(int t, int b)$/;" h modifiedFile:a/st.c
+-1529,29 +1530,44 patches/st-blinking_cursor-20211116-2f6e597.diff /^@@ -1529,29 +1530,44 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)$/;" h modifiedFile:a/x.c
+-1569,35 +1573,35 patches/st-anysize-20220718-baa9357.diff /^@@ -1569,35 +1573,35 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)$/;" h modifiedFile:a/x.c
+-1589,25 +1756,18 patches/st-scrollback-reflow-0.8.5.diff /^@@ -1589,25 +1756,18 @@ tsetmode(int priv, int set, const int *args, int narg)$/;" h modifiedFile:a/st.c
+-16,7 +16,7 patches/st-alpha-20220206-0.8.5.diff /^@@ -16,7 +16,7 @@ PKG_CONFIG = pkg-config$/;" h modifiedFile:a/config.mk
+-1659,7 +1819,7 patches/st-scrollback-reflow-0.8.5.diff /^@@ -1659,7 +1819,7 @@ void$/;" h modifiedFile:a/st.c
+-1708,9 +1724,12 patches/st-blinking_cursor-20211116-2f6e597.diff /^@@ -1708,9 +1724,12 @@ xsetmode(int set, unsigned int flags)$/;" h modifiedFile:a/x.c
+-173,11 +173,11 patches/st-universcroll-0.8.4.diff /^@@ -173,11 +173,11 @@ static uint forcemousemod = ShiftMask;$/;" h modifiedFile:a/config.def.h
+-1735,11 +1797,11 patches/st-scrollback-20210507-4536f46.diff /^@@ -1735,11 +1797,11 @@ csihandle(void)$/;" h modifiedFile:a/st.c
+-1757,20 +1917,30 patches/st-scrollback-reflow-0.8.5.diff /^@@ -1757,20 +1917,30 @@ csihandle(void)$/;" h modifiedFile:a/st.c
+-176,6 +176,8 patches/st-scrollback-mouse-20220127-2c5edf2.diff /^@@ -176,6 +176,8 @@ static uint forcemousemod = ShiftMask;$/;" h modifiedFile:a/config.def.h
+-1778,24 +1948,24 patches/st-scrollback-reflow-0.8.5.diff /^@@ -1778,24 +1948,24 @@ csihandle(void)$/;" h modifiedFile:a/st.c
+-179,26 +200,37 patches/st-scrollback-reflow-0.8.5.diff /^@@ -179,26 +200,37 @@ static void tprinter(char *, size_t);$/;" h modifiedFile:a/st.c
+-1809,9 +1979,11 patches/st-scrollback-reflow-0.8.5.diff /^@@ -1809,9 +1979,11 @@ csihandle(void)$/;" h modifiedFile:a/st.c
+-1833,9 +2005,9 patches/st-scrollback-reflow-0.8.5.diff /^@@ -1833,9 +2005,9 @@ csihandle(void)$/;" h modifiedFile:a/st.c
+-184,8 +191,8 patches/st-scrollback-20210507-4536f46.diff /^@@ -184,8 +191,8 @@ static void tnewline(int);$/;" h modifiedFile:a/st.c
+-185,6 +187,7 patches/st-colorschemes-0.8.5.diff /^@@ -185,6 +187,7 @@ static void mousesel(XEvent *, int);$/;" h modifiedFile:a/x.c
+-19,6 +19,7 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -19,6 +19,7 @@$/;" h modifiedFile:a/st.h
+-1954,6 +1973,10 patches/st-blinking_cursor-20211116-2f6e597.diff /^@@ -1954,6 +1973,10 @@ run(void)$/;" h modifiedFile:a/x.c
+-1964,7 +1987,7 patches/st-blinking_cursor-20211116-2f6e597.diff /^@@ -1964,7 +1987,7 @@ run(void)$/;" h modifiedFile:a/x.c
+-199,6 +199,8 patches/st-scrollback-20210507-4536f46.diff /^@@ -199,6 +199,8 @@ static Shortcut shortcuts[] = {$/;" h modifiedFile:a/config.def.h
+-2000,7 +2023,7 patches/st-blinking_cursor-20211116-2f6e597.diff /^@@ -2000,7 +2023,7 @@ main(int argc, char *argv[])$/;" h modifiedFile:a/x.c
+-2008,6 +2011,47 patches/st-colorschemes-0.8.5.diff /^@@ -2008,6 +2011,47 @@ usage(void)$/;" h modifiedFile:a/x.c
+-201,6 +201,8 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -201,6 +201,8 @@ static Shortcut shortcuts[] = {$/;" h modifiedFile:a/config.def.h
+-201,6 +242,17 patches/st-colorschemes-0.8.5.diff /^@@ -201,6 +242,17 @@ static Shortcut shortcuts[] = {$/;" h modifiedFile:a/config.def.h
+-2019,6 +2036,9 patches/st-alpha-20220206-0.8.5.diff /^@@ -2019,6 +2036,9 @@ main(int argc, char *argv[])$/;" h modifiedFile:a/x.c
+-202,6 +215,8 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -202,6 +215,8 @@ static void tdeftran(char);$/;" h modifiedFile:a/st.c
+-2060,6 +2104,12 patches/st-colorschemes-0.8.5.diff /^@@ -2060,6 +2104,12 @@ main(int argc, char *argv[])$/;" h modifiedFile:a/x.c
+-2103,7 +2196,7 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -2103,7 +2196,7 @@ tdumpline(int n)$/;" h modifiedFile:a/st.c
+-212,7 +244,10 patches/st-scrollback-reflow-0.8.5.diff /^@@ -212,7 +244,10 @@ static void tstrsequence(uchar);$/;" h modifiedFile:a/st.c
+-2128,16 +2300,8 patches/st-scrollback-reflow-0.8.5.diff /^@@ -2128,16 +2300,8 @@ tdumpsel(void)$/;" h modifiedFile:a/st.c
+-2196,6 +2196,28 patches/st-colorschemes-0.8.5.diff /^@@ -2196,6 +2196,28 @@ tstrsequence(uchar c)$/;" h modifiedFile:a/st.c
+-22,17 +22,19 patches/st-scrollback-reflow-0.8.5.diff /^@@ -22,17 +22,19 @@$/;" h modifiedFile:a/st.h
+-2251,7 +2313,7 patches/st-scrollback-20210507-4536f46.diff /^@@ -2251,7 +2313,7 @@ eschandle(uchar ascii)$/;" h modifiedFile:a/st.c
+-2264,7 +2326,7 patches/st-scrollback-20210507-4536f46.diff /^@@ -2264,7 +2326,7 @@ eschandle(uchar ascii)$/;" h modifiedFile:a/st.c
+-2358,7 +2522,7 patches/st-scrollback-reflow-0.8.5.diff /^@@ -2358,7 +2522,7 @@ eschandle(uchar ascii)$/;" h modifiedFile:a/st.c
+-2371,7 +2535,7 patches/st-scrollback-reflow-0.8.5.diff /^@@ -2371,7 +2535,7 @@ eschandle(uchar ascii)$/;" h modifiedFile:a/st.c
+-243,6 +244,7 patches/st-alpha-20220206-0.8.5.diff /^@@ -243,6 +244,7 @@ static char *usedfont = NULL;$/;" h modifiedFile:a/x.c
+-2474,7 +2536,7 patches/st-scrollback-20210507-4536f46.diff /^@@ -2474,7 +2536,7 @@ twrite(const char *buf, int buflen, int show_ctrl)$/;" h modifiedFile:a/st.c
+-2486,11 +2579,11 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -2486,11 +2579,11 @@ check_control_code:$/;" h modifiedFile:a/st.c
+-2498,7 +2591,7 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -2498,7 +2591,7 @@ check_control_code:$/;" h modifiedFile:a/st.c
+-2511,6 +2573,14 patches/st-scrollback-20210507-4536f46.diff /^@@ -2511,6 +2573,14 @@ tresize(int col, int row)$/;" h modifiedFile:a/st.c
+-2511,7 +2675,8 patches/st-scrollback-reflow-0.8.5.diff /^@@ -2511,7 +2675,8 @@ check_control_code:$/;" h modifiedFile:a/st.c
+-2529,6 +2622,11 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -2529,6 +2622,11 @@ twrite(const char *buf, int buflen, int show_ctrl)$/;" h modifiedFile:a/st.c
+-253,6 +253,7 patches/st-blinking_cursor-20211116-2f6e597.diff /^@@ -253,6 +253,7 @@ static char *opt_name = NULL;$/;" h modifiedFile:a/x.c
+-2546,6 +2711,7 patches/st-scrollback-reflow-0.8.5.diff /^@@ -2546,6 +2711,7 @@ check_control_code:$/;" h modifiedFile:a/st.c
+-2555,56 +2653,85 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -2555,56 +2653,85 @@ twrite(const char *buf, int buflen, int show_ctrl)$/;" h modifiedFile:a/st.c
+-2569,7 +2639,7 patches/st-scrollback-20210507-4536f46.diff /^@@ -2569,7 +2639,7 @@ drawregion(int x1, int y1, int x2, int y2)$/;" h modifiedFile:a/st.c
+-2583,93 +2749,275 patches/st-scrollback-reflow-0.8.5.diff /^@@ -2583,93 +2749,275 @@ twrite(const char *buf, int buflen, int show_ctrl)$/;" h modifiedFile:a/st.c
+-2590,8 +2660,9 patches/st-scrollback-20210507-4536f46.diff /^@@ -2590,8 +2660,9 @@ draw(void)$/;" h modifiedFile:a/st.c
+-2614,26 +2741,16 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -2614,26 +2741,16 @@ tresize(int col, int row)$/;" h modifiedFile:a/st.c
+-2645,14 +2762,15 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -2645,14 +2762,15 @@ resettitle(void)$/;" h modifiedFile:a/st.c
+-2667,14 +2785,15 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -2667,14 +2785,15 @@ draw(void)$/;" h modifiedFile:a/st.c
+-2709,9 +3057,8 patches/st-scrollback-reflow-0.8.5.diff /^@@ -2709,9 +3057,8 @@ draw(void)$/;" h modifiedFile:a/st.c
+-331,7 +332,7 patches/st-anysize-20220718-baa9357.diff /^@@ -331,7 +332,7 @@ ttysend(const Arg *arg)$/;" h modifiedFile:a/x.c
+-339,7 +340,7 patches/st-anysize-20220718-baa9357.diff /^@@ -339,7 +340,7 @@ evcol(XEvent *e)$/;" h modifiedFile:a/x.c
+-34,6 +34,7 patches/st-universcroll-0.8.4.diff /^@@ -34,6 +34,7 @@ typedef struct {$/;" h modifiedFile:a/x.c
+-35,6 +35,7 patches/st-scrollback-20210507-4536f46.diff /^@@ -35,6 +35,7 @@$/;" h modifiedFile:a/st.c
+-36,6 +36,7 patches/st-scrollback-reflow-0.8.5.diff /^@@ -36,6 +36,7 @@$/;" h modifiedFile:a/st.c
+-412,17 +447,46 patches/st-scrollback-reflow-0.8.5.diff /^@@ -412,17 +447,46 @@ selinit(void)$/;" h modifiedFile:a/st.c
+-415,11 +430,12 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -415,11 +430,12 @@ int$/;" h modifiedFile:a/st.c
+-416,10 +423,10 patches/st-scrollback-20210507-4536f46.diff /^@@ -416,10 +423,10 @@ tlinelen(int y)$/;" h modifiedFile:a/st.c
+-42,6 +43,9 patches/st-scrollback-20210507-4536f46.diff /^@@ -42,6 +43,9 @@$/;" h modifiedFile:a/st.c
+-43,6 +43,10 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -43,6 +43,10 @@$/;" h modifiedFile:a/st.c
+-43,9 +44,22 patches/st-scrollback-reflow-0.8.5.diff /^@@ -43,9 +44,22 @@$/;" h modifiedFile:a/st.c
+-446,6 +447,7 patches/st-universcroll-0.8.4.diff /^@@ -446,6 +447,7 @@ mouseaction(XEvent *e, uint release)$/;" h modifiedFile:a/x.c
+-462,10 +526,11 patches/st-scrollback-reflow-0.8.5.diff /^@@ -462,10 +526,11 @@ selextend(int col, int row, int type, int done)$/;" h modifiedFile:a/st.c
+-492,36 +557,43 patches/st-scrollback-reflow-0.8.5.diff /^@@ -492,36 +557,43 @@ selnormalize(void)$/;" h modifiedFile:a/st.c
+-528,7 +535,7 patches/st-scrollback-20210507-4536f46.diff /^@@ -528,7 +535,7 @@ selsnap(int *x, int *y, int direction)$/;" h modifiedFile:a/st.c
+-528,7 +544,7 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -528,7 +544,7 @@ selsnap(int *x, int *y, int direction)$/;" h modifiedFile:a/st.c
+-536,7 +608,7 patches/st-scrollback-reflow-0.8.5.diff /^@@ -536,7 +608,7 @@ selsnap(int *x, int *y, int direction)$/;" h modifiedFile:a/st.c
+-543,14 +550,14 patches/st-scrollback-20210507-4536f46.diff /^@@ -543,14 +550,14 @@ selsnap(int *x, int *y, int direction)$/;" h modifiedFile:a/st.c
+-543,14 +559,14 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -543,14 +559,14 @@ selsnap(int *x, int *y, int direction)$/;" h modifiedFile:a/st.c
+-547,13 +619,13 patches/st-scrollback-reflow-0.8.5.diff /^@@ -547,13 +619,13 @@ selsnap(int *x, int *y, int direction)$/;" h modifiedFile:a/st.c
+-57,6 +71,12 patches/st-scrollback-reflow-0.8.5.diff /^@@ -57,6 +71,12 @@ enum term_mode {$/;" h modifiedFile:a/st.c
+-570,18 +642,14 patches/st-scrollback-reflow-0.8.5.diff /^@@ -570,18 +642,14 @@ selsnap(int *x, int *y, int direction)$/;" h modifiedFile:a/st.c
+-571,14 +578,14 patches/st-scrollback-20210507-4536f46.diff /^@@ -571,14 +578,14 @@ selsnap(int *x, int *y, int direction)$/;" h modifiedFile:a/st.c
+-571,14 +587,14 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -571,14 +587,14 @@ selsnap(int *x, int *y, int direction)$/;" h modifiedFile:a/st.c
+-59,6 +59,8 patches/st-colorschemes-0.8.5.diff /^@@ -59,6 +59,8 @@ static void zoom(const Arg *);$/;" h modifiedFile:a/x.c
+-59,6 +59,8 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -59,6 +59,8 @@ static void zoom(const Arg *);$/;" h modifiedFile:a/x.c
+-592,40 +660,34 patches/st-scrollback-reflow-0.8.5.diff /^@@ -592,40 +660,34 @@ char *$/;" h modifiedFile:a/st.c
+-609,13 +616,13 patches/st-scrollback-20210507-4536f46.diff /^@@ -609,13 +616,13 @@ getsel(void)$/;" h modifiedFile:a/st.c
+-609,13 +625,13 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -609,13 +625,13 @@ getsel(void)$/;" h modifiedFile:a/st.c
+-636,10 +698,10 patches/st-scrollback-reflow-0.8.5.diff /^@@ -636,10 +698,10 @@ getsel(void)$/;" h modifiedFile:a/st.c
+-648,9 +710,15 patches/st-scrollback-reflow-0.8.5.diff /^@@ -648,9 +710,15 @@ selclear(void)$/;" h modifiedFile:a/st.c
+-736,7 +738,7 patches/st-alpha-20220206-0.8.5.diff /^@@ -736,7 +738,7 @@ xresize(int col, int row)$/;" h modifiedFile:a/x.c
+-739,6 +740,9 patches/st-anysize-20220718-baa9357.diff /^@@ -739,6 +740,9 @@ cresize(int width, int height)$/;" h modifiedFile:a/x.c
+-785,7 +788,7 patches/st-colorschemes-0.8.5.diff /^@@ -785,7 +788,7 @@ xloadcols(void)$/;" h modifiedFile:a/x.c
+-796,6 +798,13 patches/st-alpha-20220206-0.8.5.diff /^@@ -796,6 +798,13 @@ xloadcols(void)$/;" h modifiedFile:a/x.c
+-81,6 +81,7 patches/st-anysize-20220718-baa9357.diff /^@@ -81,6 +81,7 @@ typedef XftGlyphFontSpec GlyphFontSpec;$/;" h modifiedFile:a/x.c
+-81,6 +81,8 patches/st-scrollback-20210507-4536f46.diff /^@@ -81,6 +81,8 @@ void die(const char *, ...);$/;" h modifiedFile:a/st.h
+-850,6 +857,9 patches/st-scrollback-20210507-4536f46.diff /^@@ -850,6 +857,9 @@ void$/;" h modifiedFile:a/st.c
+-851,10 +919,8 patches/st-scrollback-reflow-0.8.5.diff /^@@ -851,10 +919,8 @@ void$/;" h modifiedFile:a/st.c
+-869,8 +873,8 patches/st-anysize-20220718-baa9357.diff /^@@ -869,8 +873,8 @@ xhints(void)$/;" h modifiedFile:a/x.c
+-87,6 +87,7 patches/st-universcroll-0.8.4.diff /^@@ -87,6 +87,7 @@ void sendbreak(const Arg *);$/;" h modifiedFile:a/st.h
+-90,6 +90,8 patches/st-colorschemes-0.8.5.diff /^@@ -90,6 +90,8 @@ int tattrset(int);$/;" h modifiedFile:a/st.h
+-90,6 +92,7 patches/st-scrollback-reflow-0.8.5.diff /^@@ -90,6 +92,7 @@ void toggleprinter(const Arg *);$/;" h modifiedFile:a/st.h
+-93,46 +93,87 patches/st-colorschemes-0.8.5.diff /^@@ -93,46 +93,87 @@ char *termname = "st-256color";$/;" h modifiedFile:a/config.def.h
+-93,6 +93,9 patches/st-alpha-20220206-0.8.5.diff /^@@ -93,6 +93,9 @@ char *termname = "st-256color";$/;" h modifiedFile:a/config.def.h
+-956,12 +972,15 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -956,12 +972,15 @@ int$/;" h modifiedFile:a/st.c
+-96,32 +96,24 patches/st-gruvbox-dark-0.8.5.diff /^@@ -96,32 +96,24 @@ unsigned int tabspaces = 8;$/;" h modifiedFile:a/config.def.h
+-983,14 +1002,17 patches/st-scrollback-ringbuffer-0.8.5.diff /^@@ -983,14 +1002,17 @@ void$/;" h modifiedFile:a/st.c
+-990,7 +1056,7 patches/st-scrollback-reflow-0.8.5.diff /^@@ -990,7 +1056,7 @@ tsetdirtattr(int attr)$/;" h modifiedFile:a/st.c
+.c.o Makefile /^.c.o:$/;" t
+ARGBEGIN arg.h /^#define ARGBEGIN /;" d
+ARGC arg.h /^#define ARGC(/;" d
+ARGEND arg.h /^#define ARGEND /;" d
+ARGF arg.h /^#define ARGF(/;" d
+ARG_H__ arg.h /^#define ARG_H__$/;" d
+ATTRCMP st.h /^#define ATTRCMP(/;" d
+ATTR_BLINK st.h /^ ATTR_BLINK = 1 << 4,$/;" e enum:glyph_attribute
+ATTR_BOLD st.h /^ ATTR_BOLD = 1 << 0,$/;" e enum:glyph_attribute
+ATTR_BOLD_FAINT st.h /^ ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,$/;" e enum:glyph_attribute
+ATTR_FAINT st.h /^ ATTR_FAINT = 1 << 1,$/;" e enum:glyph_attribute
+ATTR_INVISIBLE st.h /^ ATTR_INVISIBLE = 1 << 6,$/;" e enum:glyph_attribute
+ATTR_ITALIC st.h /^ ATTR_ITALIC = 1 << 2,$/;" e enum:glyph_attribute
+ATTR_NULL st.h /^ ATTR_NULL = 0,$/;" e enum:glyph_attribute
+ATTR_REVERSE st.h /^ ATTR_REVERSE = 1 << 5,$/;" e enum:glyph_attribute
+ATTR_STRUCK st.h /^ ATTR_STRUCK = 1 << 7,$/;" e enum:glyph_attribute
+ATTR_UNDERLINE st.h /^ ATTR_UNDERLINE = 1 << 3,$/;" e enum:glyph_attribute
+ATTR_WDUMMY st.h /^ ATTR_WDUMMY = 1 << 10,$/;" e enum:glyph_attribute
+ATTR_WIDE st.h /^ ATTR_WIDE = 1 << 9,$/;" e enum:glyph_attribute
+ATTR_WRAP st.h /^ ATTR_WRAP = 1 << 8,$/;" e enum:glyph_attribute
+AUTHORS st.1 /^.SH AUTHORS$/;" s title:ST
+Arg st.h /^} Arg;$/;" t typeref:union:__anon7c9e12e2020a
+BETWEEN st.h /^#define BETWEEN(/;" d
+BUGS st.1 /^.SH BUGS$/;" s title:ST
+CUSTOMIZATION st.1 /^.SH CUSTOMIZATION$/;" s title:ST
+ColorScheme config.def.h /^} ColorScheme;$/;" t typeref:struct:__anon9258968e0108
+ColorScheme config.h /^} ColorScheme;$/;" t typeref:struct:__anon41b17d910108
+DEFAULT st.h /^#define DEFAULT(/;" d
+DESCRIPTION st.1 /^.SH DESCRIPTION$/;" s title:ST
+DIVCEIL st.h /^#define DIVCEIL(/;" d
+EARGF arg.h /^#define EARGF(/;" d
+Glyph st.h /^#define Glyph /;" d
+Glyph st.h /^} Glyph;$/;" t typeref:struct:__anon7c9e12e20108
+INCS config.mk /^INCS = -I$(X11INC) \\$/;" m
+IS_TRUECOL st.h /^#define IS_TRUECOL(/;" d
+LEN st.h /^#define LEN(/;" d
+LIBS config.mk /^LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\\$/;" m
+LICENSE st.1 /^.SH LICENSE$/;" s title:ST
+LIMIT st.h /^#define LIMIT(/;" d
+Line st.h /^typedef Glyph *Line;$/;" t typeref:typename:Glyph *
+MANPREFIX config.mk /^MANPREFIX = $(PREFIX)\/share\/man$/;" m
+MAX st.h /^#define MAX(/;" d
+MIN st.h /^#define MIN(/;" d
+MODBIT st.h /^#define MODBIT(/;" d
+MODE_8BIT win.h /^ MODE_8BIT = 1 << 10,$/;" e enum:win_mode
+MODE_APPCURSOR win.h /^ MODE_APPCURSOR = 1 << 8,$/;" e enum:win_mode
+MODE_APPKEYPAD win.h /^ MODE_APPKEYPAD = 1 << 2,$/;" e enum:win_mode
+MODE_BLINK win.h /^ MODE_BLINK = 1 << 11,$/;" e enum:win_mode
+MODE_BRCKTPASTE win.h /^ MODE_BRCKTPASTE = 1 << 16,$/;" e enum:win_mode
+MODE_FBLINK win.h /^ MODE_FBLINK = 1 << 12,$/;" e enum:win_mode
+MODE_FOCUS win.h /^ MODE_FOCUS = 1 << 13,$/;" e enum:win_mode
+MODE_FOCUSED win.h /^ MODE_FOCUSED = 1 << 1,$/;" e enum:win_mode
+MODE_HIDE win.h /^ MODE_HIDE = 1 << 7,$/;" e enum:win_mode
+MODE_KBDLOCK win.h /^ MODE_KBDLOCK = 1 << 6,$/;" e enum:win_mode
+MODE_MOUSE win.h /^ MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\\$/;" e enum:win_mode
+MODE_MOUSEBTN win.h /^ MODE_MOUSEBTN = 1 << 3,$/;" e enum:win_mode
+MODE_MOUSEMANY win.h /^ MODE_MOUSEMANY = 1 << 15,$/;" e enum:win_mode
+MODE_MOUSEMOTION win.h /^ MODE_MOUSEMOTION = 1 << 4,$/;" e enum:win_mode
+MODE_MOUSESGR win.h /^ MODE_MOUSESGR = 1 << 9,$/;" e enum:win_mode
+MODE_MOUSEX10 win.h /^ MODE_MOUSEX10 = 1 << 14,$/;" e enum:win_mode
+MODE_NUMLOCK win.h /^ MODE_NUMLOCK = 1 << 17,$/;" e enum:win_mode
+MODE_REVERSE win.h /^ MODE_REVERSE = 1 << 5,$/;" e enum:win_mode
+MODE_VISIBLE win.h /^ MODE_VISIBLE = 1 << 0,$/;" e enum:win_mode
+MODKEY config.def.h /^#define MODKEY /;" d
+MODKEY config.h /^#define MODKEY /;" d
+Makefile Makefile 1;" F epoch:1667356258
+NAME st.1 /^.SH NAME$/;" s title:ST
+OBJ Makefile /^OBJ = $(SRC:.c=.o)$/;" m
+OPTIONS st.1 /^.SH OPTIONS$/;" s title:ST
+PKG_CONFIG config.mk /^PKG_CONFIG = pkg-config$/;" m
+PREFIX config.mk /^PREFIX = \/usr\/local$/;" m
+Rune st.h /^typedef uint_least32_t Rune;$/;" t typeref:typename:uint_least32_t
+SEE ALSO st.1 /^.SH SEE ALSO$/;" s title:ST
+SEL_EMPTY st.h /^ SEL_EMPTY = 1,$/;" e enum:selection_mode
+SEL_IDLE st.h /^ SEL_IDLE = 0,$/;" e enum:selection_mode
+SEL_READY st.h /^ SEL_READY = 2$/;" e enum:selection_mode
+SEL_RECTANGULAR st.h /^ SEL_RECTANGULAR = 2$/;" e enum:selection_type
+SEL_REGULAR st.h /^ SEL_REGULAR = 1,$/;" e enum:selection_type
+SHORTCUTS st.1 /^.SH SHORTCUTS$/;" s title:ST
+SNAP_LINE st.h /^ SNAP_LINE = 2$/;" e enum:selection_snap
+SNAP_WORD st.h /^ SNAP_WORD = 1,$/;" e enum:selection_snap
+SRC Makefile /^SRC = st.c x.c$/;" m
+ST st.1 /^.TH ST 1 st\\-VERSION$/;" t
+STCFLAGS config.mk /^STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)$/;" m
+STCPPFLAGS config.mk /^STCPPFLAGS = -DVERSION=\\"$(VERSION)\\" -D_XOPEN_SOURCE=600$/;" m
+STLDFLAGS config.mk /^STLDFLAGS = $(LIBS) $(LDFLAGS)$/;" m
+SYNOPSIS st.1 /^.SH SYNOPSIS$/;" s title:ST
+TERMMOD config.def.h /^#define TERMMOD /;" d
+TERMMOD config.h /^#define TERMMOD /;" d
+TIMEDIFF st.h /^#define TIMEDIFF(/;" d
+TRUECOLOR st.h /^#define TRUECOLOR(/;" d
+VERSION config.mk /^VERSION = 0.8.5$/;" m
+X11INC config.mk /^X11INC = \/usr\/X11R6\/include$/;" m
+X11LIB config.mk /^X11LIB = \/usr\/X11R6\/lib$/;" m
+a/config.def.h patches/st-alpha-20220206-0.8.5.diff /^--- a\/config.def.h$/;" m
+a/config.def.h patches/st-blinking_cursor-20211116-2f6e597.diff /^--- a\/config.def.h$/;" m
+a/config.def.h patches/st-colorschemes-0.8.5.diff /^--- a\/config.def.h$/;" m
+a/config.def.h patches/st-gruvbox-dark-0.8.5.diff /^--- a\/config.def.h$/;" m
+a/config.def.h patches/st-scrollback-20210507-4536f46.diff /^--- a\/config.def.h$/;" m
+a/config.def.h patches/st-scrollback-mouse-20220127-2c5edf2.diff /^--- a\/config.def.h$/;" m
+a/config.def.h patches/st-scrollback-ringbuffer-0.8.5.diff /^--- a\/config.def.h$/;" m
+a/config.def.h patches/st-universcroll-0.8.4.diff /^--- a\/config.def.h$/;" m
+a/config.mk patches/st-alpha-20220206-0.8.5.diff /^--- a\/config.mk$/;" m
+a/st.c patches/st-colorschemes-0.8.5.diff /^--- a\/st.c$/;" m
+a/st.c patches/st-scrollback-20210507-4536f46.diff /^--- a\/st.c$/;" m
+a/st.c patches/st-scrollback-reflow-0.8.5.diff /^--- a\/st.c$/;" m
+a/st.c patches/st-scrollback-ringbuffer-0.8.5.diff /^--- a\/st.c$/;" m
+a/st.c patches/st-universcroll-0.8.4.diff /^--- a\/st.c$/;" m
+a/st.h patches/st-alpha-20220206-0.8.5.diff /^--- a\/st.h$/;" m
+a/st.h patches/st-colorschemes-0.8.5.diff /^--- a\/st.h$/;" m
+a/st.h patches/st-scrollback-20210507-4536f46.diff /^--- a\/st.h$/;" m
+a/st.h patches/st-scrollback-reflow-0.8.5.diff /^--- a\/st.h$/;" m
+a/st.h patches/st-scrollback-ringbuffer-0.8.5.diff /^--- a\/st.h$/;" m
+a/st.h patches/st-universcroll-0.8.4.diff /^--- a\/st.h$/;" m
+a/x.c patches/st-alpha-20220206-0.8.5.diff /^--- a\/x.c$/;" m
+a/x.c patches/st-anysize-20220718-baa9357.diff /^--- a\/x.c$/;" m
+a/x.c patches/st-blinking_cursor-20211116-2f6e597.diff /^--- a\/x.c$/;" m
+a/x.c patches/st-colorschemes-0.8.5.diff /^--- a\/x.c$/;" m
+a/x.c patches/st-scrollback-ringbuffer-0.8.5.diff /^--- a\/x.c$/;" m
+a/x.c patches/st-universcroll-0.8.4.diff /^--- a\/x.c$/;" m
+all Makefile /^all: options st$/;" t
+allowaltscreen config.def.h /^int allowaltscreen = 1;$/;" v typeref:typename:int
+allowaltscreen config.h /^int allowaltscreen = 1;$/;" v typeref:typename:int
+allowwindowops config.def.h /^int allowwindowops = 0;$/;" v typeref:typename:int
+allowwindowops config.h /^int allowwindowops = 0;$/;" v typeref:typename:int
+alpha config.def.h /^float alpha = 0.92;$/;" v typeref:typename:float
+alpha config.h /^float alpha = 0.92;$/;" v typeref:typename:float
+arg.h arg.h 1;" F epoch:1667356258
+argv0 x.c /^char *argv0;$/;" v typeref:typename:char *
+ascii_printable config.def.h /^static char ascii_printable[] =$/;" v typeref:typename:char[]
+ascii_printable config.h /^static char ascii_printable[] =$/;" v typeref:typename:char[]
+base64dec st.c /^base64dec(const char *src)$/;" f typeref:typename:char *
+base64dec_getc st.c /^base64dec_getc(const char **src)$/;" f typeref:typename:char
+bellvolume config.def.h /^static int bellvolume = 0;$/;" v typeref:typename:int
+bellvolume config.h /^static int bellvolume = 0;$/;" v typeref:typename:int
+bg config.def.h /^ unsigned int bg; \/* background *\/$/;" m struct:__anon9258968e0108 typeref:typename:unsigned int
+bg config.h /^ unsigned int bg; \/* background *\/$/;" m struct:__anon41b17d910108 typeref:typename:unsigned int
+bg st.h /^ uint32_t bg; \/* background *\/$/;" m struct:__anon7c9e12e20108 typeref:typename:uint32_t
+blinktimeout config.def.h /^static unsigned int blinktimeout = 800;$/;" v typeref:typename:unsigned int
+blinktimeout config.h /^static unsigned int blinktimeout = 800;$/;" v typeref:typename:unsigned int
+bmotion x.c /^bmotion(XEvent *e)$/;" f typeref:typename:void
+borderpx config.def.h /^static int borderpx = 0;$/;" v typeref:typename:int
+borderpx config.h /^static int borderpx = 0;$/;" v typeref:typename:int
+bpress x.c /^bpress(XEvent *e)$/;" f typeref:typename:void
+brelease x.c /^brelease(XEvent *e)$/;" f typeref:typename:void
+buttonmask x.c /^buttonmask(uint button)$/;" f typeref:typename:uint
+chscale config.def.h /^static float chscale = 1.0;$/;" v typeref:typename:float
+chscale config.h /^static float chscale = 1.0;$/;" v typeref:typename:float
+clean Makefile /^clean:$/;" t
+clipcopy x.c /^clipcopy(const Arg *dummy)$/;" f typeref:typename:void
+clippaste x.c /^clippaste(const Arg *dummy)$/;" f typeref:typename:void
+cmessage x.c /^cmessage(XEvent *e)$/;" f typeref:typename:void
+colorname config.def.h /^static const char * const * colorname;$/;" v typeref:typename:const char * const *
+colorname config.h /^static const char * const * colorname;$/;" v typeref:typename:const char * const *
+colors config.def.h /^ const char* const colors[258]; \/* terminal colors *\/$/;" m struct:__anon9258968e0108 typeref:typename:const char * const[258]
+colors config.h /^ const char* const colors[258]; \/* terminal colors *\/$/;" m struct:__anon41b17d910108 typeref:typename:const char * const[258]
+colorscheme config.def.h /^int colorscheme = 0;$/;" v typeref:typename:int
+colorscheme config.h /^int colorscheme = 0;$/;" v typeref:typename:int
+cols config.def.h /^static unsigned int cols = 80;$/;" v typeref:typename:unsigned int
+cols config.h /^static unsigned int cols = 80;$/;" v typeref:typename:unsigned int
+config.def.h config.def.h 1;" F epoch:1667356965
+config.h Makefile /^config.h:$/;" t
+config.h config.h 1;" F epoch:1667356753
+config.mk config.mk 1;" F epoch:1667356258
+cresize x.c /^cresize(int width, int height)$/;" f typeref:typename:void
+cs config.def.h /^ unsigned int cs; \/* cursor *\/$/;" m struct:__anon9258968e0108 typeref:typename:unsigned int
+cs config.h /^ unsigned int cs; \/* cursor *\/$/;" m struct:__anon41b17d910108 typeref:typename:unsigned int
+csidump st.c /^csidump(void)$/;" f typeref:typename:void
+csihandle st.c /^csihandle(void)$/;" f typeref:typename:void
+csiparse st.c /^csiparse(void)$/;" f typeref:typename:void
+csireset st.c /^csireset(void)$/;" f typeref:typename:void
+cursorstyle config.def.h /^static unsigned int cursorstyle = 1;$/;" v typeref:typename:unsigned int
+cursorstyle config.h /^static unsigned int cursorstyle = 1;$/;" v typeref:typename:unsigned int
+cursorthickness config.def.h /^static unsigned int cursorthickness = 2;$/;" v typeref:typename:unsigned int
+cursorthickness config.h /^static unsigned int cursorthickness = 2;$/;" v typeref:typename:unsigned int
+cwscale config.def.h /^static float cwscale = 1.05;$/;" v typeref:typename:float
+cwscale config.h /^static float cwscale = 1.05;$/;" v typeref:typename:float
+defaultattr config.def.h /^static unsigned int defaultattr = 11;$/;" v typeref:typename:unsigned int
+defaultattr config.h /^static unsigned int defaultattr = 11;$/;" v typeref:typename:unsigned int
+defaultbg config.def.h /^unsigned int defaultbg;$/;" v typeref:typename:unsigned int
+defaultbg config.h /^unsigned int defaultbg;$/;" v typeref:typename:unsigned int
+defaultcs config.def.h /^unsigned int defaultcs;$/;" v typeref:typename:unsigned int
+defaultcs config.h /^unsigned int defaultcs;$/;" v typeref:typename:unsigned int
+defaultfg config.def.h /^unsigned int defaultfg;$/;" v typeref:typename:unsigned int
+defaultfg config.h /^unsigned int defaultfg;$/;" v typeref:typename:unsigned int
+defaultrcs config.def.h /^static unsigned int defaultrcs;$/;" v typeref:typename:unsigned int
+defaultrcs config.h /^static unsigned int defaultrcs;$/;" v typeref:typename:unsigned int
+die st.c /^die(const char *errstr, ...)$/;" f typeref:typename:void
+dist Makefile /^dist: clean$/;" t
+doubleclicktimeout config.def.h /^static unsigned int doubleclicktimeout = 300;$/;" v typeref:typename:unsigned int
+doubleclicktimeout config.h /^static unsigned int doubleclicktimeout = 300;$/;" v typeref:typename:unsigned int
+draw st.c /^draw(void)$/;" f typeref:typename:void
+drawregion st.c /^drawregion(int x1, int y1, int x2, int y2)$/;" f typeref:typename:void
+eschandle st.c /^eschandle(uchar ascii)$/;" f typeref:typename:int
+evcol x.c /^evcol(XEvent *e)$/;" f typeref:typename:int
+evrow x.c /^evrow(XEvent *e)$/;" f typeref:typename:int
+execsh st.c /^execsh(char *cmd, char **args)$/;" f typeref:typename:void
+expose x.c /^expose(XEvent *ev)$/;" f typeref:typename:void
+f st.h /^ float f;$/;" m union:__anon7c9e12e2020a typeref:typename:float
+fg config.def.h /^ unsigned int fg; \/* foreground *\/$/;" m struct:__anon9258968e0108 typeref:typename:unsigned int
+fg config.h /^ unsigned int fg; \/* foreground *\/$/;" m struct:__anon41b17d910108 typeref:typename:unsigned int
+fg st.h /^ uint32_t fg; \/* foreground *\/$/;" m struct:__anon7c9e12e20108 typeref:typename:uint32_t
+focus x.c /^focus(XEvent *ev)$/;" f typeref:typename:void
+font config.def.h /^static char *font = "Victor Mono:style=Regular:size=10:antialias=true:autohint=true";$/;" v typeref:typename:char *
+font config.h /^static char *font = "Victor Mono:style=Regular:size=10:antialias=true:autohint=true";$/;" v typeref:typename:char *
+forcemousemod config.def.h /^static uint forcemousemod = ShiftMask;$/;" v typeref:typename:uint
+forcemousemod config.h /^static uint forcemousemod = ShiftMask;$/;" v typeref:typename:uint
+getsel st.c /^getsel(void)$/;" f typeref:typename:char *
+glyph_attribute st.h /^enum glyph_attribute {$/;" g
+i st.h /^ int i;$/;" m union:__anon7c9e12e2020a typeref:typename:int
+ignoremod config.def.h /^static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;$/;" v typeref:typename:uint
+ignoremod config.h /^static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;$/;" v typeref:typename:uint
+install Makefile /^install: st$/;" t
+key config.def.h /^static Key key[] = {$/;" v typeref:typename:Key[]
+key config.h /^static Key key[] = {$/;" v typeref:typename:Key[]
+kmap x.c /^kmap(KeySym k, uint state)$/;" f typeref:typename:char *
+kpress x.c /^kpress(XEvent *ev)$/;" f typeref:typename:void
+kscrolldown st.c /^kscrolldown(const Arg* a)$/;" f typeref:typename:void
+kscrollup st.c /^kscrollup(const Arg* a)$/;" f typeref:typename:void
+main x.c /^main(int argc, char *argv[])$/;" f typeref:typename:int
+mappedkeys config.def.h /^static KeySym mappedkeys[] = { -1 };$/;" v typeref:typename:KeySym[]
+mappedkeys config.h /^static KeySym mappedkeys[] = { -1 };$/;" v typeref:typename:KeySym[]
+match x.c /^match(uint mask, uint state)$/;" f typeref:typename:int
+maxlatency config.def.h /^static double maxlatency = 33;$/;" v typeref:typename:double
+maxlatency config.h /^static double maxlatency = 33;$/;" v typeref:typename:double
+minlatency config.def.h /^static double minlatency = 8;$/;" v typeref:typename:double
+minlatency config.h /^static double minlatency = 8;$/;" v typeref:typename:double
+mode st.h /^ ushort mode; \/* attribute flags *\/$/;" m struct:__anon7c9e12e20108 typeref:typename:ushort
+mouseaction x.c /^mouseaction(XEvent *e, uint release)$/;" f typeref:typename:int
+mousebg config.def.h /^static unsigned int mousebg = 0;$/;" v typeref:typename:unsigned int
+mousebg config.h /^static unsigned int mousebg = 0;$/;" v typeref:typename:unsigned int
+mousefg config.def.h /^static unsigned int mousefg = 7;$/;" v typeref:typename:unsigned int
+mousefg config.h /^static unsigned int mousefg = 7;$/;" v typeref:typename:unsigned int
+mousereport x.c /^mousereport(XEvent *e)$/;" f typeref:typename:void
+mousesel x.c /^mousesel(XEvent *e, int done)$/;" f typeref:typename:void
+mouseshape config.def.h /^static unsigned int mouseshape = XC_xterm;$/;" v typeref:typename:unsigned int
+mouseshape config.h /^static unsigned int mouseshape = XC_xterm;$/;" v typeref:typename:unsigned int
+mshortcuts config.def.h /^static MouseShortcut mshortcuts[] = {$/;" v typeref:typename:MouseShortcut[]
+mshortcuts config.h /^static MouseShortcut mshortcuts[] = {$/;" v typeref:typename:MouseShortcut[]
+nextscheme x.c /^nextscheme(const Arg *arg)$/;" f typeref:typename:void
+numlock x.c /^numlock(const Arg *dummy)$/;" f typeref:typename:void
+options Makefile /^options:$/;" t
+osc_color_response st.c /^osc_color_response(int num, int index, int is_osc4)$/;" f typeref:typename:void
+printscreen st.c /^printscreen(const Arg *arg)$/;" f typeref:typename:void
+printsel st.c /^printsel(const Arg *arg)$/;" f typeref:typename:void
+propnotify x.c /^propnotify(XEvent *e)$/;" f typeref:typename:void
+rcs config.def.h /^ unsigned int rcs; \/* reverse cursor *\/$/;" m struct:__anon9258968e0108 typeref:typename:unsigned int
+rcs config.h /^ unsigned int rcs; \/* reverse cursor *\/$/;" m struct:__anon41b17d910108 typeref:typename:unsigned int
+redraw st.c /^redraw(void)$/;" f typeref:typename:void
+resettitle st.c /^resettitle(void)$/;" f typeref:typename:void
+resize x.c /^resize(XEvent *e)$/;" f typeref:typename:void
+rows config.def.h /^static unsigned int rows = 24;$/;" v typeref:typename:unsigned int
+rows config.h /^static unsigned int rows = 24;$/;" v typeref:typename:unsigned int
+run x.c /^run(void)$/;" f typeref:typename:void
+s st.h /^ const char *s;$/;" m union:__anon7c9e12e2020a typeref:typename:const char *
+scheme config.def.h /^static void scheme = 0;$/;" v typeref:typename:void
+scheme config.h /^static unsigned char scheme = 0;$/;" v typeref:typename:unsigned char
+schemes config.def.h /^static const ColorScheme schemes[] = {$/;" v typeref:typename:const ColorScheme[]
+schemes config.h /^static const ColorScheme schemes[] = {$/;" v typeref:typename:const ColorScheme[]
+scroll config.def.h /^char *scroll = NULL;$/;" v typeref:typename:char *
+scroll config.h /^char *scroll = NULL;$/;" v typeref:typename:char *
+selclear st.c /^selclear(void)$/;" f typeref:typename:void
+selclear_ x.c /^selclear_(XEvent *e)$/;" f typeref:typename:void
+selected st.c /^selected(int x, int y)$/;" f typeref:typename:int
+selection_mode st.h /^enum selection_mode {$/;" g
+selection_snap st.h /^enum selection_snap {$/;" g
+selection_type st.h /^enum selection_type {$/;" g
+selectscheme x.c /^selectscheme(const Arg *arg)$/;" f typeref:typename:void
+selextend st.c /^selextend(int col, int row, int type, int done)$/;" f typeref:typename:void
+selinit st.c /^selinit(void)$/;" f typeref:typename:void
+selmasks config.def.h /^static uint selmasks[] = {$/;" v typeref:typename:uint[]
+selmasks config.h /^static uint selmasks[] = {$/;" v typeref:typename:uint[]
+selnormalize st.c /^selnormalize(void)$/;" f typeref:typename:void
+selnotify x.c /^selnotify(XEvent *e)$/;" f typeref:typename:void
+selpaste x.c /^selpaste(const Arg *dummy)$/;" f typeref:typename:void
+selrequest x.c /^selrequest(XEvent *e)$/;" f typeref:typename:void
+selscroll st.c /^selscroll(int orig, int n)$/;" f typeref:typename:void
+selsnap st.c /^selsnap(int *x, int *y, int direction)$/;" f typeref:typename:void
+selstart st.c /^selstart(int col, int row, int snap)$/;" f typeref:typename:void
+sendbreak st.c /^sendbreak(const Arg *arg)$/;" f typeref:typename:void
+setsel x.c /^setsel(char *str, Time t)$/;" f typeref:typename:void
+shell config.def.h /^static char *shell = "\/bin\/sh";$/;" v typeref:typename:char *
+shell config.h /^static char *shell = "\/bin\/sh";$/;" v typeref:typename:char *
+shortcuts config.def.h /^static Shortcut shortcuts[] = {$/;" v typeref:typename:Shortcut[]
+shortcuts config.h /^static Shortcut shortcuts[] = {$/;" v typeref:typename:Shortcut[]
+sigchld st.c /^sigchld(int a)$/;" f typeref:typename:void
+sixd_to_16bit x.c /^sixd_to_16bit(int x)$/;" f typeref:typename:ushort
+st Makefile /^st: $(OBJ)$/;" t
+st-alpha-20220206-0.8.5.diff patches/st-alpha-20220206-0.8.5.diff 1;" F epoch:1667356258
+st-anysize-20220718-baa9357.diff patches/st-anysize-20220718-baa9357.diff 1;" F epoch:1667356258
+st-blinking_cursor-20211116-2f6e597.diff patches/st-blinking_cursor-20211116-2f6e597.diff 1;" F epoch:1667356258
+st-colorschemes-0.8.5.diff patches/st-colorschemes-0.8.5.diff 1;" F epoch:1667356324
+st-gruvbox-dark-0.8.5.diff patches/st-gruvbox-dark-0.8.5.diff 1;" F epoch:1667356258
+st-scrollback-20210507-4536f46.diff patches/st-scrollback-20210507-4536f46.diff 1;" F epoch:1667356258
+st-scrollback-mouse-20220127-2c5edf2.diff patches/st-scrollback-mouse-20220127-2c5edf2.diff 1;" F epoch:1667356258
+st-scrollback-reflow-0.8.5.diff patches/st-scrollback-reflow-0.8.5.diff 1;" F epoch:1667356258
+st-scrollback-ringbuffer-0.8.5.diff patches/st-scrollback-ringbuffer-0.8.5.diff 1;" F epoch:1667356258
+st-universcroll-0.8.4.diff patches/st-universcroll-0.8.4.diff 1;" F epoch:1667356258
+st.1 st.1 1;" F epoch:1667356258
+st.c st.c 1;" F epoch:1667356329
+st.h st.h 1;" F epoch:1667356329
+st.o Makefile /^st.o: config.h st.h win.h$/;" t
+stcursor config.def.h /^static Rune stcursor = 0x2603; \/* snowman ("☃") *\/$/;" v typeref:typename:Rune
+stcursor config.h /^static Rune stcursor = 0x2603; \/* snowman ("☃") *\/$/;" v typeref:typename:Rune
+strdump st.c /^strdump(void)$/;" f typeref:typename:void
+strhandle st.c /^strhandle(void)$/;" f typeref:typename:void
+strparse st.c /^strparse(void)$/;" f typeref:typename:void
+strreset st.c /^strreset(void)$/;" f typeref:typename:void
+stty st.c /^stty(char **args)$/;" f typeref:typename:void
+stty_args config.def.h /^char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";$/;" v typeref:typename:char *
+stty_args config.h /^char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";$/;" v typeref:typename:char *
+tabspaces config.def.h /^unsigned int tabspaces = 8;$/;" v typeref:typename:unsigned int
+tabspaces config.h /^unsigned int tabspaces = 8;$/;" v typeref:typename:unsigned int
+tattrset st.c /^tattrset(int attr)$/;" f typeref:typename:int
+tclearregion st.c /^tclearregion(int x1, int y1, int x2, int y2)$/;" f typeref:typename:void
+tcontrolcode st.c /^tcontrolcode(uchar ascii)$/;" f typeref:typename:void
+tcursor st.c /^tcursor(int mode)$/;" f typeref:typename:void
+tdectest st.c /^tdectest(char c)$/;" f typeref:typename:void
+tdefcolor st.c /^tdefcolor(const int *attr, int *npar, int l)$/;" f typeref:typename:int32_t
+tdeftran st.c /^tdeftran(char ascii)$/;" f typeref:typename:void
+tdefutf8 st.c /^tdefutf8(char ascii)$/;" f typeref:typename:void
+tdeletechar st.c /^tdeletechar(int n)$/;" f typeref:typename:void
+tdeleteline st.c /^tdeleteline(int n)$/;" f typeref:typename:void
+tdump st.c /^tdump(void)$/;" f typeref:typename:void
+tdumpline st.c /^tdumpline(int n)$/;" f typeref:typename:void
+tdumpsel st.c /^tdumpsel(void)$/;" f typeref:typename:void
+termname config.def.h /^char *termname = "st-256color";$/;" v typeref:typename:char *
+termname config.h /^char *termname = "st-256color";$/;" v typeref:typename:char *
+tfulldirt st.c /^tfulldirt(void)$/;" f typeref:typename:void
+tinsertblank st.c /^tinsertblank(int n)$/;" f typeref:typename:void
+tinsertblankline st.c /^tinsertblankline(int n)$/;" f typeref:typename:void
+tisaltscr st.c /^int tisaltscr(void)$/;" f typeref:typename:int
+tlinelen st.c /^tlinelen(int y)$/;" f typeref:typename:int
+tmoveato st.c /^tmoveato(int x, int y)$/;" f typeref:typename:void
+tmoveto st.c /^tmoveto(int x, int y)$/;" f typeref:typename:void
+tnew st.c /^tnew(int col, int row)$/;" f typeref:typename:void
+tnewline st.c /^tnewline(int first_col)$/;" f typeref:typename:void
+toggleprinter st.c /^toggleprinter(const Arg *arg)$/;" f typeref:typename:void
+togglescheme config.def.h /^static void togglescheme() {$/;" f typeref:typename:void
+togglescheme config.h /^static unsigned char togglescheme() {$/;" f typeref:typename:unsigned char
+tprinter st.c /^tprinter(char *s, size_t len)$/;" f typeref:typename:void
+tputc st.c /^tputc(Rune u)$/;" f typeref:typename:void
+tputtab st.c /^tputtab(int n)$/;" f typeref:typename:void
+treset st.c /^treset(void)$/;" f typeref:typename:void
+tresize st.c /^tresize(int col, int row)$/;" f typeref:typename:void
+tripleclicktimeout config.def.h /^static unsigned int tripleclicktimeout = 600;$/;" v typeref:typename:unsigned int
+tripleclicktimeout config.h /^static unsigned int tripleclicktimeout = 600;$/;" v typeref:typename:unsigned int
+tscrolldown st.c /^tscrolldown(int orig, int n, int copyhist)$/;" f typeref:typename:void
+tscrollup st.c /^tscrollup(int orig, int n, int copyhist)$/;" f typeref:typename:void
+tsetattr st.c /^tsetattr(const int *attr, int l)$/;" f typeref:typename:void
+tsetchar st.c /^tsetchar(Rune u, const Glyph *attr, int x, int y)$/;" f typeref:typename:void
+tsetdirt st.c /^tsetdirt(int top, int bot)$/;" f typeref:typename:void
+tsetdirtattr st.c /^tsetdirtattr(int attr)$/;" f typeref:typename:void
+tsetmode st.c /^tsetmode(int priv, int set, const int *args, int narg)$/;" f typeref:typename:void
+tsetscroll st.c /^tsetscroll(int t, int b)$/;" f typeref:typename:void
+tstrsequence st.c /^tstrsequence(uchar c)$/;" f typeref:typename:void
+tswapscreen st.c /^tswapscreen(void)$/;" f typeref:typename:void
+ttyhangup st.c /^ttyhangup(void)$/;" f typeref:typename:void
+ttynew st.c /^ttynew(const char *line, char *cmd, const char *out, char **args)$/;" f typeref:typename:int
+ttyread st.c /^ttyread(void)$/;" f typeref:typename:size_t
+ttyresize st.c /^ttyresize(int tw, int th)$/;" f typeref:typename:void
+ttysend x.c /^ttysend(const Arg *arg)$/;" f typeref:typename:void
+ttywrite st.c /^ttywrite(const char *s, size_t n, int may_echo)$/;" f typeref:typename:void
+ttywriteraw st.c /^ttywriteraw(const char *s, size_t n)$/;" f typeref:typename:void
+tupdatebgcolor st.c /^tupdatebgcolor(int oldbg, int newbg)$/;" f typeref:typename:void
+tupdatefgcolor st.c /^tupdatefgcolor(int oldfg, int newfg)$/;" f typeref:typename:void
+twrite st.c /^twrite(const char *buf, int buflen, int show_ctrl)$/;" f typeref:typename:int
+u st.h /^ Rune u; \/* character code *\/$/;" m struct:__anon7c9e12e20108 typeref:typename:Rune
+uchar st.h /^typedef unsigned char uchar;$/;" t typeref:typename:unsigned char
+ui st.h /^ uint ui;$/;" m union:__anon7c9e12e2020a typeref:typename:uint
+uint st.h /^typedef unsigned int uint;$/;" t typeref:typename:unsigned int
+ulong st.h /^typedef unsigned long ulong;$/;" t typeref:typename:unsigned long
+uninstall Makefile /^uninstall:$/;" t
+unmap x.c /^unmap(XEvent *ev)$/;" f typeref:typename:void
+updatescheme x.c /^updatescheme(void)$/;" f typeref:typename:void
+usage x.c /^usage(void)$/;" f typeref:typename:void
+ushort st.h /^typedef unsigned short ushort;$/;" t typeref:typename:unsigned short
+utf8decode st.c /^utf8decode(const char *c, Rune *u, size_t clen)$/;" f typeref:typename:size_t
+utf8decodebyte st.c /^utf8decodebyte(char c, size_t *i)$/;" f typeref:typename:Rune
+utf8encode st.c /^utf8encode(Rune u, char *c)$/;" f typeref:typename:size_t
+utf8encodebyte st.c /^utf8encodebyte(Rune u, size_t i)$/;" f typeref:typename:char
+utf8validate st.c /^utf8validate(Rune *u, size_t i)$/;" f typeref:typename:size_t
+utmp config.def.h /^char *utmp = NULL;$/;" v typeref:typename:char *
+utmp config.h /^char *utmp = NULL;$/;" v typeref:typename:char *
+v st.h /^ const void *v;$/;" m union:__anon7c9e12e2020a typeref:typename:const void *
+visibility x.c /^visibility(XEvent *ev)$/;" f typeref:typename:void
+vtiden config.def.h /^char *vtiden = "\\033[?6c";$/;" v typeref:typename:char *
+vtiden config.h /^char *vtiden = "\\033[?6c";$/;" v typeref:typename:char *
+win.h win.h 1;" F epoch:1667356258
+win_mode win.h /^enum win_mode {$/;" g
+worddelimiters config.def.h /^wchar_t *worddelimiters = L" ";$/;" v typeref:typename:wchar_t *
+worddelimiters config.h /^wchar_t *worddelimiters = L" ";$/;" v typeref:typename:wchar_t *
+x.c x.c 1;" F epoch:1667356911
+x.o Makefile /^x.o: arg.h config.h st.h win.h$/;" t
+xbell x.c /^xbell(void)$/;" f typeref:typename:void
+xclear x.c /^xclear(int x1, int y1, int x2, int y2)$/;" f typeref:typename:void
+xclipcopy x.c /^xclipcopy(void)$/;" f typeref:typename:void
+xdrawcursor x.c /^xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)$/;" f typeref:typename:void
+xdrawglyph x.c /^xdrawglyph(Glyph g, int x, int y)$/;" f typeref:typename:void
+xdrawglyphfontspecs x.c /^xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y)$/;" f typeref:typename:void
+xdrawline x.c /^xdrawline(Line line, int x1, int y1, int x2)$/;" f typeref:typename:void
+xfinishdraw x.c /^xfinishdraw(void)$/;" f typeref:typename:void
+xgeommasktogravity x.c /^xgeommasktogravity(int mask)$/;" f typeref:typename:int
+xgetcolor x.c /^xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b)$/;" f typeref:typename:int
+xhints x.c /^xhints(void)$/;" f typeref:typename:void
+xicdestroy x.c /^xicdestroy(XIC xim, XPointer client, XPointer call)$/;" f typeref:typename:int
+ximdestroy x.c /^ximdestroy(XIM xim, XPointer client, XPointer call)$/;" f typeref:typename:void
+ximinstantiate x.c /^ximinstantiate(Display *dpy, XPointer client, XPointer call)$/;" f typeref:typename:void
+ximopen x.c /^ximopen(Display *dpy)$/;" f typeref:typename:int
+xinit x.c /^xinit(int cols, int rows)$/;" f typeref:typename:void
+xloadcolor x.c /^xloadcolor(int i, const char *name, Color *ncolor)$/;" f typeref:typename:int
+xloadcols x.c /^xloadcols(void)$/;" f typeref:typename:void
+xloadfont x.c /^xloadfont(Font *f, FcPattern *pattern)$/;" f typeref:typename:int
+xloadfonts x.c /^xloadfonts(const char *fontstr, double fontsize)$/;" f typeref:typename:void
+xmakeglyphfontspecs x.c /^xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)$/;" f typeref:typename:int
+xmalloc st.c /^xmalloc(size_t len)$/;" f typeref:typename:void *
+xrealloc st.c /^xrealloc(void *p, size_t len)$/;" f typeref:typename:void *
+xresize x.c /^xresize(int col, int row)$/;" f typeref:typename:void
+xsetcolorname x.c /^xsetcolorname(int x, const char *name)$/;" f typeref:typename:int
+xsetcursor x.c /^xsetcursor(int cursor)$/;" f typeref:typename:int
+xsetenv x.c /^xsetenv(void)$/;" f typeref:typename:void
+xseticontitle x.c /^xseticontitle(char *p)$/;" f typeref:typename:void
+xsetmode x.c /^xsetmode(int set, unsigned int flags)$/;" f typeref:typename:void
+xsetpointermotion x.c /^xsetpointermotion(int set)$/;" f typeref:typename:void
+xsetsel x.c /^xsetsel(char *str)$/;" f typeref:typename:void
+xsettitle x.c /^xsettitle(char *p)$/;" f typeref:typename:void
+xseturgency x.c /^xseturgency(int add)$/;" f typeref:typename:void
+xstartdraw x.c /^xstartdraw(void)$/;" f typeref:typename:int
+xstrdup st.c /^xstrdup(const char *s)$/;" f typeref:typename:char *
+xunloadfont x.c /^xunloadfont(Font *f)$/;" f typeref:typename:void
+xunloadfonts x.c /^xunloadfonts(void)$/;" f typeref:typename:void
+xwrite st.c /^xwrite(int fd, const char *s, size_t len)$/;" f typeref:typename:ssize_t
+xximspot x.c /^xximspot(int x, int y)$/;" f typeref:typename:void
+zoom x.c /^zoom(const Arg *arg)$/;" f typeref:typename:void
+zoomabs x.c /^zoomabs(const Arg *arg)$/;" f typeref:typename:void
+zoomreset x.c /^zoomreset(const Arg *arg)$/;" f typeref:typename:void
diff --git a/x.c b/x.c
@@ -34,6 +34,7 @@ typedef struct {
void (*func)(const Arg *);
const Arg arg;
uint release;
+ int altscrn; /* 0: don't care, -1: not alt screen, 1: alt screen */
} MouseShortcut;
typedef struct {
@@ -59,6 +60,8 @@ static void zoom(const Arg *);
static void zoomabs(const Arg *);
static void zoomreset(const Arg *);
static void ttysend(const Arg *);
+static void nextscheme(const Arg *);
+static void selectscheme(const Arg *);
/* config.h for applying patches and the configuration. */
#include "config.h"
@@ -81,6 +84,7 @@ typedef XftGlyphFontSpec GlyphFontSpec;
typedef struct {
int tw, th; /* tty width and height */
int w, h; /* window width and height */
+ int hborderpx, vborderpx;
int ch; /* char height */
int cw; /* char width */
int mode; /* window state/mode flags */
@@ -186,6 +190,7 @@ static void mousesel(XEvent *, int);
static void mousereport(XEvent *);
static char *kmap(KeySym, uint);
static int match(uint, uint);
+static void updatescheme(void);
static void run(void);
static void usage(void);
@@ -255,6 +260,7 @@ static char *opt_name = NULL;
static char *opt_title = NULL;
static uint buttons; /* bit field of pressed buttons */
+static int cursorblinks = 0;
void
clipcopy(const Arg *dummy)
@@ -333,7 +339,7 @@ ttysend(const Arg *arg)
int
evcol(XEvent *e)
{
- int x = e->xbutton.x - borderpx;
+ int x = e->xbutton.x - win.hborderpx;
LIMIT(x, 0, win.tw - 1);
return x / win.cw;
}
@@ -341,7 +347,7 @@ evcol(XEvent *e)
int
evrow(XEvent *e)
{
- int y = e->xbutton.y - borderpx;
+ int y = e->xbutton.y - win.vborderpx;
LIMIT(y, 0, win.th - 1);
return y / win.ch;
}
@@ -457,6 +463,7 @@ mouseaction(XEvent *e, uint release)
for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
if (ms->release == release &&
ms->button == e->xbutton.button &&
+ (!ms->altscrn || (ms->altscrn == (tisaltscr() ? 1 : -1))) &&
(match(ms->mod, state) || /* exact or forced */
match(ms->mod, state & ~forcemousemod))) {
ms->func(&(ms->arg));
@@ -741,6 +748,9 @@ cresize(int width, int height)
col = MAX(1, col);
row = MAX(1, row);
+ win.hborderpx = (win.w - col * win.cw) / 2;
+ win.vborderpx = (win.h - row * win.ch) / 2;
+
tresize(col, row);
xresize(col, row);
ttyresize(win.tw, win.th);
@@ -803,7 +813,7 @@ xloadcols(void)
for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp)
XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
} else {
- dc.collen = MAX(LEN(colorname), 256);
+ dc.collen = 258;
dc.col = xmalloc(dc.collen * sizeof(Color));
}
@@ -878,8 +888,8 @@ xhints(void)
sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize;
sizeh->height = win.h;
sizeh->width = win.w;
- sizeh->height_inc = win.ch;
- sizeh->width_inc = win.cw;
+ sizeh->height_inc = 1;
+ sizeh->width_inc = 1;
sizeh->base_height = 2 * borderpx;
sizeh->base_width = 2 * borderpx;
sizeh->min_height = win.ch + 2 * borderpx;
@@ -1173,8 +1183,8 @@ xinit(int cols, int rows)
xloadcols();
/* adjust fixed window geometry */
- win.w = 2 * borderpx + cols * win.cw;
- win.h = 2 * borderpx + rows * win.ch;
+ win.w = 2 * win.hborderpx + 2 * borderpx + cols * win.cw;
+ win.h = 2 * win.vborderpx + 2 * borderpx + rows * win.ch;
if (xw.gm & XNegative)
xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2;
if (xw.gm & YNegative)
@@ -1259,7 +1269,7 @@ xinit(int cols, int rows)
int
xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
{
- float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, yp;
+ float winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch, xp, yp;
ushort mode, prevmode = USHRT_MAX;
Font *font = &dc.font;
int frcflags = FRC_NORMAL;
@@ -1392,7 +1402,7 @@ void
xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y)
{
int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1);
- int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch,
+ int winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch,
width = charlen * win.cw;
Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
XRenderColor colfg, colbg;
@@ -1482,17 +1492,17 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
/* Intelligent cleaning up of the borders. */
if (x == 0) {
- xclear(0, (y == 0)? 0 : winy, borderpx,
+ xclear(0, (y == 0)? 0 : winy, win.hborderpx,
winy + win.ch +
- ((winy + win.ch >= borderpx + win.th)? win.h : 0));
+ ((winy + win.ch >= win.vborderpx + win.th)? win.h : 0));
}
- if (winx + width >= borderpx + win.tw) {
+ if (winx + width >= win.hborderpx + win.tw) {
xclear(winx + width, (y == 0)? 0 : winy, win.w,
- ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch)));
+ ((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch)));
}
if (y == 0)
- xclear(winx, 0, winx + width, borderpx);
- if (winy + win.ch >= borderpx + win.th)
+ xclear(winx, 0, winx + width, win.vborderpx);
+ if (winy + win.ch >= win.vborderpx + win.th)
xclear(winx, winy + win.ch, winx + width, win.h);
/* Clean up the region we want to draw to. */
@@ -1575,46 +1585,60 @@ 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 */
- g.u = 0x2603; /* snowman (U+2603) */
- /* FALLTHROUGH */
- case 0: /* Blinking Block */
- case 1: /* Blinking Block (Default) */
+ default:
+ case 0: /* blinking block */
+ case 1: /* blinking block (default) */
+ if (IS_SET(MODE_BLINK))
+ break;
case 2: /* Steady Block */
xdrawglyph(g, cx, cy);
break;
- case 3: /* Blinking Underline */
- case 4: /* Steady Underline */
+ case 3: /* blinking underline */
+ if (IS_SET(MODE_BLINK))
+ break;
+ /* FALLTHROUGH */
+ case 4: /* steady underline */
XftDrawRect(xw.draw, &drawcol,
- borderpx + cx * win.cw,
- borderpx + (cy + 1) * win.ch - \
+ win.hborderpx + cx * win.cw,
+ win.vborderpx + (cy + 1) * win.ch - \
cursorthickness,
win.cw, cursorthickness);
break;
- case 5: /* Blinking bar */
- case 6: /* Steady bar */
+ case 5: /* blinking bar */
+ if (IS_SET(MODE_BLINK))
+ break;
+ /* FALLTHROUGH */
+ case 6: /* steady bar */
XftDrawRect(xw.draw, &drawcol,
- borderpx + cx * win.cw,
- borderpx + cy * win.ch,
+ win.hborderpx + cx * win.cw,
+ win.vborderpx + cy * win.ch,
cursorthickness, win.ch);
break;
+ case 7: /* blinking st cursor */
+ if (IS_SET(MODE_BLINK))
+ break;
+ /* FALLTHROUGH */
+ case 8: /* steady st cursor */
+ g.u = stcursor;
+ xdrawglyph(g, cx, cy);
+ break;
}
} else {
XftDrawRect(xw.draw, &drawcol,
- borderpx + cx * win.cw,
- borderpx + cy * win.ch,
+ win.hborderpx + cx * win.cw,
+ win.vborderpx + cy * win.ch,
win.cw - 1, 1);
XftDrawRect(xw.draw, &drawcol,
- borderpx + cx * win.cw,
- borderpx + cy * win.ch,
+ win.hborderpx + cx * win.cw,
+ win.vborderpx + cy * win.ch,
1, win.ch - 1);
XftDrawRect(xw.draw, &drawcol,
- borderpx + (cx + 1) * win.cw - 1,
- borderpx + cy * win.ch,
+ win.hborderpx + (cx + 1) * win.cw - 1,
+ win.vborderpx + cy * win.ch,
1, win.ch - 1);
XftDrawRect(xw.draw, &drawcol,
- borderpx + cx * win.cw,
- borderpx + (cy + 1) * win.ch - 1,
+ win.hborderpx + cx * win.cw,
+ win.vborderpx + (cy + 1) * win.ch - 1,
win.cw, 1);
}
}
@@ -1754,9 +1778,12 @@ xsetmode(int set, unsigned int flags)
int
xsetcursor(int cursor)
{
- if (!BETWEEN(cursor, 0, 7)) /* 7: st extension */
+ if (!BETWEEN(cursor, 0, 8)) /* 7-8: st extensions */
return 1;
win.cursor = cursor;
+ cursorblinks = win.cursor == 0 || win.cursor == 1 ||
+ win.cursor == 3 || win.cursor == 5 ||
+ win.cursor == 7;
return 0;
}
@@ -2000,6 +2027,10 @@ run(void)
if (FD_ISSET(ttyfd, &rfd) || xev) {
if (!drawing) {
trigger = now;
+ if (IS_SET(MODE_BLINK)) {
+ win.mode ^= MODE_BLINK;
+ }
+ lastblink = now;
drawing = 1;
}
timeout = (maxlatency - TIMEDIFF(now, trigger)) \
@@ -2010,7 +2041,7 @@ run(void)
/* idle detected or maxlatency exhausted -> draw */
timeout = -1;
- if (blinktimeout && tattrset(ATTR_BLINK)) {
+ if (blinktimeout && (cursorblinks || tattrset(ATTR_BLINK))) {
timeout = blinktimeout - TIMEDIFF(now, lastblink);
if (timeout <= 0) {
if (-timeout > blinktimeout) /* start visible */
@@ -2041,12 +2072,53 @@ usage(void)
" [stty_args ...]\n", argv0, argv0);
}
+void
+nextscheme(const Arg *arg)
+{
+ colorscheme += arg->i;
+ if (colorscheme >= (int)LEN(schemes))
+ colorscheme = 0;
+ else if (colorscheme < 0)
+ colorscheme = LEN(schemes) - 1;
+ updatescheme();
+}
+
+void
+selectscheme(const Arg *arg)
+{
+ if (BETWEEN(arg->i, 0, LEN(schemes)-1)) {
+ colorscheme = arg->i;
+ updatescheme();
+ }
+}
+
+void
+updatescheme(void)
+{
+ int oldbg, oldfg;
+
+ oldbg = defaultbg;
+ oldfg = defaultfg;
+ colorname = schemes[colorscheme].colors;
+ defaultbg = schemes[colorscheme].bg;
+ defaultfg = schemes[colorscheme].fg;
+ defaultcs = schemes[colorscheme].cs;
+ defaultrcs = schemes[colorscheme].rcs;
+ xloadcols();
+ if (defaultbg != oldbg)
+ tupdatebgcolor(oldbg, defaultbg);
+ if (defaultfg != oldfg)
+ tupdatefgcolor(oldfg, defaultfg);
+ cresize(win.w, win.h);
+ redraw();
+}
+
int
main(int argc, char *argv[])
{
xw.l = xw.t = 0;
xw.isfixed = False;
- xsetcursor(cursorshape);
+ xsetcursor(cursorstyle);
ARGBEGIN {
case 'a':
@@ -2096,6 +2168,12 @@ main(int argc, char *argv[])
} ARGEND;
run:
+ colorname = schemes[colorscheme].colors;
+ defaultbg = schemes[colorscheme].bg;
+ defaultfg = schemes[colorscheme].fg;
+ defaultcs = schemes[colorscheme].cs;
+ defaultrcs = schemes[colorscheme].rcs;
+
if (argc > 0) /* eat all remaining arguments */
opt_cmd = argv;