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); |