Annotation of embedaddon/tmux/screen-write.c, revision 1.1
1.1 ! misho 1: /* $OpenBSD$ */
! 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: static void screen_write_initctx(struct screen_write_ctx *,
! 27: struct tty_ctx *);
! 28: static void screen_write_collect_clear(struct screen_write_ctx *, u_int,
! 29: u_int);
! 30: static void screen_write_collect_scroll(struct screen_write_ctx *);
! 31: static void screen_write_collect_flush(struct screen_write_ctx *, int);
! 32:
! 33: static int screen_write_overwrite(struct screen_write_ctx *,
! 34: struct grid_cell *, u_int);
! 35: static const struct grid_cell *screen_write_combine(struct screen_write_ctx *,
! 36: const struct utf8_data *, u_int *);
! 37:
! 38: static const struct grid_cell screen_write_pad_cell = {
! 39: GRID_FLAG_PADDING, 0, 8, 8, { { 0 }, 0, 0, 0 }
! 40: };
! 41:
! 42: struct screen_write_collect_item {
! 43: u_int x;
! 44:
! 45: u_int used;
! 46: char data[256];
! 47:
! 48: struct grid_cell gc;
! 49:
! 50: TAILQ_ENTRY (screen_write_collect_item) entry;
! 51: };
! 52: struct screen_write_collect_line {
! 53: TAILQ_HEAD(, screen_write_collect_item) items;
! 54: };
! 55:
! 56: /* Initialize writing with a window. */
! 57: void
! 58: screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp,
! 59: struct screen *s)
! 60: {
! 61: char tmp[16];
! 62: u_int y;
! 63:
! 64: memset(ctx, 0, sizeof *ctx);
! 65:
! 66: ctx->wp = wp;
! 67: if (wp != NULL && s == NULL)
! 68: ctx->s = wp->screen;
! 69: else
! 70: ctx->s = s;
! 71:
! 72: ctx->list = xcalloc(screen_size_y(ctx->s), sizeof *ctx->list);
! 73: for (y = 0; y < screen_size_y(ctx->s); y++)
! 74: TAILQ_INIT(&ctx->list[y].items);
! 75: ctx->item = xcalloc(1, sizeof *ctx->item);
! 76:
! 77: if (wp != NULL)
! 78: snprintf(tmp, sizeof tmp, "pane %%%u", wp->id);
! 79: log_debug("%s: size %ux%u, %s", __func__, screen_size_x(ctx->s),
! 80: screen_size_y(ctx->s), wp == NULL ? "no pane" : tmp);
! 81: }
! 82:
! 83: /* Finish writing. */
! 84: void
! 85: screen_write_stop(struct screen_write_ctx *ctx)
! 86: {
! 87: screen_write_collect_end(ctx);
! 88: screen_write_collect_flush(ctx, 0);
! 89:
! 90: log_debug("%s: %u cells (%u written, %u skipped)", __func__,
! 91: ctx->cells, ctx->written, ctx->skipped);
! 92:
! 93: free(ctx->item);
! 94: free(ctx->list); /* flush will have emptied */
! 95: }
! 96:
! 97: /* Reset screen state. */
! 98: void
! 99: screen_write_reset(struct screen_write_ctx *ctx)
! 100: {
! 101: struct screen *s = ctx->s;
! 102:
! 103: screen_reset_tabs(s);
! 104: screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1);
! 105:
! 106: s->mode &= ~(MODE_INSERT|MODE_KCURSOR|MODE_KKEYPAD|MODE_FOCUSON);
! 107: s->mode &= ~(ALL_MOUSE_MODES|MODE_MOUSE_UTF8|MODE_MOUSE_SGR);
! 108:
! 109: screen_write_clearscreen(ctx, 8);
! 110: screen_write_cursormove(ctx, 0, 0);
! 111: }
! 112:
! 113: /* Write character. */
! 114: void
! 115: screen_write_putc(struct screen_write_ctx *ctx, const struct grid_cell *gcp,
! 116: u_char ch)
! 117: {
! 118: struct grid_cell gc;
! 119:
! 120: memcpy(&gc, gcp, sizeof gc);
! 121:
! 122: utf8_set(&gc.data, ch);
! 123: screen_write_cell(ctx, &gc);
! 124: }
! 125:
! 126: /* Calculate string length, with embedded formatting. */
! 127: size_t
! 128: screen_write_cstrlen(const char *fmt, ...)
! 129: {
! 130: va_list ap;
! 131: char *msg, *msg2, *ptr, *ptr2;
! 132: size_t size;
! 133:
! 134: va_start(ap, fmt);
! 135: xvasprintf(&msg, fmt, ap);
! 136: va_end(ap);
! 137: msg2 = xmalloc(strlen(msg) + 1);
! 138:
! 139: ptr = msg;
! 140: ptr2 = msg2;
! 141: while (*ptr != '\0') {
! 142: if (ptr[0] == '#' && ptr[1] == '[') {
! 143: while (*ptr != ']' && *ptr != '\0')
! 144: ptr++;
! 145: if (*ptr == ']')
! 146: ptr++;
! 147: continue;
! 148: }
! 149: *ptr2++ = *ptr++;
! 150: }
! 151: *ptr2 = '\0';
! 152:
! 153: size = screen_write_strlen("%s", msg2);
! 154:
! 155: free(msg);
! 156: free(msg2);
! 157:
! 158: return (size);
! 159: }
! 160:
! 161: /* Calculate string length. */
! 162: size_t
! 163: screen_write_strlen(const char *fmt, ...)
! 164: {
! 165: va_list ap;
! 166: char *msg;
! 167: struct utf8_data ud;
! 168: u_char *ptr;
! 169: size_t left, size = 0;
! 170: enum utf8_state more;
! 171:
! 172: va_start(ap, fmt);
! 173: xvasprintf(&msg, fmt, ap);
! 174: va_end(ap);
! 175:
! 176: ptr = msg;
! 177: while (*ptr != '\0') {
! 178: if (*ptr > 0x7f && utf8_open(&ud, *ptr) == UTF8_MORE) {
! 179: ptr++;
! 180:
! 181: left = strlen(ptr);
! 182: if (left < (size_t)ud.size - 1)
! 183: break;
! 184: while ((more = utf8_append(&ud, *ptr)) == UTF8_MORE)
! 185: ptr++;
! 186: ptr++;
! 187:
! 188: if (more == UTF8_DONE)
! 189: size += ud.width;
! 190: } else {
! 191: if (*ptr > 0x1f && *ptr < 0x7f)
! 192: size++;
! 193: ptr++;
! 194: }
! 195: }
! 196:
! 197: free(msg);
! 198: return (size);
! 199: }
! 200:
! 201: /* Write simple string (no UTF-8 or maximum length). */
! 202: void
! 203: screen_write_puts(struct screen_write_ctx *ctx, const struct grid_cell *gcp,
! 204: const char *fmt, ...)
! 205: {
! 206: va_list ap;
! 207:
! 208: va_start(ap, fmt);
! 209: screen_write_vnputs(ctx, -1, gcp, fmt, ap);
! 210: va_end(ap);
! 211: }
! 212:
! 213: /* Write string with length limit (-1 for unlimited). */
! 214: void
! 215: screen_write_nputs(struct screen_write_ctx *ctx, ssize_t maxlen,
! 216: const struct grid_cell *gcp, const char *fmt, ...)
! 217: {
! 218: va_list ap;
! 219:
! 220: va_start(ap, fmt);
! 221: screen_write_vnputs(ctx, maxlen, gcp, fmt, ap);
! 222: va_end(ap);
! 223: }
! 224:
! 225: void
! 226: screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
! 227: const struct grid_cell *gcp, const char *fmt, va_list ap)
! 228: {
! 229: struct grid_cell gc;
! 230: struct utf8_data *ud = &gc.data;
! 231: char *msg;
! 232: u_char *ptr;
! 233: size_t left, size = 0;
! 234: enum utf8_state more;
! 235:
! 236: memcpy(&gc, gcp, sizeof gc);
! 237: xvasprintf(&msg, fmt, ap);
! 238:
! 239: ptr = msg;
! 240: while (*ptr != '\0') {
! 241: if (*ptr > 0x7f && utf8_open(ud, *ptr) == UTF8_MORE) {
! 242: ptr++;
! 243:
! 244: left = strlen(ptr);
! 245: if (left < (size_t)ud->size - 1)
! 246: break;
! 247: while ((more = utf8_append(ud, *ptr)) == UTF8_MORE)
! 248: ptr++;
! 249: ptr++;
! 250:
! 251: if (more != UTF8_DONE)
! 252: continue;
! 253: if (maxlen > 0 && size + ud->width > (size_t)maxlen) {
! 254: while (size < (size_t)maxlen) {
! 255: screen_write_putc(ctx, &gc, ' ');
! 256: size++;
! 257: }
! 258: break;
! 259: }
! 260: size += ud->width;
! 261: screen_write_cell(ctx, &gc);
! 262: } else {
! 263: if (maxlen > 0 && size + 1 > (size_t)maxlen)
! 264: break;
! 265:
! 266: if (*ptr == '\001')
! 267: gc.attr ^= GRID_ATTR_CHARSET;
! 268: else if (*ptr > 0x1f && *ptr < 0x7f) {
! 269: size++;
! 270: screen_write_putc(ctx, &gc, *ptr);
! 271: }
! 272: ptr++;
! 273: }
! 274: }
! 275:
! 276: free(msg);
! 277: }
! 278:
! 279: /* Write string, similar to nputs, but with embedded formatting (#[]). */
! 280: void
! 281: screen_write_cnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
! 282: const struct grid_cell *gcp, const char *fmt, ...)
! 283: {
! 284: struct grid_cell gc;
! 285: struct utf8_data *ud = &gc.data;
! 286: va_list ap;
! 287: char *msg;
! 288: u_char *ptr, *last;
! 289: size_t left, size = 0;
! 290: enum utf8_state more;
! 291:
! 292: memcpy(&gc, gcp, sizeof gc);
! 293:
! 294: va_start(ap, fmt);
! 295: xvasprintf(&msg, fmt, ap);
! 296: va_end(ap);
! 297:
! 298: ptr = msg;
! 299: while (*ptr != '\0') {
! 300: if (ptr[0] == '#' && ptr[1] == '[') {
! 301: ptr += 2;
! 302: last = ptr + strcspn(ptr, "]");
! 303: if (*last == '\0') {
! 304: /* No ]. Not much point in doing anything. */
! 305: break;
! 306: }
! 307: *last = '\0';
! 308:
! 309: style_parse(gcp, &gc, ptr);
! 310: ptr = last + 1;
! 311: continue;
! 312: }
! 313:
! 314: if (*ptr > 0x7f && utf8_open(ud, *ptr) == UTF8_MORE) {
! 315: ptr++;
! 316:
! 317: left = strlen(ptr);
! 318: if (left < (size_t)ud->size - 1)
! 319: break;
! 320: while ((more = utf8_append(ud, *ptr)) == UTF8_MORE)
! 321: ptr++;
! 322: ptr++;
! 323:
! 324: if (more != UTF8_DONE)
! 325: continue;
! 326: if (maxlen > 0 && size + ud->width > (size_t)maxlen) {
! 327: while (size < (size_t)maxlen) {
! 328: screen_write_putc(ctx, &gc, ' ');
! 329: size++;
! 330: }
! 331: break;
! 332: }
! 333: size += ud->width;
! 334: screen_write_cell(ctx, &gc);
! 335: } else {
! 336: if (maxlen > 0 && size + 1 > (size_t)maxlen)
! 337: break;
! 338:
! 339: if (*ptr > 0x1f && *ptr < 0x7f) {
! 340: size++;
! 341: screen_write_putc(ctx, &gc, *ptr);
! 342: }
! 343: ptr++;
! 344: }
! 345: }
! 346:
! 347: free(msg);
! 348: }
! 349:
! 350: /* Copy from another screen. */
! 351: void
! 352: screen_write_copy(struct screen_write_ctx *ctx, struct screen *src, u_int px,
! 353: u_int py, u_int nx, u_int ny, bitstr_t *markbs,
! 354: const struct grid_cell *markgc)
! 355: {
! 356: struct screen *s = ctx->s;
! 357: struct grid *gd = src->grid;
! 358: struct grid_cell gc;
! 359: u_int xx, yy, cx, cy, b;
! 360:
! 361: cx = s->cx;
! 362: cy = s->cy;
! 363:
! 364: for (yy = py; yy < py + ny; yy++) {
! 365: for (xx = px; xx < px + nx; xx++) {
! 366: grid_get_cell(gd, xx, yy, &gc);
! 367: if (markbs != NULL) {
! 368: b = (yy * screen_size_x(src)) + xx;
! 369: if (bit_test(markbs, b)) {
! 370: gc.attr = markgc->attr;
! 371: gc.fg = markgc->fg;
! 372: gc.bg = markgc->bg;
! 373: }
! 374: }
! 375: screen_write_cell(ctx, &gc);
! 376: }
! 377:
! 378: cy++;
! 379: screen_write_cursormove(ctx, cx, cy);
! 380: }
! 381: }
! 382:
! 383: /* Set up context for TTY command. */
! 384: static void
! 385: screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx)
! 386: {
! 387: struct screen *s = ctx->s;
! 388:
! 389: ttyctx->wp = ctx->wp;
! 390:
! 391: ttyctx->ocx = s->cx;
! 392: ttyctx->ocy = s->cy;
! 393:
! 394: ttyctx->orlower = s->rlower;
! 395: ttyctx->orupper = s->rupper;
! 396: }
! 397:
! 398: /* Set a mode. */
! 399: void
! 400: screen_write_mode_set(struct screen_write_ctx *ctx, int mode)
! 401: {
! 402: struct screen *s = ctx->s;
! 403:
! 404: s->mode |= mode;
! 405: }
! 406:
! 407: /* Clear a mode. */
! 408: void
! 409: screen_write_mode_clear(struct screen_write_ctx *ctx, int mode)
! 410: {
! 411: struct screen *s = ctx->s;
! 412:
! 413: s->mode &= ~mode;
! 414: }
! 415:
! 416: /* Cursor up by ny. */
! 417: void
! 418: screen_write_cursorup(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->rupper) {
! 426: /* Above region. */
! 427: if (ny > s->cy)
! 428: ny = s->cy;
! 429: } else {
! 430: /* Below region. */
! 431: if (ny > s->cy - s->rupper)
! 432: ny = s->cy - s->rupper;
! 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 down by ny. */
! 443: void
! 444: screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny)
! 445: {
! 446: struct screen *s = ctx->s;
! 447:
! 448: if (ny == 0)
! 449: ny = 1;
! 450:
! 451: if (s->cy > s->rlower) {
! 452: /* Below region. */
! 453: if (ny > screen_size_y(s) - 1 - s->cy)
! 454: ny = screen_size_y(s) - 1 - s->cy;
! 455: } else {
! 456: /* Above region. */
! 457: if (ny > s->rlower - s->cy)
! 458: ny = s->rlower - s->cy;
! 459: }
! 460: if (s->cx == screen_size_x(s))
! 461: s->cx--;
! 462: if (ny == 0)
! 463: return;
! 464:
! 465: s->cy += ny;
! 466: }
! 467:
! 468: /* Cursor right by nx. */
! 469: void
! 470: screen_write_cursorright(struct screen_write_ctx *ctx, u_int nx)
! 471: {
! 472: struct screen *s = ctx->s;
! 473:
! 474: if (nx == 0)
! 475: nx = 1;
! 476:
! 477: if (nx > screen_size_x(s) - 1 - s->cx)
! 478: nx = screen_size_x(s) - 1 - s->cx;
! 479: if (nx == 0)
! 480: return;
! 481:
! 482: s->cx += nx;
! 483: }
! 484:
! 485: /* Cursor left by nx. */
! 486: void
! 487: screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx)
! 488: {
! 489: struct screen *s = ctx->s;
! 490:
! 491: if (nx == 0)
! 492: nx = 1;
! 493:
! 494: if (nx > s->cx)
! 495: nx = s->cx;
! 496: if (nx == 0)
! 497: return;
! 498:
! 499: s->cx -= nx;
! 500: }
! 501:
! 502: /* Backspace; cursor left unless at start of wrapped line when can move up. */
! 503: void
! 504: screen_write_backspace(struct screen_write_ctx *ctx)
! 505: {
! 506: struct screen *s = ctx->s;
! 507: struct grid_line *gl;
! 508:
! 509: if (s->cx == 0) {
! 510: if (s->cy == 0)
! 511: return;
! 512: gl = &s->grid->linedata[s->grid->hsize + s->cy - 1];
! 513: if (gl->flags & GRID_LINE_WRAPPED) {
! 514: s->cy--;
! 515: s->cx = screen_size_x(s) - 1;
! 516: }
! 517: } else
! 518: s->cx--;
! 519: }
! 520:
! 521: /* VT100 alignment test. */
! 522: void
! 523: screen_write_alignmenttest(struct screen_write_ctx *ctx)
! 524: {
! 525: struct screen *s = ctx->s;
! 526: struct tty_ctx ttyctx;
! 527: struct grid_cell gc;
! 528: u_int xx, yy;
! 529:
! 530: screen_write_initctx(ctx, &ttyctx);
! 531:
! 532: memcpy(&gc, &grid_default_cell, sizeof gc);
! 533: utf8_set(&gc.data, 'E');
! 534:
! 535: for (yy = 0; yy < screen_size_y(s); yy++) {
! 536: for (xx = 0; xx < screen_size_x(s); xx++)
! 537: grid_view_set_cell(s->grid, xx, yy, &gc);
! 538: }
! 539:
! 540: s->cx = 0;
! 541: s->cy = 0;
! 542:
! 543: s->rupper = 0;
! 544: s->rlower = screen_size_y(s) - 1;
! 545:
! 546: screen_write_collect_clear(ctx, 0, screen_size_y(s) - 1);
! 547: tty_write(tty_cmd_alignmenttest, &ttyctx);
! 548: }
! 549:
! 550: /* Insert nx characters. */
! 551: void
! 552: screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
! 553: {
! 554: struct screen *s = ctx->s;
! 555: struct tty_ctx ttyctx;
! 556:
! 557: if (nx == 0)
! 558: nx = 1;
! 559:
! 560: if (nx > screen_size_x(s) - s->cx)
! 561: nx = screen_size_x(s) - s->cx;
! 562: if (nx == 0)
! 563: return;
! 564:
! 565: if (s->cx > screen_size_x(s) - 1)
! 566: return;
! 567:
! 568: screen_write_initctx(ctx, &ttyctx);
! 569: ttyctx.bg = bg;
! 570:
! 571: grid_view_insert_cells(s->grid, s->cx, s->cy, nx, bg);
! 572:
! 573: screen_write_collect_flush(ctx, 0);
! 574: ttyctx.num = nx;
! 575: tty_write(tty_cmd_insertcharacter, &ttyctx);
! 576: }
! 577:
! 578: /* Delete nx characters. */
! 579: void
! 580: screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx, u_int bg)
! 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: if (s->cx > screen_size_x(s) - 1)
! 594: return;
! 595:
! 596: screen_write_initctx(ctx, &ttyctx);
! 597: ttyctx.bg = bg;
! 598:
! 599: grid_view_delete_cells(s->grid, s->cx, s->cy, nx, bg);
! 600:
! 601: screen_write_collect_flush(ctx, 0);
! 602: ttyctx.num = nx;
! 603: tty_write(tty_cmd_deletecharacter, &ttyctx);
! 604: }
! 605:
! 606: /* Clear nx characters. */
! 607: void
! 608: screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx)
! 609: {
! 610: struct screen *s = ctx->s;
! 611: struct tty_ctx ttyctx;
! 612:
! 613: if (nx == 0)
! 614: nx = 1;
! 615:
! 616: if (nx > screen_size_x(s) - s->cx)
! 617: nx = screen_size_x(s) - s->cx;
! 618: if (nx == 0)
! 619: return;
! 620:
! 621: if (s->cx > screen_size_x(s) - 1)
! 622: return;
! 623:
! 624: screen_write_initctx(ctx, &ttyctx);
! 625:
! 626: grid_view_clear(s->grid, s->cx, s->cy, nx, 1, 8);
! 627:
! 628: screen_write_collect_flush(ctx, 0);
! 629: ttyctx.num = nx;
! 630: tty_write(tty_cmd_clearcharacter, &ttyctx);
! 631: }
! 632:
! 633: /* Insert ny lines. */
! 634: void
! 635: screen_write_insertline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
! 636: {
! 637: struct screen *s = ctx->s;
! 638: struct grid *gd = s->grid;
! 639: struct tty_ctx ttyctx;
! 640:
! 641: if (ny == 0)
! 642: ny = 1;
! 643:
! 644: if (s->cy < s->rupper || s->cy > s->rlower) {
! 645: if (ny > screen_size_y(s) - s->cy)
! 646: ny = screen_size_y(s) - s->cy;
! 647: if (ny == 0)
! 648: return;
! 649:
! 650: screen_write_initctx(ctx, &ttyctx);
! 651: ttyctx.bg = bg;
! 652:
! 653: grid_view_insert_lines(gd, s->cy, ny, bg);
! 654:
! 655: screen_write_collect_flush(ctx, 0);
! 656: ttyctx.num = ny;
! 657: tty_write(tty_cmd_insertline, &ttyctx);
! 658: return;
! 659: }
! 660:
! 661: if (ny > s->rlower + 1 - s->cy)
! 662: ny = s->rlower + 1 - s->cy;
! 663: if (ny == 0)
! 664: return;
! 665:
! 666: screen_write_initctx(ctx, &ttyctx);
! 667: ttyctx.bg = bg;
! 668:
! 669: if (s->cy < s->rupper || s->cy > s->rlower)
! 670: grid_view_insert_lines(gd, s->cy, ny, bg);
! 671: else
! 672: grid_view_insert_lines_region(gd, s->rlower, s->cy, ny, bg);
! 673:
! 674: screen_write_collect_flush(ctx, 0);
! 675: ttyctx.num = ny;
! 676: tty_write(tty_cmd_insertline, &ttyctx);
! 677: }
! 678:
! 679: /* Delete ny lines. */
! 680: void
! 681: screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg)
! 682: {
! 683: struct screen *s = ctx->s;
! 684: struct grid *gd = s->grid;
! 685: struct tty_ctx ttyctx;
! 686:
! 687: if (ny == 0)
! 688: ny = 1;
! 689:
! 690: if (s->cy < s->rupper || s->cy > s->rlower) {
! 691: if (ny > screen_size_y(s) - s->cy)
! 692: ny = screen_size_y(s) - s->cy;
! 693: if (ny == 0)
! 694: return;
! 695:
! 696: screen_write_initctx(ctx, &ttyctx);
! 697: ttyctx.bg = bg;
! 698:
! 699: grid_view_delete_lines(gd, s->cy, ny, bg);
! 700:
! 701: screen_write_collect_flush(ctx, 0);
! 702: ttyctx.num = ny;
! 703: tty_write(tty_cmd_deleteline, &ttyctx);
! 704: return;
! 705: }
! 706:
! 707: if (ny > s->rlower + 1 - s->cy)
! 708: ny = s->rlower + 1 - s->cy;
! 709: if (ny == 0)
! 710: return;
! 711:
! 712: screen_write_initctx(ctx, &ttyctx);
! 713: ttyctx.bg = bg;
! 714:
! 715: if (s->cy < s->rupper || s->cy > s->rlower)
! 716: grid_view_delete_lines(gd, s->cy, ny, bg);
! 717: else
! 718: grid_view_delete_lines_region(gd, s->rlower, s->cy, ny, bg);
! 719:
! 720: screen_write_collect_flush(ctx, 0);
! 721: ttyctx.num = ny;
! 722: tty_write(tty_cmd_deleteline, &ttyctx);
! 723: }
! 724:
! 725: /* Clear line at cursor. */
! 726: void
! 727: screen_write_clearline(struct screen_write_ctx *ctx, u_int bg)
! 728: {
! 729: struct screen *s = ctx->s;
! 730: struct grid_line *gl;
! 731: struct tty_ctx ttyctx;
! 732: u_int sx = screen_size_x(s);
! 733:
! 734: gl = &s->grid->linedata[s->grid->hsize + s->cy];
! 735: if (gl->cellsize == 0 && bg == 8)
! 736: return;
! 737:
! 738: screen_write_initctx(ctx, &ttyctx);
! 739: ttyctx.bg = bg;
! 740:
! 741: grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
! 742:
! 743: screen_write_collect_clear(ctx, s->cy, 1);
! 744: screen_write_collect_flush(ctx, 0);
! 745: tty_write(tty_cmd_clearline, &ttyctx);
! 746: }
! 747:
! 748: /* Clear to end of line from cursor. */
! 749: void
! 750: screen_write_clearendofline(struct screen_write_ctx *ctx, u_int bg)
! 751: {
! 752: struct screen *s = ctx->s;
! 753: struct grid_line *gl;
! 754: struct tty_ctx ttyctx;
! 755: u_int sx = screen_size_x(s);
! 756:
! 757: gl = &s->grid->linedata[s->grid->hsize + s->cy];
! 758: if (s->cx > sx - 1 || (s->cx >= gl->cellsize && bg == 8))
! 759: return;
! 760:
! 761: screen_write_initctx(ctx, &ttyctx);
! 762: ttyctx.bg = bg;
! 763:
! 764: grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg);
! 765:
! 766: if (s->cx == 0)
! 767: screen_write_collect_clear(ctx, s->cy, 1);
! 768: screen_write_collect_flush(ctx, 0);
! 769: tty_write(tty_cmd_clearendofline, &ttyctx);
! 770: }
! 771:
! 772: /* Clear to start of line from cursor. */
! 773: void
! 774: screen_write_clearstartofline(struct screen_write_ctx *ctx, u_int bg)
! 775: {
! 776: struct screen *s = ctx->s;
! 777: struct tty_ctx ttyctx;
! 778: u_int sx = screen_size_x(s);
! 779:
! 780: screen_write_initctx(ctx, &ttyctx);
! 781: ttyctx.bg = bg;
! 782:
! 783: if (s->cx > sx - 1)
! 784: grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
! 785: else
! 786: grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg);
! 787:
! 788: if (s->cx > sx - 1)
! 789: screen_write_collect_clear(ctx, s->cy, 1);
! 790: screen_write_collect_flush(ctx, 0);
! 791: tty_write(tty_cmd_clearstartofline, &ttyctx);
! 792: }
! 793:
! 794: /* Move cursor to px,py. */
! 795: void
! 796: screen_write_cursormove(struct screen_write_ctx *ctx, u_int px, u_int py)
! 797: {
! 798: struct screen *s = ctx->s;
! 799:
! 800: if (px > screen_size_x(s) - 1)
! 801: px = screen_size_x(s) - 1;
! 802: if (py > screen_size_y(s) - 1)
! 803: py = screen_size_y(s) - 1;
! 804:
! 805: s->cx = px;
! 806: s->cy = py;
! 807: }
! 808:
! 809: /* Reverse index (up with scroll). */
! 810: void
! 811: screen_write_reverseindex(struct screen_write_ctx *ctx)
! 812: {
! 813: struct screen *s = ctx->s;
! 814: struct tty_ctx ttyctx;
! 815:
! 816: screen_write_initctx(ctx, &ttyctx);
! 817:
! 818: if (s->cy == s->rupper)
! 819: grid_view_scroll_region_down(s->grid, s->rupper, s->rlower);
! 820: else if (s->cy > 0)
! 821: s->cy--;
! 822:
! 823: screen_write_collect_flush(ctx, 0);
! 824: tty_write(tty_cmd_reverseindex, &ttyctx);
! 825: }
! 826:
! 827: /* Set scroll region. */
! 828: void
! 829: screen_write_scrollregion(struct screen_write_ctx *ctx, u_int rupper,
! 830: u_int rlower)
! 831: {
! 832: struct screen *s = ctx->s;
! 833:
! 834: if (rupper > screen_size_y(s) - 1)
! 835: rupper = screen_size_y(s) - 1;
! 836: if (rlower > screen_size_y(s) - 1)
! 837: rlower = screen_size_y(s) - 1;
! 838: if (rupper >= rlower) /* cannot be one line */
! 839: return;
! 840:
! 841: screen_write_collect_flush(ctx, 0);
! 842:
! 843: /* Cursor moves to top-left. */
! 844: s->cx = 0;
! 845: s->cy = 0;
! 846:
! 847: s->rupper = rupper;
! 848: s->rlower = rlower;
! 849: }
! 850:
! 851: /* Line feed. */
! 852: void
! 853: screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped)
! 854: {
! 855: struct screen *s = ctx->s;
! 856: struct grid *gd = s->grid;
! 857: struct grid_line *gl;
! 858:
! 859: gl = &gd->linedata[gd->hsize + s->cy];
! 860: if (wrapped)
! 861: gl->flags |= GRID_LINE_WRAPPED;
! 862: else
! 863: gl->flags &= ~GRID_LINE_WRAPPED;
! 864:
! 865: log_debug("%s: at %u,%u (region %u-%u)", __func__, s->cx, s->cy,
! 866: s->rupper, s->rlower);
! 867:
! 868: if (s->cy == s->rlower) {
! 869: grid_view_scroll_region_up(gd, s->rupper, s->rlower);
! 870: screen_write_collect_scroll(ctx);
! 871: ctx->scrolled++;
! 872: } else if (s->cy < screen_size_y(s) - 1)
! 873: s->cy++;
! 874: }
! 875:
! 876: /* Scroll up. */
! 877: void
! 878: screen_write_scrollup(struct screen_write_ctx *ctx, u_int lines)
! 879: {
! 880: struct screen *s = ctx->s;
! 881: struct grid *gd = s->grid;
! 882: u_int i;
! 883:
! 884: if (lines == 0)
! 885: lines = 1;
! 886: else if (lines > s->rlower - s->rupper + 1)
! 887: lines = s->rlower - s->rupper + 1;
! 888:
! 889: for (i = 0; i < lines; i++) {
! 890: grid_view_scroll_region_up(gd, s->rupper, s->rlower);
! 891: screen_write_collect_scroll(ctx);
! 892: }
! 893: ctx->scrolled += lines;
! 894: }
! 895:
! 896: /* Carriage return (cursor to start of line). */
! 897: void
! 898: screen_write_carriagereturn(struct screen_write_ctx *ctx)
! 899: {
! 900: struct screen *s = ctx->s;
! 901:
! 902: s->cx = 0;
! 903: }
! 904:
! 905: /* Clear to end of screen from cursor. */
! 906: void
! 907: screen_write_clearendofscreen(struct screen_write_ctx *ctx, u_int bg)
! 908: {
! 909: struct screen *s = ctx->s;
! 910: struct grid *gd = s->grid;
! 911: struct tty_ctx ttyctx;
! 912: u_int sx = screen_size_x(s), sy = screen_size_y(s);
! 913:
! 914: screen_write_initctx(ctx, &ttyctx);
! 915: ttyctx.bg = bg;
! 916:
! 917: /* Scroll into history if it is enabled and clearing entire screen. */
! 918: if (s->cx == 0 && s->cy == 0 && (gd->flags & GRID_HISTORY))
! 919: grid_view_clear_history(gd, bg);
! 920: else {
! 921: if (s->cx <= sx - 1)
! 922: grid_view_clear(gd, s->cx, s->cy, sx - s->cx, 1, bg);
! 923: grid_view_clear(gd, 0, s->cy + 1, sx, sy - (s->cy + 1), bg);
! 924: }
! 925:
! 926: screen_write_collect_clear(ctx, s->cy + 1, sy - (s->cy + 1));
! 927: screen_write_collect_flush(ctx, 0);
! 928: tty_write(tty_cmd_clearendofscreen, &ttyctx);
! 929: }
! 930:
! 931: /* Clear to start of screen. */
! 932: void
! 933: screen_write_clearstartofscreen(struct screen_write_ctx *ctx, u_int bg)
! 934: {
! 935: struct screen *s = ctx->s;
! 936: struct tty_ctx ttyctx;
! 937: u_int sx = screen_size_x(s);
! 938:
! 939: screen_write_initctx(ctx, &ttyctx);
! 940: ttyctx.bg = bg;
! 941:
! 942: if (s->cy > 0)
! 943: grid_view_clear(s->grid, 0, 0, sx, s->cy, bg);
! 944: if (s->cx > sx - 1)
! 945: grid_view_clear(s->grid, 0, s->cy, sx, 1, 8);
! 946: else
! 947: grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, 8);
! 948:
! 949: screen_write_collect_clear(ctx, 0, s->cy);
! 950: screen_write_collect_flush(ctx, 0);
! 951: tty_write(tty_cmd_clearstartofscreen, &ttyctx);
! 952: }
! 953:
! 954: /* Clear entire screen. */
! 955: void
! 956: screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg)
! 957: {
! 958: struct screen *s = ctx->s;
! 959: struct tty_ctx ttyctx;
! 960: u_int sx = screen_size_x(s), sy = screen_size_y(s);
! 961:
! 962: screen_write_initctx(ctx, &ttyctx);
! 963: ttyctx.bg = bg;
! 964:
! 965: /* Scroll into history if it is enabled. */
! 966: if (s->grid->flags & GRID_HISTORY)
! 967: grid_view_clear_history(s->grid, bg);
! 968: else
! 969: grid_view_clear(s->grid, 0, 0, sx, sy, bg);
! 970:
! 971: screen_write_collect_clear(ctx, 0, sy);
! 972: tty_write(tty_cmd_clearscreen, &ttyctx);
! 973: }
! 974:
! 975: /* Clear entire history. */
! 976: void
! 977: screen_write_clearhistory(struct screen_write_ctx *ctx)
! 978: {
! 979: struct screen *s = ctx->s;
! 980: struct grid *gd = s->grid;
! 981:
! 982: grid_move_lines(gd, 0, gd->hsize, gd->sy, 8);
! 983: gd->hscrolled = gd->hsize = 0;
! 984: }
! 985:
! 986: /* Clear a collected line. */
! 987: static void
! 988: screen_write_collect_clear(struct screen_write_ctx *ctx, u_int y, u_int n)
! 989: {
! 990: struct screen_write_collect_item *ci, *tmp;
! 991: u_int i;
! 992: size_t size;
! 993:
! 994: for (i = y ; i < y + n; i++) {
! 995: if (TAILQ_EMPTY(&ctx->list[i].items))
! 996: continue;
! 997: size = 0;
! 998: TAILQ_FOREACH_SAFE(ci, &ctx->list[i].items, entry, tmp) {
! 999: size += ci->used;
! 1000: TAILQ_REMOVE(&ctx->list[i].items, ci, entry);
! 1001: free(ci);
! 1002: }
! 1003: ctx->skipped += size;
! 1004: log_debug("%s: dropped %zu bytes (line %u)", __func__, size, i);
! 1005: }
! 1006: }
! 1007:
! 1008: /* Scroll collected lines up. */
! 1009: static void
! 1010: screen_write_collect_scroll(struct screen_write_ctx *ctx)
! 1011: {
! 1012: struct screen *s = ctx->s;
! 1013: struct screen_write_collect_line *cl;
! 1014: u_int y;
! 1015:
! 1016: log_debug("%s: at %u,%u (region %u-%u)", __func__, s->cx, s->cy,
! 1017: s->rupper, s->rlower);
! 1018:
! 1019: screen_write_collect_clear(ctx, s->rupper, 1);
! 1020: for (y = s->rupper; y < s->rlower; y++) {
! 1021: cl = &ctx->list[y + 1];
! 1022: TAILQ_CONCAT(&ctx->list[y].items, &cl->items, entry);
! 1023: TAILQ_INIT(&cl->items);
! 1024: }
! 1025: }
! 1026:
! 1027: /* Flush collected lines. */
! 1028: static void
! 1029: screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only)
! 1030: {
! 1031: struct screen *s = ctx->s;
! 1032: struct screen_write_collect_item *ci, *tmp;
! 1033: u_int y, cx, cy, items = 0;
! 1034: struct tty_ctx ttyctx;
! 1035: size_t written = 0;
! 1036:
! 1037: if (ctx->scrolled != 0) {
! 1038: log_debug("%s: scrolled %u (region %u-%u)", __func__,
! 1039: ctx->scrolled, s->rupper, s->rlower);
! 1040: if (ctx->scrolled > s->rlower - s->rupper + 1)
! 1041: ctx->scrolled = s->rlower - s->rupper + 1;
! 1042:
! 1043: screen_write_initctx(ctx, &ttyctx);
! 1044: ttyctx.num = ctx->scrolled;
! 1045: tty_write(tty_cmd_scrollup, &ttyctx);
! 1046: }
! 1047: ctx->scrolled = 0;
! 1048: if (scroll_only)
! 1049: return;
! 1050:
! 1051: cx = s->cx; cy = s->cy;
! 1052: for (y = 0; y < screen_size_y(s); y++) {
! 1053: TAILQ_FOREACH_SAFE(ci, &ctx->list[y].items, entry, tmp) {
! 1054: screen_write_cursormove(ctx, ci->x, y);
! 1055: screen_write_initctx(ctx, &ttyctx);
! 1056: ttyctx.cell = &ci->gc;
! 1057: ttyctx.ptr = ci->data;
! 1058: ttyctx.num = ci->used;
! 1059: tty_write(tty_cmd_cells, &ttyctx);
! 1060:
! 1061: items++;
! 1062: written += ci->used;
! 1063:
! 1064: TAILQ_REMOVE(&ctx->list[y].items, ci, entry);
! 1065: free(ci);
! 1066: }
! 1067: }
! 1068: s->cx = cx; s->cy = cy;
! 1069:
! 1070: log_debug("%s: flushed %u items (%zu bytes)", __func__, items, written);
! 1071: ctx->written += written;
! 1072: }
! 1073:
! 1074: /* Finish and store collected cells. */
! 1075: void
! 1076: screen_write_collect_end(struct screen_write_ctx *ctx)
! 1077: {
! 1078: struct screen *s = ctx->s;
! 1079: struct screen_write_collect_item *ci = ctx->item;
! 1080: struct grid_cell gc;
! 1081:
! 1082: if (ci->used == 0)
! 1083: return;
! 1084: ci->data[ci->used] = '\0';
! 1085:
! 1086: ci->x = s->cx;
! 1087: TAILQ_INSERT_TAIL(&ctx->list[s->cy].items, ci, entry);
! 1088: ctx->item = xcalloc(1, sizeof *ctx->item);
! 1089:
! 1090: log_debug("%s: %u %s (at %u,%u)", __func__, ci->used, ci->data, s->cx,
! 1091: s->cy);
! 1092:
! 1093: memcpy(&gc, &ci->gc, sizeof gc);
! 1094: grid_view_set_cells(s->grid, s->cx, s->cy, &gc, ci->data, ci->used);
! 1095: s->cx += ci->used;
! 1096: }
! 1097:
! 1098: /* Write cell data, collecting if necessary. */
! 1099: void
! 1100: screen_write_collect_add(struct screen_write_ctx *ctx,
! 1101: const struct grid_cell *gc)
! 1102: {
! 1103: struct screen *s = ctx->s;
! 1104: struct screen_write_collect_item *ci;
! 1105: u_int sx = screen_size_x(s);
! 1106: int collect;
! 1107:
! 1108: /*
! 1109: * Don't need to check that the attributes and whatnot are still the
! 1110: * same - input_parse will end the collection when anything that isn't
! 1111: * a plain character is encountered. Also nothing should make it here
! 1112: * that isn't a single ASCII character.
! 1113: */
! 1114:
! 1115: collect = 1;
! 1116: if (gc->data.width != 1)
! 1117: collect = 0;
! 1118: else if (gc->attr & GRID_ATTR_CHARSET)
! 1119: collect = 0;
! 1120: else if (~s->mode & MODE_WRAP)
! 1121: collect = 0;
! 1122: else if (s->mode & MODE_INSERT)
! 1123: collect = 0;
! 1124: else if (s->sel.flag)
! 1125: collect = 0;
! 1126: if (!collect) {
! 1127: screen_write_collect_end(ctx);
! 1128: screen_write_collect_flush(ctx, 0);
! 1129: screen_write_cell(ctx, gc);
! 1130: return;
! 1131: }
! 1132: ctx->cells++;
! 1133:
! 1134: if (s->cx > sx - 1 || ctx->item->used > sx - 1 - s->cx)
! 1135: screen_write_collect_end(ctx);
! 1136: if (s->cx > sx - 1) {
! 1137: log_debug("%s: wrapped at %u,%u", __func__, s->cx, s->cy);
! 1138: screen_write_linefeed(ctx, 1);
! 1139: s->cx = 0;
! 1140: }
! 1141:
! 1142: ci = ctx->item; /* may have changed */
! 1143: if (ci->used == 0)
! 1144: memcpy(&ci->gc, gc, sizeof ci->gc);
! 1145: ci->data[ci->used++] = gc->data.data[0];
! 1146: if (ci->used == (sizeof ci->data) - 1)
! 1147: screen_write_collect_end(ctx);
! 1148: }
! 1149:
! 1150: /* Write cell data. */
! 1151: void
! 1152: screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
! 1153: {
! 1154: struct screen *s = ctx->s;
! 1155: struct grid *gd = s->grid;
! 1156: struct grid_line *gl;
! 1157: struct grid_cell_entry *gce;
! 1158: struct grid_cell tmp_gc, now_gc;
! 1159: struct tty_ctx ttyctx;
! 1160: u_int sx = screen_size_x(s), sy = screen_size_y(s);
! 1161: u_int width = gc->data.width, xx, last, cx, cy;
! 1162: int selected, skip = 1;
! 1163:
! 1164: /* Ignore padding cells. */
! 1165: if (gc->flags & GRID_FLAG_PADDING)
! 1166: return;
! 1167: ctx->cells++;
! 1168:
! 1169: /* If the width is zero, combine onto the previous character. */
! 1170: if (width == 0) {
! 1171: screen_write_collect_flush(ctx, 0);
! 1172: if ((gc = screen_write_combine(ctx, &gc->data, &xx)) != 0) {
! 1173: cx = s->cx; cy = s->cy;
! 1174: screen_write_cursormove(ctx, xx, s->cy);
! 1175: screen_write_initctx(ctx, &ttyctx);
! 1176: ttyctx.cell = gc;
! 1177: tty_write(tty_cmd_cell, &ttyctx);
! 1178: s->cx = cx; s->cy = cy;
! 1179: }
! 1180: return;
! 1181: }
! 1182:
! 1183: /* Flush any existing scrolling. */
! 1184: screen_write_collect_flush(ctx, 1);
! 1185:
! 1186: /* If this character doesn't fit, ignore it. */
! 1187: if ((~s->mode & MODE_WRAP) &&
! 1188: width > 1 &&
! 1189: (width > sx || (s->cx != sx && s->cx > sx - width)))
! 1190: return;
! 1191:
! 1192: /* If in insert mode, make space for the cells. */
! 1193: if (s->mode & MODE_INSERT) {
! 1194: grid_view_insert_cells(s->grid, s->cx, s->cy, width, 8);
! 1195: skip = 0;
! 1196: }
! 1197:
! 1198: /* Check this will fit on the current line and wrap if not. */
! 1199: if ((s->mode & MODE_WRAP) && s->cx > sx - width) {
! 1200: screen_write_linefeed(ctx, 1);
! 1201: s->cx = 0;
! 1202: }
! 1203:
! 1204: /* Sanity check cursor position. */
! 1205: if (s->cx > sx - width || s->cy > sy - 1)
! 1206: return;
! 1207: screen_write_initctx(ctx, &ttyctx);
! 1208:
! 1209: /* Handle overwriting of UTF-8 characters. */
! 1210: gl = &s->grid->linedata[s->grid->hsize + s->cy];
! 1211: if (gl->flags & GRID_LINE_EXTENDED) {
! 1212: grid_view_get_cell(gd, s->cx, s->cy, &now_gc);
! 1213: if (screen_write_overwrite(ctx, &now_gc, width))
! 1214: skip = 0;
! 1215: }
! 1216:
! 1217: /*
! 1218: * If the new character is UTF-8 wide, fill in padding cells. Have
! 1219: * already ensured there is enough room.
! 1220: */
! 1221: for (xx = s->cx + 1; xx < s->cx + width; xx++) {
! 1222: grid_view_set_cell(gd, xx, s->cy, &screen_write_pad_cell);
! 1223: skip = 0;
! 1224: }
! 1225:
! 1226: /* If no change, do not draw. */
! 1227: if (skip) {
! 1228: if (s->cx >= gl->cellsize)
! 1229: skip = grid_cells_equal(gc, &grid_default_cell);
! 1230: else {
! 1231: gce = &gl->celldata[s->cx];
! 1232: if (gce->flags & GRID_FLAG_EXTENDED)
! 1233: skip = 0;
! 1234: else if (gc->flags != gce->flags)
! 1235: skip = 0;
! 1236: else if (gc->attr != gce->data.attr)
! 1237: skip = 0;
! 1238: else if (gc->fg != gce->data.fg)
! 1239: skip = 0;
! 1240: else if (gc->bg != gce->data.bg)
! 1241: skip = 0;
! 1242: else if (gc->data.width != 1)
! 1243: skip = 0;
! 1244: else if (gc->data.size != 1)
! 1245: skip = 0;
! 1246: else if (gce->data.data != gc->data.data[0])
! 1247: skip = 0;
! 1248: }
! 1249: }
! 1250:
! 1251: /* Update the selection the flag and set the cell. */
! 1252: selected = screen_check_selection(s, s->cx, s->cy);
! 1253: if (selected && (~gc->flags & GRID_FLAG_SELECTED)) {
! 1254: memcpy(&tmp_gc, gc, sizeof tmp_gc);
! 1255: tmp_gc.flags |= GRID_FLAG_SELECTED;
! 1256: grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc);
! 1257: } else if (!selected && (gc->flags & GRID_FLAG_SELECTED)) {
! 1258: memcpy(&tmp_gc, gc, sizeof tmp_gc);
! 1259: tmp_gc.flags &= ~GRID_FLAG_SELECTED;
! 1260: grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc);
! 1261: } else if (!skip)
! 1262: grid_view_set_cell(gd, s->cx, s->cy, gc);
! 1263: if (selected)
! 1264: skip = 0;
! 1265:
! 1266: /*
! 1267: * Move the cursor. If not wrapping, stick at the last character and
! 1268: * replace it.
! 1269: */
! 1270: last = !(s->mode & MODE_WRAP);
! 1271: if (s->cx <= sx - last - width)
! 1272: s->cx += width;
! 1273: else
! 1274: s->cx = sx - last;
! 1275:
! 1276: /* Create space for character in insert mode. */
! 1277: if (s->mode & MODE_INSERT) {
! 1278: screen_write_collect_flush(ctx, 0);
! 1279: ttyctx.num = width;
! 1280: tty_write(tty_cmd_insertcharacter, &ttyctx);
! 1281: }
! 1282:
! 1283: /* Write to the screen. */
! 1284: if (!skip) {
! 1285: if (selected) {
! 1286: screen_select_cell(s, &tmp_gc, gc);
! 1287: ttyctx.cell = &tmp_gc;
! 1288: } else
! 1289: ttyctx.cell = gc;
! 1290: tty_write(tty_cmd_cell, &ttyctx);
! 1291: ctx->written++;
! 1292: } else
! 1293: ctx->skipped++;
! 1294: }
! 1295:
! 1296: /* Combine a UTF-8 zero-width character onto the previous. */
! 1297: static const struct grid_cell *
! 1298: screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud,
! 1299: u_int *xx)
! 1300: {
! 1301: struct screen *s = ctx->s;
! 1302: struct grid *gd = s->grid;
! 1303: static struct grid_cell gc;
! 1304: u_int n;
! 1305:
! 1306: /* Can't combine if at 0. */
! 1307: if (s->cx == 0)
! 1308: return (NULL);
! 1309:
! 1310: /* Empty data is out. */
! 1311: if (ud->size == 0)
! 1312: fatalx("UTF-8 data empty");
! 1313:
! 1314: /* Retrieve the previous cell. */
! 1315: for (n = 1; n < s->cx; n++) {
! 1316: grid_view_get_cell(gd, s->cx - n, s->cy, &gc);
! 1317: if (~gc.flags & GRID_FLAG_PADDING)
! 1318: break;
! 1319: }
! 1320: if (n == s->cx)
! 1321: return (NULL);
! 1322: *xx = s->cx - n;
! 1323:
! 1324: /* Check there is enough space. */
! 1325: if (gc.data.size + ud->size > sizeof gc.data.data)
! 1326: return (NULL);
! 1327:
! 1328: log_debug("%s: %.*s onto %.*s at %u,%u", __func__, (int)ud->size,
! 1329: ud->data, (int)gc.data.size, gc.data.data, *xx, s->cy);
! 1330:
! 1331: /* Append the data. */
! 1332: memcpy(gc.data.data + gc.data.size, ud->data, ud->size);
! 1333: gc.data.size += ud->size;
! 1334:
! 1335: /* Set the new cell. */
! 1336: grid_view_set_cell(gd, *xx, s->cy, &gc);
! 1337:
! 1338: return (&gc);
! 1339: }
! 1340:
! 1341: /*
! 1342: * UTF-8 wide characters are a bit of an annoyance. They take up more than one
! 1343: * cell on the screen, so following cells must not be drawn by marking them as
! 1344: * padding.
! 1345: *
! 1346: * So far, so good. The problem is, when overwriting a padding cell, or a UTF-8
! 1347: * character, it is necessary to also overwrite any other cells which covered
! 1348: * by the same character.
! 1349: */
! 1350: static int
! 1351: screen_write_overwrite(struct screen_write_ctx *ctx, struct grid_cell *gc,
! 1352: u_int width)
! 1353: {
! 1354: struct screen *s = ctx->s;
! 1355: struct grid *gd = s->grid;
! 1356: struct grid_cell tmp_gc;
! 1357: u_int xx;
! 1358: int done = 0;
! 1359:
! 1360: if (gc->flags & GRID_FLAG_PADDING) {
! 1361: /*
! 1362: * A padding cell, so clear any following and leading padding
! 1363: * cells back to the character. Don't overwrite the current
! 1364: * cell as that happens later anyway.
! 1365: */
! 1366: xx = s->cx + 1;
! 1367: while (--xx > 0) {
! 1368: grid_view_get_cell(gd, xx, s->cy, &tmp_gc);
! 1369: if (~tmp_gc.flags & GRID_FLAG_PADDING)
! 1370: break;
! 1371: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
! 1372: }
! 1373:
! 1374: /* Overwrite the character at the start of this padding. */
! 1375: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
! 1376: done = 1;
! 1377: }
! 1378:
! 1379: /*
! 1380: * Overwrite any padding cells that belong to any UTF-8 characters
! 1381: * we'll be overwriting with the current character.
! 1382: */
! 1383: if (width != 1 ||
! 1384: gc->data.width != 1 ||
! 1385: gc->flags & GRID_FLAG_PADDING) {
! 1386: xx = s->cx + width - 1;
! 1387: while (++xx < screen_size_x(s)) {
! 1388: grid_view_get_cell(gd, xx, s->cy, &tmp_gc);
! 1389: if (~tmp_gc.flags & GRID_FLAG_PADDING)
! 1390: break;
! 1391: grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
! 1392: done = 1;
! 1393: }
! 1394: }
! 1395:
! 1396: return (done);
! 1397: }
! 1398:
! 1399: /* Set external clipboard. */
! 1400: void
! 1401: screen_write_setselection(struct screen_write_ctx *ctx, u_char *str, u_int len)
! 1402: {
! 1403: struct tty_ctx ttyctx;
! 1404:
! 1405: screen_write_initctx(ctx, &ttyctx);
! 1406: ttyctx.ptr = str;
! 1407: ttyctx.num = len;
! 1408:
! 1409: tty_write(tty_cmd_setselection, &ttyctx);
! 1410: }
! 1411:
! 1412: /* Write unmodified string. */
! 1413: void
! 1414: screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len)
! 1415: {
! 1416: struct tty_ctx ttyctx;
! 1417:
! 1418: screen_write_initctx(ctx, &ttyctx);
! 1419: ttyctx.ptr = str;
! 1420: ttyctx.num = len;
! 1421:
! 1422: tty_write(tty_cmd_rawstring, &ttyctx);
! 1423: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>