commit 13dc0574919f4b7fbc598e719c6b4c94d3c2deee
Author: sewn <[email protected]>
Date:   Wed Jun 7 12:41:19 2023 +0300

    [st][patch][scrollback-reflow]: update patch, add 0.9 to index

diff --git a/st.suckless.org/patches/scrollback/index.md 
b/st.suckless.org/patches/scrollback/index.md
index 16c626de..3404b22e 100644
--- a/st.suckless.org/patches/scrollback/index.md
+++ b/st.suckless.org/patches/scrollback/index.md
@@ -17,10 +17,11 @@ efficient scrolling:
 
 * [st-scrollback-ringbuffer-0.8.5.diff](st-scrollback-ringbuffer-0.8.5.diff)
 
-Apply the following patch on top of the [original scrollback patch 
(=>0.8.5)](st-scrollback-0.8.5.diff) to allow
-column and row reflow.
+Apply the following patch on top of the previous to allow column and row 
reflow.
 
 * [st-scrollback-reflow-0.8.5.diff](st-scrollback-reflow-0.8.5.diff)
+* [st-scrollback-reflow-0.9.diff](st-scrollback-reflow-0.9.diff)
+* 
[st-scrollback-reflow-20230607-211964d.diff](st-scrollback-reflow-20230607-211964d.diff)
 
 Apply the following patch on top of the previous to allow scrolling
 using `Shift+MouseWheel`.
diff --git 
a/st.suckless.org/patches/scrollback/st-scrollback-reflow-20230607-211964d.diff 
b/st.suckless.org/patches/scrollback/st-scrollback-reflow-20230607-211964d.diff
new file mode 100644
index 00000000..7f6912bc
--- /dev/null
+++ 
b/st.suckless.org/patches/scrollback/st-scrollback-reflow-20230607-211964d.diff
@@ -0,0 +1,1493 @@
+From 633fe6b0231a0f08e6c1e32ae167117a7809cb7f Mon Sep 17 00:00:00 2001
+From: sewn <[email protected]>
+Date: Wed, 7 Jun 2023 12:27:38 +0300
+Subject: [PATCH] reflow columns and rows in case of hidden by resize.
+
+Extracted from https://github.com/ashish-yadav11/st
+Based on the works of BeyondMagic et al.
+---
+ st.c | 941 ++++++++++++++++++++++++++++++++++++++++-------------------
+ st.h |  25 +-
+ 2 files changed, 658 insertions(+), 308 deletions(-)
+
+diff --git a/st.c b/st.c
+index afb862b..46ba498 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++) = '
';
++      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++ = '
';
+                       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++ = '
';
+       }
+-      *ptr = 0;
++      *ptr = '+       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);
+@@ -1837,9 +2009,9 @@ csihandle(void)
+                       ttywrite("", sizeof("") - 1, 0);
+                       break;
+               case 6: /* Report Cursor Position (CPR) "<row>;<column>R" */
+-                      len = snprintf(buf, sizeof(buf), "[%i;%iR",
++                      n = snprintf(buf, sizeof(buf), "[%i;%iR",
+                                      term.c.y+1, term.c.x+1);
+-                      ttywrite(buf, len, 0);
++                      ttywrite(buf, n, 0);
+                       break;
+               default:
+                       goto unknown;
+@@ -2137,16 +2309,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("
", 1);
++      char str[(term.col + 1) * UTF_SIZ];
++  tprinter(str, tgetline(str, &term.line[n][0]));
+ }
+ 
+ void
+@@ -2367,7 +2531,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);
+               }
+@@ -2380,7 +2544,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);
+               }
+@@ -2523,7 +2687,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];
+@@ -2558,6 +2723,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;
+       }
+ }
+@@ -2595,93 +2761,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
", 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
", 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
+@@ -2721,9 +3069,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);
+-- 
+2.40.1
+



Reply via email to