st-scrollback-ringbuffer.diff (18818B)
1 diff --git a/config.def.h b/config.def.h 2 index 2cd740a..8b25d40 100644 3 --- a/config.def.h 4 +++ b/config.def.h 5 @@ -201,6 +201,8 @@ static Shortcut shortcuts[] = { 6 { TERMMOD, XK_Y, selpaste, {.i = 0} }, 7 { ShiftMask, XK_Insert, selpaste, {.i = 0} }, 8 { TERMMOD, XK_Num_Lock, numlock, {.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 57c6e96..a3b3c9d 100644 16 --- a/st.c 17 +++ b/st.c 18 @@ -43,6 +43,10 @@ 19 #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) 20 #define ISDELIM(u) (u && wcschr(worddelimiters, u)) 21 22 +#define TSCREEN term.screen[IS_SET(MODE_ALTSCREEN)] 23 +#define TLINEOFFSET(y) (((y) + TSCREEN.cur - TSCREEN.off + TSCREEN.size) % TSCREEN.size) 24 +#define TLINE(y) (TSCREEN.buffer[TLINEOFFSET(y)]) 25 + 26 enum term_mode { 27 MODE_WRAP = 1 << 0, 28 MODE_INSERT = 1 << 1, 29 @@ -109,12 +113,21 @@ typedef struct { 30 int alt; 31 } Selection; 32 33 +/* Screen lines */ 34 +typedef struct { 35 + Line* buffer; /* ring buffer */ 36 + int size; /* size of buffer */ 37 + int cur; /* start of active screen */ 38 + int off; /* scrollback line offset */ 39 + TCursor sc; /* saved cursor */ 40 +} LineBuffer; 41 + 42 /* Internal representation of the screen */ 43 typedef struct { 44 int row; /* nb row */ 45 int col; /* nb col */ 46 - Line *line; /* screen */ 47 - Line *alt; /* alternate screen */ 48 + LineBuffer screen[2]; /* screen and alternate screen */ 49 + int linelen; /* allocated line length */ 50 int *dirty; /* dirtyness of lines */ 51 TCursor c; /* cursor */ 52 int ocx; /* old cursor col */ 53 @@ -203,6 +216,8 @@ static void tdeftran(char); 54 static void tstrsequence(uchar); 55 56 static void drawregion(int, int, int, int); 57 +static void clearline(Line, Glyph, int, int); 58 +static Line ensureline(Line); 59 60 static void selnormalize(void); 61 static void selscroll(int, int); 62 @@ -408,11 +423,12 @@ int 63 tlinelen(int y) 64 { 65 int i = term.col; 66 + Line line = TLINE(y); 67 68 - if (term.line[y][i - 1].mode & ATTR_WRAP) 69 + if (line[i - 1].mode & ATTR_WRAP) 70 return i; 71 72 - while (i > 0 && term.line[y][i - 1].u == ' ') 73 + while (i > 0 && line[i - 1].u == ' ') 74 --i; 75 76 return i; 77 @@ -521,7 +537,7 @@ selsnap(int *x, int *y, int direction) 78 * Snap around if the word wraps around at the end or 79 * beginning of a line. 80 */ 81 - prevgp = &term.line[*y][*x]; 82 + prevgp = &TLINE(*y)[*x]; 83 prevdelim = ISDELIM(prevgp->u); 84 for (;;) { 85 newx = *x + direction; 86 @@ -536,14 +552,14 @@ selsnap(int *x, int *y, int direction) 87 yt = *y, xt = *x; 88 else 89 yt = newy, xt = newx; 90 - if (!(term.line[yt][xt].mode & ATTR_WRAP)) 91 + if (!(TLINE(yt)[xt].mode & ATTR_WRAP)) 92 break; 93 } 94 95 if (newx >= tlinelen(newy)) 96 break; 97 98 - gp = &term.line[newy][newx]; 99 + gp = &TLINE(newy)[newx]; 100 delim = ISDELIM(gp->u); 101 if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim 102 || (delim && gp->u != prevgp->u))) 103 @@ -564,14 +580,14 @@ selsnap(int *x, int *y, int direction) 104 *x = (direction < 0) ? 0 : term.col - 1; 105 if (direction < 0) { 106 for (; *y > 0; *y += direction) { 107 - if (!(term.line[*y-1][term.col-1].mode 108 + if (!(TLINE(*y-1)[term.col-1].mode 109 & ATTR_WRAP)) { 110 break; 111 } 112 } 113 } else if (direction > 0) { 114 for (; *y < term.row-1; *y += direction) { 115 - if (!(term.line[*y][term.col-1].mode 116 + if (!(TLINE(*y)[term.col-1].mode 117 & ATTR_WRAP)) { 118 break; 119 } 120 @@ -602,13 +618,13 @@ getsel(void) 121 } 122 123 if (sel.type == SEL_RECTANGULAR) { 124 - gp = &term.line[y][sel.nb.x]; 125 + gp = &TLINE(y)[sel.nb.x]; 126 lastx = sel.ne.x; 127 } else { 128 - gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; 129 + gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0]; 130 lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; 131 } 132 - last = &term.line[y][MIN(lastx, linelen-1)]; 133 + last = &TLINE(y)[MIN(lastx, linelen-1)]; 134 while (last >= gp && last->u == ' ') 135 --last; 136 137 @@ -949,12 +965,15 @@ int 138 tattrset(int attr) 139 { 140 int i, j; 141 + int y = TLINEOFFSET(0); 142 143 for (i = 0; i < term.row-1; i++) { 144 + Line line = TSCREEN.buffer[y]; 145 for (j = 0; j < term.col-1; j++) { 146 - if (term.line[i][j].mode & attr) 147 + if (line[j].mode & attr) 148 return 1; 149 } 150 + y = (y+1) % TSCREEN.size; 151 } 152 153 return 0; 154 @@ -976,14 +995,17 @@ void 155 tsetdirtattr(int attr) 156 { 157 int i, j; 158 + int y = TLINEOFFSET(0); 159 160 for (i = 0; i < term.row-1; i++) { 161 + Line line = TSCREEN.buffer[y]; 162 for (j = 0; j < term.col-1; j++) { 163 - if (term.line[i][j].mode & attr) { 164 + if (line[j].mode & attr) { 165 tsetdirt(i, i); 166 break; 167 } 168 } 169 + y = (y+1) % TSCREEN.size; 170 } 171 } 172 173 @@ -996,27 +1018,19 @@ tfulldirt(void) 174 void 175 tcursor(int mode) 176 { 177 - static TCursor c[2]; 178 - int alt = IS_SET(MODE_ALTSCREEN); 179 - 180 if (mode == CURSOR_SAVE) { 181 - c[alt] = term.c; 182 + TSCREEN.sc = term.c; 183 } else if (mode == CURSOR_LOAD) { 184 - term.c = c[alt]; 185 - tmoveto(c[alt].x, c[alt].y); 186 + term.c = TSCREEN.sc; 187 + tmoveto(term.c.x, term.c.y); 188 } 189 } 190 191 void 192 treset(void) 193 { 194 - uint i; 195 - 196 - term.c = (TCursor){{ 197 - .mode = ATTR_NULL, 198 - .fg = defaultfg, 199 - .bg = defaultbg 200 - }, .x = 0, .y = 0, .state = CURSOR_DEFAULT}; 201 + int i, j; 202 + Glyph g = (Glyph){ .fg = defaultfg, .bg = defaultbg}; 203 204 memset(term.tabs, 0, term.col * sizeof(*term.tabs)); 205 for (i = tabspaces; i < term.col; i += tabspaces) 206 @@ -1028,17 +1042,37 @@ treset(void) 207 term.charset = 0; 208 209 for (i = 0; i < 2; i++) { 210 - tmoveto(0, 0); 211 - tcursor(CURSOR_SAVE); 212 - tclearregion(0, 0, term.col-1, term.row-1); 213 - tswapscreen(); 214 + term.screen[i].sc = (TCursor){{ 215 + .fg = defaultfg, 216 + .bg = defaultbg 217 + }}; 218 + term.screen[i].cur = 0; 219 + term.screen[i].off = 0; 220 + for (j = 0; j < term.row; ++j) { 221 + if (term.col != term.linelen) 222 + term.screen[i].buffer[j] = xrealloc(term.screen[i].buffer[j], term.col * sizeof(Glyph)); 223 + clearline(term.screen[i].buffer[j], g, 0, term.col); 224 + } 225 + for (j = term.row; j < term.screen[i].size; ++j) { 226 + free(term.screen[i].buffer[j]); 227 + term.screen[i].buffer[j] = NULL; 228 + } 229 } 230 + tcursor(CURSOR_LOAD); 231 + term.linelen = term.col; 232 + tfulldirt(); 233 } 234 235 void 236 tnew(int col, int row) 237 { 238 - term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } }; 239 + int i; 240 + term = (Term){}; 241 + term.screen[0].buffer = xmalloc(HISTSIZE * sizeof(Line)); 242 + term.screen[0].size = HISTSIZE; 243 + term.screen[1].buffer = NULL; 244 + for (i = 0; i < HISTSIZE; ++i) term.screen[0].buffer[i] = NULL; 245 + 246 tresize(col, row); 247 treset(); 248 } 249 @@ -1046,14 +1080,42 @@ tnew(int col, int row) 250 void 251 tswapscreen(void) 252 { 253 - Line *tmp = term.line; 254 - 255 - term.line = term.alt; 256 - term.alt = tmp; 257 term.mode ^= MODE_ALTSCREEN; 258 tfulldirt(); 259 } 260 261 +void 262 +kscrollup(const Arg *a) 263 +{ 264 + int n = a->i; 265 + 266 + if (IS_SET(MODE_ALTSCREEN)) 267 + return; 268 + 269 + if (n < 0) n = (-n) * term.row; 270 + if (n > TSCREEN.size - term.row - TSCREEN.off) n = TSCREEN.size - term.row - TSCREEN.off; 271 + while (!TLINE(-n)) --n; 272 + TSCREEN.off += n; 273 + selscroll(0, n); 274 + tfulldirt(); 275 +} 276 + 277 +void 278 +kscrolldown(const Arg *a) 279 +{ 280 + 281 + int n = a->i; 282 + 283 + if (IS_SET(MODE_ALTSCREEN)) 284 + return; 285 + 286 + if (n < 0) n = (-n) * term.row; 287 + if (n > TSCREEN.off) n = TSCREEN.off; 288 + TSCREEN.off -= n; 289 + selscroll(0, -n); 290 + tfulldirt(); 291 +} 292 + 293 void 294 tscrolldown(int orig, int n) 295 { 296 @@ -1062,15 +1124,29 @@ tscrolldown(int orig, int n) 297 298 LIMIT(n, 0, term.bot-orig+1); 299 300 - tsetdirt(orig, term.bot-n); 301 - tclearregion(0, term.bot-n+1, term.col-1, term.bot); 302 + /* Ensure that lines are allocated */ 303 + for (i = -n; i < 0; i++) { 304 + TLINE(i) = ensureline(TLINE(i)); 305 + } 306 307 - for (i = term.bot; i >= orig+n; i--) { 308 - temp = term.line[i]; 309 - term.line[i] = term.line[i-n]; 310 - term.line[i-n] = temp; 311 + /* Shift non-scrolling areas in ring buffer */ 312 + for (i = term.bot+1; i < term.row; i++) { 313 + temp = TLINE(i); 314 + TLINE(i) = TLINE(i-n); 315 + TLINE(i-n) = temp; 316 + } 317 + for (i = 0; i < orig; i++) { 318 + temp = TLINE(i); 319 + TLINE(i) = TLINE(i-n); 320 + TLINE(i-n) = temp; 321 } 322 323 + /* Scroll buffer */ 324 + TSCREEN.cur = (TSCREEN.cur + TSCREEN.size - n) % TSCREEN.size; 325 + /* Clear lines that have entered the view */ 326 + tclearregion(0, orig, term.linelen-1, orig+n-1); 327 + /* Redraw portion of the screen that has scrolled */ 328 + tsetdirt(orig+n-1, term.bot); 329 selscroll(orig, n); 330 } 331 332 @@ -1082,15 +1158,29 @@ tscrollup(int orig, int n) 333 334 LIMIT(n, 0, term.bot-orig+1); 335 336 - tclearregion(0, orig, term.col-1, orig+n-1); 337 - tsetdirt(orig+n, term.bot); 338 + /* Ensure that lines are allocated */ 339 + for (i = term.row; i < term.row + n; i++) { 340 + TLINE(i) = ensureline(TLINE(i)); 341 + } 342 343 - for (i = orig; i <= term.bot-n; i++) { 344 - temp = term.line[i]; 345 - term.line[i] = term.line[i+n]; 346 - term.line[i+n] = temp; 347 + /* Shift non-scrolling areas in ring buffer */ 348 + for (i = orig-1; i >= 0; i--) { 349 + temp = TLINE(i); 350 + TLINE(i) = TLINE(i+n); 351 + TLINE(i+n) = temp; 352 + } 353 + for (i = term.row-1; i >term.bot; i--) { 354 + temp = TLINE(i); 355 + TLINE(i) = TLINE(i+n); 356 + TLINE(i+n) = temp; 357 } 358 359 + /* Scroll buffer */ 360 + TSCREEN.cur = (TSCREEN.cur + n) % TSCREEN.size; 361 + /* Clear lines that have entered the view */ 362 + tclearregion(0, term.bot-n+1, term.linelen-1, term.bot); 363 + /* Redraw portion of the screen that has scrolled */ 364 + tsetdirt(orig, term.bot-n+1); 365 selscroll(orig, -n); 366 } 367 368 @@ -1197,6 +1287,7 @@ tsetchar(Rune u, const Glyph *attr, int x, int y) 369 "⎻", "─", "⎼", "⎽", "├", "┤", "┴", "┬", /* p - w */ 370 "│", "≤", "≥", "π", "≠", "£", "·", /* x - ~ */ 371 }; 372 + Line line = TLINE(y); 373 374 /* 375 * The table is proudly stolen from rxvt. 376 @@ -1205,25 +1296,25 @@ tsetchar(Rune u, const Glyph *attr, int x, int y) 377 BETWEEN(u, 0x41, 0x7e) && vt100_0[u - 0x41]) 378 utf8decode(vt100_0[u - 0x41], &u, UTF_SIZ); 379 380 - if (term.line[y][x].mode & ATTR_WIDE) { 381 + if (line[x].mode & ATTR_WIDE) { 382 if (x+1 < term.col) { 383 - term.line[y][x+1].u = ' '; 384 - term.line[y][x+1].mode &= ~ATTR_WDUMMY; 385 + line[x+1].u = ' '; 386 + line[x+1].mode &= ~ATTR_WDUMMY; 387 } 388 - } else if (term.line[y][x].mode & ATTR_WDUMMY) { 389 - term.line[y][x-1].u = ' '; 390 - term.line[y][x-1].mode &= ~ATTR_WIDE; 391 + } else if (line[x].mode & ATTR_WDUMMY) { 392 + line[x-1].u = ' '; 393 + line[x-1].mode &= ~ATTR_WIDE; 394 } 395 396 term.dirty[y] = 1; 397 - term.line[y][x] = *attr; 398 - term.line[y][x].u = u; 399 + line[x] = *attr; 400 + line[x].u = u; 401 } 402 403 void 404 tclearregion(int x1, int y1, int x2, int y2) 405 { 406 - int x, y, temp; 407 + int x, y, L, S, temp; 408 Glyph *gp; 409 410 if (x1 > x2) 411 @@ -1231,15 +1322,16 @@ tclearregion(int x1, int y1, int x2, int y2) 412 if (y1 > y2) 413 temp = y1, y1 = y2, y2 = temp; 414 415 - LIMIT(x1, 0, term.col-1); 416 - LIMIT(x2, 0, term.col-1); 417 + LIMIT(x1, 0, term.linelen-1); 418 + LIMIT(x2, 0, term.linelen-1); 419 LIMIT(y1, 0, term.row-1); 420 LIMIT(y2, 0, term.row-1); 421 422 + L = TLINEOFFSET(y1); 423 for (y = y1; y <= y2; y++) { 424 term.dirty[y] = 1; 425 for (x = x1; x <= x2; x++) { 426 - gp = &term.line[y][x]; 427 + gp = &TSCREEN.buffer[L][x]; 428 if (selected(x, y)) 429 selclear(); 430 gp->fg = term.c.attr.fg; 431 @@ -1247,6 +1339,7 @@ tclearregion(int x1, int y1, int x2, int y2) 432 gp->mode = 0; 433 gp->u = ' '; 434 } 435 + L = (L + 1) % TSCREEN.size; 436 } 437 } 438 439 @@ -1261,7 +1354,7 @@ tdeletechar(int n) 440 dst = term.c.x; 441 src = term.c.x + n; 442 size = term.col - src; 443 - line = term.line[term.c.y]; 444 + line = TLINE(term.c.y); 445 446 memmove(&line[dst], &line[src], size * sizeof(Glyph)); 447 tclearregion(term.col-n, term.c.y, term.col-1, term.c.y); 448 @@ -1278,7 +1371,7 @@ tinsertblank(int n) 449 dst = term.c.x + n; 450 src = term.c.x; 451 size = term.col - dst; 452 - line = term.line[term.c.y]; 453 + line = TLINE(term.c.y); 454 455 memmove(&line[dst], &line[src], size * sizeof(Glyph)); 456 tclearregion(src, term.c.y, dst - 1, term.c.y); 457 @@ -2082,7 +2175,7 @@ tdumpline(int n) 458 char buf[UTF_SIZ]; 459 const Glyph *bp, *end; 460 461 - bp = &term.line[n][0]; 462 + bp = &TLINE(n)[0]; 463 end = &bp[MIN(tlinelen(n), term.col) - 1]; 464 if (bp != end || bp->u != ' ') { 465 for ( ; bp <= end; ++bp) 466 @@ -2469,11 +2562,11 @@ check_control_code: 467 if (selected(term.c.x, term.c.y)) 468 selclear(); 469 470 - gp = &term.line[term.c.y][term.c.x]; 471 + gp = &TLINE(term.c.y)[term.c.x]; 472 if (IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) { 473 gp->mode |= ATTR_WRAP; 474 tnewline(1); 475 - gp = &term.line[term.c.y][term.c.x]; 476 + gp = &TLINE(term.c.y)[term.c.x]; 477 } 478 479 if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) { 480 @@ -2486,7 +2579,7 @@ check_control_code: 481 tnewline(1); 482 else 483 tmoveto(term.col - width, term.c.y); 484 - gp = &term.line[term.c.y][term.c.x]; 485 + gp = &TLINE(term.c.y)[term.c.x]; 486 } 487 488 tsetchar(u, &term.c.attr, term.c.x, term.c.y); 489 @@ -2517,6 +2610,11 @@ twrite(const char *buf, int buflen, int show_ctrl) 490 Rune u; 491 int n; 492 493 + if (TSCREEN.off) { 494 + TSCREEN.off = 0; 495 + tfulldirt(); 496 + } 497 + 498 for (n = 0; n < buflen; n += charsize) { 499 if (IS_SET(MODE_UTF8)) { 500 /* process a complete utf8 char */ 501 @@ -2543,56 +2641,85 @@ twrite(const char *buf, int buflen, int show_ctrl) 502 } 503 504 void 505 -tresize(int col, int row) 506 +clearline(Line line, Glyph g, int x, int xend) 507 { 508 int i; 509 + g.mode = 0; 510 + g.u = ' '; 511 + for (i = x; i < xend; ++i) { 512 + line[i] = g; 513 + } 514 +} 515 + 516 +Line 517 +ensureline(Line line) 518 +{ 519 + if (!line) { 520 + line = xmalloc(term.linelen * sizeof(Glyph)); 521 + } 522 + return line; 523 +} 524 + 525 +void 526 +tresize(int col, int row) 527 +{ 528 + int i, j; 529 int minrow = MIN(row, term.row); 530 int mincol = MIN(col, term.col); 531 + int linelen = MAX(col, term.linelen); 532 int *bp; 533 - TCursor c; 534 535 - if (col < 1 || row < 1) { 536 + if (col < 1 || row < 1 || row > HISTSIZE) { 537 fprintf(stderr, 538 "tresize: error resizing to %dx%d\n", col, row); 539 return; 540 } 541 542 - /* 543 - * slide screen to keep cursor where we expect it - 544 - * tscrollup would work here, but we can optimize to 545 - * memmove because we're freeing the earlier lines 546 - */ 547 - for (i = 0; i <= term.c.y - row; i++) { 548 - free(term.line[i]); 549 - free(term.alt[i]); 550 + /* Shift buffer to keep the cursor where we expect it */ 551 + if (row <= term.c.y) { 552 + term.screen[0].cur = (term.screen[0].cur - row + term.c.y + 1) % term.screen[0].size; 553 + } 554 + 555 + /* Resize and clear line buffers as needed */ 556 + if (linelen > term.linelen) { 557 + for (i = 0; i < term.screen[0].size; ++i) { 558 + if (term.screen[0].buffer[i]) { 559 + term.screen[0].buffer[i] = xrealloc(term.screen[0].buffer[i], linelen * sizeof(Glyph)); 560 + clearline(term.screen[0].buffer[i], term.c.attr, term.linelen, linelen); 561 + } 562 + } 563 + for (i = 0; i < minrow; ++i) { 564 + term.screen[1].buffer[i] = xrealloc(term.screen[1].buffer[i], linelen * sizeof(Glyph)); 565 + clearline(term.screen[1].buffer[i], term.c.attr, term.linelen, linelen); 566 + } 567 } 568 - /* ensure that both src and dst are not NULL */ 569 - if (i > 0) { 570 - memmove(term.line, term.line + i, row * sizeof(Line)); 571 - memmove(term.alt, term.alt + i, row * sizeof(Line)); 572 + /* Allocate all visible lines for regular line buffer */ 573 + for (j = term.screen[0].cur, i = 0; i < row; ++i, j = (j + 1) % term.screen[0].size) 574 + { 575 + if (!term.screen[0].buffer[j]) { 576 + term.screen[0].buffer[j] = xmalloc(linelen * sizeof(Glyph)); 577 + } 578 + if (i >= term.row) { 579 + clearline(term.screen[0].buffer[j], term.c.attr, 0, linelen); 580 + } 581 } 582 - for (i += row; i < term.row; i++) { 583 - free(term.line[i]); 584 - free(term.alt[i]); 585 + /* Resize alt screen */ 586 + term.screen[1].cur = 0; 587 + term.screen[1].size = row; 588 + for (i = row; i < term.row; ++i) { 589 + free(term.screen[1].buffer[i]); 590 + } 591 + term.screen[1].buffer = xrealloc(term.screen[1].buffer, row * sizeof(Line)); 592 + for (i = term.row; i < row; ++i) { 593 + term.screen[1].buffer[i] = xmalloc(linelen * sizeof(Glyph)); 594 + clearline(term.screen[1].buffer[i], term.c.attr, 0, linelen); 595 } 596 597 /* resize to new height */ 598 - term.line = xrealloc(term.line, row * sizeof(Line)); 599 - term.alt = xrealloc(term.alt, row * sizeof(Line)); 600 term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); 601 term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); 602 603 - /* resize each row to new width, zero-pad if needed */ 604 - for (i = 0; i < minrow; i++) { 605 - term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); 606 - term.alt[i] = xrealloc(term.alt[i], col * sizeof(Glyph)); 607 - } 608 - 609 - /* allocate any new rows */ 610 - for (/* i = minrow */; i < row; i++) { 611 - term.line[i] = xmalloc(col * sizeof(Glyph)); 612 - term.alt[i] = xmalloc(col * sizeof(Glyph)); 613 - } 614 + /* fix tabstops */ 615 if (col > term.col) { 616 bp = term.tabs + term.col; 617 618 @@ -2602,26 +2729,16 @@ tresize(int col, int row) 619 for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces) 620 *bp = 1; 621 } 622 + 623 /* update terminal size */ 624 term.col = col; 625 term.row = row; 626 + term.linelen = linelen; 627 /* reset scrolling region */ 628 tsetscroll(0, row-1); 629 /* make use of the LIMIT in tmoveto */ 630 tmoveto(term.c.x, term.c.y); 631 - /* Clearing both screens (it makes dirty all lines) */ 632 - c = term.c; 633 - for (i = 0; i < 2; i++) { 634 - if (mincol < col && 0 < minrow) { 635 - tclearregion(mincol, 0, col - 1, minrow - 1); 636 - } 637 - if (0 < col && minrow < row) { 638 - tclearregion(0, minrow, col - 1, row - 1); 639 - } 640 - tswapscreen(); 641 - tcursor(CURSOR_LOAD); 642 - } 643 - term.c = c; 644 + tfulldirt(); 645 } 646 647 void 648 @@ -2633,14 +2750,15 @@ resettitle(void) 649 void 650 drawregion(int x1, int y1, int x2, int y2) 651 { 652 - int y; 653 + int y, L; 654 655 + L = TLINEOFFSET(y1); 656 for (y = y1; y < y2; y++) { 657 - if (!term.dirty[y]) 658 - continue; 659 - 660 - term.dirty[y] = 0; 661 - xdrawline(term.line[y], x1, y, x2); 662 + if (term.dirty[y]) { 663 + term.dirty[y] = 0; 664 + xdrawline(TSCREEN.buffer[L], x1, y, x2); 665 + } 666 + L = (L + 1) % TSCREEN.size; 667 } 668 } 669 670 @@ -2655,14 +2773,15 @@ draw(void) 671 /* adjust cursor position */ 672 LIMIT(term.ocx, 0, term.col-1); 673 LIMIT(term.ocy, 0, term.row-1); 674 - if (term.line[term.ocy][term.ocx].mode & ATTR_WDUMMY) 675 + if (TLINE(term.ocy)[term.ocx].mode & ATTR_WDUMMY) 676 term.ocx--; 677 - if (term.line[term.c.y][cx].mode & ATTR_WDUMMY) 678 + if (TLINE(term.c.y)[cx].mode & ATTR_WDUMMY) 679 cx--; 680 681 drawregion(0, 0, term.col, term.row); 682 - xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], 683 - term.ocx, term.ocy, term.line[term.ocy][term.ocx]); 684 + if (TSCREEN.off == 0) 685 + xdrawcursor(cx, term.c.y, TLINE(term.c.y)[cx], 686 + term.ocx, term.ocy, TLINE(term.ocy)[term.ocx]); 687 term.ocx = cx; 688 term.ocy = term.c.y; 689 xfinishdraw(); 690 diff --git a/st.h b/st.h 691 index fd3b0d8..3cea73b 100644 692 --- a/st.h 693 +++ b/st.h 694 @@ -19,6 +19,7 @@ 695 696 #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) 697 #define IS_TRUECOL(x) (1 << 24 & (x)) 698 +#define HISTSIZE 2000 699 700 enum glyph_attribute { 701 ATTR_NULL = 0, 702 diff --git a/x.c b/x.c 703 index bd23686..25785a6 100644 704 --- a/x.c 705 +++ b/x.c 706 @@ -59,6 +59,8 @@ static void zoom(const Arg *); 707 static void zoomabs(const Arg *); 708 static void zoomreset(const Arg *); 709 static void ttysend(const Arg *); 710 +void kscrollup(const Arg *); 711 +void kscrolldown(const Arg *); 712 713 /* config.h for applying patches and the configuration. */ 714 #include "config.h"