st-scrollback-0.7.diff (10362B)
1 diff --git a/config.def.h b/config.def.h 2 index b41747f..eae969e 100644 3 --- a/config.def.h 4 +++ b/config.def.h 5 @@ -7,6 +7,7 @@ 6 */ 7 static char font[] = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; 8 static int borderpx = 2; 9 +#define histsize 2000 10 11 /* 12 * What program is execed by st depends of these precedence rules: 13 @@ -172,6 +173,8 @@ static Shortcut shortcuts[] = { 14 { MODKEY|ShiftMask, XK_C, clipcopy, {.i = 0} }, 15 { MODKEY|ShiftMask, XK_V, clippaste, {.i = 0} }, 16 { MODKEY, XK_Num_Lock, numlock, {.i = 0} }, 17 + { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} }, 18 + { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} }, 19 }; 20 21 /* 22 diff --git a/st.c b/st.c 23 index 2594c65..233d301 100644 24 --- a/st.c 25 +++ b/st.c 26 @@ -86,6 +86,8 @@ char *argv0; 27 #define TRUERED(x) (((x) & 0xff0000) >> 8) 28 #define TRUEGREEN(x) (((x) & 0xff00)) 29 #define TRUEBLUE(x) (((x) & 0xff) << 8) 30 +#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - term.scr \ 31 + + histsize + 1) % histsize] : term.line[(y) - term.scr]) 32 33 34 enum glyph_attribute { 35 @@ -228,26 +230,6 @@ typedef struct { 36 int narg; /* nb of args */ 37 } STREscape; 38 39 -/* Internal representation of the screen */ 40 -typedef struct { 41 - int row; /* nb row */ 42 - int col; /* nb col */ 43 - Line *line; /* screen */ 44 - Line *alt; /* alternate screen */ 45 - int *dirty; /* dirtyness of lines */ 46 - XftGlyphFontSpec *specbuf; /* font spec buffer used for rendering */ 47 - TCursor c; /* cursor */ 48 - int top; /* top scroll limit */ 49 - int bot; /* bottom scroll limit */ 50 - int mode; /* terminal mode flags */ 51 - int esc; /* escape state flags */ 52 - char trantbl[4]; /* charset table translation */ 53 - int charset; /* current charset */ 54 - int icharset; /* selected charset for sequence */ 55 - int numlock; /* lock numbers in keyboard */ 56 - int *tabs; 57 -} Term; 58 - 59 /* Purely graphic info */ 60 typedef struct { 61 Display *dpy; 62 @@ -327,6 +309,8 @@ typedef struct { 63 /* function definitions used in config.h */ 64 static void clipcopy(const Arg *); 65 static void clippaste(const Arg *); 66 +static void kscrolldown(const Arg *); 67 +static void kscrollup(const Arg *); 68 static void numlock(const Arg *); 69 static void selpaste(const Arg *); 70 static void xzoom(const Arg *); 71 @@ -340,6 +324,29 @@ static void sendbreak(const Arg *); 72 /* Config.h for applying patches and the configuration. */ 73 #include "config.h" 74 75 +/* Internal representation of the screen */ 76 +typedef struct { 77 + int row; /* nb row */ 78 + int col; /* nb col */ 79 + Line *line; /* screen */ 80 + Line *alt; /* alternate screen */ 81 + Line hist[histsize]; /* history buffer */ 82 + int histi; /* history index */ 83 + int scr; /* scroll back */ 84 + int *dirty; /* dirtyness of lines */ 85 + XftGlyphFontSpec *specbuf; /* font spec buffer used for rendering */ 86 + TCursor c; /* cursor */ 87 + int top; /* top scroll limit */ 88 + int bot; /* bottom scroll limit */ 89 + int mode; /* terminal mode flags */ 90 + int esc; /* escape state flags */ 91 + char trantbl[4]; /* charset table translation */ 92 + int charset; /* current charset */ 93 + int icharset; /* selected charset for sequence */ 94 + int numlock; /* lock numbers in keyboard */ 95 + int *tabs; 96 +} Term; 97 + 98 /* Font structure */ 99 typedef struct { 100 int height; 101 @@ -399,8 +406,8 @@ static void tputtab(int); 102 static void tputc(Rune); 103 static void treset(void); 104 static void tresize(int, int); 105 -static void tscrollup(int, int); 106 -static void tscrolldown(int, int); 107 +static void tscrollup(int, int, int); 108 +static void tscrolldown(int, int, int); 109 static void tsetattr(int *, int); 110 static void tsetchar(Rune, Glyph *, int, int); 111 static void tsetscroll(int, int); 112 @@ -731,10 +738,10 @@ tlinelen(int y) 113 { 114 int i = term.col; 115 116 - if (term.line[y][i - 1].mode & ATTR_WRAP) 117 + if (TLINE(y)[i - 1].mode & ATTR_WRAP) 118 return i; 119 120 - while (i > 0 && term.line[y][i - 1].u == ' ') 121 + while (i > 0 && TLINE(y)[i - 1].u == ' ') 122 --i; 123 124 return i; 125 @@ -796,7 +803,7 @@ selsnap(int *x, int *y, int direction) 126 * Snap around if the word wraps around at the end or 127 * beginning of a line. 128 */ 129 - prevgp = &term.line[*y][*x]; 130 + prevgp = &TLINE(*y)[*x]; 131 prevdelim = ISDELIM(prevgp->u); 132 for (;;) { 133 newx = *x + direction; 134 @@ -811,14 +818,14 @@ selsnap(int *x, int *y, int direction) 135 yt = *y, xt = *x; 136 else 137 yt = newy, xt = newx; 138 - if (!(term.line[yt][xt].mode & ATTR_WRAP)) 139 + if (!(TLINE(yt)[xt].mode & ATTR_WRAP)) 140 break; 141 } 142 143 if (newx >= tlinelen(newy)) 144 break; 145 146 - gp = &term.line[newy][newx]; 147 + gp = &TLINE(newy)[newx]; 148 delim = ISDELIM(gp->u); 149 if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim 150 || (delim && gp->u != prevgp->u))) 151 @@ -839,14 +846,14 @@ selsnap(int *x, int *y, int direction) 152 *x = (direction < 0) ? 0 : term.col - 1; 153 if (direction < 0) { 154 for (; *y > 0; *y += direction) { 155 - if (!(term.line[*y-1][term.col-1].mode 156 + if (!(TLINE(*y-1)[term.col-1].mode 157 & ATTR_WRAP)) { 158 break; 159 } 160 } 161 } else if (direction > 0) { 162 for (; *y < term.row-1; *y += direction) { 163 - if (!(term.line[*y][term.col-1].mode 164 + if (!(TLINE(*y)[term.col-1].mode 165 & ATTR_WRAP)) { 166 break; 167 } 168 @@ -1012,13 +1019,13 @@ getsel(void) 169 } 170 171 if (sel.type == SEL_RECTANGULAR) { 172 - gp = &term.line[y][sel.nb.x]; 173 + gp = &TLINE(y)[sel.nb.x]; 174 lastx = sel.ne.x; 175 } else { 176 - gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; 177 + gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0]; 178 lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; 179 } 180 - last = &term.line[y][MIN(lastx, linelen-1)]; 181 + last = &TLINE(y)[MIN(lastx, linelen-1)]; 182 while (last >= gp && last->u == ' ') 183 --last; 184 185 @@ -1490,6 +1497,9 @@ ttyread(void) 186 /* keep any uncomplete utf8 char for the next call */ 187 memmove(buf, ptr, buflen); 188 189 + if (term.scr > 0 && term.scr < histsize-1) 190 + term.scr++; 191 + 192 return ret; 193 } 194 195 @@ -1499,6 +1509,9 @@ ttywrite(const char *s, size_t n) 196 fd_set wfd, rfd; 197 ssize_t r; 198 size_t lim = 256; 199 + Arg arg = (Arg){ .i = term.scr }; 200 + 201 + kscrolldown(&arg); 202 203 /* 204 * Remember that we are using a pty, which might be a modem line. 205 @@ -1690,13 +1703,53 @@ tswapscreen(void) 206 } 207 208 void 209 -tscrolldown(int orig, int n) 210 +kscrolldown(const Arg* a) 211 +{ 212 + int n = a->i; 213 + 214 + if (n < 0) 215 + n = term.row + n; 216 + 217 + if (n > term.scr) 218 + n = term.scr; 219 + 220 + if (term.scr > 0) { 221 + term.scr -= n; 222 + selscroll(0, -n); 223 + tfulldirt(); 224 + } 225 +} 226 + 227 +void 228 +kscrollup(const Arg* a) 229 +{ 230 + int n = a->i; 231 + 232 + if (n < 0) 233 + n = term.row + n; 234 + 235 + if (term.scr <= histsize - n) { 236 + term.scr += n; 237 + selscroll(0, n); 238 + tfulldirt(); 239 + } 240 +} 241 + 242 +void 243 +tscrolldown(int orig, int n, int copyhist) 244 { 245 int i; 246 Line temp; 247 248 LIMIT(n, 0, term.bot-orig+1); 249 250 + if (copyhist) { 251 + term.histi = (term.histi - 1 + histsize) % histsize; 252 + temp = term.hist[term.histi]; 253 + term.hist[term.histi] = term.line[term.bot]; 254 + term.line[term.bot] = temp; 255 + } 256 + 257 tsetdirt(orig, term.bot-n); 258 tclearregion(0, term.bot-n+1, term.col-1, term.bot); 259 260 @@ -1710,13 +1763,20 @@ tscrolldown(int orig, int n) 261 } 262 263 void 264 -tscrollup(int orig, int n) 265 +tscrollup(int orig, int n, int copyhist) 266 { 267 int i; 268 Line temp; 269 270 LIMIT(n, 0, term.bot-orig+1); 271 272 + if (copyhist) { 273 + term.histi = (term.histi + 1) % histsize; 274 + temp = term.hist[term.histi]; 275 + term.hist[term.histi] = term.line[orig]; 276 + term.line[orig] = temp; 277 + } 278 + 279 tclearregion(0, orig, term.col-1, orig+n-1); 280 tsetdirt(orig+n, term.bot); 281 282 @@ -1765,7 +1825,7 @@ tnewline(int first_col) 283 int y = term.c.y; 284 285 if (y == term.bot) { 286 - tscrollup(term.top, 1); 287 + tscrollup(term.top, 1, 1); 288 } else { 289 y++; 290 } 291 @@ -1930,14 +1990,14 @@ void 292 tinsertblankline(int n) 293 { 294 if (BETWEEN(term.c.y, term.top, term.bot)) 295 - tscrolldown(term.c.y, n); 296 + tscrolldown(term.c.y, n, 0); 297 } 298 299 void 300 tdeleteline(int n) 301 { 302 if (BETWEEN(term.c.y, term.top, term.bot)) 303 - tscrollup(term.c.y, n); 304 + tscrollup(term.c.y, n, 0); 305 } 306 307 int32_t 308 @@ -2371,11 +2431,11 @@ csihandle(void) 309 break; 310 case 'S': /* SU -- Scroll <n> line up */ 311 DEFAULT(csiescseq.arg[0], 1); 312 - tscrollup(term.top, csiescseq.arg[0]); 313 + tscrollup(term.top, csiescseq.arg[0], 0); 314 break; 315 case 'T': /* SD -- Scroll <n> line down */ 316 DEFAULT(csiescseq.arg[0], 1); 317 - tscrolldown(term.top, csiescseq.arg[0]); 318 + tscrolldown(term.top, csiescseq.arg[0], 0); 319 break; 320 case 'L': /* IL -- Insert <n> blank lines */ 321 DEFAULT(csiescseq.arg[0], 1); 322 @@ -2871,7 +2931,7 @@ eschandle(uchar ascii) 323 return 0; 324 case 'D': /* IND -- Linefeed */ 325 if (term.c.y == term.bot) { 326 - tscrollup(term.top, 1); 327 + tscrollup(term.top, 1, 1); 328 } else { 329 tmoveto(term.c.x, term.c.y+1); 330 } 331 @@ -2884,7 +2944,7 @@ eschandle(uchar ascii) 332 break; 333 case 'M': /* RI -- Reverse index */ 334 if (term.c.y == term.top) { 335 - tscrolldown(term.top, 1); 336 + tscrolldown(term.top, 1, 1); 337 } else { 338 tmoveto(term.c.x, term.c.y-1); 339 } 340 @@ -3047,7 +3107,7 @@ tputc(Rune u) 341 void 342 tresize(int col, int row) 343 { 344 - int i; 345 + int i, j; 346 int minrow = MIN(row, term.row); 347 int mincol = MIN(col, term.col); 348 int *bp; 349 @@ -3087,6 +3147,14 @@ tresize(int col, int row) 350 term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); 351 term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); 352 353 + for (i = 0; i < histsize; i++) { 354 + term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph)); 355 + for (j = mincol; j < col; j++) { 356 + term.hist[i][j] = term.c.attr; 357 + term.hist[i][j].u = ' '; 358 + } 359 + } 360 + 361 /* resize each row to new width, zero-pad if needed */ 362 for (i = 0; i < minrow; i++) { 363 term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); 364 @@ -3976,11 +4044,11 @@ drawregion(int x1, int y1, int x2, int y2) 365 term.dirty[y] = 0; 366 367 specs = term.specbuf; 368 - numspecs = xmakeglyphfontspecs(specs, &term.line[y][x1], x2 - x1, x1, y); 369 + numspecs = xmakeglyphfontspecs(specs, &TLINE(y)[x1], x2 - x1, x1, y); 370 371 i = ox = 0; 372 for (x = x1; x < x2 && i < numspecs; x++) { 373 - new = term.line[y][x]; 374 + new = TLINE(y)[x]; 375 if (new.mode == ATTR_WDUMMY) 376 continue; 377 if (ena_sel && selected(x, y)) 378 @@ -4000,7 +4068,8 @@ drawregion(int x1, int y1, int x2, int y2) 379 if (i > 0) 380 xdrawglyphfontspecs(specs, base, i, ox, y); 381 } 382 - xdrawcursor(); 383 + if (term.scr == 0) 384 + xdrawcursor(); 385 } 386 387 void