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