screen-write.c 24 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114
  1. /* $OpenBSD$ */
  2. /*
  3. * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
  14. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  15. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include <sys/types.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include "tmux.h"
  21. void screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *, int);
  22. void screen_write_overwrite(struct screen_write_ctx *, u_int);
  23. int screen_write_combine(struct screen_write_ctx *,
  24. const struct utf8_data *);
  25. /* Initialise writing with a window. */
  26. void
  27. screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp,
  28. struct screen *s)
  29. {
  30. ctx->wp = wp;
  31. if (wp != NULL && s == NULL)
  32. ctx->s = wp->screen;
  33. else
  34. ctx->s = s;
  35. }
  36. /* Finish writing. */
  37. void
  38. screen_write_stop(__unused struct screen_write_ctx *ctx)
  39. {
  40. }
  41. /* Reset screen state. */
  42. void
  43. screen_write_reset(struct screen_write_ctx *ctx)
  44. {
  45. struct screen *s = ctx->s;
  46. screen_reset_tabs(s);
  47. screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1);
  48. s->mode &= ~(MODE_INSERT|MODE_KCURSOR|MODE_KKEYPAD|MODE_FOCUSON);
  49. s->mode &= ~(ALL_MOUSE_MODES|MODE_MOUSE_UTF8|MODE_MOUSE_SGR);
  50. screen_write_clearscreen(ctx);
  51. screen_write_cursormove(ctx, 0, 0);
  52. }
  53. /* Write character. */
  54. void
  55. screen_write_putc(struct screen_write_ctx *ctx, struct grid_cell *gc,
  56. u_char ch)
  57. {
  58. utf8_set(&gc->data, ch);
  59. screen_write_cell(ctx, gc);
  60. }
  61. /* Calculate string length, with embedded formatting. */
  62. size_t
  63. screen_write_cstrlen(const char *fmt, ...)
  64. {
  65. va_list ap;
  66. char *msg, *msg2, *ptr, *ptr2;
  67. size_t size;
  68. va_start(ap, fmt);
  69. xvasprintf(&msg, fmt, ap);
  70. va_end(ap);
  71. msg2 = xmalloc(strlen(msg) + 1);
  72. ptr = msg;
  73. ptr2 = msg2;
  74. while (*ptr != '\0') {
  75. if (ptr[0] == '#' && ptr[1] == '[') {
  76. while (*ptr != ']' && *ptr != '\0')
  77. ptr++;
  78. if (*ptr == ']')
  79. ptr++;
  80. continue;
  81. }
  82. *ptr2++ = *ptr++;
  83. }
  84. *ptr2 = '\0';
  85. size = screen_write_strlen("%s", msg2);
  86. free(msg);
  87. free(msg2);
  88. return (size);
  89. }
  90. /* Calculate string length. */
  91. size_t
  92. screen_write_strlen(const char *fmt, ...)
  93. {
  94. va_list ap;
  95. char *msg;
  96. struct utf8_data ud;
  97. u_char *ptr;
  98. size_t left, size = 0;
  99. enum utf8_state more;
  100. va_start(ap, fmt);
  101. xvasprintf(&msg, fmt, ap);
  102. va_end(ap);
  103. ptr = msg;
  104. while (*ptr != '\0') {
  105. if (*ptr > 0x7f && utf8_open(&ud, *ptr) == UTF8_MORE) {
  106. ptr++;
  107. left = strlen(ptr);
  108. if (left < (size_t)ud.size - 1)
  109. break;
  110. while ((more = utf8_append(&ud, *ptr)) == UTF8_MORE)
  111. ptr++;
  112. ptr++;
  113. if (more == UTF8_DONE)
  114. size += ud.width;
  115. } else {
  116. if (*ptr > 0x1f && *ptr < 0x7f)
  117. size++;
  118. ptr++;
  119. }
  120. }
  121. free(msg);
  122. return (size);
  123. }
  124. /* Write simple string (no UTF-8 or maximum length). */
  125. void
  126. screen_write_puts(struct screen_write_ctx *ctx, struct grid_cell *gc,
  127. const char *fmt, ...)
  128. {
  129. va_list ap;
  130. va_start(ap, fmt);
  131. screen_write_vnputs(ctx, -1, gc, fmt, ap);
  132. va_end(ap);
  133. }
  134. /* Write string with length limit (-1 for unlimited). */
  135. void
  136. screen_write_nputs(struct screen_write_ctx *ctx, ssize_t maxlen,
  137. struct grid_cell *gc, const char *fmt, ...)
  138. {
  139. va_list ap;
  140. va_start(ap, fmt);
  141. screen_write_vnputs(ctx, maxlen, gc, fmt, ap);
  142. va_end(ap);
  143. }
  144. void
  145. screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
  146. struct grid_cell *gc, const char *fmt, va_list ap)
  147. {
  148. char *msg;
  149. struct utf8_data ud;
  150. u_char *ptr;
  151. size_t left, size = 0;
  152. enum utf8_state more;
  153. xvasprintf(&msg, fmt, ap);
  154. ptr = msg;
  155. while (*ptr != '\0') {
  156. if (*ptr > 0x7f && utf8_open(&ud, *ptr) == UTF8_MORE) {
  157. ptr++;
  158. left = strlen(ptr);
  159. if (left < (size_t)ud.size - 1)
  160. break;
  161. while ((more = utf8_append(&ud, *ptr)) == UTF8_MORE)
  162. ptr++;
  163. ptr++;
  164. if (more == UTF8_DONE) {
  165. if (maxlen > 0 &&
  166. size + ud.width > (size_t) maxlen) {
  167. while (size < (size_t) maxlen) {
  168. screen_write_putc(ctx, gc, ' ');
  169. size++;
  170. }
  171. break;
  172. }
  173. size += ud.width;
  174. utf8_copy(&gc->data, &ud);
  175. screen_write_cell(ctx, gc);
  176. }
  177. } else {
  178. if (maxlen > 0 && size + 1 > (size_t) maxlen)
  179. break;
  180. if (*ptr == '\001')
  181. gc->attr ^= GRID_ATTR_CHARSET;
  182. else if (*ptr > 0x1f && *ptr < 0x7f) {
  183. size++;
  184. screen_write_putc(ctx, gc, *ptr);
  185. }
  186. ptr++;
  187. }
  188. }
  189. free(msg);
  190. }
  191. /* Write string, similar to nputs, but with embedded formatting (#[]). */
  192. void
  193. screen_write_cnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
  194. struct grid_cell *gc, const char *fmt, ...)
  195. {
  196. struct grid_cell lgc;
  197. struct utf8_data ud;
  198. va_list ap;
  199. char *msg;
  200. u_char *ptr, *last;
  201. size_t left, size = 0;
  202. enum utf8_state more;
  203. va_start(ap, fmt);
  204. xvasprintf(&msg, fmt, ap);
  205. va_end(ap);
  206. memcpy(&lgc, gc, sizeof lgc);
  207. ptr = msg;
  208. while (*ptr != '\0') {
  209. if (ptr[0] == '#' && ptr[1] == '[') {
  210. ptr += 2;
  211. last = ptr + strcspn(ptr, "]");
  212. if (*last == '\0') {
  213. /* No ]. Not much point in doing anything. */
  214. break;
  215. }
  216. *last = '\0';
  217. style_parse(gc, &lgc, ptr);
  218. ptr = last + 1;
  219. continue;
  220. }
  221. if (*ptr > 0x7f && utf8_open(&ud, *ptr) == UTF8_MORE) {
  222. ptr++;
  223. left = strlen(ptr);
  224. if (left < (size_t)ud.size - 1)
  225. break;
  226. while ((more = utf8_append(&ud, *ptr)) == UTF8_MORE)
  227. ptr++;
  228. ptr++;
  229. if (more == UTF8_DONE) {
  230. if (maxlen > 0 &&
  231. size + ud.width > (size_t) maxlen) {
  232. while (size < (size_t) maxlen) {
  233. screen_write_putc(ctx, gc, ' ');
  234. size++;
  235. }
  236. break;
  237. }
  238. size += ud.width;
  239. utf8_copy(&lgc.data, &ud);
  240. screen_write_cell(ctx, &lgc);
  241. }
  242. } else {
  243. if (maxlen > 0 && size + 1 > (size_t) maxlen)
  244. break;
  245. if (*ptr > 0x1f && *ptr < 0x7f) {
  246. size++;
  247. screen_write_putc(ctx, &lgc, *ptr);
  248. }
  249. ptr++;
  250. }
  251. }
  252. free(msg);
  253. }
  254. /* Copy from another screen. */
  255. void
  256. screen_write_copy(struct screen_write_ctx *ctx,
  257. struct screen *src, u_int px, u_int py, u_int nx, u_int ny)
  258. {
  259. struct screen *s = ctx->s;
  260. struct grid *gd = src->grid;
  261. struct grid_line *gl;
  262. struct grid_cell gc;
  263. u_int xx, yy, cx, cy, ax, bx;
  264. cx = s->cx;
  265. cy = s->cy;
  266. for (yy = py; yy < py + ny; yy++) {
  267. gl = &gd->linedata[yy];
  268. if (yy < gd->hsize + gd->sy) {
  269. /*
  270. * Find start and end position and copy between
  271. * them. Limit to the real end of the line then use a
  272. * clear EOL only if copying to the end, otherwise
  273. * could overwrite whatever is there already.
  274. */
  275. if (px > gl->cellsize)
  276. ax = gl->cellsize;
  277. else
  278. ax = px;
  279. if (px + nx == gd->sx && px + nx > gl->cellsize)
  280. bx = gl->cellsize;
  281. else
  282. bx = px + nx;
  283. for (xx = ax; xx < bx; xx++) {
  284. grid_get_cell(gd, xx, yy, &gc);
  285. screen_write_cell(ctx, &gc);
  286. }
  287. if (px + nx == gd->sx && px + nx > gl->cellsize)
  288. screen_write_clearendofline(ctx);
  289. } else
  290. screen_write_clearline(ctx);
  291. cy++;
  292. screen_write_cursormove(ctx, cx, cy);
  293. }
  294. }
  295. /* Set up context for TTY command. */
  296. void
  297. screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx,
  298. int save_last)
  299. {
  300. struct screen *s = ctx->s;
  301. struct grid *gd = s->grid;
  302. struct grid_cell gc;
  303. u_int xx;
  304. ttyctx->wp = ctx->wp;
  305. ttyctx->ocx = s->cx;
  306. ttyctx->ocy = s->cy;
  307. ttyctx->orlower = s->rlower;
  308. ttyctx->orupper = s->rupper;
  309. if (!save_last)
  310. return;
  311. /* Save the last cell on the screen. */
  312. memcpy(&gc, &grid_default_cell, sizeof gc);
  313. for (xx = 1; xx <= screen_size_x(s); xx++) {
  314. grid_view_get_cell(gd, screen_size_x(s) - xx, s->cy, &gc);
  315. if (~gc.flags & GRID_FLAG_PADDING)
  316. break;
  317. }
  318. ttyctx->last_width = xx;
  319. memcpy(&ttyctx->last_cell, &gc, sizeof ttyctx->last_cell);
  320. }
  321. /* Set a mode. */
  322. void
  323. screen_write_mode_set(struct screen_write_ctx *ctx, int mode)
  324. {
  325. struct screen *s = ctx->s;
  326. s->mode |= mode;
  327. }
  328. /* Clear a mode. */
  329. void
  330. screen_write_mode_clear(struct screen_write_ctx *ctx, int mode)
  331. {
  332. struct screen *s = ctx->s;
  333. s->mode &= ~mode;
  334. }
  335. /* Cursor up by ny. */
  336. void
  337. screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny)
  338. {
  339. struct screen *s = ctx->s;
  340. if (ny == 0)
  341. ny = 1;
  342. if (s->cy < s->rupper) {
  343. /* Above region. */
  344. if (ny > s->cy)
  345. ny = s->cy;
  346. } else {
  347. /* Below region. */
  348. if (ny > s->cy - s->rupper)
  349. ny = s->cy - s->rupper;
  350. }
  351. if (s->cx == screen_size_x(s))
  352. s->cx--;
  353. if (ny == 0)
  354. return;
  355. s->cy -= ny;
  356. }
  357. /* Cursor down by ny. */
  358. void
  359. screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny)
  360. {
  361. struct screen *s = ctx->s;
  362. if (ny == 0)
  363. ny = 1;
  364. if (s->cy > s->rlower) {
  365. /* Below region. */
  366. if (ny > screen_size_y(s) - 1 - s->cy)
  367. ny = screen_size_y(s) - 1 - s->cy;
  368. } else {
  369. /* Above region. */
  370. if (ny > s->rlower - s->cy)
  371. ny = s->rlower - s->cy;
  372. }
  373. if (s->cx == screen_size_x(s))
  374. s->cx--;
  375. if (ny == 0)
  376. return;
  377. s->cy += ny;
  378. }
  379. /* Cursor right by nx. */
  380. void
  381. screen_write_cursorright(struct screen_write_ctx *ctx, u_int nx)
  382. {
  383. struct screen *s = ctx->s;
  384. if (nx == 0)
  385. nx = 1;
  386. if (nx > screen_size_x(s) - 1 - s->cx)
  387. nx = screen_size_x(s) - 1 - s->cx;
  388. if (nx == 0)
  389. return;
  390. s->cx += nx;
  391. }
  392. /* Cursor left by nx. */
  393. void
  394. screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx)
  395. {
  396. struct screen *s = ctx->s;
  397. if (nx == 0)
  398. nx = 1;
  399. if (nx > s->cx)
  400. nx = s->cx;
  401. if (nx == 0)
  402. return;
  403. s->cx -= nx;
  404. }
  405. /* Backspace; cursor left unless at start of wrapped line when can move up. */
  406. void
  407. screen_write_backspace(struct screen_write_ctx *ctx)
  408. {
  409. struct screen *s = ctx->s;
  410. struct grid_line *gl;
  411. if (s->cx == 0) {
  412. if (s->cy == 0)
  413. return;
  414. gl = &s->grid->linedata[s->grid->hsize + s->cy - 1];
  415. if (gl->flags & GRID_LINE_WRAPPED) {
  416. s->cy--;
  417. s->cx = screen_size_x(s) - 1;
  418. }
  419. } else
  420. s->cx--;
  421. }
  422. /* VT100 alignment test. */
  423. void
  424. screen_write_alignmenttest(struct screen_write_ctx *ctx)
  425. {
  426. struct screen *s = ctx->s;
  427. struct tty_ctx ttyctx;
  428. struct grid_cell gc;
  429. u_int xx, yy;
  430. screen_write_initctx(ctx, &ttyctx, 0);
  431. memcpy(&gc, &grid_default_cell, sizeof gc);
  432. utf8_set(&gc.data, 'E');
  433. for (yy = 0; yy < screen_size_y(s); yy++) {
  434. for (xx = 0; xx < screen_size_x(s); xx++)
  435. grid_view_set_cell(s->grid, xx, yy, &gc);
  436. }
  437. s->cx = 0;
  438. s->cy = 0;
  439. s->rupper = 0;
  440. s->rlower = screen_size_y(s) - 1;
  441. tty_write(tty_cmd_alignmenttest, &ttyctx);
  442. }
  443. /* Insert nx characters. */
  444. void
  445. screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx)
  446. {
  447. struct screen *s = ctx->s;
  448. struct tty_ctx ttyctx;
  449. if (nx == 0)
  450. nx = 1;
  451. if (nx > screen_size_x(s) - s->cx)
  452. nx = screen_size_x(s) - s->cx;
  453. if (nx == 0)
  454. return;
  455. screen_write_initctx(ctx, &ttyctx, 0);
  456. if (s->cx <= screen_size_x(s) - 1)
  457. grid_view_insert_cells(s->grid, s->cx, s->cy, nx);
  458. ttyctx.num = nx;
  459. tty_write(tty_cmd_insertcharacter, &ttyctx);
  460. }
  461. /* Delete nx characters. */
  462. void
  463. screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx)
  464. {
  465. struct screen *s = ctx->s;
  466. struct tty_ctx ttyctx;
  467. if (nx == 0)
  468. nx = 1;
  469. if (nx > screen_size_x(s) - s->cx)
  470. nx = screen_size_x(s) - s->cx;
  471. if (nx == 0)
  472. return;
  473. screen_write_initctx(ctx, &ttyctx, 0);
  474. if (s->cx <= screen_size_x(s) - 1)
  475. grid_view_delete_cells(s->grid, s->cx, s->cy, nx);
  476. ttyctx.num = nx;
  477. tty_write(tty_cmd_deletecharacter, &ttyctx);
  478. }
  479. /* Clear nx characters. */
  480. void
  481. screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx)
  482. {
  483. struct screen *s = ctx->s;
  484. struct tty_ctx ttyctx;
  485. if (nx == 0)
  486. nx = 1;
  487. if (nx > screen_size_x(s) - s->cx)
  488. nx = screen_size_x(s) - s->cx;
  489. if (nx == 0)
  490. return;
  491. screen_write_initctx(ctx, &ttyctx, 0);
  492. if (s->cx <= screen_size_x(s) - 1)
  493. grid_view_clear(s->grid, s->cx, s->cy, nx, 1);
  494. ttyctx.num = nx;
  495. tty_write(tty_cmd_clearcharacter, &ttyctx);
  496. }
  497. /* Insert ny lines. */
  498. void
  499. screen_write_insertline(struct screen_write_ctx *ctx, u_int ny)
  500. {
  501. struct screen *s = ctx->s;
  502. struct tty_ctx ttyctx;
  503. if (ny == 0)
  504. ny = 1;
  505. if (s->cy < s->rupper || s->cy > s->rlower) {
  506. if (ny > screen_size_y(s) - s->cy)
  507. ny = screen_size_y(s) - s->cy;
  508. if (ny == 0)
  509. return;
  510. screen_write_initctx(ctx, &ttyctx, 0);
  511. grid_view_insert_lines(s->grid, s->cy, ny);
  512. ttyctx.num = ny;
  513. tty_write(tty_cmd_insertline, &ttyctx);
  514. return;
  515. }
  516. if (ny > s->rlower + 1 - s->cy)
  517. ny = s->rlower + 1 - s->cy;
  518. if (ny == 0)
  519. return;
  520. screen_write_initctx(ctx, &ttyctx, 0);
  521. if (s->cy < s->rupper || s->cy > s->rlower)
  522. grid_view_insert_lines(s->grid, s->cy, ny);
  523. else
  524. grid_view_insert_lines_region(s->grid, s->rlower, s->cy, ny);
  525. ttyctx.num = ny;
  526. tty_write(tty_cmd_insertline, &ttyctx);
  527. }
  528. /* Delete ny lines. */
  529. void
  530. screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny)
  531. {
  532. struct screen *s = ctx->s;
  533. struct tty_ctx ttyctx;
  534. if (ny == 0)
  535. ny = 1;
  536. if (s->cy < s->rupper || s->cy > s->rlower) {
  537. if (ny > screen_size_y(s) - s->cy)
  538. ny = screen_size_y(s) - s->cy;
  539. if (ny == 0)
  540. return;
  541. screen_write_initctx(ctx, &ttyctx, 0);
  542. grid_view_delete_lines(s->grid, s->cy, ny);
  543. ttyctx.num = ny;
  544. tty_write(tty_cmd_deleteline, &ttyctx);
  545. return;
  546. }
  547. if (ny > s->rlower + 1 - s->cy)
  548. ny = s->rlower + 1 - s->cy;
  549. if (ny == 0)
  550. return;
  551. screen_write_initctx(ctx, &ttyctx, 0);
  552. if (s->cy < s->rupper || s->cy > s->rlower)
  553. grid_view_delete_lines(s->grid, s->cy, ny);
  554. else
  555. grid_view_delete_lines_region(s->grid, s->rlower, s->cy, ny);
  556. ttyctx.num = ny;
  557. tty_write(tty_cmd_deleteline, &ttyctx);
  558. }
  559. /* Clear line at cursor. */
  560. void
  561. screen_write_clearline(struct screen_write_ctx *ctx)
  562. {
  563. struct screen *s = ctx->s;
  564. struct tty_ctx ttyctx;
  565. screen_write_initctx(ctx, &ttyctx, 0);
  566. grid_view_clear(s->grid, 0, s->cy, screen_size_x(s), 1);
  567. tty_write(tty_cmd_clearline, &ttyctx);
  568. }
  569. /* Clear to end of line from cursor. */
  570. void
  571. screen_write_clearendofline(struct screen_write_ctx *ctx)
  572. {
  573. struct screen *s = ctx->s;
  574. struct tty_ctx ttyctx;
  575. u_int sx;
  576. screen_write_initctx(ctx, &ttyctx, 0);
  577. sx = screen_size_x(s);
  578. if (s->cx <= sx - 1)
  579. grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1);
  580. tty_write(tty_cmd_clearendofline, &ttyctx);
  581. }
  582. /* Clear to start of line from cursor. */
  583. void
  584. screen_write_clearstartofline(struct screen_write_ctx *ctx)
  585. {
  586. struct screen *s = ctx->s;
  587. struct tty_ctx ttyctx;
  588. u_int sx;
  589. screen_write_initctx(ctx, &ttyctx, 0);
  590. sx = screen_size_x(s);
  591. if (s->cx > sx - 1)
  592. grid_view_clear(s->grid, 0, s->cy, sx, 1);
  593. else
  594. grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1);
  595. tty_write(tty_cmd_clearstartofline, &ttyctx);
  596. }
  597. /* Move cursor to px,py. */
  598. void
  599. screen_write_cursormove(struct screen_write_ctx *ctx, u_int px, u_int py)
  600. {
  601. struct screen *s = ctx->s;
  602. if (px > screen_size_x(s) - 1)
  603. px = screen_size_x(s) - 1;
  604. if (py > screen_size_y(s) - 1)
  605. py = screen_size_y(s) - 1;
  606. s->cx = px;
  607. s->cy = py;
  608. }
  609. /* Reverse index (up with scroll). */
  610. void
  611. screen_write_reverseindex(struct screen_write_ctx *ctx)
  612. {
  613. struct screen *s = ctx->s;
  614. struct tty_ctx ttyctx;
  615. screen_write_initctx(ctx, &ttyctx, 0);
  616. if (s->cy == s->rupper)
  617. grid_view_scroll_region_down(s->grid, s->rupper, s->rlower);
  618. else if (s->cy > 0)
  619. s->cy--;
  620. tty_write(tty_cmd_reverseindex, &ttyctx);
  621. }
  622. /* Set scroll region. */
  623. void
  624. screen_write_scrollregion(struct screen_write_ctx *ctx, u_int rupper,
  625. u_int rlower)
  626. {
  627. struct screen *s = ctx->s;
  628. if (rupper > screen_size_y(s) - 1)
  629. rupper = screen_size_y(s) - 1;
  630. if (rlower > screen_size_y(s) - 1)
  631. rlower = screen_size_y(s) - 1;
  632. if (rupper >= rlower) /* cannot be one line */
  633. return;
  634. /* Cursor moves to top-left. */
  635. s->cx = 0;
  636. s->cy = 0;
  637. s->rupper = rupper;
  638. s->rlower = rlower;
  639. }
  640. /* Line feed. */
  641. void
  642. screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped)
  643. {
  644. struct screen *s = ctx->s;
  645. struct grid_line *gl;
  646. struct tty_ctx ttyctx;
  647. screen_write_initctx(ctx, &ttyctx, 0);
  648. gl = &s->grid->linedata[s->grid->hsize + s->cy];
  649. if (wrapped)
  650. gl->flags |= GRID_LINE_WRAPPED;
  651. else
  652. gl->flags &= ~GRID_LINE_WRAPPED;
  653. if (s->cy == s->rlower)
  654. grid_view_scroll_region_up(s->grid, s->rupper, s->rlower);
  655. else if (s->cy < screen_size_y(s) - 1)
  656. s->cy++;
  657. ttyctx.num = wrapped;
  658. tty_write(tty_cmd_linefeed, &ttyctx);
  659. }
  660. /* Carriage return (cursor to start of line). */
  661. void
  662. screen_write_carriagereturn(struct screen_write_ctx *ctx)
  663. {
  664. struct screen *s = ctx->s;
  665. s->cx = 0;
  666. }
  667. /* Clear to end of screen from cursor. */
  668. void
  669. screen_write_clearendofscreen(struct screen_write_ctx *ctx)
  670. {
  671. struct screen *s = ctx->s;
  672. struct tty_ctx ttyctx;
  673. u_int sx, sy;
  674. screen_write_initctx(ctx, &ttyctx, 0);
  675. sx = screen_size_x(s);
  676. sy = screen_size_y(s);
  677. /* Scroll into history if it is enabled and clearing entire screen. */
  678. if (s->cy == 0 && s->grid->flags & GRID_HISTORY)
  679. grid_view_clear_history(s->grid);
  680. else {
  681. if (s->cx <= sx - 1)
  682. grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1);
  683. grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1));
  684. }
  685. tty_write(tty_cmd_clearendofscreen, &ttyctx);
  686. }
  687. /* Clear to start of screen. */
  688. void
  689. screen_write_clearstartofscreen(struct screen_write_ctx *ctx)
  690. {
  691. struct screen *s = ctx->s;
  692. struct tty_ctx ttyctx;
  693. u_int sx;
  694. screen_write_initctx(ctx, &ttyctx, 0);
  695. sx = screen_size_x(s);
  696. if (s->cy > 0)
  697. grid_view_clear(s->grid, 0, 0, sx, s->cy);
  698. if (s->cx > sx - 1)
  699. grid_view_clear(s->grid, 0, s->cy, sx, 1);
  700. else
  701. grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1);
  702. tty_write(tty_cmd_clearstartofscreen, &ttyctx);
  703. }
  704. /* Clear entire screen. */
  705. void
  706. screen_write_clearscreen(struct screen_write_ctx *ctx)
  707. {
  708. struct screen *s = ctx->s;
  709. struct tty_ctx ttyctx;
  710. u_int sx = screen_size_x(s);
  711. u_int sy = screen_size_y(s);
  712. screen_write_initctx(ctx, &ttyctx, 0);
  713. /* Scroll into history if it is enabled. */
  714. if (s->grid->flags & GRID_HISTORY)
  715. grid_view_clear_history(s->grid);
  716. else
  717. grid_view_clear(s->grid, 0, 0, sx, sy);
  718. tty_write(tty_cmd_clearscreen, &ttyctx);
  719. }
  720. /* Clear entire history. */
  721. void
  722. screen_write_clearhistory(struct screen_write_ctx *ctx)
  723. {
  724. struct screen *s = ctx->s;
  725. struct grid *gd = s->grid;
  726. grid_move_lines(gd, 0, gd->hsize, gd->sy);
  727. gd->hsize = 0;
  728. }
  729. /* Write cell data. */
  730. void
  731. screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
  732. {
  733. struct screen *s = ctx->s;
  734. struct grid *gd = s->grid;
  735. struct tty_ctx ttyctx;
  736. u_int width, xx, last;
  737. struct grid_cell tmp_gc;
  738. int insert;
  739. /* Ignore padding. */
  740. if (gc->flags & GRID_FLAG_PADDING)
  741. return;
  742. width = gc->data.width;
  743. /*
  744. * If this is a wide character and there is no room on the screen, for
  745. * the entire character, don't print it.
  746. */
  747. if (!(s->mode & MODE_WRAP)
  748. && (width > 1 && (width > screen_size_x(s) ||
  749. (s->cx != screen_size_x(s)
  750. && s->cx > screen_size_x(s) - width))))
  751. return;
  752. /*
  753. * If the width is zero, combine onto the previous character, if
  754. * there is space.
  755. */
  756. if (width == 0) {
  757. if (screen_write_combine(ctx, &gc->data) == 0) {
  758. screen_write_initctx(ctx, &ttyctx, 0);
  759. tty_write(tty_cmd_utf8character, &ttyctx);
  760. }
  761. return;
  762. }
  763. /* Initialise the redraw context, saving the last cell. */
  764. screen_write_initctx(ctx, &ttyctx, 1);
  765. /* If in insert mode, make space for the cells. */
  766. if ((s->mode & MODE_INSERT) && s->cx <= screen_size_x(s) - width) {
  767. xx = screen_size_x(s) - s->cx - width;
  768. grid_move_cells(s->grid, s->cx + width, s->cx, s->cy, xx);
  769. insert = 1;
  770. } else
  771. insert = 0;
  772. /* Check this will fit on the current line and wrap if not. */
  773. if ((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width) {
  774. screen_write_linefeed(ctx, 1);
  775. s->cx = 0; /* carriage return */
  776. }
  777. /* Sanity check cursor position. */
  778. if (s->cx > screen_size_x(s) - width || s->cy > screen_size_y(s) - 1)
  779. return;
  780. /* Handle overwriting of UTF-8 characters. */
  781. screen_write_overwrite(ctx, width);
  782. /*
  783. * If the new character is UTF-8 wide, fill in padding cells. Have
  784. * already ensured there is enough room.
  785. */
  786. memcpy(&tmp_gc, &grid_default_cell, sizeof tmp_gc);
  787. tmp_gc.flags |= GRID_FLAG_PADDING;
  788. tmp_gc.data.width = 0;
  789. for (xx = s->cx + 1; xx < s->cx + width; xx++)
  790. grid_view_set_cell(gd, xx, s->cy, &tmp_gc);
  791. /* Set the cell. */
  792. grid_view_set_cell(gd, s->cx, s->cy, gc);
  793. /*
  794. * Move the cursor. If not wrapping, stick at the last character and
  795. * replace it.
  796. */
  797. last = !(s->mode & MODE_WRAP);
  798. if (s->cx <= screen_size_x(s) - last - width)
  799. s->cx += width;
  800. else
  801. s->cx = screen_size_x(s) - last;
  802. /* Draw to the screen if necessary. */
  803. if (insert) {
  804. ttyctx.num = width;
  805. tty_write(tty_cmd_insertcharacter, &ttyctx);
  806. }
  807. if (screen_check_selection(s, s->cx - width, s->cy)) {
  808. memcpy(&tmp_gc, &s->sel.cell, sizeof tmp_gc);
  809. utf8_copy(&tmp_gc.data, &gc->data);
  810. tmp_gc.attr = tmp_gc.attr & ~GRID_ATTR_CHARSET;
  811. tmp_gc.attr |= gc->attr & GRID_ATTR_CHARSET;
  812. tmp_gc.flags = gc->flags;
  813. tmp_gc.flags &= ~(GRID_FLAG_FGRGB|GRID_FLAG_BGRGB);
  814. tmp_gc.flags &= ~(GRID_FLAG_FG256|GRID_FLAG_BG256);
  815. tmp_gc.flags |= s->sel.cell.flags &
  816. (GRID_FLAG_FG256|GRID_FLAG_BG256);
  817. ttyctx.cell = &tmp_gc;
  818. tty_write(tty_cmd_cell, &ttyctx);
  819. } else {
  820. ttyctx.cell = gc;
  821. tty_write(tty_cmd_cell, &ttyctx);
  822. }
  823. }
  824. /* Combine a UTF-8 zero-width character onto the previous. */
  825. int
  826. screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud)
  827. {
  828. struct screen *s = ctx->s;
  829. struct grid *gd = s->grid;
  830. struct grid_cell gc;
  831. /* Can't combine if at 0. */
  832. if (s->cx == 0)
  833. return (-1);
  834. /* Empty data is out. */
  835. if (ud->size == 0)
  836. fatalx("UTF-8 data empty");
  837. /* Retrieve the previous cell. */
  838. grid_view_get_cell(gd, s->cx - 1, s->cy, &gc);
  839. /* Check there is enough space. */
  840. if (gc.data.size + ud->size > sizeof gc.data.data)
  841. return (-1);
  842. /* Append the data. */
  843. memcpy(gc.data.data + gc.data.size, ud->data, ud->size);
  844. gc.data.size += ud->size;
  845. /* Set the new cell. */
  846. grid_view_set_cell(gd, s->cx - 1, s->cy, &gc);
  847. return (0);
  848. }
  849. /*
  850. * UTF-8 wide characters are a bit of an annoyance. They take up more than one
  851. * cell on the screen, so following cells must not be drawn by marking them as
  852. * padding.
  853. *
  854. * So far, so good. The problem is, when overwriting a padding cell, or a UTF-8
  855. * character, it is necessary to also overwrite any other cells which covered
  856. * by the same character.
  857. */
  858. void
  859. screen_write_overwrite(struct screen_write_ctx *ctx, u_int width)
  860. {
  861. struct screen *s = ctx->s;
  862. struct grid *gd = s->grid;
  863. struct grid_cell gc;
  864. u_int xx;
  865. grid_view_get_cell(gd, s->cx, s->cy, &gc);
  866. if (gc.flags & GRID_FLAG_PADDING) {
  867. /*
  868. * A padding cell, so clear any following and leading padding
  869. * cells back to the character. Don't overwrite the current
  870. * cell as that happens later anyway.
  871. */
  872. xx = s->cx + 1;
  873. while (--xx > 0) {
  874. grid_view_get_cell(gd, xx, s->cy, &gc);
  875. if (~gc.flags & GRID_FLAG_PADDING)
  876. break;
  877. grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
  878. }
  879. /* Overwrite the character at the start of this padding. */
  880. grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
  881. }
  882. /*
  883. * Overwrite any padding cells that belong to a UTF-8 character
  884. * we'll be overwriting with the current character.
  885. */
  886. xx = s->cx + width - 1;
  887. while (++xx < screen_size_x(s)) {
  888. grid_view_get_cell(gd, xx, s->cy, &gc);
  889. if (~gc.flags & GRID_FLAG_PADDING)
  890. break;
  891. grid_view_set_cell(gd, xx, s->cy, &grid_default_cell);
  892. }
  893. }
  894. void
  895. screen_write_setselection(struct screen_write_ctx *ctx, u_char *str, u_int len)
  896. {
  897. struct tty_ctx ttyctx;
  898. screen_write_initctx(ctx, &ttyctx, 0);
  899. ttyctx.ptr = str;
  900. ttyctx.num = len;
  901. tty_write(tty_cmd_setselection, &ttyctx);
  902. }
  903. void
  904. screen_write_rawstring(struct screen_write_ctx *ctx, u_char *str, u_int len)
  905. {
  906. struct tty_ctx ttyctx;
  907. screen_write_initctx(ctx, &ttyctx, 0);
  908. ttyctx.ptr = str;
  909. ttyctx.num = len;
  910. tty_write(tty_cmd_rawstring, &ttyctx);
  911. }