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