1 /* $OpenBSD: screen-write.c,v 1.73 2015/07/13 13:28:50 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 else 799 gl->flags &= ~GRID_LINE_WRAPPED; 800 801 if (s->cy == s->rlower) 802 grid_view_scroll_region_up(s->grid, s->rupper, s->rlower); 803 else if (s->cy < screen_size_y(s) - 1) 804 s->cy++; 805 806 ttyctx.num = wrapped; 807 tty_write(tty_cmd_linefeed, &ttyctx); 808 } 809 810 /* Carriage return (cursor to start of line). */ 811 void 812 screen_write_carriagereturn(struct screen_write_ctx *ctx) 813 { 814 struct screen *s = ctx->s; 815 816 s->cx = 0; 817 } 818 819 /* Clear to end of screen from cursor. */ 820 void 821 screen_write_clearendofscreen(struct screen_write_ctx *ctx) 822 { 823 struct screen *s = ctx->s; 824 struct tty_ctx ttyctx; 825 u_int sx, sy; 826 827 screen_write_initctx(ctx, &ttyctx, 0); 828 829 sx = screen_size_x(s); 830 sy = screen_size_y(s); 831 832 /* Scroll into history if it is enabled and clearing entire screen. */ 833 if (s->cy == 0 && s->grid->flags & GRID_HISTORY) 834 grid_view_clear_history(s->grid); 835 else { 836 if (s->cx <= sx - 1) 837 grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1); 838 grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1)); 839 } 840 841 tty_write(tty_cmd_clearendofscreen, &ttyctx); 842 } 843 844 /* Clear to start of screen. */ 845 void 846 screen_write_clearstartofscreen(struct screen_write_ctx *ctx) 847 { 848 struct screen *s = ctx->s; 849 struct tty_ctx ttyctx; 850 u_int sx; 851 852 screen_write_initctx(ctx, &ttyctx, 0); 853 854 sx = screen_size_x(s); 855 856 if (s->cy > 0) 857 grid_view_clear(s->grid, 0, 0, sx, s->cy); 858 if (s->cx > sx - 1) 859 grid_view_clear(s->grid, 0, s->cy, sx, 1); 860 else 861 grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1); 862 863 tty_write(tty_cmd_clearstartofscreen, &ttyctx); 864 } 865 866 /* Clear entire screen. */ 867 void 868 screen_write_clearscreen(struct screen_write_ctx *ctx) 869 { 870 struct screen *s = ctx->s; 871 struct tty_ctx ttyctx; 872 873 screen_write_initctx(ctx, &ttyctx, 0); 874 875 /* Scroll into history if it is enabled. */ 876 if (s->grid->flags & GRID_HISTORY) 877 grid_view_clear_history(s->grid); 878 else { 879 grid_view_clear( 880 s->grid, 0, 0, screen_size_x(s), screen_size_y(s)); 881 } 882 883 tty_write(tty_cmd_clearscreen, &ttyctx); 884 } 885 886 /* Clear entire history. */ 887 void 888 screen_write_clearhistory(struct screen_write_ctx *ctx) 889 { 890 struct screen *s = ctx->s; 891 struct grid *gd = s->grid; 892 893 grid_move_lines(gd, 0, gd->hsize, gd->sy); 894 gd->hsize = 0; 895 } 896 897 /* Write cell data. */ 898 void 899 screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) 900 { 901 struct screen *s = ctx->s; 902 struct grid *gd = s->grid; 903 struct tty_ctx ttyctx; 904 u_int width, xx, last; 905 struct grid_cell tmp_gc, *tmp_gcp; 906 struct utf8_data ud; 907 int insert; 908 909 /* Ignore padding. */ 910 if (gc->flags & GRID_FLAG_PADDING) 911 return; 912 width = grid_cell_width(gc); 913 914 /* 915 * If this is a wide character and there is no room on the screen, for 916 * the entire character, don't print it. 917 */ 918 if (!(s->mode & MODE_WRAP) 919 && (width > 1 && (width > screen_size_x(s) || 920 (s->cx != screen_size_x(s) 921 && s->cx > screen_size_x(s) - width)))) 922 return; 923 924 /* 925 * If the width is zero, combine onto the previous character, if 926 * there is space. 927 */ 928 if (width == 0) { 929 grid_cell_get(gc, &ud); 930 if (screen_write_combine(ctx, &ud) == 0) { 931 screen_write_initctx(ctx, &ttyctx, 0); 932 tty_write(tty_cmd_utf8character, &ttyctx); 933 } 934 return; 935 } 936 937 /* Initialise the redraw context, saving the last cell. */ 938 screen_write_initctx(ctx, &ttyctx, 1); 939 940 /* If in insert mode, make space for the cells. */ 941 if ((s->mode & MODE_INSERT) && s->cx <= screen_size_x(s) - width) { 942 xx = screen_size_x(s) - s->cx - width; 943 grid_move_cells(s->grid, s->cx + width, s->cx, s->cy, xx); 944 insert = 1; 945 } else 946 insert = 0; 947 948 /* Check this will fit on the current line and wrap if not. */ 949 if ((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width) { 950 screen_write_linefeed(ctx, 1); 951 s->cx = 0; /* carriage return */ 952 } 953 954 /* Sanity check cursor position. */ 955 if (s->cx > screen_size_x(s) - width || s->cy > screen_size_y(s) - 1) 956 return; 957 958 /* Handle overwriting of UTF-8 characters. */ 959 screen_write_overwrite(ctx, width); 960 961 /* 962 * If the new character is UTF-8 wide, fill in padding cells. Have 963 * already ensured there is enough room. 964 */ 965 for (xx = s->cx + 1; xx < s->cx + width; xx++) { 966 tmp_gcp = grid_view_get_cell(gd, xx, s->cy); 967 if (tmp_gcp != NULL) 968 tmp_gcp->flags |= GRID_FLAG_PADDING; 969 } 970 971 /* Set the cell. */ 972 grid_view_set_cell(gd, s->cx, s->cy, gc); 973 974 /* 975 * Move the cursor. If not wrapping, stick at the last character and 976 * replace it. 977 */ 978 last = !(s->mode & MODE_WRAP); 979 if (s->cx <= screen_size_x(s) - last - width) 980 s->cx += width; 981 else 982 s->cx = screen_size_x(s) - last; 983 984 /* Draw to the screen if necessary. */ 985 if (insert) { 986 ttyctx.num = width; 987 tty_write(tty_cmd_insertcharacter, &ttyctx); 988 } 989 if (screen_check_selection(s, s->cx - width, s->cy)) { 990 memcpy(&tmp_gc, &s->sel.cell, sizeof tmp_gc); 991 grid_cell_get(gc, &ud); 992 grid_cell_set(&tmp_gc, &ud); 993 tmp_gc.attr = tmp_gc.attr & ~GRID_ATTR_CHARSET; 994 tmp_gc.attr |= gc->attr & GRID_ATTR_CHARSET; 995 tmp_gc.flags = gc->flags & ~(GRID_FLAG_FG256|GRID_FLAG_BG256); 996 tmp_gc.flags |= s->sel.cell.flags & 997 (GRID_FLAG_FG256|GRID_FLAG_BG256); 998 ttyctx.cell = &tmp_gc; 999 tty_write(tty_cmd_cell, &ttyctx); 1000 } else { 1001 ttyctx.cell = gc; 1002 tty_write(tty_cmd_cell, &ttyctx); 1003 } 1004 } 1005 1006 /* Combine a UTF-8 zero-width character onto the previous. */ 1007 int 1008 screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud) 1009 { 1010 struct screen *s = ctx->s; 1011 struct grid *gd = s->grid; 1012 struct grid_cell *gc; 1013 struct utf8_data ud1; 1014 1015 /* Can't combine if at 0. */ 1016 if (s->cx == 0) 1017 return (-1); 1018 1019 /* Empty data is out. */ 1020 if (ud->size == 0) 1021 fatalx("UTF-8 data empty"); 1022 1023 /* Retrieve the previous cell. */ 1024 gc = grid_view_get_cell(gd, s->cx - 1, s->cy); 1025 grid_cell_get(gc, &ud1); 1026 1027 /* Check there is enough space. */ 1028 if (ud1.size + ud->size > sizeof ud1.data) 1029 return (-1); 1030 1031 /* Append the data and set the cell. */ 1032 memcpy(ud1.data + ud1.size, ud->data, ud->size); 1033 ud1.size += ud->size; 1034 grid_cell_set(gc, &ud1); 1035 1036 return (0); 1037 } 1038 1039 /* 1040 * UTF-8 wide characters are a bit of an annoyance. They take up more than one 1041 * cell on the screen, so following cells must not be drawn by marking them as 1042 * padding. 1043 * 1044 * So far, so good. The problem is, when overwriting a padding cell, or a UTF-8 1045 * character, it is necessary to also overwrite any other cells which covered 1046 * by the same character. 1047 */ 1048 void 1049 screen_write_overwrite(struct screen_write_ctx *ctx, u_int width) 1050 { 1051 struct screen *s = ctx->s; 1052 struct grid *gd = s->grid; 1053 const struct grid_cell *gc; 1054 u_int xx; 1055 1056 gc = grid_view_peek_cell(gd, s->cx, s->cy); 1057 if (gc->flags & GRID_FLAG_PADDING) { 1058 /* 1059 * A padding cell, so clear any following and leading padding 1060 * cells back to the character. Don't overwrite the current 1061 * cell as that happens later anyway. 1062 */ 1063 xx = s->cx + 1; 1064 while (--xx > 0) { 1065 gc = grid_view_peek_cell(gd, xx, s->cy); 1066 if (!(gc->flags & GRID_FLAG_PADDING)) 1067 break; 1068 grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); 1069 } 1070 1071 /* Overwrite the character at the start of this padding. */ 1072 grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); 1073 } 1074 1075 /* 1076 * Overwrite any padding cells that belong to a UTF-8 character 1077 * we'll be overwriting with the current character. 1078 */ 1079 xx = s->cx + width - 1; 1080 while (++xx < screen_size_x(s)) { 1081 gc = grid_view_peek_cell(gd, xx, s->cy); 1082 if (!(gc->flags & GRID_FLAG_PADDING)) 1083 break; 1084 grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); 1085 } 1086 } 1087 1088 void 1089 screen_write_setselection(struct screen_write_ctx *ctx, u_char *str, u_int len) 1090 { 1091 struct tty_ctx ttyctx; 1092 1093 screen_write_initctx(ctx, &ttyctx, 0); 1094 ttyctx.ptr = str; 1095 ttyctx.num = len; 1096 1097 tty_write(tty_cmd_setselection, &ttyctx); 1098 } 1099 1100 void 1101 screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len) 1102 { 1103 struct tty_ctx ttyctx; 1104 1105 screen_write_initctx(ctx, &ttyctx, 0); 1106 ttyctx.ptr = str; 1107 ttyctx.num = len; 1108 1109 tty_write(tty_cmd_rawstring, &ttyctx); 1110 } 1111