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