| st-scrollback-reflow-0.9.diff - sites - public wiki contents of suckless.org | |
| git clone git://git.suckless.org/sites | |
| Log | |
| Files | |
| Refs | |
| --- | |
| st-scrollback-reflow-0.9.diff (37402B) | |
| --- | |
| 1 diff --git a/st.c b/st.c | |
| 2 index 79ee9ba..5170cd4 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 - | |
| 845 - LIMIT(n, 0, term.col - term.c.x); | |
| 846 + int src, dst, size; | |
| 847 + Line line; | |
| 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 diff --git a/st.h b/st.h | |
| 1425 index 818a6f8..514ec08 100644 | |
| 1426 --- a/st.h | |
| 1427 +++ b/st.h | |
| 1428 @@ -22,17 +22,19 @@ | |
| 1429 | |
| 1430 enum glyph_attribute { | |
| 1431 ATTR_NULL = 0, | |
| 1432 - ATTR_BOLD = 1 << 0, | |
| 1433 - ATTR_FAINT = 1 << 1, | |
| 1434 - ATTR_ITALIC = 1 << 2, | |
| 1435 - ATTR_UNDERLINE = 1 << 3, | |
| 1436 - ATTR_BLINK = 1 << 4, | |
| 1437 - ATTR_REVERSE = 1 << 5, | |
| 1438 - ATTR_INVISIBLE = 1 << 6, | |
| 1439 - ATTR_STRUCK = 1 << 7, | |
| 1440 - ATTR_WRAP = 1 << 8, | |
| 1441 - ATTR_WIDE = 1 << 9, | |
| 1442 - ATTR_WDUMMY = 1 << 10, | |
| 1443 + ATTR_SET = 1 << 0, | |
| 1444 + ATTR_BOLD = 1 << 1, | |
| 1445 + ATTR_FAINT = 1 << 2, | |
| 1446 + ATTR_ITALIC = 1 << 3, | |
| 1447 + ATTR_UNDERLINE = 1 << 4, | |
| 1448 + ATTR_BLINK = 1 << 5, | |
| 1449 + ATTR_REVERSE = 1 << 6, | |
| 1450 + ATTR_INVISIBLE = 1 << 7, | |
| 1451 + ATTR_STRUCK = 1 << 8, | |
| 1452 + ATTR_WRAP = 1 << 9, | |
| 1453 + ATTR_WIDE = 1 << 10, | |
| 1454 + ATTR_WDUMMY = 1 << 11, | |
| 1455 + ATTR_SELECTED = 1 << 12, | |
| 1456 ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, | |
| 1457 }; | |
| 1458 | |
| 1459 @@ -90,6 +92,7 @@ void toggleprinter(const Arg *); | |
| 1460 | |
| 1461 int tattrset(int); | |
| 1462 void tnew(int, int); | |
| 1463 +int tisaltscreen(void); | |
| 1464 void tresize(int, int); | |
| 1465 void tsetdirtattr(int); | |
| 1466 void ttyhangup(void); |