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