st/patches/st-scrollback-20190331-21367a0.diff (view raw)
1diff --git a/config.def.h b/config.def.h
2index 482901e..5352f43 100644
3--- a/config.def.h
4+++ b/config.def.h
5@@ -178,6 +178,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 /*
14diff --git a/st.c b/st.c
15index 8e6ccb5..2599333 100644
16--- a/st.c
17+++ b/st.c
18@@ -35,6 +35,7 @@
19 #define ESC_ARG_SIZ 16
20 #define STR_BUF_SIZ ESC_BUF_SIZ
21 #define STR_ARG_SIZ ESC_ARG_SIZ
22+#define HISTSIZE 2000
23
24 /* macros */
25 #define IS_SET(flag) ((term.mode & (flag)) != 0)
26@@ -42,6 +43,9 @@
27 #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
28 #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
29 #define ISDELIM(u) (u && wcschr(worddelimiters, u))
30+#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \
31+ term.scr + HISTSIZE + 1) % HISTSIZE] : \
32+ term.line[(y) - term.scr])
33
34 enum term_mode {
35 MODE_WRAP = 1 << 0,
36@@ -117,6 +121,9 @@ typedef struct {
37 int col; /* nb col */
38 Line *line; /* screen */
39 Line *alt; /* alternate screen */
40+ Line hist[HISTSIZE]; /* history buffer */
41+ int histi; /* history index */
42+ int scr; /* scroll back */
43 int *dirty; /* dirtyness of lines */
44 TCursor c; /* cursor */
45 int ocx; /* old cursor col */
46@@ -184,8 +191,8 @@ static void tnewline(int);
47 static void tputtab(int);
48 static void tputc(Rune);
49 static void treset(void);
50-static void tscrollup(int, int);
51-static void tscrolldown(int, int);
52+static void tscrollup(int, int, int);
53+static void tscrolldown(int, int, int);
54 static void tsetattr(int *, int);
55 static void tsetchar(Rune, Glyph *, int, int);
56 static void tsetdirt(int, int);
57@@ -409,10 +416,10 @@ tlinelen(int y)
58 {
59 int i = term.col;
60
61- if (term.line[y][i - 1].mode & ATTR_WRAP)
62+ if (TLINE(y)[i - 1].mode & ATTR_WRAP)
63 return i;
64
65- while (i > 0 && term.line[y][i - 1].u == ' ')
66+ while (i > 0 && TLINE(y)[i - 1].u == ' ')
67 --i;
68
69 return i;
70@@ -521,7 +528,7 @@ selsnap(int *x, int *y, int direction)
71 * Snap around if the word wraps around at the end or
72 * beginning of a line.
73 */
74- prevgp = &term.line[*y][*x];
75+ prevgp = &TLINE(*y)[*x];
76 prevdelim = ISDELIM(prevgp->u);
77 for (;;) {
78 newx = *x + direction;
79@@ -536,14 +543,14 @@ selsnap(int *x, int *y, int direction)
80 yt = *y, xt = *x;
81 else
82 yt = newy, xt = newx;
83- if (!(term.line[yt][xt].mode & ATTR_WRAP))
84+ if (!(TLINE(yt)[xt].mode & ATTR_WRAP))
85 break;
86 }
87
88 if (newx >= tlinelen(newy))
89 break;
90
91- gp = &term.line[newy][newx];
92+ gp = &TLINE(newy)[newx];
93 delim = ISDELIM(gp->u);
94 if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
95 || (delim && gp->u != prevgp->u)))
96@@ -564,14 +571,14 @@ selsnap(int *x, int *y, int direction)
97 *x = (direction < 0) ? 0 : term.col - 1;
98 if (direction < 0) {
99 for (; *y > 0; *y += direction) {
100- if (!(term.line[*y-1][term.col-1].mode
101+ if (!(TLINE(*y-1)[term.col-1].mode
102 & ATTR_WRAP)) {
103 break;
104 }
105 }
106 } else if (direction > 0) {
107 for (; *y < term.row-1; *y += direction) {
108- if (!(term.line[*y][term.col-1].mode
109+ if (!(TLINE(*y)[term.col-1].mode
110 & ATTR_WRAP)) {
111 break;
112 }
113@@ -602,13 +609,13 @@ getsel(void)
114 }
115
116 if (sel.type == SEL_RECTANGULAR) {
117- gp = &term.line[y][sel.nb.x];
118+ gp = &TLINE(y)[sel.nb.x];
119 lastx = sel.ne.x;
120 } else {
121- gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0];
122+ gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0];
123 lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
124 }
125- last = &term.line[y][MIN(lastx, linelen-1)];
126+ last = &TLINE(y)[MIN(lastx, linelen-1)];
127 while (last >= gp && last->u == ' ')
128 --last;
129
130@@ -831,6 +838,9 @@ void
131 ttywrite(const char *s, size_t n, int may_echo)
132 {
133 const char *next;
134+ Arg arg = (Arg) { .i = term.scr };
135+
136+ kscrolldown(&arg);
137
138 if (may_echo && IS_SET(MODE_ECHO))
139 twrite(s, n, 1);
140@@ -1042,13 +1052,53 @@ tswapscreen(void)
141 }
142
143 void
144-tscrolldown(int orig, int n)
145+kscrolldown(const Arg* a)
146+{
147+ int n = a->i;
148+
149+ if (n < 0)
150+ n = term.row + n;
151+
152+ if (n > term.scr)
153+ n = term.scr;
154+
155+ if (term.scr > 0) {
156+ term.scr -= n;
157+ selscroll(0, -n);
158+ tfulldirt();
159+ }
160+}
161+
162+void
163+kscrollup(const Arg* a)
164+{
165+ int n = a->i;
166+
167+ if (n < 0)
168+ n = term.row + n;
169+
170+ if (term.scr <= HISTSIZE-n) {
171+ term.scr += n;
172+ selscroll(0, n);
173+ tfulldirt();
174+ }
175+}
176+
177+void
178+tscrolldown(int orig, int n, int copyhist)
179 {
180 int i;
181 Line temp;
182
183 LIMIT(n, 0, term.bot-orig+1);
184
185+ if (copyhist) {
186+ term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE;
187+ temp = term.hist[term.histi];
188+ term.hist[term.histi] = term.line[term.bot];
189+ term.line[term.bot] = temp;
190+ }
191+
192 tsetdirt(orig, term.bot-n);
193 tclearregion(0, term.bot-n+1, term.col-1, term.bot);
194
195@@ -1062,13 +1112,23 @@ tscrolldown(int orig, int n)
196 }
197
198 void
199-tscrollup(int orig, int n)
200+tscrollup(int orig, int n, int copyhist)
201 {
202 int i;
203 Line temp;
204
205 LIMIT(n, 0, term.bot-orig+1);
206
207+ if (copyhist) {
208+ term.histi = (term.histi + 1) % HISTSIZE;
209+ temp = term.hist[term.histi];
210+ term.hist[term.histi] = term.line[orig];
211+ term.line[orig] = temp;
212+ }
213+
214+ if (term.scr > 0 && term.scr < HISTSIZE)
215+ term.scr = MIN(term.scr + n, HISTSIZE-1);
216+
217 tclearregion(0, orig, term.col-1, orig+n-1);
218 tsetdirt(orig+n, term.bot);
219
220@@ -1117,7 +1177,7 @@ tnewline(int first_col)
221 int y = term.c.y;
222
223 if (y == term.bot) {
224- tscrollup(term.top, 1);
225+ tscrollup(term.top, 1, 1);
226 } else {
227 y++;
228 }
229@@ -1282,14 +1342,14 @@ void
230 tinsertblankline(int n)
231 {
232 if (BETWEEN(term.c.y, term.top, term.bot))
233- tscrolldown(term.c.y, n);
234+ tscrolldown(term.c.y, n, 0);
235 }
236
237 void
238 tdeleteline(int n)
239 {
240 if (BETWEEN(term.c.y, term.top, term.bot))
241- tscrollup(term.c.y, n);
242+ tscrollup(term.c.y, n, 0);
243 }
244
245 int32_t
246@@ -1720,11 +1780,11 @@ csihandle(void)
247 break;
248 case 'S': /* SU -- Scroll <n> line up */
249 DEFAULT(csiescseq.arg[0], 1);
250- tscrollup(term.top, csiescseq.arg[0]);
251+ tscrollup(term.top, csiescseq.arg[0], 0);
252 break;
253 case 'T': /* SD -- Scroll <n> line down */
254 DEFAULT(csiescseq.arg[0], 1);
255- tscrolldown(term.top, csiescseq.arg[0]);
256+ tscrolldown(term.top, csiescseq.arg[0], 0);
257 break;
258 case 'L': /* IL -- Insert <n> blank lines */
259 DEFAULT(csiescseq.arg[0], 1);
260@@ -2227,7 +2287,7 @@ eschandle(uchar ascii)
261 return 0;
262 case 'D': /* IND -- Linefeed */
263 if (term.c.y == term.bot) {
264- tscrollup(term.top, 1);
265+ tscrollup(term.top, 1, 1);
266 } else {
267 tmoveto(term.c.x, term.c.y+1);
268 }
269@@ -2240,7 +2300,7 @@ eschandle(uchar ascii)
270 break;
271 case 'M': /* RI -- Reverse index */
272 if (term.c.y == term.top) {
273- tscrolldown(term.top, 1);
274+ tscrolldown(term.top, 1, 1);
275 } else {
276 tmoveto(term.c.x, term.c.y-1);
277 }
278@@ -2458,7 +2518,7 @@ twrite(const char *buf, int buflen, int show_ctrl)
279 void
280 tresize(int col, int row)
281 {
282- int i;
283+ int i, j;
284 int minrow = MIN(row, term.row);
285 int mincol = MIN(col, term.col);
286 int *bp;
287@@ -2495,6 +2555,14 @@ tresize(int col, int row)
288 term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
289 term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
290
291+ for (i = 0; i < HISTSIZE; i++) {
292+ term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph));
293+ for (j = mincol; j < col; j++) {
294+ term.hist[i][j] = term.c.attr;
295+ term.hist[i][j].u = ' ';
296+ }
297+ }
298+
299 /* resize each row to new width, zero-pad if needed */
300 for (i = 0; i < minrow; i++) {
301 term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
302@@ -2552,7 +2620,7 @@ drawregion(int x1, int y1, int x2, int y2)
303 continue;
304
305 term.dirty[y] = 0;
306- xdrawline(term.line[y], x1, y, x2);
307+ xdrawline(TLINE(y), x1, y, x2);
308 }
309 }
310
311@@ -2573,8 +2641,9 @@ draw(void)
312 cx--;
313
314 drawregion(0, 0, term.col, term.row);
315- xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
316- term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
317+ if (term.scr == 0)
318+ xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
319+ term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
320 term.ocx = cx, term.ocy = term.c.y;
321 xfinishdraw();
322 xximspot(term.ocx, term.ocy);
323diff --git a/st.h b/st.h
324index 4da3051..f11685d 100644
325--- a/st.h
326+++ b/st.h
327@@ -80,6 +80,8 @@ void die(const char *, ...);
328 void redraw(void);
329 void draw(void);
330
331+void kscrolldown(const Arg *);
332+void kscrollup(const Arg *);
333 void printscreen(const Arg *);
334 void printsel(const Arg *);
335 void sendbreak(const Arg *);