aboutsummaryrefslogtreecommitdiff
path: root/st.c
diff options
context:
space:
mode:
authorFederico Igne <git@federicoigne.com>2020-05-23 10:45:45 +0100
committerFederico Igne <git@federicoigne.com>2020-05-23 10:45:45 +0100
commit682f9c27ab916894aa788a14b3520546c1da7ba6 (patch)
treec815445e0bbec960fba5e9b158af16574b04006b /st.c
parent5bf570ff51b54228e8be399387f6a4928f3edbbd (diff)
downloadst-682f9c27ab916894aa788a14b3520546c1da7ba6.tar.gz
st-682f9c27ab916894aa788a14b3520546c1da7ba6.zip
Apply Scrollback patch
Homepage link: https://st.suckless.org/patches/scrollback/ Patch link: https://st.suckless.org/patches/scrollback/st-scrollback-20200419-72e3f6c.diff https://st.suckless.org/patches/scrollback/st-scrollback-mouse-20191024-a2c479c.diff https://st.suckless.org/patches/scrollback/st-scrollback-mouse-altscreen-20200416-5703aa0.diff https://st.suckless.org/patches/scrollback/st-scrollback-mouse-increment-0.8.2.diff Additional info: + patch applied because I'm planning on ditching tmux, which currently provides this functionality; + patches applied manually.
Diffstat (limited to 'st.c')
-rw-r--r--st.c133
1 files changed, 105 insertions, 28 deletions
diff --git a/st.c b/st.c
index 3e48410..83681c1 100644
--- a/st.c
+++ b/st.c
@@ -35,13 +35,17 @@
35#define ESC_ARG_SIZ 16 35#define ESC_ARG_SIZ 16
36#define STR_BUF_SIZ ESC_BUF_SIZ 36#define STR_BUF_SIZ ESC_BUF_SIZ
37#define STR_ARG_SIZ ESC_ARG_SIZ 37#define STR_ARG_SIZ ESC_ARG_SIZ
38#define HISTSIZE 5000
38 39
39/* macros */ 40/* macros */
40#define IS_SET(flag) ((term.mode & (flag)) != 0) 41#define IS_SET(flag) ((term.mode & (flag)) != 0)
41#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177') 42#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177')
42#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) 43#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
43#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) 44#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
44#define ISDELIM(u) (u && wcschr(worddelimiters, u)) 45#define ISDELIM(u) (u && wcschr(worddelimiters, u))
46#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \
47 term.scr + HISTSIZE + 1) % HISTSIZE] : \
48 term.line[(y) - term.scr])
45 49
46enum term_mode { 50enum term_mode {
47 MODE_WRAP = 1 << 0, 51 MODE_WRAP = 1 << 0,
@@ -117,6 +121,9 @@ typedef struct {
117 int col; /* nb col */ 121 int col; /* nb col */
118 Line *line; /* screen */ 122 Line *line; /* screen */
119 Line *alt; /* alternate screen */ 123 Line *alt; /* alternate screen */
124 Line hist[HISTSIZE]; /* history buffer */
125 int histi; /* history index */
126 int scr; /* scroll back */
120 int *dirty; /* dirtyness of lines */ 127 int *dirty; /* dirtyness of lines */
121 TCursor c; /* cursor */ 128 TCursor c; /* cursor */
122 int ocx; /* old cursor col */ 129 int ocx; /* old cursor col */
@@ -185,8 +192,8 @@ static void tnewline(int);
185static void tputtab(int); 192static void tputtab(int);
186static void tputc(Rune); 193static void tputc(Rune);
187static void treset(void); 194static void treset(void);
188static void tscrollup(int, int); 195static void tscrollup(int, int, int);
189static void tscrolldown(int, int); 196static void tscrolldown(int, int, int);
190static void tsetattr(int *, int); 197static void tsetattr(int *, int);
191static void tsetchar(Rune, Glyph *, int, int); 198static void tsetchar(Rune, Glyph *, int, int);
192static void tsetdirt(int, int); 199static void tsetdirt(int, int);
@@ -414,10 +421,10 @@ tlinelen(int y)
414{ 421{
415 int i = term.col; 422 int i = term.col;
416 423
417 if (term.line[y][i - 1].mode & ATTR_WRAP) 424 if (TLINE(y)[i - 1].mode & ATTR_WRAP)
418 return i; 425 return i;
419 426
420 while (i > 0 && term.line[y][i - 1].u == ' ') 427 while (i > 0 && TLINE(y)[i - 1].u == ' ')
421 --i; 428 --i;
422 429
423 return i; 430 return i;
@@ -526,7 +533,7 @@ selsnap(int *x, int *y, int direction)
526 * Snap around if the word wraps around at the end or 533 * Snap around if the word wraps around at the end or
527 * beginning of a line. 534 * beginning of a line.
528 */ 535 */
529 prevgp = &term.line[*y][*x]; 536 prevgp = &TLINE(*y)[*x];
530 prevdelim = ISDELIM(prevgp->u); 537 prevdelim = ISDELIM(prevgp->u);
531 for (;;) { 538 for (;;) {
532 newx = *x + direction; 539 newx = *x + direction;
@@ -541,14 +548,14 @@ selsnap(int *x, int *y, int direction)
541 yt = *y, xt = *x; 548 yt = *y, xt = *x;
542 else 549 else
543 yt = newy, xt = newx; 550 yt = newy, xt = newx;
544 if (!(term.line[yt][xt].mode & ATTR_WRAP)) 551 if (!(TLINE(yt)[xt].mode & ATTR_WRAP))
545 break; 552 break;
546 } 553 }
547 554
548 if (newx >= tlinelen(newy)) 555 if (newx >= tlinelen(newy))
549 break; 556 break;
550 557
551 gp = &term.line[newy][newx]; 558 gp = &TLINE(newy)[newx];
552 delim = ISDELIM(gp->u); 559 delim = ISDELIM(gp->u);
553 if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim 560 if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
554 || (delim && gp->u != prevgp->u))) 561 || (delim && gp->u != prevgp->u)))
@@ -569,14 +576,14 @@ selsnap(int *x, int *y, int direction)
569 *x = (direction < 0) ? 0 : term.col - 1; 576 *x = (direction < 0) ? 0 : term.col - 1;
570 if (direction < 0) { 577 if (direction < 0) {
571 for (; *y > 0; *y += direction) { 578 for (; *y > 0; *y += direction) {
572 if (!(term.line[*y-1][term.col-1].mode 579 if (!(TLINE(*y-1)[term.col-1].mode
573 & ATTR_WRAP)) { 580 & ATTR_WRAP)) {
574 break; 581 break;
575 } 582 }
576 } 583 }
577 } else if (direction > 0) { 584 } else if (direction > 0) {
578 for (; *y < term.row-1; *y += direction) { 585 for (; *y < term.row-1; *y += direction) {
579 if (!(term.line[*y][term.col-1].mode 586 if (!(TLINE(*y)[term.col-1].mode
580 & ATTR_WRAP)) { 587 & ATTR_WRAP)) {
581 break; 588 break;
582 } 589 }
@@ -607,13 +614,13 @@ getsel(void)
607 } 614 }
608 615
609 if (sel.type == SEL_RECTANGULAR) { 616 if (sel.type == SEL_RECTANGULAR) {
610 gp = &term.line[y][sel.nb.x]; 617 gp = &TLINE(y)[sel.nb.x];
611 lastx = sel.ne.x; 618 lastx = sel.ne.x;
612 } else { 619 } else {
613 gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; 620 gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0];
614 lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; 621 lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
615 } 622 }
616 last = &term.line[y][MIN(lastx, linelen-1)]; 623 last = &TLINE(y)[MIN(lastx, linelen-1)];
617 while (last >= gp && last->u == ' ') 624 while (last >= gp && last->u == ' ')
618 --last; 625 --last;
619 626
@@ -836,6 +843,9 @@ void
836ttywrite(const char *s, size_t n, int may_echo) 843ttywrite(const char *s, size_t n, int may_echo)
837{ 844{
838 const char *next; 845 const char *next;
846 Arg arg = (Arg) { .i = term.scr };
847
848 kscrolldown(&arg);
839 849
840 if (may_echo && IS_SET(MODE_ECHO)) 850 if (may_echo && IS_SET(MODE_ECHO))
841 twrite(s, n, 1); 851 twrite(s, n, 1);
@@ -1035,6 +1045,12 @@ tnew(int col, int row)
1035 treset(); 1045 treset();
1036} 1046}
1037 1047
1048int
1049tisaltscr(void)
1050{
1051 return IS_SET(MODE_ALTSCREEN);
1052}
1053
1038void 1054void
1039tswapscreen(void) 1055tswapscreen(void)
1040{ 1056{
@@ -1047,13 +1063,53 @@ tswapscreen(void)
1047} 1063}
1048 1064
1049void 1065void
1050tscrolldown(int orig, int n) 1066kscrolldown(const Arg* a)
1067{
1068 int n = a->i;
1069
1070 if (n < 0)
1071 n = term.row + n;
1072
1073 if (n > term.scr)
1074 n = term.scr;
1075
1076 if (term.scr > 0) {
1077 term.scr -= n;
1078 selscroll(0, -n);
1079 tfulldirt();
1080 }
1081}
1082
1083void
1084kscrollup(const Arg* a)
1085{
1086 int n = a->i;
1087
1088 if (n < 0)
1089 n = term.row + n;
1090
1091 if (term.scr <= HISTSIZE-n) {
1092 term.scr += n;
1093 selscroll(0, n);
1094 tfulldirt();
1095 }
1096}
1097
1098void
1099tscrolldown(int orig, int n, int copyhist)
1051{ 1100{
1052 int i; 1101 int i;
1053 Line temp; 1102 Line temp;
1054 1103
1055 LIMIT(n, 0, term.bot-orig+1); 1104 LIMIT(n, 0, term.bot-orig+1);
1056 1105
1106 if (copyhist) {
1107 term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE;
1108 temp = term.hist[term.histi];
1109 term.hist[term.histi] = term.line[term.bot];
1110 term.line[term.bot] = temp;
1111 }
1112
1057 tsetdirt(orig, term.bot-n); 1113 tsetdirt(orig, term.bot-n);
1058 tclearregion(0, term.bot-n+1, term.col-1, term.bot); 1114 tclearregion(0, term.bot-n+1, term.col-1, term.bot);
1059 1115
@@ -1063,17 +1119,28 @@ tscrolldown(int orig, int n)
1063 term.line[i-n] = temp; 1119 term.line[i-n] = temp;
1064 } 1120 }
1065 1121
1066 selscroll(orig, n); 1122 if (term.scr == 0)
1123 selscroll(orig, n);
1067} 1124}
1068 1125
1069void 1126void
1070tscrollup(int orig, int n) 1127tscrollup(int orig, int n, int copyhist)
1071{ 1128{
1072 int i; 1129 int i;
1073 Line temp; 1130 Line temp;
1074 1131
1075 LIMIT(n, 0, term.bot-orig+1); 1132 LIMIT(n, 0, term.bot-orig+1);
1076 1133
1134 if (copyhist) {
1135 term.histi = (term.histi + 1) % HISTSIZE;
1136 temp = term.hist[term.histi];
1137 term.hist[term.histi] = term.line[orig];
1138 term.line[orig] = temp;
1139 }
1140
1141 if (term.scr > 0 && term.scr < HISTSIZE)
1142 term.scr = MIN(term.scr + n, HISTSIZE-1);
1143
1077 tclearregion(0, orig, term.col-1, orig+n-1); 1144 tclearregion(0, orig, term.col-1, orig+n-1);
1078 tsetdirt(orig+n, term.bot); 1145 tsetdirt(orig+n, term.bot);
1079 1146
@@ -1083,7 +1150,8 @@ tscrollup(int orig, int n)
1083 term.line[i+n] = temp; 1150 term.line[i+n] = temp;
1084 } 1151 }
1085 1152
1086 selscroll(orig, -n); 1153 if (term.scr == 0)
1154 selscroll(orig, -n);
1087} 1155}
1088 1156
1089void 1157void
@@ -1122,7 +1190,7 @@ tnewline(int first_col)
1122 int y = term.c.y; 1190 int y = term.c.y;
1123 1191
1124 if (y == term.bot) { 1192 if (y == term.bot) {
1125 tscrollup(term.top, 1); 1193 tscrollup(term.top, 1, 1);
1126 } else { 1194 } else {
1127 y++; 1195 y++;
1128 } 1196 }
@@ -1287,14 +1355,14 @@ void
1287tinsertblankline(int n) 1355tinsertblankline(int n)
1288{ 1356{
1289 if (BETWEEN(term.c.y, term.top, term.bot)) 1357 if (BETWEEN(term.c.y, term.top, term.bot))
1290 tscrolldown(term.c.y, n); 1358 tscrolldown(term.c.y, n, 0);
1291} 1359}
1292 1360
1293void 1361void
1294tdeleteline(int n) 1362tdeleteline(int n)
1295{ 1363{
1296 if (BETWEEN(term.c.y, term.top, term.bot)) 1364 if (BETWEEN(term.c.y, term.top, term.bot))
1297 tscrollup(term.c.y, n); 1365 tscrollup(term.c.y, n, 0);
1298} 1366}
1299 1367
1300int32_t 1368int32_t
@@ -1725,11 +1793,11 @@ csihandle(void)
1725 break; 1793 break;
1726 case 'S': /* SU -- Scroll <n> line up */ 1794 case 'S': /* SU -- Scroll <n> line up */
1727 DEFAULT(csiescseq.arg[0], 1); 1795 DEFAULT(csiescseq.arg[0], 1);
1728 tscrollup(term.top, csiescseq.arg[0]); 1796 tscrollup(term.top, csiescseq.arg[0], 0);
1729 break; 1797 break;
1730 case 'T': /* SD -- Scroll <n> line down */ 1798 case 'T': /* SD -- Scroll <n> line down */
1731 DEFAULT(csiescseq.arg[0], 1); 1799 DEFAULT(csiescseq.arg[0], 1);
1732 tscrolldown(term.top, csiescseq.arg[0]); 1800 tscrolldown(term.top, csiescseq.arg[0], 0);
1733 break; 1801 break;
1734 case 'L': /* IL -- Insert <n> blank lines */ 1802 case 'L': /* IL -- Insert <n> blank lines */
1735 DEFAULT(csiescseq.arg[0], 1); 1803 DEFAULT(csiescseq.arg[0], 1);
@@ -2235,7 +2303,7 @@ eschandle(uchar ascii)
2235 return 0; 2303 return 0;
2236 case 'D': /* IND -- Linefeed */ 2304 case 'D': /* IND -- Linefeed */
2237 if (term.c.y == term.bot) { 2305 if (term.c.y == term.bot) {
2238 tscrollup(term.top, 1); 2306 tscrollup(term.top, 1, 1);
2239 } else { 2307 } else {
2240 tmoveto(term.c.x, term.c.y+1); 2308 tmoveto(term.c.x, term.c.y+1);
2241 } 2309 }
@@ -2248,7 +2316,7 @@ eschandle(uchar ascii)
2248 break; 2316 break;
2249 case 'M': /* RI -- Reverse index */ 2317 case 'M': /* RI -- Reverse index */
2250 if (term.c.y == term.top) { 2318 if (term.c.y == term.top) {
2251 tscrolldown(term.top, 1); 2319 tscrolldown(term.top, 1, 1);
2252 } else { 2320 } else {
2253 tmoveto(term.c.x, term.c.y-1); 2321 tmoveto(term.c.x, term.c.y-1);
2254 } 2322 }
@@ -2469,7 +2537,7 @@ twrite(const char *buf, int buflen, int show_ctrl)
2469void 2537void
2470tresize(int col, int row) 2538tresize(int col, int row)
2471{ 2539{
2472 int i; 2540 int i, j;
2473 int minrow = MIN(row, term.row); 2541 int minrow = MIN(row, term.row);
2474 int mincol = MIN(col, term.col); 2542 int mincol = MIN(col, term.col);
2475 int *bp; 2543 int *bp;
@@ -2506,6 +2574,14 @@ tresize(int col, int row)
2506 term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); 2574 term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
2507 term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); 2575 term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
2508 2576
2577 for (i = 0; i < HISTSIZE; i++) {
2578 term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph));
2579 for (j = mincol; j < col; j++) {
2580 term.hist[i][j] = term.c.attr;
2581 term.hist[i][j].u = ' ';
2582 }
2583 }
2584
2509 /* resize each row to new width, zero-pad if needed */ 2585 /* resize each row to new width, zero-pad if needed */
2510 for (i = 0; i < minrow; i++) { 2586 for (i = 0; i < minrow; i++) {
2511 term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); 2587 term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
@@ -2563,7 +2639,7 @@ drawregion(int x1, int y1, int x2, int y2)
2563 continue; 2639 continue;
2564 2640
2565 term.dirty[y] = 0; 2641 term.dirty[y] = 0;
2566 xdrawline(term.line[y], x1, y, x2); 2642 xdrawline(TLINE(y), x1, y, x2);
2567 } 2643 }
2568} 2644}
2569 2645
@@ -2584,8 +2660,9 @@ draw(void)
2584 cx--; 2660 cx--;
2585 2661
2586 drawregion(0, 0, term.col, term.row); 2662 drawregion(0, 0, term.col, term.row);
2587 xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], 2663 if (term.scr == 0)
2588 term.ocx, term.ocy, term.line[term.ocy][term.ocx]); 2664 xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
2665 term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
2589 term.ocx = cx, term.ocy = term.c.y; 2666 term.ocx = cx, term.ocy = term.c.y;
2590 xfinishdraw(); 2667 xfinishdraw();
2591 xximspot(term.ocx, term.ocy); 2668 xximspot(term.ocx, term.ocy);