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