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