1 /* $OpenBSD: screen-write.c,v 1.85 2016/01/31 14:11:49 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 21 #include <stdlib.h> 22 #include <string.h> 23 24 #include "tmux.h" 25 26 void screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *, int); 27 void screen_write_overwrite(struct screen_write_ctx *, u_int); 28 int screen_write_combine(struct screen_write_ctx *, 29 const struct utf8_data *); 30 31 /* Initialise writing with a window. */ 32 void 33 screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp, 34 struct screen *s) 35 { 36 ctx->wp = wp; 37 if (wp != NULL && s == NULL) 38 ctx->s = wp->screen; 39 else 40 ctx->s = s; 41 } 42 43 /* Finish writing. */ 44 void 45 screen_write_stop(__unused struct screen_write_ctx *ctx) 46 { 47 } 48 49 /* Reset screen state. */ 50 void 51 screen_write_reset(struct screen_write_ctx *ctx) 52 { 53 struct screen *s = ctx->s; 54 55 screen_reset_tabs(s); 56 screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1); 57 58 s->mode &= ~(MODE_INSERT|MODE_KCURSOR|MODE_KKEYPAD|MODE_FOCUSON); 59 s->mode &= ~(ALL_MOUSE_MODES|MODE_MOUSE_UTF8|MODE_MOUSE_SGR); 60 61 screen_write_clearscreen(ctx); 62 screen_write_cursormove(ctx, 0, 0); 63 } 64 65 /* Write character. */ 66 void 67 screen_write_putc(struct screen_write_ctx *ctx, struct grid_cell *gc, 68 u_char ch) 69 { 70 utf8_set(&gc->data, ch); 71 screen_write_cell(ctx, gc); 72 } 73 74 /* Calculate string length, with embedded formatting. */ 75 size_t 76 screen_write_cstrlen(const char *fmt, ...) 77 { 78 va_list ap; 79 char *msg, *msg2, *ptr, *ptr2; 80 size_t size; 81 82 va_start(ap, fmt); 83 xvasprintf(&msg, fmt, ap); 84 va_end(ap); 85 msg2 = xmalloc(strlen(msg) + 1); 86 87 ptr = msg; 88 ptr2 = msg2; 89 while (*ptr != '\0') { 90 if (ptr[0] == '#' && ptr[1] == '[') { 91 while (*ptr != ']' && *ptr != '\0') 92 ptr++; 93 if (*ptr == ']') 94 ptr++; 95 continue; 96 } 97 *ptr2++ = *ptr++; 98 } 99 *ptr2 = '\0'; 100 101 size = screen_write_strlen("%s", msg2); 102 103 free(msg); 104 free(msg2); 105 106 return (size); 107 } 108 109 /* Calculate string length. */ 110 size_t 111 screen_write_strlen(const char *fmt, ...) 112 { 113 va_list ap; 114 char *msg; 115 struct utf8_data ud; 116 u_char *ptr; 117 size_t left, size = 0; 118 enum utf8_state more; 119 120 va_start(ap, fmt); 121 xvasprintf(&msg, fmt, ap); 122 va_end(ap); 123 124 ptr = msg; 125 while (*ptr != '\0') { 126 if (*ptr > 0x7f && utf8_open(&ud, *ptr) == UTF8_MORE) { 127 ptr++; 128 129 left = strlen(ptr); 130 if (left < (size_t)ud.size - 1) 131 break; 132 while ((more = utf8_append(&ud, *ptr)) == UTF8_MORE) 133 ptr++; 134 ptr++; 135 136 if (more == UTF8_DONE) 137 size += ud.width; 138 } else { 139 if (*ptr > 0x1f && *ptr < 0x7f) 140 size++; 141 ptr++; 142 } 143 } 144 145 free(msg); 146 return (size); 147 } 148 149 /* Write simple string (no UTF-8 or maximum length). */ 150 void 151 screen_write_puts(struct screen_write_ctx *ctx, struct grid_cell *gc, 152 const char *fmt, ...) 153 { 154 va_list ap; 155 156 va_start(ap, fmt); 157 screen_write_vnputs(ctx, -1, gc, fmt, ap); 158 va_end(ap); 159 } 160 161 /* Write string with length limit (-1 for unlimited). */ 162 void 163 screen_write_nputs(struct screen_write_ctx *ctx, ssize_t maxlen, 164 struct grid_cell *gc, const char *fmt, ...) 165 { 166 va_list ap; 167 168 va_start(ap, fmt); 169 screen_write_vnputs(ctx, maxlen, gc, fmt, ap); 170 va_end(ap); 171 } 172 173 void 174 screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen, 175 struct grid_cell *gc, const char *fmt, va_list ap) 176 { 177 char *msg; 178 struct utf8_data ud; 179 u_char *ptr; 180 size_t left, size = 0; 181 enum utf8_state more; 182 183 xvasprintf(&msg, fmt, ap); 184 185 ptr = msg; 186 while (*ptr != '\0') { 187 if (*ptr > 0x7f && utf8_open(&ud, *ptr) == UTF8_MORE) { 188 ptr++; 189 190 left = strlen(ptr); 191 if (left < (size_t)ud.size - 1) 192 break; 193 while ((more = utf8_append(&ud, *ptr)) == UTF8_MORE) 194 ptr++; 195 ptr++; 196 197 if (more == UTF8_DONE) { 198 if (maxlen > 0 && 199 size + ud.width > (size_t) maxlen) { 200 while (size < (size_t) maxlen) { 201 screen_write_putc(ctx, gc, ' '); 202 size++; 203 } 204 break; 205 } 206 size += ud.width; 207 208 utf8_copy(&gc->data, &ud); 209 screen_write_cell(ctx, gc); 210 } 211 } else { 212 if (maxlen > 0 && size + 1 > (size_t) maxlen) 213 break; 214 215 if (*ptr == '\001') 216 gc->attr ^= GRID_ATTR_CHARSET; 217 else if (*ptr > 0x1f && *ptr < 0x7f) { 218 size++; 219 screen_write_putc(ctx, gc, *ptr); 220 } 221 ptr++; 222 } 223 } 224 225 free(msg); 226 } 227 228 /* Write string, similar to nputs, but with embedded formatting (#[]). */ 229 void 230 screen_write_cnputs(struct screen_write_ctx *ctx, ssize_t maxlen, 231 struct grid_cell *gc, const char *fmt, ...) 232 { 233 struct grid_cell lgc; 234 struct utf8_data ud; 235 va_list ap; 236 char *msg; 237 u_char *ptr, *last; 238 size_t left, size = 0; 239 enum utf8_state more; 240 241 va_start(ap, fmt); 242 xvasprintf(&msg, fmt, ap); 243 va_end(ap); 244 245 memcpy(&lgc, gc, sizeof lgc); 246 247 ptr = msg; 248 while (*ptr != '\0') { 249 if (ptr[0] == '#' && ptr[1] == '[') { 250 ptr += 2; 251 last = ptr + strcspn(ptr, "]"); 252 if (*last == '\0') { 253 /* No ]. Not much point in doing anything. */ 254 break; 255 } 256 *last = '\0'; 257 258 style_parse(gc, &lgc, ptr); 259 ptr = last + 1; 260 continue; 261 } 262 263 if (*ptr > 0x7f && utf8_open(&ud, *ptr) == UTF8_MORE) { 264 ptr++; 265 266 left = strlen(ptr); 267 if (left < (size_t)ud.size - 1) 268 break; 269 while ((more = utf8_append(&ud, *ptr)) == UTF8_MORE) 270 ptr++; 271 ptr++; 272 273 if (more == UTF8_DONE) { 274 if (maxlen > 0 && 275 size + ud.width > (size_t) maxlen) { 276 while (size < (size_t) maxlen) { 277 screen_write_putc(ctx, gc, ' '); 278 size++; 279 } 280 break; 281 } 282 size += ud.width; 283 284 utf8_copy(&lgc.data, &ud); 285 screen_write_cell(ctx, &lgc); 286 } 287 } else { 288 if (maxlen > 0 && size + 1 > (size_t) maxlen) 289 break; 290 291 if (*ptr > 0x1f && *ptr < 0x7f) { 292 size++; 293 screen_write_putc(ctx, &lgc, *ptr); 294 } 295 ptr++; 296 } 297 } 298 299 free(msg); 300 } 301 302 /* Copy from another screen. */ 303 void 304 screen_write_copy(struct screen_write_ctx *ctx, 305 struct screen *src, u_int px, u_int py, u_int nx, u_int ny) 306 { 307 struct screen *s = ctx->s; 308 struct grid *gd = src->grid; 309 struct grid_line *gl; 310 struct grid_cell gc; 311 u_int xx, yy, cx, cy, ax, bx; 312 313 cx = s->cx; 314 cy = s->cy; 315 for (yy = py; yy < py + ny; yy++) { 316 gl = &gd->linedata[yy]; 317 if (yy < gd->hsize + gd->sy) { 318 /* 319 * Find start and end position and copy between 320 * them. Limit to the real end of the line then use a 321 * clear EOL only if copying to the end, otherwise 322 * could overwrite whatever is there already. 323 */ 324 if (px > gl->cellsize) 325 ax = gl->cellsize; 326 else 327 ax = px; 328 if (px + nx == gd->sx && px + nx > gl->cellsize) 329 bx = gl->cellsize; 330 else 331 bx = px + nx; 332 333 for (xx = ax; xx < bx; xx++) { 334 grid_get_cell(gd, xx, yy, &gc); 335 screen_write_cell(ctx, &gc); 336 } 337 if (px + nx == gd->sx && px + nx > gl->cellsize) 338 screen_write_clearendofline(ctx); 339 } else 340 screen_write_clearline(ctx); 341 cy++; 342 screen_write_cursormove(ctx, cx, cy); 343 } 344 } 345 346 /* Set up context for TTY command. */ 347 void 348 screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx, 349 int save_last) 350 { 351 struct screen *s = ctx->s; 352 struct grid *gd = s->grid; 353 struct grid_cell gc; 354 u_int xx; 355 356 ttyctx->wp = ctx->wp; 357 358 ttyctx->ocx = s->cx; 359 ttyctx->ocy = s->cy; 360 361 ttyctx->orlower = s->rlower; 362 ttyctx->orupper = s->rupper; 363 364 if (!save_last) 365 return; 366 367 /* Save the last cell on the screen. */ 368 memcpy(&gc, &grid_default_cell, sizeof gc); 369 for (xx = 1; xx <= screen_size_x(s); xx++) { 370 grid_view_get_cell(gd, screen_size_x(s) - xx, s->cy, &gc); 371 if (~gc.flags & GRID_FLAG_PADDING) 372 break; 373 } 374 ttyctx->last_width = xx; 375 memcpy(&ttyctx->last_cell, &gc, sizeof ttyctx->last_cell); 376 } 377 378 /* Set a mode. */ 379 void 380 screen_write_mode_set(struct screen_write_ctx *ctx, int mode) 381 { 382 struct screen *s = ctx->s; 383 384 s->mode |= mode; 385 } 386 387 /* Clear a mode. */ 388 void 389 screen_write_mode_clear(struct screen_write_ctx *ctx, int mode) 390 { 391 struct screen *s = ctx->s; 392 393 s->mode &= ~mode; 394 } 395 396 /* Cursor up by ny. */ 397 void 398 screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny) 399 { 400 struct screen *s = ctx->s; 401 402 if (ny == 0) 403 ny = 1; 404 405 if (s->cy < s->rupper) { 406 /* Above region. */ 407 if (ny > s->cy) 408 ny = s->cy; 409 } else { 410 /* Below region. */ 411 if (ny > s->cy - s->rupper) 412 ny = s->cy - s->rupper; 413 } 414 if (s->cx == screen_size_x(s)) 415 s->cx--; 416 if (ny == 0) 417 return; 418 419 s->cy -= ny; 420 } 421 422 /* Cursor down by ny. */ 423 void 424 screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny) 425 { 426 struct screen *s = ctx->s; 427 428 if (ny == 0) 429 ny = 1; 430 431 if (s->cy > s->rlower) { 432 /* Below region. */ 433 if (ny > screen_size_y(s) - 1 - s->cy) 434 ny = screen_size_y(s) - 1 - s->cy; 435 } else { 436 /* Above region. */ 437 if (ny > s->rlower - s->cy) 438 ny = s->rlower - s->cy; 439 } 440 if (s->cx == screen_size_x(s)) 441 s->cx--; 442 if (ny == 0) 443 return; 444 445 s->cy += ny; 446 } 447 448 /* Cursor right by nx. */ 449 void 450 screen_write_cursorright(struct screen_write_ctx *ctx, u_int nx) 451 { 452 struct screen *s = ctx->s; 453 454 if (nx == 0) 455 nx = 1; 456 457 if (nx > screen_size_x(s) - 1 - s->cx) 458 nx = screen_size_x(s) - 1 - s->cx; 459 if (nx == 0) 460 return; 461 462 s->cx += nx; 463 } 464 465 /* Cursor left by nx. */ 466 void 467 screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx) 468 { 469 struct screen *s = ctx->s; 470 471 if (nx == 0) 472 nx = 1; 473 474 if (nx > s->cx) 475 nx = s->cx; 476 if (nx == 0) 477 return; 478 479 s->cx -= nx; 480 } 481 482 /* Backspace; cursor left unless at start of wrapped line when can move up. */ 483 void 484 screen_write_backspace(struct screen_write_ctx *ctx) 485 { 486 struct screen *s = ctx->s; 487 struct grid_line *gl; 488 489 if (s->cx == 0) { 490 if (s->cy == 0) 491 return; 492 gl = &s->grid->linedata[s->grid->hsize + s->cy - 1]; 493 if (gl->flags & GRID_LINE_WRAPPED) { 494 s->cy--; 495 s->cx = screen_size_x(s) - 1; 496 } 497 } else 498 s->cx--; 499 } 500 501 /* VT100 alignment test. */ 502 void 503 screen_write_alignmenttest(struct screen_write_ctx *ctx) 504 { 505 struct screen *s = ctx->s; 506 struct tty_ctx ttyctx; 507 struct grid_cell gc; 508 u_int xx, yy; 509 510 screen_write_initctx(ctx, &ttyctx, 0); 511 512 memcpy(&gc, &grid_default_cell, sizeof gc); 513 utf8_set(&gc.data, 'E'); 514 515 for (yy = 0; yy < screen_size_y(s); yy++) { 516 for (xx = 0; xx < screen_size_x(s); xx++) 517 grid_view_set_cell(s->grid, xx, yy, &gc); 518 } 519 520 s->cx = 0; 521 s->cy = 0; 522 523 s->rupper = 0; 524 525 s->rlower = screen_size_y(s) - 1; 526 527 tty_write(tty_cmd_alignmenttest, &ttyctx); 528 } 529 530 /* Insert nx characters. */ 531 void 532 screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx) 533 { 534 struct screen *s = ctx->s; 535 struct tty_ctx ttyctx; 536 537 if (nx == 0) 538 nx = 1; 539 540 if (nx > screen_size_x(s) - s->cx) 541 nx = screen_size_x(s) - s->cx; 542 if (nx == 0) 543 return; 544 545 screen_write_initctx(ctx, &ttyctx, 0); 546 547 if (s->cx <= screen_size_x(s) - 1) 548 grid_view_insert_cells(s->grid, s->cx, s->cy, nx); 549 550 ttyctx.num = nx; 551 tty_write(tty_cmd_insertcharacter, &ttyctx); 552 } 553 554 /* Delete nx characters. */ 555 void 556 screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx) 557 { 558 struct screen *s = ctx->s; 559 struct tty_ctx ttyctx; 560 561 if (nx == 0) 562 nx = 1; 563 564 if (nx > screen_size_x(s) - s->cx) 565 nx = screen_size_x(s) - s->cx; 566 if (nx == 0) 567 return; 568 569 screen_write_initctx(ctx, &ttyctx, 0); 570 571 if (s->cx <= screen_size_x(s) - 1) 572 grid_view_delete_cells(s->grid, s->cx, s->cy, nx); 573 574 ttyctx.num = nx; 575 tty_write(tty_cmd_deletecharacter, &ttyctx); 576 } 577 578 /* Clear nx characters. */ 579 void 580 screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx) 581 { 582 struct screen *s = ctx->s; 583 struct tty_ctx ttyctx; 584 585 if (nx == 0) 586 nx = 1; 587 588 if (nx > screen_size_x(s) - s->cx) 589 nx = screen_size_x(s) - s->cx; 590 if (nx == 0) 591 return; 592 593 screen_write_initctx(ctx, &ttyctx, 0); 594 595 if (s->cx <= screen_size_x(s) - 1) 596 grid_view_clear(s->grid, s->cx, s->cy, nx, 1); 597 598 ttyctx.num = nx; 599 tty_write(tty_cmd_clearcharacter, &ttyctx); 600 } 601 602 /* Insert ny lines. */ 603 void 604 screen_write_insertline(struct screen_write_ctx *ctx, u_int ny) 605 { 606 struct screen *s = ctx->s; 607 struct tty_ctx ttyctx; 608 609 if (ny == 0) 610 ny = 1; 611 612 if (s->cy < s->rupper || s->cy > s->rlower) { 613 if (ny > screen_size_y(s) - s->cy) 614 ny = screen_size_y(s) - s->cy; 615 if (ny == 0) 616 return; 617 618 screen_write_initctx(ctx, &ttyctx, 0); 619 620 grid_view_insert_lines(s->grid, s->cy, ny); 621 622 ttyctx.num = ny; 623 tty_write(tty_cmd_insertline, &ttyctx); 624 return; 625 } 626 627 if (ny > s->rlower + 1 - s->cy) 628 ny = s->rlower + 1 - s->cy; 629 if (ny == 0) 630 return; 631 632 screen_write_initctx(ctx, &ttyctx, 0); 633 634 if (s->cy < s->rupper || s->cy > s->rlower) 635 grid_view_insert_lines(s->grid, s->cy, ny); 636 else 637 grid_view_insert_lines_region(s->grid, s->rlower, s->cy, ny); 638 639 ttyctx.num = ny; 640 tty_write(tty_cmd_insertline, &ttyctx); 641 } 642 643 /* Delete ny lines. */ 644 void 645 screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny) 646 { 647 struct screen *s = ctx->s; 648 struct tty_ctx ttyctx; 649 650 if (ny == 0) 651 ny = 1; 652 653 if (s->cy < s->rupper || s->cy > s->rlower) { 654 if (ny > screen_size_y(s) - s->cy) 655 ny = screen_size_y(s) - s->cy; 656 if (ny == 0) 657 return; 658 659 screen_write_initctx(ctx, &ttyctx, 0); 660 661 grid_view_delete_lines(s->grid, s->cy, ny); 662 663 ttyctx.num = ny; 664 tty_write(tty_cmd_deleteline, &ttyctx); 665 return; 666 } 667 668 if (ny > s->rlower + 1 - s->cy) 669 ny = s->rlower + 1 - s->cy; 670 if (ny == 0) 671 return; 672 673 screen_write_initctx(ctx, &ttyctx, 0); 674 675 if (s->cy < s->rupper || s->cy > s->rlower) 676 grid_view_delete_lines(s->grid, s->cy, ny); 677 else 678 grid_view_delete_lines_region(s->grid, s->rlower, s->cy, ny); 679 680 ttyctx.num = ny; 681 tty_write(tty_cmd_deleteline, &ttyctx); 682 } 683 684 /* Clear line at cursor. */ 685 void 686 screen_write_clearline(struct screen_write_ctx *ctx) 687 { 688 struct screen *s = ctx->s; 689 struct tty_ctx ttyctx; 690 691 screen_write_initctx(ctx, &ttyctx, 0); 692 693 grid_view_clear(s->grid, 0, s->cy, screen_size_x(s), 1); 694 695 tty_write(tty_cmd_clearline, &ttyctx); 696 } 697 698 /* Clear to end of line from cursor. */ 699 void 700 screen_write_clearendofline(struct screen_write_ctx *ctx) 701 { 702 struct screen *s = ctx->s; 703 struct tty_ctx ttyctx; 704 u_int sx; 705 706 screen_write_initctx(ctx, &ttyctx, 0); 707 708 sx = screen_size_x(s); 709 710 if (s->cx <= sx - 1) 711 grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1); 712 713 tty_write(tty_cmd_clearendofline, &ttyctx); 714 } 715 716 /* Clear to start of line from cursor. */ 717 void 718 screen_write_clearstartofline(struct screen_write_ctx *ctx) 719 { 720 struct screen *s = ctx->s; 721 struct tty_ctx ttyctx; 722 u_int sx; 723 724 screen_write_initctx(ctx, &ttyctx, 0); 725 726 sx = screen_size_x(s); 727 728 if (s->cx > sx - 1) 729 grid_view_clear(s->grid, 0, s->cy, sx, 1); 730 else 731 grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1); 732 733 tty_write(tty_cmd_clearstartofline, &ttyctx); 734 } 735 736 /* Move cursor to px,py. */ 737 void 738 screen_write_cursormove(struct screen_write_ctx *ctx, u_int px, u_int py) 739 { 740 struct screen *s = ctx->s; 741 742 if (px > screen_size_x(s) - 1) 743 px = screen_size_x(s) - 1; 744 if (py > screen_size_y(s) - 1) 745 py = screen_size_y(s) - 1; 746 747 s->cx = px; 748 s->cy = py; 749 } 750 751 /* Reverse index (up with scroll). */ 752 void 753 screen_write_reverseindex(struct screen_write_ctx *ctx) 754 { 755 struct screen *s = ctx->s; 756 struct tty_ctx ttyctx; 757 758 screen_write_initctx(ctx, &ttyctx, 0); 759 760 if (s->cy == s->rupper) 761 grid_view_scroll_region_down(s->grid, s->rupper, s->rlower); 762 else if (s->cy > 0) 763 s->cy--; 764 765 tty_write(tty_cmd_reverseindex, &ttyctx); 766 } 767 768 /* Set scroll region. */ 769 void 770 screen_write_scrollregion(struct screen_write_ctx *ctx, u_int rupper, 771 u_int rlower) 772 { 773 struct screen *s = ctx->s; 774 775 if (rupper > screen_size_y(s) - 1) 776 rupper = screen_size_y(s) - 1; 777 if (rlower > screen_size_y(s) - 1) 778 rlower = screen_size_y(s) - 1; 779 if (rupper >= rlower) /* cannot be one line */ 780 return; 781 782 /* Cursor moves to top-left. */ 783 s->cx = 0; 784 s->cy = 0; 785 786 s->rupper = rupper; 787 s->rlower = rlower; 788 } 789 790 /* Line feed. */ 791 void 792 screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) 793 { 794 struct screen *s = ctx->s; 795 struct grid_line *gl; 796 struct tty_ctx ttyctx; 797 798 screen_write_initctx(ctx, &ttyctx, 0); 799 800 gl = &s->grid->linedata[s->grid->hsize + s->cy]; 801 if (wrapped) 802 gl->flags |= GRID_LINE_WRAPPED; 803 else 804 gl->flags &= ~GRID_LINE_WRAPPED; 805 806 if (s->cy == s->rlower) 807 grid_view_scroll_region_up(s->grid, s->rupper, s->rlower); 808 else if (s->cy < screen_size_y(s) - 1) 809 s->cy++; 810 811 ttyctx.num = wrapped; 812 tty_write(tty_cmd_linefeed, &ttyctx); 813 } 814 815 /* Carriage return (cursor to start of line). */ 816 void 817 screen_write_carriagereturn(struct screen_write_ctx *ctx) 818 { 819 struct screen *s = ctx->s; 820 821 s->cx = 0; 822 } 823 824 /* Clear to end of screen from cursor. */ 825 void 826 screen_write_clearendofscreen(struct screen_write_ctx *ctx) 827 { 828 struct screen *s = ctx->s; 829 struct tty_ctx ttyctx; 830 u_int sx, sy; 831 832 screen_write_initctx(ctx, &ttyctx, 0); 833 834 sx = screen_size_x(s); 835 sy = screen_size_y(s); 836 837 /* Scroll into history if it is enabled and clearing entire screen. */ 838 if (s->cy == 0 && s->grid->flags & GRID_HISTORY) 839 grid_view_clear_history(s->grid); 840 else { 841 if (s->cx <= sx - 1) 842 grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1); 843 grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1)); 844 } 845 846 tty_write(tty_cmd_clearendofscreen, &ttyctx); 847 } 848 849 /* Clear to start of screen. */ 850 void 851 screen_write_clearstartofscreen(struct screen_write_ctx *ctx) 852 { 853 struct screen *s = ctx->s; 854 struct tty_ctx ttyctx; 855 u_int sx; 856 857 screen_write_initctx(ctx, &ttyctx, 0); 858 859 sx = screen_size_x(s); 860 861 if (s->cy > 0) 862 grid_view_clear(s->grid, 0, 0, sx, s->cy); 863 if (s->cx > sx - 1) 864 grid_view_clear(s->grid, 0, s->cy, sx, 1); 865 else 866 grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1); 867 868 tty_write(tty_cmd_clearstartofscreen, &ttyctx); 869 } 870 871 /* Clear entire screen. */ 872 void 873 screen_write_clearscreen(struct screen_write_ctx *ctx) 874 { 875 struct screen *s = ctx->s; 876 struct tty_ctx ttyctx; 877 u_int sx = screen_size_x(s); 878 u_int sy = screen_size_y(s); 879 880 screen_write_initctx(ctx, &ttyctx, 0); 881 882 /* Scroll into history if it is enabled. */ 883 if (s->grid->flags & GRID_HISTORY) 884 grid_view_clear_history(s->grid); 885 else 886 grid_view_clear(s->grid, 0, 0, sx, sy); 887 888 tty_write(tty_cmd_clearscreen, &ttyctx); 889 } 890 891 /* Clear entire history. */ 892 void 893 screen_write_clearhistory(struct screen_write_ctx *ctx) 894 { 895 struct screen *s = ctx->s; 896 struct grid *gd = s->grid; 897 898 grid_move_lines(gd, 0, gd->hsize, gd->sy); 899 gd->hsize = 0; 900 } 901 902 /* Write cell data. */ 903 void 904 screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) 905 { 906 struct screen *s = ctx->s; 907 struct grid *gd = s->grid; 908 struct tty_ctx ttyctx; 909 u_int width, xx, last; 910 struct grid_cell tmp_gc; 911 int insert; 912 913 /* Ignore padding. */ 914 if (gc->flags & GRID_FLAG_PADDING) 915 return; 916 width = gc->data.width; 917 918 /* 919 * If this is a wide character and there is no room on the screen, for 920 * the entire character, don't print it. 921 */ 922 if (!(s->mode & MODE_WRAP) 923 && (width > 1 && (width > screen_size_x(s) || 924 (s->cx != screen_size_x(s) 925 && s->cx > screen_size_x(s) - width)))) 926 return; 927 928 /* 929 * If the width is zero, combine onto the previous character, if 930 * there is space. 931 */ 932 if (width == 0) { 933 if (screen_write_combine(ctx, &gc->data) == 0) { 934 screen_write_initctx(ctx, &ttyctx, 0); 935 tty_write(tty_cmd_utf8character, &ttyctx); 936 } 937 return; 938 } 939 940 /* Initialise the redraw context, saving the last cell. */ 941 screen_write_initctx(ctx, &ttyctx, 1); 942 943 /* If in insert mode, make space for the cells. */ 944 if ((s->mode & MODE_INSERT) && s->cx <= screen_size_x(s) - width) { 945 xx = screen_size_x(s) - s->cx - width; 946 grid_move_cells(s->grid, s->cx + width, s->cx, s->cy, xx); 947 insert = 1; 948 } else 949 insert = 0; 950 951 /* Check this will fit on the current line and wrap if not. */ 952 if ((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width) { 953 screen_write_linefeed(ctx, 1); 954 s->cx = 0; /* carriage return */ 955 } 956 957 /* Sanity check cursor position. */ 958 if (s->cx > screen_size_x(s) - width || s->cy > screen_size_y(s) - 1) 959 return; 960 961 /* Handle overwriting of UTF-8 characters. */ 962 screen_write_overwrite(ctx, width); 963 964 /* 965 * If the new character is UTF-8 wide, fill in padding cells. Have 966 * already ensured there is enough room. 967 */ 968 memcpy(&tmp_gc, &grid_default_cell, sizeof tmp_gc); 969 tmp_gc.flags |= GRID_FLAG_PADDING; 970 tmp_gc.data.width = 0; 971 for (xx = s->cx + 1; xx < s->cx + width; xx++) 972 grid_view_set_cell(gd, xx, s->cy, &tmp_gc); 973 974 /* Set the cell. */ 975 grid_view_set_cell(gd, s->cx, s->cy, gc); 976 977 /* 978 * Move the cursor. If not wrapping, stick at the last character and 979 * replace it. 980 */ 981 last = !(s->mode & MODE_WRAP); 982 if (s->cx <= screen_size_x(s) - last - width) 983 s->cx += width; 984 else 985 s->cx = screen_size_x(s) - last; 986 987 /* Draw to the screen if necessary. */ 988 if (insert) { 989 ttyctx.num = width; 990 tty_write(tty_cmd_insertcharacter, &ttyctx); 991 } 992 if (screen_check_selection(s, s->cx - width, s->cy)) { 993 memcpy(&tmp_gc, &s->sel.cell, sizeof tmp_gc); 994 utf8_copy(&tmp_gc.data, &gc->data); 995 tmp_gc.attr = tmp_gc.attr & ~GRID_ATTR_CHARSET; 996 tmp_gc.attr |= gc->attr & GRID_ATTR_CHARSET; 997 tmp_gc.flags = gc->flags; 998 tmp_gc.flags &= ~(GRID_FLAG_FGRGB|GRID_FLAG_BGRGB); 999 tmp_gc.flags &= ~(GRID_FLAG_FG256|GRID_FLAG_BG256); 1000 tmp_gc.flags |= s->sel.cell.flags & 1001 (GRID_FLAG_FG256|GRID_FLAG_BG256); 1002 ttyctx.cell = &tmp_gc; 1003 tty_write(tty_cmd_cell, &ttyctx); 1004 } else { 1005 ttyctx.cell = gc; 1006 tty_write(tty_cmd_cell, &ttyctx); 1007 } 1008 } 1009 1010 /* Combine a UTF-8 zero-width character onto the previous. */ 1011 int 1012 screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud) 1013 { 1014 struct screen *s = ctx->s; 1015 struct grid *gd = s->grid; 1016 struct grid_cell gc; 1017 1018 /* Can't combine if at 0. */ 1019 if (s->cx == 0) 1020 return (-1); 1021 1022 /* Empty data is out. */ 1023 if (ud->size == 0) 1024 fatalx("UTF-8 data empty"); 1025 1026 /* Retrieve the previous cell. */ 1027 grid_view_get_cell(gd, s->cx - 1, s->cy, &gc); 1028 1029 /* Check there is enough space. */ 1030 if (gc.data.size + ud->size > sizeof gc.data.data) 1031 return (-1); 1032 1033 /* Append the data. */ 1034 memcpy(gc.data.data + gc.data.size, ud->data, ud->size); 1035 gc.data.size += ud->size; 1036 1037 /* Set the new cell. */ 1038 grid_view_set_cell(gd, s->cx - 1, s->cy, &gc); 1039 1040 return (0); 1041 } 1042 1043 /* 1044 * UTF-8 wide characters are a bit of an annoyance. They take up more than one 1045 * cell on the screen, so following cells must not be drawn by marking them as 1046 * padding. 1047 * 1048 * So far, so good. The problem is, when overwriting a padding cell, or a UTF-8 1049 * character, it is necessary to also overwrite any other cells which covered 1050 * by the same character. 1051 */ 1052 void 1053 screen_write_overwrite(struct screen_write_ctx *ctx, u_int width) 1054 { 1055 struct screen *s = ctx->s; 1056 struct grid *gd = s->grid; 1057 struct grid_cell gc; 1058 u_int xx; 1059 1060 grid_view_get_cell(gd, s->cx, s->cy, &gc); 1061 if (gc.flags & GRID_FLAG_PADDING) { 1062 /* 1063 * A padding cell, so clear any following and leading padding 1064 * cells back to the character. Don't overwrite the current 1065 * cell as that happens later anyway. 1066 */ 1067 xx = s->cx + 1; 1068 while (--xx > 0) { 1069 grid_view_get_cell(gd, xx, s->cy, &gc); 1070 if (~gc.flags & GRID_FLAG_PADDING) 1071 break; 1072 grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); 1073 } 1074 1075 /* Overwrite the character at the start of this padding. */ 1076 grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); 1077 } 1078 1079 /* 1080 * Overwrite any padding cells that belong to a UTF-8 character 1081 * we'll be overwriting with the current character. 1082 */ 1083 xx = s->cx + width - 1; 1084 while (++xx < screen_size_x(s)) { 1085 grid_view_get_cell(gd, xx, s->cy, &gc); 1086 if (~gc.flags & GRID_FLAG_PADDING) 1087 break; 1088 grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); 1089 } 1090 } 1091 1092 void 1093 screen_write_setselection(struct screen_write_ctx *ctx, u_char *str, u_int len) 1094 { 1095 struct tty_ctx ttyctx; 1096 1097 screen_write_initctx(ctx, &ttyctx, 0); 1098 ttyctx.ptr = str; 1099 ttyctx.num = len; 1100 1101 tty_write(tty_cmd_setselection, &ttyctx); 1102 } 1103 1104 void 1105 screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len) 1106 { 1107 struct tty_ctx ttyctx; 1108 1109 screen_write_initctx(ctx, &ttyctx, 0); 1110 ttyctx.ptr = str; 1111 ttyctx.num = len; 1112 1113 tty_write(tty_cmd_rawstring, &ttyctx); 1114 } 1115