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