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