diff options
author | jack <[email protected]> | 2024-06-21 12:08:53 -0600 |
---|---|---|
committer | jack <[email protected]> | 2024-06-21 12:08:53 -0600 |
commit | 75bc5a9c7586ce23151692898caf3d721fd11cfb (patch) | |
tree | 0429ec52223a17c37f0599382ee08ced80f56733 | |
parent | 070294ef0135c9e886e8490a64b929b0548b04f2 (diff) | |
download | st-wl.tar.gz st-wl.zip |
remove patches & update license headerswl
-rw-r--r-- | arg.h | 2 | ||||
-rw-r--r-- | config.h | 2 | ||||
-rw-r--r-- | patches/st-scrollback-mouse-0.8.2.diff | 85 | ||||
-rw-r--r-- | patches/st-scrollback-mouse-altscreen-0.8.diff | 66 | ||||
-rw-r--r-- | patches/st-scrollback-reflow-0.8.5.diff | 1478 | ||||
-rw-r--r-- | patches/st-scrollback-ringbuffer-0.8.5.diff | 717 | ||||
-rw-r--r-- | st.c | 2 | ||||
-rw-r--r-- | st.h | 4 | ||||
-rw-r--r-- | win.h | 2 | ||||
-rw-r--r-- | wl.c | 5 |
10 files changed, 9 insertions, 2354 deletions
@@ -1,4 +1,4 @@ -// Copyright 2024 @waffle87 +// Copyright 2024 [email protected] // SPDX-License-Identifier: MIT/X #pragma once @@ -1,4 +1,4 @@ -// Copyright 2024 @waffle87 +// Copyright 2024 [email protected] // SPDX-License-Identifier: MIT/X #pragma once diff --git a/patches/st-scrollback-mouse-0.8.2.diff b/patches/st-scrollback-mouse-0.8.2.diff deleted file mode 100644 index c49bf89..0000000 --- a/patches/st-scrollback-mouse-0.8.2.diff +++ /dev/null @@ -1,85 +0,0 @@ -From 315f69069017122ca69d0319d0ad9481113fe5c8 Mon Sep 17 00:00:00 2001 -From: Jacob Prosser <[email protected]> -Date: Fri, 26 Apr 2019 17:23:27 +1000 -Subject: [PATCH] Scrollback-Mouse for 0.8.2 - ---- - config.def.h | 10 ++++++++-- - st.h | 8 ++++++++ - x.c | 9 +++++++++ - 3 files changed, 25 insertions(+), 2 deletions(-) - -diff --git a/config.def.h b/config.def.h -index 7326a74..ad20c4c 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -156,8 +156,14 @@ static unsigned int defaultattr = 11; - */ - static MouseShortcut mshortcuts[] = { - /* button mask string */ -- { Button4, XK_ANY_MOD, "\031" }, -- { Button5, XK_ANY_MOD, "\005" }, -+ { Button4, XK_NO_MOD, "\031" }, -+ { Button5, XK_NO_MOD, "\005" }, -+}; -+ -+MouseKey mkeys[] = { -+ /* button mask function argument */ -+ { Button4, ShiftMask, kscrollup, {.i = 1} }, -+ { Button5, ShiftMask, kscrolldown, {.i = 1} }, - }; - - /* Internal keyboard shortcuts. */ -diff --git a/st.h b/st.h -index 17a79e0..3ac7f57 100644 ---- a/st.h -+++ b/st.h -@@ -76,6 +76,13 @@ typedef union { - const void *v; - } Arg; - -+typedef struct { -+ uint b; -+ uint mask; -+ void (*func)(const Arg *); -+ const Arg arg; -+} MouseKey; -+ - void die(const char *, ...); - void redraw(void); - void draw(void); -@@ -122,3 +129,4 @@ extern char *termname; - extern unsigned int tabspaces; - extern unsigned int defaultfg; - extern unsigned int defaultbg; -+extern MouseKey mkeys[]; -diff --git a/x.c b/x.c -index 0422421..e9fd6e9 100644 ---- a/x.c -+++ b/x.c -@@ -409,6 +409,7 @@ bpress(XEvent *e) - { - struct timespec now; - MouseShortcut *ms; -+ MouseKey *mk; - int snap; - - if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { -@@ -424,6 +425,14 @@ bpress(XEvent *e) - } - } - -+ for (mk = mkeys; mk < mkeys + LEN(mkeys); mk++) { -+ if (e->xbutton.button == mk->b -+ && match(mk->mask, e->xbutton.state)) { -+ mk->func(&mk->arg); -+ return; -+ } -+ } -+ - if (e->xbutton.button == Button1) { - /* - * If the user clicks below predefined timeouts specific --- -2.21.0 - diff --git a/patches/st-scrollback-mouse-altscreen-0.8.diff b/patches/st-scrollback-mouse-altscreen-0.8.diff deleted file mode 100644 index 8ee58d9..0000000 --- a/patches/st-scrollback-mouse-altscreen-0.8.diff +++ /dev/null @@ -1,66 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index feec7e2..f1a9768 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -162,8 +162,8 @@ static MouseShortcut mshortcuts[] = { - - MouseKey mkeys[] = { - /* button mask function argument */ -- { Button4, ShiftMask, kscrollup, {.i = 1} }, -- { Button5, ShiftMask, kscrolldown, {.i = 1} }, -+ { Button4, XK_NO_MOD, kscrollup, {.i = 1} }, -+ { Button5, XK_NO_MOD, kscrolldown, {.i = 1} }, - }; - - /* Internal keyboard shortcuts. */ -diff --git a/st.c b/st.c -index 1d8c12a..458dcfa 100644 ---- a/st.c -+++ b/st.c -@@ -1051,6 +1051,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 cdd25ae..e6143f0 100644 ---- a/st.h -+++ b/st.h -@@ -99,6 +99,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 1de5f6c..991bc3e 100644 ---- a/x.c -+++ b/x.c -@@ -417,11 +417,13 @@ bpress(XEvent *e) - return; - } - -- for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { -- if (e->xbutton.button == ms->b -- && match(ms->mask, e->xbutton.state)) { -- ttywrite(ms->s, strlen(ms->s), 1); -- return; -+ if (tisaltscr()) { -+ for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { -+ if (e->xbutton.button == ms->b -+ && match(ms->mask, e->xbutton.state)) { -+ ttywrite(ms->s, strlen(ms->s), 1); -+ return; -+ } - } - } - diff --git a/patches/st-scrollback-reflow-0.8.5.diff b/patches/st-scrollback-reflow-0.8.5.diff deleted file mode 100644 index 085c828..0000000 --- a/patches/st-scrollback-reflow-0.8.5.diff +++ /dev/null @@ -1,1478 +0,0 @@ -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 deleted file mode 100644 index a507cc4..0000000 --- a/patches/st-scrollback-ringbuffer-0.8.5.diff +++ /dev/null @@ -1,717 +0,0 @@ -commit 0663bdf11a409961da5b1120741a69814da8ce65 -Author: Timo Röhling <[email protected]> -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, @@ -1,4 +1,4 @@ -// Copyright 2024 @waffle87 +// Copyright 2024 [email protected] // SPDX-License-Identifier: MIT/X #include <ctype.h> #include <errno.h> @@ -1,4 +1,4 @@ -// Copyright 2024 @waffle87 +// Copyright 2024 [email protected] // SPDX-License-Identifier: MIT/X #include <stdint.h> #include <sys/types.h> @@ -25,7 +25,7 @@ #define LEN(a) \ (__builtin_choose_expr(CHECK((a)), sizeof((a)) / sizeof((a)[0]), (void)0)) #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) -#define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) +#define DIVCEIL(n, d) (((n) + ((d)-1)) / (d)) #define DEFAULT(a, b) (a) = (a) ? (a) : (b) #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) #define ATTRCMP(a, b) \ @@ -1,4 +1,4 @@ -// Copyright 2024 @waffle87 +// Copyright 2024 [email protected] // SPDX-License-Identifier: MIT/X enum win_mode { @@ -1,4 +1,4 @@ -// Copyright 2024 @waffle87 +// Copyright 2024 [email protected] // SPDX-License-Identifier: MIT/X #include <errno.h> #include <fcntl.h> @@ -317,7 +317,8 @@ static char *opt_title = NULL; static int oldbutton = 3; /* button event on startup: 3 = release */ -void xbell(void) { /* Do nothing, no bell in wayland. */ } +void xbell(void) { /* Do nothing, no bell in wayland. */ +} void xsetpointermotion(int dummy) { /* Do nothing, not required under wayland. */ |