Introduction
Introduction Statistics Contact Development Disclaimer Help
st-scrollback-reflow-20230607-211964d.diff - sites - public wiki contents of su…
git clone git://git.suckless.org/sites
Log
Files
Refs
---
st-scrollback-reflow-20230607-211964d.diff (38252B)
---
1 From 633fe6b0231a0f08e6c1e32ae167117a7809cb7f Mon Sep 17 00:00:00 2001
2 From: sewn <[email protected]>
3 Date: Wed, 7 Jun 2023 12:27:38 +0300
4 Subject: [PATCH] reflow columns and rows in case of hidden by resize.
5
6 Extracted from https://github.com/ashish-yadav11/st
7 Based on the works of BeyondMagic et al.
8 ---
9 st.c | 941 ++++++++++++++++++++++++++++++++++++++++-------------------
10 st.h | 25 +-
11 2 files changed, 658 insertions(+), 308 deletions(-)
12
13 diff --git a/st.c b/st.c
14 index afb862b..46ba498 100644
15 --- a/st.c
16 +++ b/st.c
17 @@ -36,6 +36,7 @@
18 #define STR_BUF_SIZ ESC_BUF_SIZ
19 #define STR_ARG_SIZ ESC_ARG_SIZ
20 #define HISTSIZE 2000
21 +#define RESIZEBUFFER 1000
22
23 /* macros */
24 #define IS_SET(flag) ((term.mode & (flag)) != 0)
25 @@ -43,9 +44,22 @@
26 #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
27 #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
28 #define ISDELIM(u) (u && wcschr(worddelimiters, u))
29 -#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term…
30 - term.scr + HISTSIZE + 1) % HISTSIZE] : \
31 - term.line[(y) - term.scr])
32 +
33 +#define TLINE(y) ( \
34 + (y) < term.scr ? term.hist[(term.histi + (y) - term.scr + 1 + H…
35 + : term.line[(y) - term.scr] \
36 +)
37 +
38 +#define TLINEABS(y) ( \
39 + (y) < 0 ? term.hist[(term.histi + (y) + 1 + HISTSIZE) % HISTSIZ…
40 +)
41 +
42 +#define UPDATEWRAPNEXT(alt, col) do { \
43 + if ((term.c.state & CURSOR_WRAPNEXT) && term.c.x + term.wrapcwi…
44 + term.c.x += term.wrapcwidth[alt]; \
45 + term.c.state &= ~CURSOR_WRAPNEXT; \
46 + } \
47 +} while (0);
48
49 enum term_mode {
50 MODE_WRAP = 1 << 0,
51 @@ -57,6 +71,12 @@ enum term_mode {
52 MODE_UTF8 = 1 << 6,
53 };
54
55 +enum scroll_mode {
56 + SCROLL_RESIZE = -1,
57 + SCROLL_NOSAVEHIST = 0,
58 + SCROLL_SAVEHIST = 1
59 +};
60 +
61 enum cursor_movement {
62 CURSOR_SAVE,
63 CURSOR_LOAD
64 @@ -118,10 +138,11 @@ typedef struct {
65 int row; /* nb row */
66 int col; /* nb col */
67 Line *line; /* screen */
68 - Line *alt; /* alternate screen */
69 Line hist[HISTSIZE]; /* history buffer */
70 - int histi; /* history index */
71 - int scr; /* scroll back */
72 + int histi; /* history index */
73 + int histf; /* nb history available */
74 + int scr; /* scroll back */
75 + int wrapcwidth[2]; /* used in updating WRAPNEXT when resizing…
76 int *dirty; /* dirtyness of lines */
77 TCursor c; /* cursor */
78 int ocx; /* old cursor col */
79 @@ -179,26 +200,37 @@ static void tprinter(char *, size_t);
80 static void tdumpsel(void);
81 static void tdumpline(int);
82 static void tdump(void);
83 -static void tclearregion(int, int, int, int);
84 +static void tclearregion(int, int, int, int, int);
85 static void tcursor(int);
86 +static void tclearglyph(Glyph *, int);
87 +static void tresetcursor(void);
88 static void tdeletechar(int);
89 static void tdeleteline(int);
90 static void tinsertblank(int);
91 static void tinsertblankline(int);
92 -static int tlinelen(int);
93 +static int tlinelen(Line len);
94 +static int tiswrapped(Line line);
95 +static char *tgetglyphs(char *, const Glyph *, const Glyph *);
96 +static size_t tgetline(char *, const Glyph *);
97 static void tmoveto(int, int);
98 static void tmoveato(int, int);
99 static void tnewline(int);
100 static void tputtab(int);
101 static void tputc(Rune);
102 static void treset(void);
103 -static void tscrollup(int, int, int);
104 -static void tscrolldown(int, int, int);
105 +static void tscrollup(int, int, int, int);
106 +static void tscrolldown(int, int);
107 +static void treflow(int, int);
108 +static void rscrolldown(int);
109 +static void tresizedef(int, int);
110 +static void tresizealt(int, int);
111 static void tsetattr(const int *, int);
112 static void tsetchar(Rune, const Glyph *, int, int);
113 static void tsetdirt(int, int);
114 static void tsetscroll(int, int);
115 static void tswapscreen(void);
116 +static void tloaddefscreen(int, int);
117 +static void tloadaltscreen(int, int);
118 static void tsetmode(int, int, const int *, int);
119 static int twrite(const char *, int, int);
120 static void tfulldirt(void);
121 @@ -212,7 +244,10 @@ static void tstrsequence(uchar);
122 static void drawregion(int, int, int, int);
123
124 static void selnormalize(void);
125 -static void selscroll(int, int);
126 +static void selscroll(int, int, int);
127 +static void selmove(int);
128 +static void selremove(void);
129 +static int regionselected(int, int, int, int);
130 static void selsnap(int *, int *, int);
131
132 static size_t utf8decode(const char *, Rune *, size_t);
133 @@ -412,17 +447,46 @@ selinit(void)
134 }
135
136 int
137 -tlinelen(int y)
138 +tlinelen(Line line)
139 {
140 - int i = term.col;
141 + int i = term.col - 1;
142 +
143 + for (; i >= 0 && !(line[i].mode & (ATTR_SET | ATTR_WRAP)); i--);
144 + return i + 1;
145 +}
146
147 - if (TLINE(y)[i - 1].mode & ATTR_WRAP)
148 - return i;
149 +int
150 +tiswrapped(Line line)
151 +{
152 + int len = tlinelen(line);
153
154 - while (i > 0 && TLINE(y)[i - 1].u == ' ')
155 - --i;
156 + return len > 0 && (line[len - 1].mode & ATTR_WRAP);
157 +}
158
159 - return i;
160 +char *
161 +tgetglyphs(char *buf, const Glyph *gp, const Glyph *lgp)
162 +{
163 + while (gp <= lgp)
164 + if (gp->mode & ATTR_WDUMMY) {
165 + gp++;
166 + } else {
167 + buf += utf8encode((gp++)->u, buf);
168 + }
169 + return buf;
170 +}
171 +
172 +size_t
173 +tgetline(char *buf, const Glyph *fgp)
174 +{
175 + char *ptr;
176 + const Glyph *lgp = &fgp[term.col - 1];
177 +
178 + while (lgp > fgp && !(lgp->mode & (ATTR_SET | ATTR_WRAP)))
179 + lgp--;
180 + ptr = tgetglyphs(buf, fgp, lgp);
181 + if (!(lgp->mode & ATTR_WRAP))
182 + *(ptr++) = '\n';
183 + return ptr - buf;
184 }
185
186 void
187 @@ -462,10 +526,11 @@ selextend(int col, int row, int type, int done)
188
189 sel.oe.x = col;
190 sel.oe.y = row;
191 - selnormalize();
192 sel.type = type;
193 + selnormalize();
194
195 - if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.ty…
196 + if (oldey != sel.oe.y || oldex != sel.oe.x ||
197 + oldtype != sel.type || sel.mode == SEL_EMPTY)
198 tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
199
200 sel.mode = done ? SEL_IDLE : SEL_READY;
201 @@ -492,36 +557,43 @@ selnormalize(void)
202 /* expand selection over line breaks */
203 if (sel.type == SEL_RECTANGULAR)
204 return;
205 - i = tlinelen(sel.nb.y);
206 - if (i < sel.nb.x)
207 +
208 + i = tlinelen(TLINE(sel.nb.y));
209 + if (sel.nb.x > i)
210 sel.nb.x = i;
211 - if (tlinelen(sel.ne.y) <= sel.ne.x)
212 - sel.ne.x = term.col - 1;
213 + if (sel.ne.x >= tlinelen(TLINE(sel.ne.y)))
214 + sel.ne.x = term.col - 1;
215 }
216
217 int
218 -selected(int x, int y)
219 +regionselected(int x1, int y1, int x2, int y2)
220 {
221 - if (sel.mode == SEL_EMPTY || sel.ob.x == -1 ||
222 - sel.alt != IS_SET(MODE_ALTSCREEN))
223 + if (sel.ob.x == -1 || sel.mode == SEL_EMPTY ||
224 + sel.alt != IS_SET(MODE_ALTSCREEN) || sel.nb.y > y2 || sel.n…
225 return 0;
226
227 - if (sel.type == SEL_RECTANGULAR)
228 - return BETWEEN(y, sel.nb.y, sel.ne.y)
229 - && BETWEEN(x, sel.nb.x, sel.ne.x);
230 + return (sel.type == SEL_RECTANGULAR) ? sel.nb.x <= x2 && sel.ne…
231 + : (sel.nb.y != y2 || sel.nb.x <= x2) &&
232 + (sel.ne.y != y1 || sel.ne.x >= x1);
233 +}
234
235 - return BETWEEN(y, sel.nb.y, sel.ne.y)
236 - && (y != sel.nb.y || x >= sel.nb.x)
237 - && (y != sel.ne.y || x <= sel.ne.x);
238 +int
239 +selected(int x, int y)
240 +{
241 + return regionselected(x, y, x, y);
242 }
243
244 void
245 selsnap(int *x, int *y, int direction)
246 {
247 int newx, newy, xt, yt;
248 + int rtop = 0, rbot = term.row - 1;
249 int delim, prevdelim;
250 const Glyph *gp, *prevgp;
251
252 + if (!IS_SET(MODE_ALTSCREEN))
253 + rtop += -term.histf + term.scr, rbot += term.scr;
254 +
255 switch (sel.snap) {
256 case SNAP_WORD:
257 /*
258 @@ -536,7 +608,7 @@ selsnap(int *x, int *y, int direction)
259 if (!BETWEEN(newx, 0, term.col - 1)) {
260 newy += direction;
261 newx = (newx + term.col) % term.col;
262 - if (!BETWEEN(newy, 0, term.row - 1))
263 + if (!BETWEEN(newy, rtop, rbot))
264 break;
265
266 if (direction > 0)
267 @@ -547,13 +619,13 @@ selsnap(int *x, int *y, int direction)
268 break;
269 }
270
271 - if (newx >= tlinelen(newy))
272 + if (newx >= tlinelen(TLINE(newy)))
273 break;
274
275 gp = &TLINE(newy)[newx];
276 delim = ISDELIM(gp->u);
277 - if (!(gp->mode & ATTR_WDUMMY) && (delim != prev…
278 - || (delim && gp->u != prevgp->u…
279 + if (!(gp->mode & ATTR_WDUMMY) && (delim != prev…
280 + (delim && !(gp->u == ' ' && prevgp->u == ' …
281 break;
282
283 *x = newx;
284 @@ -570,18 +642,14 @@ selsnap(int *x, int *y, int direction)
285 */
286 *x = (direction < 0) ? 0 : term.col - 1;
287 if (direction < 0) {
288 - for (; *y > 0; *y += direction) {
289 - if (!(TLINE(*y-1)[term.col-1].mode
290 - & ATTR_WRAP)) {
291 + for (; *y > rtop; *y -= 1) {
292 + if (!tiswrapped(TLINE(*y-1)))
293 break;
294 - }
295 }
296 } else if (direction > 0) {
297 - for (; *y < term.row-1; *y += direction) {
298 - if (!(TLINE(*y)[term.col-1].mode
299 - & ATTR_WRAP)) {
300 + for (; *y < rbot; *y += 1) {
301 + if (!tiswrapped(TLINE(*y)))
302 break;
303 - }
304 }
305 }
306 break;
307 @@ -592,40 +660,34 @@ char *
308 getsel(void)
309 {
310 char *str, *ptr;
311 - int y, bufsize, lastx, linelen;
312 - const Glyph *gp, *last;
313 + int y, lastx, linelen;
314 + const Glyph *gp, *lgp;
315
316 - if (sel.ob.x == -1)
317 + if (sel.ob.x == -1 || sel.alt != IS_SET(MODE_ALTSCREEN))
318 return NULL;
319
320 - bufsize = (term.col+1) * (sel.ne.y-sel.nb.y+1) * UTF_SIZ;
321 - ptr = str = xmalloc(bufsize);
322 + str = xmalloc((term.col + 1) * (sel.ne.y - sel.nb.y + 1) * UTF_…
323 + ptr = str;
324
325 /* append every set & selected glyph to the selection */
326 for (y = sel.nb.y; y <= sel.ne.y; y++) {
327 - if ((linelen = tlinelen(y)) == 0) {
328 + Line line = TLINE(y);
329 +
330 + if ((linelen = tlinelen(line)) == 0) {
331 *ptr++ = '\n';
332 continue;
333 }
334
335 if (sel.type == SEL_RECTANGULAR) {
336 - gp = &TLINE(y)[sel.nb.x];
337 + gp = &line[sel.nb.x];
338 lastx = sel.ne.x;
339 } else {
340 - gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0];
341 + gp = &line[sel.nb.y == y ? sel.nb.x : 0];
342 lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
343 }
344 - last = &TLINE(y)[MIN(lastx, linelen-1)];
345 - while (last >= gp && last->u == ' ')
346 - --last;
347 -
348 - for ( ; gp <= last; ++gp) {
349 - if (gp->mode & ATTR_WDUMMY)
350 - continue;
351 -
352 - ptr += utf8encode(gp->u, ptr);
353 - }
354 + lgp = &line[MIN(lastx, linelen-1)];
355
356 + ptr = tgetglyphs(ptr, gp, lgp);
357 /*
358 * Copy and pasting of line endings is inconsistent
359 * in the inconsistent terminal and GUI world.
360 @@ -636,10 +698,10 @@ getsel(void)
361 * FIXME: Fix the computer world.
362 */
363 if ((y < sel.ne.y || lastx >= linelen) &&
364 - (!(last->mode & ATTR_WRAP) || sel.type == SEL_RECTA…
365 + (!(lgp->mode & ATTR_WRAP) || sel.type == SEL_RECTAN…
366 *ptr++ = '\n';
367 }
368 - *ptr = 0;
369 + *ptr = '\0';
370 return str;
371 }
372
373 @@ -648,9 +710,15 @@ selclear(void)
374 {
375 if (sel.ob.x == -1)
376 return;
377 + selremove();
378 + tsetdirt(sel.nb.y, sel.ne.y);
379 +}
380 +
381 +void
382 +selremove(void)
383 +{
384 sel.mode = SEL_IDLE;
385 sel.ob.x = -1;
386 - tsetdirt(sel.nb.y, sel.ne.y);
387 }
388
389 void
390 @@ -851,10 +919,8 @@ void
391 ttywrite(const char *s, size_t n, int may_echo)
392 {
393 const char *next;
394 - Arg arg = (Arg) { .i = term.scr };
395 -
396 - kscrolldown(&arg);
397
398 + kscrolldown(&((Arg){ .i = term.scr }));
399 if (may_echo && IS_SET(MODE_ECHO))
400 twrite(s, n, 1);
401
402 @@ -990,7 +1056,7 @@ tsetdirtattr(int attr)
403 for (i = 0; i < term.row-1; i++) {
404 for (j = 0; j < term.col-1; j++) {
405 if (term.line[i][j].mode & attr) {
406 - tsetdirt(i, i);
407 + term.dirty[i] = 1;
408 break;
409 }
410 }
411 @@ -1000,7 +1066,8 @@ tsetdirtattr(int attr)
412 void
413 tfulldirt(void)
414 {
415 - tsetdirt(0, term.row-1);
416 + for (int i = 0; i < term.row; i++)
417 + term.dirty[i] = 1;
418 }
419
420 void
421 @@ -1017,51 +1084,116 @@ tcursor(int mode)
422 }
423 }
424
425 +void
426 +tresetcursor(void)
427 +{
428 + term.c = (TCursor){ { .mode = ATTR_NULL, .fg = defaultfg, .bg =…
429 + .x = 0, .y = 0, .state = CURSOR_DEFAULT };
430 +}
431 +
432 void
433 treset(void)
434 {
435 uint i;
436 + int x, y;
437
438 - term.c = (TCursor){{
439 - .mode = ATTR_NULL,
440 - .fg = defaultfg,
441 - .bg = defaultbg
442 - }, .x = 0, .y = 0, .state = CURSOR_DEFAULT};
443 + tresetcursor();
444
445 memset(term.tabs, 0, term.col * sizeof(*term.tabs));
446 for (i = tabspaces; i < term.col; i += tabspaces)
447 term.tabs[i] = 1;
448 term.top = 0;
449 + term.histf = 0;
450 + term.scr = 0;
451 term.bot = term.row - 1;
452 term.mode = MODE_WRAP|MODE_UTF8;
453 memset(term.trantbl, CS_USA, sizeof(term.trantbl));
454 term.charset = 0;
455
456 + selremove();
457 for (i = 0; i < 2; i++) {
458 - tmoveto(0, 0);
459 - tcursor(CURSOR_SAVE);
460 - tclearregion(0, 0, term.col-1, term.row-1);
461 + tcursor(CURSOR_SAVE); /* reset saved cursor */
462 + for (y = 0; y < term.row; y++)
463 + for (x = 0; x < term.col; x++)
464 + tclearglyph(&term.line[y][x], 0);
465 tswapscreen();
466 }
467 + tfulldirt();
468 }
469
470 void
471 tnew(int col, int row)
472 {
473 - term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultb…
474 - tresize(col, row);
475 - treset();
476 + int i, j;
477 +
478 + for (i = 0; i < 2; i++) {
479 + term.line = xmalloc(row * sizeof(Line));
480 + for (j = 0; j < row; j++)
481 + term.line[j] = xmalloc(col * sizeof(Glyph));
482 + term.col = col, term.row = row;
483 + tswapscreen();
484 + }
485 + term.dirty = xmalloc(row * sizeof(*term.dirty));
486 + term.tabs = xmalloc(col * sizeof(*term.tabs));
487 + for (i = 0; i < HISTSIZE; i++)
488 + term.hist[i] = xmalloc(col * sizeof(Glyph));
489 + treset();
490 }
491
492 +/* handle it with care */
493 void
494 tswapscreen(void)
495 {
496 - Line *tmp = term.line;
497 + static Line *altline;
498 + static int altcol, altrow;
499 + Line *tmpline = term.line;
500 + int tmpcol = term.col, tmprow = term.row;
501
502 - term.line = term.alt;
503 - term.alt = tmp;
504 + term.line = altline;
505 + term.col = altcol, term.row = altrow;
506 + altline = tmpline;
507 + altcol = tmpcol, altrow = tmprow;
508 term.mode ^= MODE_ALTSCREEN;
509 - tfulldirt();
510 +}
511 +
512 +void
513 +tloaddefscreen(int clear, int loadcursor)
514 +{
515 + int col, row, alt = IS_SET(MODE_ALTSCREEN);
516 +
517 + if (alt) {
518 + if (clear)
519 + tclearregion(0, 0, term.col-1, term.row-1, 1);
520 + col = term.col, row = term.row;
521 + tswapscreen();
522 + }
523 + if (loadcursor)
524 + tcursor(CURSOR_LOAD);
525 + if (alt)
526 + tresizedef(col, row);
527 +}
528 +
529 +void
530 +tloadaltscreen(int clear, int savecursor)
531 +{
532 + int col, row, def = !IS_SET(MODE_ALTSCREEN);
533 +
534 + if (savecursor)
535 + tcursor(CURSOR_SAVE);
536 + if (def) {
537 + col = term.col, row = term.row;
538 + tswapscreen();
539 + term.scr = 0;
540 + tresizealt(col, row);
541 + }
542 + if (clear)
543 + tclearregion(0, 0, term.col-1, term.row-1, 1);
544 +}
545 +
546 +int
547 +tisaltscreen(void)
548 +{
549 + return IS_SET(MODE_ALTSCREEN);
550 }
551
552 void
553 @@ -1069,17 +1201,22 @@ kscrolldown(const Arg* a)
554 {
555 int n = a->i;
556
557 - if (n < 0)
558 - n = term.row + n;
559 + if (!term.scr || IS_SET(MODE_ALTSCREEN))
560 + return;
561
562 - if (n > term.scr)
563 - n = term.scr;
564 + if (n < 0)
565 + n = MAX(term.row / -n, 1);
566
567 - if (term.scr > 0) {
568 + if (n <= term.scr) {
569 term.scr -= n;
570 - selscroll(0, -n);
571 - tfulldirt();
572 + } else {
573 + n = term.scr;
574 + term.scr = 0;
575 }
576 +
577 + if (sel.ob.x != -1 && !sel.alt)
578 + selmove(-n); /* negate change in term.scr */
579 + tfulldirt();
580 }
581
582 void
583 @@ -1087,92 +1224,118 @@ kscrollup(const Arg* a)
584 {
585 int n = a->i;
586
587 + if (!term.histf || IS_SET(MODE_ALTSCREEN))
588 + return;
589 +
590 if (n < 0)
591 - n = term.row + n;
592 + n = MAX(term.row / -n, 1);
593
594 - if (term.scr <= HISTSIZE-n) {
595 + if (term.scr + n <= term.histf) {
596 term.scr += n;
597 - selscroll(0, n);
598 - tfulldirt();
599 + } else {
600 + n = term.histf - term.scr;
601 + term.scr = term.histf;
602 }
603 +
604 + if (sel.ob.x != -1 && !sel.alt)
605 + selmove(n); /* negate change in term.scr */
606 + tfulldirt();
607 }
608
609 void
610 -tscrolldown(int orig, int n, int copyhist)
611 +tscrolldown(int top, int n)
612 {
613 - int i;
614 + int i, bot = term.bot;
615 Line temp;
616
617 - LIMIT(n, 0, term.bot-orig+1);
618 - if (copyhist) {
619 - term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE;
620 - temp = term.hist[term.histi];
621 - term.hist[term.histi] = term.line[term.bot];
622 - term.line[term.bot] = temp;
623 - }
624 -
625 + if (n <= 0)
626 + return;
627 + n = MIN(n, bot-top+1);
628
629 - tsetdirt(orig, term.bot-n);
630 - tclearregion(0, term.bot-n+1, term.col-1, term.bot);
631 + tsetdirt(top, bot-n);
632 + tclearregion(0, bot-n+1, term.col-1, bot, 1);
633
634 - for (i = term.bot; i >= orig+n; i--) {
635 + for (i = bot; i >= top+n; i--) {
636 temp = term.line[i];
637 term.line[i] = term.line[i-n];
638 term.line[i-n] = temp;
639 }
640
641 - if (term.scr == 0)
642 - selscroll(orig, n);
643 + if (sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN))
644 + selscroll(top, bot, n);
645 }
646
647 void
648 -tscrollup(int orig, int n, int copyhist)
649 +tscrollup(int top, int bot, int n, int mode)
650 {
651 - int i;
652 + int i, j, s;
653 + int alt = IS_SET(MODE_ALTSCREEN);
654 + int savehist = !alt && top == 0 && mode != SCROLL_NOSAVEHIST;
655 Line temp;
656
657 - LIMIT(n, 0, term.bot-orig+1);
658 -
659 - if (copyhist) {
660 - term.histi = (term.histi + 1) % HISTSIZE;
661 - temp = term.hist[term.histi];
662 - term.hist[term.histi] = term.line[orig];
663 - term.line[orig] = temp;
664 + if (n <= 0)
665 + return;
666 + n = MIN(n, bot-top+1);
667 +
668 + if (savehist) {
669 + for (i = 0; i < n; i++) {
670 + term.histi = (term.histi + 1) % HISTSIZE;
671 + temp = term.hist[term.histi];
672 + for (j = 0; j < term.col; j++)
673 + tclearglyph(&temp[j], 1);
674 + term.hist[term.histi] = term.line[i];
675 + term.line[i] = temp;
676 + }
677 + term.histf = MIN(term.histf + n, HISTSIZE);
678 + s = n;
679 + if (term.scr) {
680 + j = term.scr;
681 + term.scr = MIN(j + n, HISTSIZE);
682 + s = j + n - term.scr;
683 + }
684 + if (mode != SCROLL_RESIZE)
685 + tfulldirt();
686 + } else {
687 + tclearregion(0, top, term.col-1, top+n-1, 1);
688 + tsetdirt(top+n, bot);
689 }
690
691 - if (term.scr > 0 && term.scr < HISTSIZE)
692 - term.scr = MIN(term.scr + n, HISTSIZE-1);
693 -
694 - tclearregion(0, orig, term.col-1, orig+n-1);
695 - tsetdirt(orig+n, term.bot);
696 -
697 - for (i = orig; i <= term.bot-n; i++) {
698 + for (i = top; i <= bot-n; i++) {
699 temp = term.line[i];
700 term.line[i] = term.line[i+n];
701 term.line[i+n] = temp;
702 }
703
704 - if (term.scr == 0)
705 - selscroll(orig, -n);
706 + if (sel.ob.x != -1 && sel.alt == alt) {
707 + if (!savehist) {
708 + selscroll(top, bot, -n);
709 + } else if (s > 0) {
710 + selmove(-s);
711 + if (-term.scr + sel.nb.y < -term.histf)
712 + selremove();
713 + }
714 + }
715 }
716
717 void
718 -selscroll(int orig, int n)
719 +selmove(int n)
720 {
721 - if (sel.ob.x == -1)
722 - return;
723 + sel.ob.y += n, sel.nb.y += n;
724 + sel.oe.y += n, sel.ne.y += n;
725 +}
726 +
727 +void
728 +selscroll(int top, int bot, int n)
729 +{
730 + /* turn absolute coordinates into relative */
731 + top += term.scr, bot += term.scr;
732
733 - if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig…
734 + if (BETWEEN(sel.nb.y, top, bot) != BETWEEN(sel.ne.y, top, bot))…
735 selclear();
736 - } else if (BETWEEN(sel.nb.y, orig, term.bot)) {
737 - sel.ob.y += n;
738 - sel.oe.y += n;
739 - if (sel.ob.y < term.top || sel.ob.y > term.bot ||
740 - sel.oe.y < term.top || sel.oe.y > term.bot) {
741 + } else if (BETWEEN(sel.nb.y, top, bot)) {
742 + selmove(n);
743 + if (sel.nb.y < top || sel.ne.y > bot)
744 selclear();
745 - } else {
746 - selnormalize();
747 - }
748 }
749 }
750
751 @@ -1182,7 +1345,7 @@ tnewline(int first_col)
752 int y = term.c.y;
753
754 if (y == term.bot) {
755 - tscrollup(term.top, 1, 1);
756 + tscrollup(term.top, term.bot, 1, SCROLL_SAVEHIST);
757 } else {
758 y++;
759 }
760 @@ -1272,89 +1435,93 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
761 } else if (term.line[y][x].mode & ATTR_WDUMMY) {
762 term.line[y][x-1].u = ' ';
763 term.line[y][x-1].mode &= ~ATTR_WIDE;
764 - }
765 + }
766
767 term.dirty[y] = 1;
768 term.line[y][x] = *attr;
769 term.line[y][x].u = u;
770 + term.line[y][x].mode |= ATTR_SET;
771 }
772
773 void
774 -tclearregion(int x1, int y1, int x2, int y2)
775 +tclearglyph(Glyph *gp, int usecurattr)
776 {
777 - int x, y, temp;
778 - Glyph *gp;
779 + if (usecurattr) {
780 + gp->fg = term.c.attr.fg;
781 + gp->bg = term.c.attr.bg;
782 + } else {
783 + gp->fg = defaultfg;
784 + gp->bg = defaultbg;
785 + }
786 + gp->mode = ATTR_NULL;
787 + gp->u = ' ';
788 +}
789
790 - if (x1 > x2)
791 - temp = x1, x1 = x2, x2 = temp;
792 - if (y1 > y2)
793 - temp = y1, y1 = y2, y2 = temp;
794 +void
795 +tclearregion(int x1, int y1, int x2, int y2, int usecurattr)
796 +{
797 + int x, y;
798
799 - LIMIT(x1, 0, term.col-1);
800 - LIMIT(x2, 0, term.col-1);
801 - LIMIT(y1, 0, term.row-1);
802 - LIMIT(y2, 0, term.row-1);
803 + /* regionselected() takes relative coordinates */
804 + if (regionselected(x1+term.scr, y1+term.scr, x2+term.scr, y2+te…
805 + selremove();
806
807 for (y = y1; y <= y2; y++) {
808 term.dirty[y] = 1;
809 - for (x = x1; x <= x2; x++) {
810 - gp = &term.line[y][x];
811 - if (selected(x, y))
812 - selclear();
813 - gp->fg = term.c.attr.fg;
814 - gp->bg = term.c.attr.bg;
815 - gp->mode = 0;
816 - gp->u = ' ';
817 - }
818 + for (x = x1; x <= x2; x++)
819 + tclearglyph(&term.line[y][x], usecurattr);
820 }
821 }
822
823 void
824 tdeletechar(int n)
825 {
826 - int dst, src, size;
827 - Glyph *line;
828 -
829 - LIMIT(n, 0, term.col - term.c.x);
830 + int src, dst, size;
831 + Line line;
832
833 + if (n <= 0)
834 + return;
835 dst = term.c.x;
836 - src = term.c.x + n;
837 + src = MIN(term.c.x + n, term.col);
838 size = term.col - src;
839 - line = term.line[term.c.y];
840 -
841 - memmove(&line[dst], &line[src], size * sizeof(Glyph));
842 - tclearregion(term.col-n, term.c.y, term.col-1, term.c.y);
843 + if (size > 0) { /* otherwise src would point beyond the array
844 + https://stackoverflow.com/questions/29844298…
845 + line = term.line[term.c.y];
846 + memmove(&line[dst], &line[src], size * sizeof(Glyph));
847 + }
848 + tclearregion(dst + size, term.c.y, term.col - 1, term.c.y, 1);
849 }
850
851 void
852 tinsertblank(int n)
853 {
854 - int dst, src, size;
855 - Glyph *line;
856 + int src, dst, size;
857 + Line line;
858
859 - LIMIT(n, 0, term.col - term.c.x);
860 -
861 - dst = term.c.x + n;
862 + if (n <= 0)
863 + return;
864 + dst = MIN(term.c.x + n, term.col);
865 src = term.c.x;
866 size = term.col - dst;
867 - line = term.line[term.c.y];
868 -
869 - memmove(&line[dst], &line[src], size * sizeof(Glyph));
870 - tclearregion(src, term.c.y, dst - 1, term.c.y);
871 + if (size > 0) { /* otherwise dst would point beyond the array */
872 + line = term.line[term.c.y];
873 + memmove(&line[dst], &line[src], size * sizeof(Glyph));
874 + }
875 + tclearregion(src, term.c.y, dst - 1, term.c.y, 1);
876 }
877
878 void
879 tinsertblankline(int n)
880 {
881 if (BETWEEN(term.c.y, term.top, term.bot))
882 - tscrolldown(term.c.y, n, 0);
883 + tscrolldown(term.c.y, n);
884 }
885
886 void
887 tdeleteline(int n)
888 {
889 if (BETWEEN(term.c.y, term.top, term.bot))
890 - tscrollup(term.c.y, n, 0);
891 + tscrollup(term.c.y, term.bot, n, SCROLL_NOSAVEHIST);
892 }
893
894 int32_t
895 @@ -1528,7 +1695,7 @@ tsetscroll(int t, int b)
896 void
897 tsetmode(int priv, int set, const int *args, int narg)
898 {
899 - int alt; const int *lim;
900 + const int *lim;
901
902 for (lim = args + narg; args < lim; ++args) {
903 if (priv) {
904 @@ -1589,25 +1756,18 @@ tsetmode(int priv, int set, const int *args, int…
905 xsetmode(set, MODE_8BIT);
906 break;
907 case 1049: /* swap screen & set/restore cursor …
908 - if (!allowaltscreen)
909 - break;
910 - tcursor((set) ? CURSOR_SAVE : CURSOR_LO…
911 - /* FALLTHROUGH */
912 case 47: /* swap screen */
913 - case 1047:
914 + case 1047: /* swap screen, clearing alternate s…
915 if (!allowaltscreen)
916 break;
917 - alt = IS_SET(MODE_ALTSCREEN);
918 - if (alt) {
919 - tclearregion(0, 0, term.col-1,
920 - term.row-1);
921 - }
922 - if (set ^ alt) /* set is always 1 or 0 …
923 - tswapscreen();
924 - if (*args != 1049)
925 - break;
926 - /* FALLTHROUGH */
927 + if (set)
928 + tloadaltscreen(*args == 1049, *…
929 + else
930 + tloaddefscreen(*args == 1047, *…
931 + break;
932 case 1048:
933 + if (!allowaltscreen)
934 + break;
935 tcursor((set) ? CURSOR_SAVE : CURSOR_LO…
936 break;
937 case 2004: /* 2004: bracketed paste mode */
938 @@ -1659,7 +1819,7 @@ void
939 csihandle(void)
940 {
941 char buf[40];
942 - int len;
943 + int n, x;
944
945 switch (csiescseq.mode[0]) {
946 default:
947 @@ -1757,20 +1917,30 @@ csihandle(void)
948 case 'J': /* ED -- Clear screen */
949 switch (csiescseq.arg[0]) {
950 case 0: /* below */
951 - tclearregion(term.c.x, term.c.y, term.col-1, te…
952 + tclearregion(term.c.x, term.c.y, term.col-1, te…
953 if (term.c.y < term.row-1) {
954 - tclearregion(0, term.c.y+1, term.col-1,
955 - term.row-1);
956 + tclearregion(0, term.c.y+1, term.col-1,…
957 }
958 break;
959 case 1: /* above */
960 - if (term.c.y > 1)
961 - tclearregion(0, 0, term.col-1, term.c.y…
962 - tclearregion(0, term.c.y, term.c.x, term.c.y);
963 + if (term.c.y >= 1)
964 + tclearregion(0, 0, term.col-1, term.c.y…
965 + tclearregion(0, term.c.y, term.c.x, term.c.y, 1…
966 break;
967 case 2: /* all */
968 - tclearregion(0, 0, term.col-1, term.row-1);
969 - break;
970 + if (IS_SET(MODE_ALTSCREEN)) {
971 + tclearregion(0, 0, term.col-1, term.row-1, 1);
972 + break;
973 + }
974 + /* vte does this:
975 + tscrollup(0, term.row-1, term.row, SCROLL_SAVEH…
976 +
977 + /* alacritty does this: */
978 + for (n = term.row-1; n >= 0 && tlinelen(term.li…
979 + if (n >= 0)
980 + tscrollup(0, term.row-1, n+1, SCROLL_SA…
981 + tscrollup(0, term.row-1, term.row-n-1, SCROLL_N…
982 + break;
983 default:
984 goto unknown;
985 }
986 @@ -1778,24 +1948,24 @@ csihandle(void)
987 case 'K': /* EL -- Clear line */
988 switch (csiescseq.arg[0]) {
989 case 0: /* right */
990 - tclearregion(term.c.x, term.c.y, term.col-1,
991 - term.c.y);
992 + tclearregion(term.c.x, term.c.y, term.col-1, te…
993 break;
994 case 1: /* left */
995 - tclearregion(0, term.c.y, term.c.x, term.c.y);
996 + tclearregion(0, term.c.y, term.c.x, term.c.y, 1…
997 break;
998 case 2: /* all */
999 - tclearregion(0, term.c.y, term.col-1, term.c.y);
1000 + tclearregion(0, term.c.y, term.col-1, term.c.y,…
1001 break;
1002 }
1003 break;
1004 case 'S': /* SU -- Scroll <n> line up */
1005 DEFAULT(csiescseq.arg[0], 1);
1006 - tscrollup(term.top, csiescseq.arg[0], 0);
1007 + /* xterm, urxvt, alacritty save this in history */
1008 + tscrollup(term.top, term.bot, csiescseq.arg[0], SCROLL_…
1009 break;
1010 case 'T': /* SD -- Scroll <n> line down */
1011 DEFAULT(csiescseq.arg[0], 1);
1012 - tscrolldown(term.top, csiescseq.arg[0], 0);
1013 + tscrolldown(term.top, csiescseq.arg[0]);
1014 break;
1015 case 'L': /* IL -- Insert <n> blank lines */
1016 DEFAULT(csiescseq.arg[0], 1);
1017 @@ -1809,9 +1979,11 @@ csihandle(void)
1018 tdeleteline(csiescseq.arg[0]);
1019 break;
1020 case 'X': /* ECH -- Erase <n> char */
1021 + if (csiescseq.arg[0] < 0)
1022 + return;
1023 DEFAULT(csiescseq.arg[0], 1);
1024 - tclearregion(term.c.x, term.c.y,
1025 - term.c.x + csiescseq.arg[0] - 1, term.c…
1026 + x = MIN(term.c.x + csiescseq.arg[0], term.col) - 1;
1027 + tclearregion(term.c.x, term.c.y, x, term.c.y, 1);
1028 break;
1029 case 'P': /* DCH -- Delete <n> char */
1030 DEFAULT(csiescseq.arg[0], 1);
1031 @@ -1837,9 +2009,9 @@ csihandle(void)
1032 ttywrite("\033[0n", sizeof("\033[0n") - 1, 0);
1033 break;
1034 case 6: /* Report Cursor Position (CPR) "<row>;<column>…
1035 - len = snprintf(buf, sizeof(buf), "\033[%i;%iR",
1036 + n = snprintf(buf, sizeof(buf), "\033[%i;%iR",
1037 term.c.y+1, term.c.x+1);
1038 - ttywrite(buf, len, 0);
1039 + ttywrite(buf, n, 0);
1040 break;
1041 default:
1042 goto unknown;
1043 @@ -2137,16 +2309,8 @@ tdumpsel(void)
1044 void
1045 tdumpline(int n)
1046 {
1047 - char buf[UTF_SIZ];
1048 - const Glyph *bp, *end;
1049 -
1050 - bp = &term.line[n][0];
1051 - end = &bp[MIN(tlinelen(n), term.col) - 1];
1052 - if (bp != end || bp->u != ' ') {
1053 - for ( ; bp <= end; ++bp)
1054 - tprinter(buf, utf8encode(bp->u, buf));
1055 - }
1056 - tprinter("\n", 1);
1057 + char str[(term.col + 1) * UTF_SIZ];
1058 + tprinter(str, tgetline(str, &term.line[n][0]));
1059 }
1060
1061 void
1062 @@ -2367,7 +2531,7 @@ eschandle(uchar ascii)
1063 return 0;
1064 case 'D': /* IND -- Linefeed */
1065 if (term.c.y == term.bot) {
1066 - tscrollup(term.top, 1, 1);
1067 + tscrollup(term.top, term.bot, 1, SCROLL_SAVEHIS…
1068 } else {
1069 tmoveto(term.c.x, term.c.y+1);
1070 }
1071 @@ -2380,7 +2544,7 @@ eschandle(uchar ascii)
1072 break;
1073 case 'M': /* RI -- Reverse index */
1074 if (term.c.y == term.top) {
1075 - tscrolldown(term.top, 1, 1);
1076 + tscrolldown(term.top, 1);
1077 } else {
1078 tmoveto(term.c.x, term.c.y-1);
1079 }
1080 @@ -2523,7 +2687,8 @@ check_control_code:
1081 */
1082 return;
1083 }
1084 - if (selected(term.c.x, term.c.y))
1085 + /* selected() takes relative coordinates */
1086 + if (selected(term.c.x + term.scr, term.c.y + term.scr))
1087 selclear();
1088
1089 gp = &term.line[term.c.y][term.c.x];
1090 @@ -2558,6 +2723,7 @@ check_control_code:
1091 if (term.c.x+width < term.col) {
1092 tmoveto(term.c.x+width, term.c.y);
1093 } else {
1094 + term.wrapcwidth[IS_SET(MODE_ALTSCREEN)] = width;
1095 term.c.state |= CURSOR_WRAPNEXT;
1096 }
1097 }
1098 @@ -2595,93 +2761,275 @@ twrite(const char *buf, int buflen, int show_ct…
1099 }
1100
1101 void
1102 -tresize(int col, int row)
1103 +treflow(int col, int row)
1104 {
1105 int i, j;
1106 - int minrow = MIN(row, term.row);
1107 - int mincol = MIN(col, term.col);
1108 - int *bp;
1109 - TCursor c;
1110 -
1111 - if (col < 1 || row < 1) {
1112 - fprintf(stderr,
1113 - "tresize: error resizing to %dx%d\n", col, row);
1114 - return;
1115 + int oce, nce, bot, scr;
1116 + int ox = 0, oy = -term.histf, nx = 0, ny = -1, len;
1117 + int cy = -1; /* proxy for new y coordinate of cursor */
1118 + int nlines;
1119 + Line *buf, line;
1120 +
1121 + /* y coordinate of cursor line end */
1122 + for (oce = term.c.y; oce < term.row - 1 &&
1123 + tiswrapped(term.line[oce]); oce++);
1124 +
1125 + nlines = term.histf + oce + 1;
1126 + if (col < term.col) {
1127 + /* each line can take this many lines after reflow */
1128 + j = (term.col + col - 1) / col;
1129 + nlines = j * nlines;
1130 + if (nlines > HISTSIZE + RESIZEBUFFER + row) {
1131 + nlines = HISTSIZE + RESIZEBUFFER + row;
1132 + oy = -(nlines / j - oce - 1);
1133 + }
1134 }
1135 + buf = xmalloc(nlines * sizeof(Line));
1136 + do {
1137 + if (!nx)
1138 + buf[++ny] = xmalloc(col * sizeof(Glyph));
1139 + if (!ox) {
1140 + line = TLINEABS(oy);
1141 + len = tlinelen(line);
1142 + }
1143 + if (oy == term.c.y) {
1144 + if (!ox)
1145 + len = MAX(len, term.c.x + 1);
1146 + /* update cursor */
1147 + if (cy < 0 && term.c.x - ox < col - nx) {
1148 + term.c.x = nx + term.c.x - ox, cy = ny;
1149 + UPDATEWRAPNEXT(0, col);
1150 + }
1151 + }
1152 + /* get reflowed lines in buf */
1153 + if (col - nx > len - ox) {
1154 + memcpy(&buf[ny][nx], &line[ox], (len-ox) * size…
1155 + nx += len - ox;
1156 + if (len == 0 || !(line[len - 1].mode & ATTR_WRA…
1157 + for (j = nx; j < col; j++)
1158 + tclearglyph(&buf[ny][j], 0);
1159 + nx = 0;
1160 + } else if (nx > 0) {
1161 + buf[ny][nx - 1].mode &= ~ATTR_WRAP;
1162 + }
1163 + ox = 0, oy++;
1164 + } else if (col - nx == len - ox) {
1165 + memcpy(&buf[ny][nx], &line[ox], (col-nx) * size…
1166 + ox = 0, oy++, nx = 0;
1167 + } else/* if (col - nx < len - ox) */ {
1168 + memcpy(&buf[ny][nx], &line[ox], (col-nx) * size…
1169 + ox += col - nx;
1170 + buf[ny][col - 1].mode |= ATTR_WRAP;
1171 + nx = 0;
1172 + }
1173 + } while (oy <= oce);
1174 + if (nx)
1175 + for (j = nx; j < col; j++)
1176 + tclearglyph(&buf[ny][j], 0);
1177
1178 - /*
1179 - * slide screen to keep cursor where we expect it -
1180 - * tscrollup would work here, but we can optimize to
1181 - * memmove because we're freeing the earlier lines
1182 - */
1183 - for (i = 0; i <= term.c.y - row; i++) {
1184 + /* free extra lines */
1185 + for (i = row; i < term.row; i++)
1186 free(term.line[i]);
1187 - free(term.alt[i]);
1188 + /* resize to new height */
1189 + term.line = xrealloc(term.line, row * sizeof(Line));
1190 +
1191 + bot = MIN(ny, row - 1);
1192 + scr = MAX(row - term.row, 0);
1193 + /* update y coordinate of cursor line end */
1194 + nce = MIN(oce + scr, bot);
1195 + /* update cursor y coordinate */
1196 + term.c.y = nce - (ny - cy);
1197 + if (term.c.y < 0) {
1198 + j = nce, nce = MIN(nce + -term.c.y, bot);
1199 + term.c.y += nce - j;
1200 + while (term.c.y < 0) {
1201 + free(buf[ny--]);
1202 + term.c.y++;
1203 + }
1204 }
1205 - /* ensure that both src and dst are not NULL */
1206 - if (i > 0) {
1207 - memmove(term.line, term.line + i, row * sizeof(Line));
1208 - memmove(term.alt, term.alt + i, row * sizeof(Line));
1209 + /* allocate new rows */
1210 + for (i = row - 1; i > nce; i--) {
1211 + term.line[i] = xmalloc(col * sizeof(Glyph));
1212 + for (j = 0; j < col; j++)
1213 + tclearglyph(&term.line[i][j], 0);
1214 }
1215 - for (i += row; i < term.row; i++) {
1216 + /* fill visible area */
1217 + for (/*i = nce */; i >= term.row; i--, ny--)
1218 + term.line[i] = buf[ny];
1219 + for (/*i = term.row - 1 */; i >= 0; i--, ny--) {
1220 free(term.line[i]);
1221 - free(term.alt[i]);
1222 + term.line[i] = buf[ny];
1223 + }
1224 + /* fill lines in history buffer and update term.histf */
1225 + for (/*i = -1 */; ny >= 0 && i >= -HISTSIZE; i--, ny--) {
1226 + j = (term.histi + i + 1 + HISTSIZE) % HISTSIZE;
1227 + free(term.hist[j]);
1228 + term.hist[j] = buf[ny];
1229 }
1230 + term.histf = -i - 1;
1231 + term.scr = MIN(term.scr, term.histf);
1232 + /* resize rest of the history lines */
1233 + for (/*i = -term.histf - 1 */; i >= -HISTSIZE; i--) {
1234 + j = (term.histi + i + 1 + HISTSIZE) % HISTSIZE;
1235 + term.hist[j] = xrealloc(term.hist[j], col * sizeof(Glyp…
1236 + }
1237 + free(buf);
1238 +}
1239
1240 - /* resize to new height */
1241 - term.line = xrealloc(term.line, row * sizeof(Line));
1242 - term.alt = xrealloc(term.alt, row * sizeof(Line));
1243 - term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
1244 - term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
1245 +void
1246 +rscrolldown(int n)
1247 +{
1248 + int i;
1249 + Line temp;
1250
1251 - for (i = 0; i < HISTSIZE; i++) {
1252 - term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyp…
1253 - for (j = mincol; j < col; j++) {
1254 - term.hist[i][j] = term.c.attr;
1255 - term.hist[i][j].u = ' ';
1256 - }
1257 - }
1258 + /* can never be true as of now
1259 + if (IS_SET(MODE_ALTSCREEN))
1260 + return; */
1261
1262 - /* resize each row to new width, zero-pad if needed */
1263 - for (i = 0; i < minrow; i++) {
1264 - term.line[i] = xrealloc(term.line[i], col * sizeof(Glyp…
1265 - term.alt[i] = xrealloc(term.alt[i], col * sizeof(Glyp…
1266 - }
1267 + if ((n = MIN(n, term.histf)) <= 0)
1268 + return;
1269
1270 - /* allocate any new rows */
1271 - for (/* i = minrow */; i < row; i++) {
1272 - term.line[i] = xmalloc(col * sizeof(Glyph));
1273 - term.alt[i] = xmalloc(col * sizeof(Glyph));
1274 + for (i = term.c.y + n; i >= n; i--) {
1275 + temp = term.line[i];
1276 + term.line[i] = term.line[i-n];
1277 + term.line[i-n] = temp;
1278 }
1279 + for (/*i = n - 1 */; i >= 0; i--) {
1280 + temp = term.line[i];
1281 + term.line[i] = term.hist[term.histi];
1282 + term.hist[term.histi] = temp;
1283 + term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE;
1284 + }
1285 + term.c.y += n;
1286 + term.histf -= n;
1287 + if ((i = term.scr - n) >= 0) {
1288 + term.scr = i;
1289 + } else {
1290 + term.scr = 0;
1291 + if (sel.ob.x != -1 && !sel.alt)
1292 + selmove(-i);
1293 + }
1294 +}
1295 +
1296 +void
1297 +tresize(int col, int row)
1298 +{
1299 + int *bp;
1300 +
1301 + /* col and row are always MAX(_, 1)
1302 + if (col < 1 || row < 1) {
1303 + fprintf(stderr, "tresize: error resizing to %dx%d\n", c…
1304 + return;
1305 + } */
1306 +
1307 + term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
1308 + term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
1309 if (col > term.col) {
1310 bp = term.tabs + term.col;
1311 -
1312 memset(bp, 0, sizeof(*term.tabs) * (col - term.col));
1313 while (--bp > term.tabs && !*bp)
1314 /* nothing */ ;
1315 for (bp += tabspaces; bp < term.tabs + col; bp += tabsp…
1316 *bp = 1;
1317 }
1318 - /* update terminal size */
1319 - term.col = col;
1320 - term.row = row;
1321 - /* reset scrolling region */
1322 - tsetscroll(0, row-1);
1323 - /* make use of the LIMIT in tmoveto */
1324 - tmoveto(term.c.x, term.c.y);
1325 - /* Clearing both screens (it makes dirty all lines) */
1326 - c = term.c;
1327 - for (i = 0; i < 2; i++) {
1328 - if (mincol < col && 0 < minrow) {
1329 - tclearregion(mincol, 0, col - 1, minrow - 1);
1330 +
1331 + if (IS_SET(MODE_ALTSCREEN))
1332 + tresizealt(col, row);
1333 + else
1334 + tresizedef(col, row);
1335 +}
1336 +
1337 +void
1338 +tresizedef(int col, int row)
1339 +{
1340 + int i, j;
1341 +
1342 + /* return if dimensions haven't changed */
1343 + if (term.col == col && term.row == row) {
1344 + tfulldirt();
1345 + return;
1346 + }
1347 + if (col != term.col) {
1348 + if (!sel.alt)
1349 + selremove();
1350 + treflow(col, row);
1351 + } else {
1352 + /* slide screen up if otherwise cursor would get out of…
1353 + if (term.c.y >= row) {
1354 + tscrollup(0, term.row - 1, term.c.y - row + 1, …
1355 + term.c.y = row - 1;
1356 }
1357 - if (0 < col && minrow < row) {
1358 - tclearregion(0, minrow, col - 1, row - 1);
1359 + for (i = row; i < term.row; i++)
1360 + free(term.line[i]);
1361 +
1362 + /* resize to new height */
1363 + term.line = xrealloc(term.line, row * sizeof(Line));
1364 + /* allocate any new rows */
1365 + for (i = term.row; i < row; i++) {
1366 + term.line[i] = xmalloc(col * sizeof(Glyph));
1367 + for (j = 0; j < col; j++)
1368 + tclearglyph(&term.line[i][j], 0);
1369 }
1370 - tswapscreen();
1371 - tcursor(CURSOR_LOAD);
1372 + /* scroll down as much as height has increased */
1373 + rscrolldown(row - term.row);
1374 + }
1375 + /* update terminal size */
1376 + term.col = col, term.row = row;
1377 + /* reset scrolling region */
1378 + term.top = 0, term.bot = row - 1;
1379 + /* dirty all lines */
1380 + tfulldirt();
1381 +}
1382 +
1383 +void
1384 +tresizealt(int col, int row)
1385 +{
1386 + int i, j;
1387 +
1388 + /* return if dimensions haven't changed */
1389 + if (term.col == col && term.row == row) {
1390 + tfulldirt();
1391 + return;
1392 }
1393 - term.c = c;
1394 + if (sel.alt)
1395 + selremove();
1396 + /* slide screen up if otherwise cursor would get out of the scr…
1397 + for (i = 0; i <= term.c.y - row; i++)
1398 + free(term.line[i]);
1399 + if (i > 0) {
1400 + /* ensure that both src and dst are not NULL */
1401 + memmove(term.line, term.line + i, row * sizeof(Line));
1402 + term.c.y = row - 1;
1403 + }
1404 + for (i += row; i < term.row; i++)
1405 + free(term.line[i]);
1406 + /* resize to new height */
1407 + term.line = xrealloc(term.line, row * sizeof(Line));
1408 + /* resize to new width */
1409 + for (i = 0; i < MIN(row, term.row); i++) {
1410 + term.line[i] = xrealloc(term.line[i], col * sizeof(Glyp…
1411 + for (j = term.col; j < col; j++)
1412 + tclearglyph(&term.line[i][j], 0);
1413 + }
1414 + /* allocate any new rows */
1415 + for (/*i = MIN(row, term.row) */; i < row; i++) {
1416 + term.line[i] = xmalloc(col * sizeof(Glyph));
1417 + for (j = 0; j < col; j++)
1418 + tclearglyph(&term.line[i][j], 0);
1419 + }
1420 + /* update cursor */
1421 + if (term.c.x >= col) {
1422 + term.c.state &= ~CURSOR_WRAPNEXT;
1423 + term.c.x = col - 1;
1424 + } else {
1425 + UPDATEWRAPNEXT(1, col);
1426 + }
1427 + /* update terminal size */
1428 + term.col = col, term.row = row;
1429 + /* reset scrolling region */
1430 + term.top = 0, term.bot = row - 1;
1431 + /* dirty all lines */
1432 + tfulldirt();
1433 }
1434
1435 void
1436 @@ -2721,9 +3069,8 @@ draw(void)
1437 cx--;
1438
1439 drawregion(0, 0, term.col, term.row);
1440 - if (term.scr == 0)
1441 - xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
1442 - term.ocx, term.ocy, term.line[term.ocy]…
1443 + xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
1444 + term.ocx, term.ocy, term.line[term.ocy][term.oc…
1445 term.ocx = cx;
1446 term.ocy = term.c.y;
1447 xfinishdraw();
1448 diff --git a/st.h b/st.h
1449 index 818a6f8..514ec08 100644
1450 --- a/st.h
1451 +++ b/st.h
1452 @@ -22,17 +22,19 @@
1453
1454 enum glyph_attribute {
1455 ATTR_NULL = 0,
1456 - ATTR_BOLD = 1 << 0,
1457 - ATTR_FAINT = 1 << 1,
1458 - ATTR_ITALIC = 1 << 2,
1459 - ATTR_UNDERLINE = 1 << 3,
1460 - ATTR_BLINK = 1 << 4,
1461 - ATTR_REVERSE = 1 << 5,
1462 - ATTR_INVISIBLE = 1 << 6,
1463 - ATTR_STRUCK = 1 << 7,
1464 - ATTR_WRAP = 1 << 8,
1465 - ATTR_WIDE = 1 << 9,
1466 - ATTR_WDUMMY = 1 << 10,
1467 + ATTR_SET = 1 << 0,
1468 + ATTR_BOLD = 1 << 1,
1469 + ATTR_FAINT = 1 << 2,
1470 + ATTR_ITALIC = 1 << 3,
1471 + ATTR_UNDERLINE = 1 << 4,
1472 + ATTR_BLINK = 1 << 5,
1473 + ATTR_REVERSE = 1 << 6,
1474 + ATTR_INVISIBLE = 1 << 7,
1475 + ATTR_STRUCK = 1 << 8,
1476 + ATTR_WRAP = 1 << 9,
1477 + ATTR_WIDE = 1 << 10,
1478 + ATTR_WDUMMY = 1 << 11,
1479 + ATTR_SELECTED = 1 << 12,
1480 ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
1481 };
1482
1483 @@ -90,6 +92,7 @@ void toggleprinter(const Arg *);
1484
1485 int tattrset(int);
1486 void tnew(int, int);
1487 +int tisaltscreen(void);
1488 void tresize(int, int);
1489 void tsetdirtattr(int);
1490 void ttyhangup(void);
1491 --
1492 2.40.1
1493
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.