Xinqi Bao's Git

patch: scrollback
[st.git] / patches / st-scrollback-20210507-4536f46.diff
1 diff --git a/config.def.h b/config.def.h
2 index 6f05dce..93cbcc0 100644
3 --- a/config.def.h
4 +++ b/config.def.h
5 @@ -199,6 +199,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 ebdf360..817cc47 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 @@ -115,6 +119,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(const int *, int);
55 static void tsetchar(Rune, const Glyph *, int, int);
56 static void tsetdirt(int, int);
57 @@ -416,10 +423,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 @@ -528,7 +535,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 @@ -543,14 +550,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 @@ -571,14 +578,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 @@ -609,13 +616,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 @@ -850,6 +857,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 @@ -1061,13 +1071,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 @@ -1077,17 +1127,28 @@ tscrolldown(int orig, int n)
196 term.line[i-n] = temp;
197 }
198
199 - selscroll(orig, n);
200 + if (term.scr == 0)
201 + selscroll(orig, n);
202 }
203
204 void
205 -tscrollup(int orig, int n)
206 +tscrollup(int orig, int n, int copyhist)
207 {
208 int i;
209 Line temp;
210
211 LIMIT(n, 0, term.bot-orig+1);
212
213 + if (copyhist) {
214 + term.histi = (term.histi + 1) % HISTSIZE;
215 + temp = term.hist[term.histi];
216 + term.hist[term.histi] = term.line[orig];
217 + term.line[orig] = temp;
218 + }
219 +
220 + if (term.scr > 0 && term.scr < HISTSIZE)
221 + term.scr = MIN(term.scr + n, HISTSIZE-1);
222 +
223 tclearregion(0, orig, term.col-1, orig+n-1);
224 tsetdirt(orig+n, term.bot);
225
226 @@ -1097,7 +1158,8 @@ tscrollup(int orig, int n)
227 term.line[i+n] = temp;
228 }
229
230 - selscroll(orig, -n);
231 + if (term.scr == 0)
232 + selscroll(orig, -n);
233 }
234
235 void
236 @@ -1126,7 +1188,7 @@ tnewline(int first_col)
237 int y = term.c.y;
238
239 if (y == term.bot) {
240 - tscrollup(term.top, 1);
241 + tscrollup(term.top, 1, 1);
242 } else {
243 y++;
244 }
245 @@ -1291,14 +1353,14 @@ void
246 tinsertblankline(int n)
247 {
248 if (BETWEEN(term.c.y, term.top, term.bot))
249 - tscrolldown(term.c.y, n);
250 + tscrolldown(term.c.y, n, 0);
251 }
252
253 void
254 tdeleteline(int n)
255 {
256 if (BETWEEN(term.c.y, term.top, term.bot))
257 - tscrollup(term.c.y, n);
258 + tscrollup(term.c.y, n, 0);
259 }
260
261 int32_t
262 @@ -1735,11 +1797,11 @@ csihandle(void)
263 break;
264 case 'S': /* SU -- Scroll <n> line up */
265 DEFAULT(csiescseq.arg[0], 1);
266 - tscrollup(term.top, csiescseq.arg[0]);
267 + tscrollup(term.top, csiescseq.arg[0], 0);
268 break;
269 case 'T': /* SD -- Scroll <n> line down */
270 DEFAULT(csiescseq.arg[0], 1);
271 - tscrolldown(term.top, csiescseq.arg[0]);
272 + tscrolldown(term.top, csiescseq.arg[0], 0);
273 break;
274 case 'L': /* IL -- Insert <n> blank lines */
275 DEFAULT(csiescseq.arg[0], 1);
276 @@ -2251,7 +2313,7 @@ eschandle(uchar ascii)
277 return 0;
278 case 'D': /* IND -- Linefeed */
279 if (term.c.y == term.bot) {
280 - tscrollup(term.top, 1);
281 + tscrollup(term.top, 1, 1);
282 } else {
283 tmoveto(term.c.x, term.c.y+1);
284 }
285 @@ -2264,7 +2326,7 @@ eschandle(uchar ascii)
286 break;
287 case 'M': /* RI -- Reverse index */
288 if (term.c.y == term.top) {
289 - tscrolldown(term.top, 1);
290 + tscrolldown(term.top, 1, 1);
291 } else {
292 tmoveto(term.c.x, term.c.y-1);
293 }
294 @@ -2474,7 +2536,7 @@ twrite(const char *buf, int buflen, int show_ctrl)
295 void
296 tresize(int col, int row)
297 {
298 - int i;
299 + int i, j;
300 int minrow = MIN(row, term.row);
301 int mincol = MIN(col, term.col);
302 int *bp;
303 @@ -2511,6 +2573,14 @@ tresize(int col, int row)
304 term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
305 term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
306
307 + for (i = 0; i < HISTSIZE; i++) {
308 + term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph));
309 + for (j = mincol; j < col; j++) {
310 + term.hist[i][j] = term.c.attr;
311 + term.hist[i][j].u = ' ';
312 + }
313 + }
314 +
315 /* resize each row to new width, zero-pad if needed */
316 for (i = 0; i < minrow; i++) {
317 term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
318 @@ -2569,7 +2639,7 @@ drawregion(int x1, int y1, int x2, int y2)
319 continue;
320
321 term.dirty[y] = 0;
322 - xdrawline(term.line[y], x1, y, x2);
323 + xdrawline(TLINE(y), x1, y, x2);
324 }
325 }
326
327 @@ -2590,8 +2660,9 @@ draw(void)
328 cx--;
329
330 drawregion(0, 0, term.col, term.row);
331 - xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
332 - term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
333 + if (term.scr == 0)
334 + xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
335 + term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
336 term.ocx = cx;
337 term.ocy = term.c.y;
338 xfinishdraw();
339 diff --git a/st.h b/st.h
340 index fa2eddf..adda2db 100644
341 --- a/st.h
342 +++ b/st.h
343 @@ -81,6 +81,8 @@ void die(const char *, ...);
344 void redraw(void);
345 void draw(void);
346
347 +void kscrolldown(const Arg *);
348 +void kscrollup(const Arg *);
349 void printscreen(const Arg *);
350 void printsel(const Arg *);
351 void sendbreak(const Arg *);