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