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