1-st-scrollback-20200419-72e3f6c.diff (8949B)
1https://st.suckless.org/patches/scrollback/ 2 3diff --git a/config.def.h b/config.def.h 4index 0895a1f..eef24df 100644 5--- a/config.def.h 6+++ b/config.def.h 7@@ -188,6 +188,8 @@ static Shortcut shortcuts[] = { 8 { TERMMOD, XK_Y, selpaste, {.i = 0} }, 9 { ShiftMask, XK_Insert, selpaste, {.i = 0} }, 10 { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, 11+ { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} }, 12+ { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} }, 13 }; 14 15 /* 16diff --git a/st.c b/st.c 17index 0ce6ac2..641edc0 100644 18--- a/st.c 19+++ b/st.c 20@@ -35,6 +35,7 @@ 21 #define ESC_ARG_SIZ 16 22 #define STR_BUF_SIZ ESC_BUF_SIZ 23 #define STR_ARG_SIZ ESC_ARG_SIZ 24+#define HISTSIZE 2000 25 26 /* macros */ 27 #define IS_SET(flag) ((term.mode & (flag)) != 0) 28@@ -42,6 +43,9 @@ 29 #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) 30 #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) 31 #define ISDELIM(u) (u && wcschr(worddelimiters, u)) 32+#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \ 33+ term.scr + HISTSIZE + 1) % HISTSIZE] : \ 34+ term.line[(y) - term.scr]) 35 36 enum term_mode { 37 MODE_WRAP = 1 << 0, 38@@ -117,6 +121,9 @@ typedef struct { 39 int col; /* nb col */ 40 Line *line; /* screen */ 41 Line *alt; /* alternate screen */ 42+ Line hist[HISTSIZE]; /* history buffer */ 43+ int histi; /* history index */ 44+ int scr; /* scroll back */ 45 int *dirty; /* dirtyness of lines */ 46 TCursor c; /* cursor */ 47 int ocx; /* old cursor col */ 48@@ -185,8 +192,8 @@ static void tnewline(int); 49 static void tputtab(int); 50 static void tputc(Rune); 51 static void treset(void); 52-static void tscrollup(int, int); 53-static void tscrolldown(int, int); 54+static void tscrollup(int, int, int); 55+static void tscrolldown(int, int, int); 56 static void tsetattr(int *, int); 57 static void tsetchar(Rune, Glyph *, int, int); 58 static void tsetdirt(int, int); 59@@ -415,10 +422,10 @@ tlinelen(int y) 60 { 61 int i = term.col; 62 63- if (term.line[y][i - 1].mode & ATTR_WRAP) 64+ if (TLINE(y)[i - 1].mode & ATTR_WRAP) 65 return i; 66 67- while (i > 0 && term.line[y][i - 1].u == ' ') 68+ while (i > 0 && TLINE(y)[i - 1].u == ' ') 69 --i; 70 71 return i; 72@@ -527,7 +534,7 @@ selsnap(int *x, int *y, int direction) 73 * Snap around if the word wraps around at the end or 74 * beginning of a line. 75 */ 76- prevgp = &term.line[*y][*x]; 77+ prevgp = &TLINE(*y)[*x]; 78 prevdelim = ISDELIM(prevgp->u); 79 for (;;) { 80 newx = *x + direction; 81@@ -542,14 +549,14 @@ selsnap(int *x, int *y, int direction) 82 yt = *y, xt = *x; 83 else 84 yt = newy, xt = newx; 85- if (!(term.line[yt][xt].mode & ATTR_WRAP)) 86+ if (!(TLINE(yt)[xt].mode & ATTR_WRAP)) 87 break; 88 } 89 90 if (newx >= tlinelen(newy)) 91 break; 92 93- gp = &term.line[newy][newx]; 94+ gp = &TLINE(newy)[newx]; 95 delim = ISDELIM(gp->u); 96 if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim 97 || (delim && gp->u != prevgp->u))) 98@@ -570,14 +577,14 @@ selsnap(int *x, int *y, int direction) 99 *x = (direction < 0) ? 0 : term.col - 1; 100 if (direction < 0) { 101 for (; *y > 0; *y += direction) { 102- if (!(term.line[*y-1][term.col-1].mode 103+ if (!(TLINE(*y-1)[term.col-1].mode 104 & ATTR_WRAP)) { 105 break; 106 } 107 } 108 } else if (direction > 0) { 109 for (; *y < term.row-1; *y += direction) { 110- if (!(term.line[*y][term.col-1].mode 111+ if (!(TLINE(*y)[term.col-1].mode 112 & ATTR_WRAP)) { 113 break; 114 } 115@@ -608,13 +615,13 @@ getsel(void) 116 } 117 118 if (sel.type == SEL_RECTANGULAR) { 119- gp = &term.line[y][sel.nb.x]; 120+ gp = &TLINE(y)[sel.nb.x]; 121 lastx = sel.ne.x; 122 } else { 123- gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; 124+ gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0]; 125 lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; 126 } 127- last = &term.line[y][MIN(lastx, linelen-1)]; 128+ last = &TLINE(y)[MIN(lastx, linelen-1)]; 129 while (last >= gp && last->u == ' ') 130 --last; 131 132@@ -849,6 +856,9 @@ void 133 ttywrite(const char *s, size_t n, int may_echo) 134 { 135 const char *next; 136+ Arg arg = (Arg) { .i = term.scr }; 137+ 138+ kscrolldown(&arg); 139 140 if (may_echo && IS_SET(MODE_ECHO)) 141 twrite(s, n, 1); 142@@ -1060,13 +1070,53 @@ tswapscreen(void) 143 } 144 145 void 146-tscrolldown(int orig, int n) 147+kscrolldown(const Arg* a) 148+{ 149+ int n = a->i; 150+ 151+ if (n < 0) 152+ n = term.row + n; 153+ 154+ if (n > term.scr) 155+ n = term.scr; 156+ 157+ if (term.scr > 0) { 158+ term.scr -= n; 159+ selscroll(0, -n); 160+ tfulldirt(); 161+ } 162+} 163+ 164+void 165+kscrollup(const Arg* a) 166+{ 167+ int n = a->i; 168+ 169+ if (n < 0) 170+ n = term.row + n; 171+ 172+ if (term.scr <= HISTSIZE-n) { 173+ term.scr += n; 174+ selscroll(0, n); 175+ tfulldirt(); 176+ } 177+} 178+ 179+void 180+tscrolldown(int orig, int n, int copyhist) 181 { 182 int i; 183 Line temp; 184 185 LIMIT(n, 0, term.bot-orig+1); 186 187+ if (copyhist) { 188+ term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE; 189+ temp = term.hist[term.histi]; 190+ term.hist[term.histi] = term.line[term.bot]; 191+ term.line[term.bot] = temp; 192+ } 193+ 194 tsetdirt(orig, term.bot-n); 195 tclearregion(0, term.bot-n+1, term.col-1, term.bot); 196 197@@ -1076,17 +1126,28 @@ tscrolldown(int orig, int n) 198 term.line[i-n] = temp; 199 } 200 201- selscroll(orig, n); 202+ if (term.scr == 0) 203+ selscroll(orig, n); 204 } 205 206 void 207-tscrollup(int orig, int n) 208+tscrollup(int orig, int n, int copyhist) 209 { 210 int i; 211 Line temp; 212 213 LIMIT(n, 0, term.bot-orig+1); 214 215+ if (copyhist) { 216+ term.histi = (term.histi + 1) % HISTSIZE; 217+ temp = term.hist[term.histi]; 218+ term.hist[term.histi] = term.line[orig]; 219+ term.line[orig] = temp; 220+ } 221+ 222+ if (term.scr > 0 && term.scr < HISTSIZE) 223+ term.scr = MIN(term.scr + n, HISTSIZE-1); 224+ 225 tclearregion(0, orig, term.col-1, orig+n-1); 226 tsetdirt(orig+n, term.bot); 227 228@@ -1096,7 +1157,8 @@ tscrollup(int orig, int n) 229 term.line[i+n] = temp; 230 } 231 232- selscroll(orig, -n); 233+ if (term.scr == 0) 234+ selscroll(orig, -n); 235 } 236 237 void 238@@ -1135,7 +1197,7 @@ tnewline(int first_col) 239 int y = term.c.y; 240 241 if (y == term.bot) { 242- tscrollup(term.top, 1); 243+ tscrollup(term.top, 1, 1); 244 } else { 245 y++; 246 } 247@@ -1300,14 +1362,14 @@ void 248 tinsertblankline(int n) 249 { 250 if (BETWEEN(term.c.y, term.top, term.bot)) 251- tscrolldown(term.c.y, n); 252+ tscrolldown(term.c.y, n, 0); 253 } 254 255 void 256 tdeleteline(int n) 257 { 258 if (BETWEEN(term.c.y, term.top, term.bot)) 259- tscrollup(term.c.y, n); 260+ tscrollup(term.c.y, n, 0); 261 } 262 263 int32_t 264@@ -1738,11 +1800,11 @@ csihandle(void) 265 break; 266 case 'S': /* SU -- Scroll <n> line up */ 267 DEFAULT(csiescseq.arg[0], 1); 268- tscrollup(term.top, csiescseq.arg[0]); 269+ tscrollup(term.top, csiescseq.arg[0], 0); 270 break; 271 case 'T': /* SD -- Scroll <n> line down */ 272 DEFAULT(csiescseq.arg[0], 1); 273- tscrolldown(term.top, csiescseq.arg[0]); 274+ tscrolldown(term.top, csiescseq.arg[0], 0); 275 break; 276 case 'L': /* IL -- Insert <n> blank lines */ 277 DEFAULT(csiescseq.arg[0], 1); 278@@ -2248,7 +2310,7 @@ eschandle(uchar ascii) 279 return 0; 280 case 'D': /* IND -- Linefeed */ 281 if (term.c.y == term.bot) { 282- tscrollup(term.top, 1); 283+ tscrollup(term.top, 1, 1); 284 } else { 285 tmoveto(term.c.x, term.c.y+1); 286 } 287@@ -2261,7 +2323,7 @@ eschandle(uchar ascii) 288 break; 289 case 'M': /* RI -- Reverse index */ 290 if (term.c.y == term.top) { 291- tscrolldown(term.top, 1); 292+ tscrolldown(term.top, 1, 1); 293 } else { 294 tmoveto(term.c.x, term.c.y-1); 295 } 296@@ -2482,7 +2544,7 @@ twrite(const char *buf, int buflen, int show_ctrl) 297 void 298 tresize(int col, int row) 299 { 300- int i; 301+ int i, j; 302 int minrow = MIN(row, term.row); 303 int mincol = MIN(col, term.col); 304 int *bp; 305@@ -2519,6 +2581,14 @@ tresize(int col, int row) 306 term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); 307 term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); 308 309+ for (i = 0; i < HISTSIZE; i++) { 310+ term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph)); 311+ for (j = mincol; j < col; j++) { 312+ term.hist[i][j] = term.c.attr; 313+ term.hist[i][j].u = ' '; 314+ } 315+ } 316+ 317 /* resize each row to new width, zero-pad if needed */ 318 for (i = 0; i < minrow; i++) { 319 term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); 320@@ -2577,7 +2647,7 @@ drawregion(int x1, int y1, int x2, int y2) 321 continue; 322 323 term.dirty[y] = 0; 324- xdrawline(term.line[y], x1, y, x2); 325+ xdrawline(TLINE(y), x1, y, x2); 326 } 327 } 328 329@@ -2598,8 +2668,9 @@ draw(void) 330 cx--; 331 332 drawregion(0, 0, term.col, term.row); 333- xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], 334- term.ocx, term.ocy, term.line[term.ocy][term.ocx]); 335+ if (term.scr == 0) 336+ xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], 337+ term.ocx, term.ocy, term.line[term.ocy][term.ocx]); 338 term.ocx = cx; 339 term.ocy = term.c.y; 340 xfinishdraw(); 341diff --git a/st.h b/st.h 342index d978458..b9a4eeb 100644 343--- a/st.h 344+++ b/st.h 345@@ -81,6 +81,8 @@ void die(const char *, ...); 346 void redraw(void); 347 void draw(void); 348 349+void kscrolldown(const Arg *); 350+void kscrollup(const Arg *); 351 void printscreen(const Arg *); 352 void printsel(const Arg *); 353 void sendbreak(const Arg *);