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