st-scrollback-20170329-149c0d3.diff (8917B)
1 diff --git a/config.def.h b/config.def.h 2 index 877afab..3e9cda5 100644 3 --- a/config.def.h 4 +++ b/config.def.h 5 @@ -178,6 +178,8 @@ Shortcut shortcuts[] = { 6 { TERMMOD, XK_Y, selpaste, {.i = 0} }, 7 { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, 8 { TERMMOD, XK_I, iso14755, {.i = 0} }, 9 + { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} }, 10 + { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} }, 11 }; 12 13 /* 14 diff --git a/st.c b/st.c 15 index ae93ade..b74b9dc 100644 16 --- a/st.c 17 +++ b/st.c 18 @@ -128,6 +128,8 @@ typedef struct { 19 /* function definitions used in config.h */ 20 static void clipcopy(const Arg *); 21 static void clippaste(const Arg *); 22 +static void kscrolldown(const Arg *); 23 +static void kscrollup(const Arg *); 24 static void numlock(const Arg *); 25 static void selpaste(const Arg *); 26 static void zoom(const Arg *); 27 @@ -174,8 +176,8 @@ static void tputtab(int); 28 static void tputc(Rune); 29 static void treset(void); 30 static void tresize(int, int); 31 -static void tscrollup(int, int); 32 -static void tscrolldown(int, int); 33 +static void tscrollup(int, int, int); 34 +static void tscrolldown(int, int, int); 35 static void tsetattr(int *, int); 36 static void tsetchar(Rune, Glyph *, int, int); 37 static void tsetscroll(int, int); 38 @@ -448,10 +450,10 @@ tlinelen(int y) 39 { 40 int i = term.col; 41 42 - if (term.line[y][i - 1].mode & ATTR_WRAP) 43 + if (TLINE(y)[i - 1].mode & ATTR_WRAP) 44 return i; 45 46 - while (i > 0 && term.line[y][i - 1].u == ' ') 47 + while (i > 0 && TLINE(y)[i - 1].u == ' ') 48 --i; 49 50 return i; 51 @@ -513,7 +515,7 @@ selsnap(int *x, int *y, int direction) 52 * Snap around if the word wraps around at the end or 53 * beginning of a line. 54 */ 55 - prevgp = &term.line[*y][*x]; 56 + prevgp = &TLINE(*y)[*x]; 57 prevdelim = ISDELIM(prevgp->u); 58 for (;;) { 59 newx = *x + direction; 60 @@ -528,14 +530,14 @@ selsnap(int *x, int *y, int direction) 61 yt = *y, xt = *x; 62 else 63 yt = newy, xt = newx; 64 - if (!(term.line[yt][xt].mode & ATTR_WRAP)) 65 + if (!(TLINE(yt)[xt].mode & ATTR_WRAP)) 66 break; 67 } 68 69 if (newx >= tlinelen(newy)) 70 break; 71 72 - gp = &term.line[newy][newx]; 73 + gp = &TLINE(newy)[newx]; 74 delim = ISDELIM(gp->u); 75 if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim 76 || (delim && gp->u != prevgp->u))) 77 @@ -556,14 +558,14 @@ selsnap(int *x, int *y, int direction) 78 *x = (direction < 0) ? 0 : term.col - 1; 79 if (direction < 0) { 80 for (; *y > 0; *y += direction) { 81 - if (!(term.line[*y-1][term.col-1].mode 82 + if (!(TLINE(*y-1)[term.col-1].mode 83 & ATTR_WRAP)) { 84 break; 85 } 86 } 87 } else if (direction > 0) { 88 for (; *y < term.row-1; *y += direction) { 89 - if (!(term.line[*y][term.col-1].mode 90 + if (!(TLINE(*y)[term.col-1].mode 91 & ATTR_WRAP)) { 92 break; 93 } 94 @@ -594,13 +596,13 @@ getsel(void) 95 } 96 97 if (sel.type == SEL_RECTANGULAR) { 98 - gp = &term.line[y][sel.nb.x]; 99 + gp = &TLINE(y)[sel.nb.x]; 100 lastx = sel.ne.x; 101 } else { 102 - gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; 103 + gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0]; 104 lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; 105 } 106 - last = &term.line[y][MIN(lastx, linelen-1)]; 107 + last = &TLINE(y)[MIN(lastx, linelen-1)]; 108 while (last >= gp && last->u == ' ') 109 --last; 110 111 @@ -844,6 +846,9 @@ ttyread(void) 112 if (buflen > 0) 113 memmove(buf, ptr, buflen); 114 115 + if (term.scr > 0 && term.scr < HISTSIZE-1) 116 + term.scr++; 117 + 118 return ret; 119 } 120 121 @@ -853,6 +858,9 @@ ttywrite(const char *s, size_t n) 122 fd_set wfd, rfd; 123 ssize_t r; 124 size_t lim = 256; 125 + Arg arg = (Arg) { .i = term.scr }; 126 + 127 + kscrolldown(&arg); 128 129 /* 130 * Remember that we are using a pty, which might be a modem line. 131 @@ -1055,13 +1063,53 @@ tswapscreen(void) 132 } 133 134 void 135 -tscrolldown(int orig, int n) 136 +kscrolldown(const Arg* a) 137 +{ 138 + int n = a->i; 139 + 140 + if (n < 0) 141 + n = term.row + n; 142 + 143 + if (n > term.scr) 144 + n = term.scr; 145 + 146 + if (term.scr > 0) { 147 + term.scr -= n; 148 + selscroll(0, -n); 149 + tfulldirt(); 150 + } 151 +} 152 + 153 +void 154 +kscrollup(const Arg* a) 155 +{ 156 + int n = a->i; 157 + 158 + if (n < 0) 159 + n = term.row + n; 160 + 161 + if (term.scr <= HISTSIZE-n) { 162 + term.scr += n; 163 + selscroll(0, n); 164 + tfulldirt(); 165 + } 166 +} 167 + 168 +void 169 +tscrolldown(int orig, int n, int copyhist) 170 { 171 int i; 172 Line temp; 173 174 LIMIT(n, 0, term.bot-orig+1); 175 176 + if (copyhist) { 177 + term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE; 178 + temp = term.hist[term.histi]; 179 + term.hist[term.histi] = term.line[term.bot]; 180 + term.line[term.bot] = temp; 181 + } 182 + 183 tsetdirt(orig, term.bot-n); 184 tclearregion(0, term.bot-n+1, term.col-1, term.bot); 185 186 @@ -1075,13 +1123,20 @@ tscrolldown(int orig, int n) 187 } 188 189 void 190 -tscrollup(int orig, int n) 191 +tscrollup(int orig, int n, int copyhist) 192 { 193 int i; 194 Line temp; 195 196 LIMIT(n, 0, term.bot-orig+1); 197 198 + if (copyhist) { 199 + term.histi = (term.histi + 1) % HISTSIZE; 200 + temp = term.hist[term.histi]; 201 + term.hist[term.histi] = term.line[orig]; 202 + term.line[orig] = temp; 203 + } 204 + 205 tclearregion(0, orig, term.col-1, orig+n-1); 206 tsetdirt(orig+n, term.bot); 207 208 @@ -1130,7 +1185,7 @@ tnewline(int first_col) 209 int y = term.c.y; 210 211 if (y == term.bot) { 212 - tscrollup(term.top, 1); 213 + tscrollup(term.top, 1, 1); 214 } else { 215 y++; 216 } 217 @@ -1295,14 +1350,14 @@ void 218 tinsertblankline(int n) 219 { 220 if (BETWEEN(term.c.y, term.top, term.bot)) 221 - tscrolldown(term.c.y, n); 222 + tscrolldown(term.c.y, n, 0); 223 } 224 225 void 226 tdeleteline(int n) 227 { 228 if (BETWEEN(term.c.y, term.top, term.bot)) 229 - tscrollup(term.c.y, n); 230 + tscrollup(term.c.y, n, 0); 231 } 232 233 int32_t 234 @@ -1736,11 +1791,11 @@ csihandle(void) 235 break; 236 case 'S': /* SU -- Scroll <n> line up */ 237 DEFAULT(csiescseq.arg[0], 1); 238 - tscrollup(term.top, csiescseq.arg[0]); 239 + tscrollup(term.top, csiescseq.arg[0], 0); 240 break; 241 case 'T': /* SD -- Scroll <n> line down */ 242 DEFAULT(csiescseq.arg[0], 1); 243 - tscrolldown(term.top, csiescseq.arg[0]); 244 + tscrolldown(term.top, csiescseq.arg[0], 0); 245 break; 246 case 'L': /* IL -- Insert <n> blank lines */ 247 DEFAULT(csiescseq.arg[0], 1); 248 @@ -2290,7 +2345,7 @@ eschandle(uchar ascii) 249 return 0; 250 case 'D': /* IND -- Linefeed */ 251 if (term.c.y == term.bot) { 252 - tscrollup(term.top, 1); 253 + tscrollup(term.top, 1, 1); 254 } else { 255 tmoveto(term.c.x, term.c.y+1); 256 } 257 @@ -2303,7 +2358,7 @@ eschandle(uchar ascii) 258 break; 259 case 'M': /* RI -- Reverse index */ 260 if (term.c.y == term.top) { 261 - tscrolldown(term.top, 1); 262 + tscrolldown(term.top, 1, 1); 263 } else { 264 tmoveto(term.c.x, term.c.y-1); 265 } 266 @@ -2490,7 +2545,7 @@ check_control_code: 267 void 268 tresize(int col, int row) 269 { 270 - int i; 271 + int i, j; 272 int minrow = MIN(row, term.row); 273 int mincol = MIN(col, term.col); 274 int *bp; 275 @@ -2530,6 +2585,14 @@ tresize(int col, int row) 276 term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); 277 term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); 278 279 + for (i = 0; i < HISTSIZE; i++) { 280 + term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph)); 281 + for (j = mincol; j < col; j++) { 282 + term.hist[i][j] = term.c.attr; 283 + term.hist[i][j].u = ' '; 284 + } 285 + } 286 + 287 /* resize each row to new width, zero-pad if needed */ 288 for (i = 0; i < minrow; i++) { 289 term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); 290 diff --git a/st.h b/st.h 291 index 44d4938..2d9b028 100644 292 --- a/st.h 293 +++ b/st.h 294 @@ -2,6 +2,7 @@ 295 296 /* Arbitrary sizes */ 297 #define UTF_SIZ 4 298 +#define HISTSIZE 2000 299 300 /* macros */ 301 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 302 @@ -20,6 +21,9 @@ 303 #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) 304 #define IS_TRUECOL(x) (1 << 24 & (x)) 305 306 +#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - term.scr \ 307 + + HISTSIZE + 1) % HISTSIZE] : term.line[(y) - term.scr]) 308 + 309 enum glyph_attribute { 310 ATTR_NULL = 0, 311 ATTR_BOLD = 1 << 0, 312 @@ -114,6 +118,9 @@ typedef struct { 313 int col; /* nb col */ 314 Line *line; /* screen */ 315 Line *alt; /* alternate screen */ 316 + Line hist[HISTSIZE]; /* history buffer */ 317 + int histi; /* history index */ 318 + int scr; /* scroll back */ 319 int *dirty; /* dirtyness of lines */ 320 GlyphFontSpec *specbuf; /* font spec buffer used for rendering */ 321 TCursor c; /* cursor */ 322 diff --git a/x.c b/x.c 323 index b7339e9..2ae8b17 100644 324 --- a/x.c 325 +++ b/x.c 326 @@ -1413,11 +1413,11 @@ drawregion(int x1, int y1, int x2, int y2) 327 term.dirty[y] = 0; 328 329 specs = term.specbuf; 330 - numspecs = xmakeglyphfontspecs(specs, &term.line[y][x1], x2 - x1, x1, y); 331 + numspecs = xmakeglyphfontspecs(specs, &TLINE(y)[x1], x2 - x1, x1, y); 332 333 i = ox = 0; 334 for (x = x1; x < x2 && i < numspecs; x++) { 335 - new = term.line[y][x]; 336 + new = TLINE(y)[x]; 337 if (new.mode == ATTR_WDUMMY) 338 continue; 339 if (ena_sel && selected(x, y)) 340 @@ -1437,7 +1437,9 @@ drawregion(int x1, int y1, int x2, int y2) 341 if (i > 0) 342 xdrawglyphfontspecs(specs, base, i, ox, y); 343 } 344 - xdrawcursor(); 345 + 346 + if (term.scr == 0) 347 + xdrawcursor(); 348 } 349 350 void