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