Advertisement
Guest User

Untitled

a guest
Mar 22nd, 2019
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 64.14 KB | None | 0 0
  1. Index: Makefile
  2. ===================================================================
  3. RCS file: /cvs/src/usr.bin/tmux/Makefile,v
  4. retrieving revision 1.92
  5. diff -u -p -r1.92 Makefile
  6. --- Makefile 18 Oct 2018 08:38:01 -0000 1.92
  7. +++ Makefile 17 Mar 2019 19:57:49 -0000
  8. @@ -75,6 +75,7 @@ SRCS= alerts.c \
  9. control.c \
  10. environ.c \
  11. format.c \
  12. + format-draw.c \
  13. grid-view.c \
  14. grid.c \
  15. hooks.c \
  16. Index: format-draw.c
  17. ===================================================================
  18. RCS file: format-draw.c
  19. diff -N format-draw.c
  20. --- /dev/null 1 Jan 1970 00:00:00 -0000
  21. +++ format-draw.c 17 Mar 2019 19:57:49 -0000
  22. @@ -0,0 +1,878 @@
  23. +/* $OpenBSD$ */
  24. +
  25. +/*
  26. + * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
  27. + *
  28. + * Permission to use, copy, modify, and distribute this software for any
  29. + * purpose with or without fee is hereby granted, provided that the above
  30. + * copyright notice and this permission notice appear in all copies.
  31. + *
  32. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  33. + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  34. + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  35. + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  36. + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
  37. + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  38. + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  39. + */
  40. +
  41. +#include <sys/types.h>
  42. +
  43. +#include <stdlib.h>
  44. +#include <string.h>
  45. +
  46. +#include "tmux.h"
  47. +
  48. +/* Format range. */
  49. +struct format_range {
  50. + u_int index;
  51. + struct screen *s;
  52. +
  53. + u_int start;
  54. + u_int end;
  55. +
  56. + enum style_range_type type;
  57. + u_int argument;
  58. +
  59. + TAILQ_ENTRY(format_range) entry;
  60. +};
  61. +TAILQ_HEAD(format_ranges, format_range);
  62. +
  63. +/* Does this range match this style? */
  64. +static int
  65. +format_is_type(struct format_range *fr, struct style *sy)
  66. +{
  67. + if (fr->type != sy->range_type)
  68. + return (0);
  69. + if (fr->type == STYLE_RANGE_WINDOW &&
  70. + fr->argument != sy->range_argument)
  71. + return (0);
  72. + return (1);
  73. +}
  74. +
  75. +/* Free a range. */
  76. +static void
  77. +format_free_range(struct format_ranges *frs, struct format_range *fr)
  78. +{
  79. + TAILQ_REMOVE(frs, fr, entry);
  80. + free(fr);
  81. +}
  82. +
  83. +/* Fix range positions. */
  84. +static void
  85. +format_update_ranges(struct format_ranges *frs, struct screen *s, u_int offset,
  86. + u_int start, u_int width)
  87. +{
  88. + struct format_range *fr, *fr1;
  89. +
  90. + if (frs == NULL)
  91. + return;
  92. +
  93. + TAILQ_FOREACH_SAFE(fr, frs, entry, fr1) {
  94. + if (fr->s != s)
  95. + continue;
  96. +
  97. + if (fr->end <= start || fr->start >= start + width) {
  98. + format_free_range(frs, fr);
  99. + continue;
  100. + }
  101. +
  102. + if (fr->start < start)
  103. + fr->start = start;
  104. + if (fr->end > start + width)
  105. + fr->end = start + width;
  106. + if (fr->start == fr->end) {
  107. + format_free_range(frs, fr);
  108. + continue;
  109. + }
  110. +
  111. + fr->start += offset;
  112. + fr->end += offset;
  113. + }
  114. +}
  115. +
  116. +/* Draw a part of the format. */
  117. +static void
  118. +format_draw_put(struct screen_write_ctx *octx, u_int ocx, u_int ocy,
  119. + struct screen *s, struct format_ranges *frs, u_int offset, u_int start,
  120. + u_int width)
  121. +{
  122. + /*
  123. + * The offset is how far from the cursor on the target screen; start
  124. + * and width how much to copy from the source screen.
  125. + */
  126. + screen_write_cursormove(octx, ocx + offset, ocy, 0);
  127. + screen_write_fast_copy(octx, s, start, 0, width, 1);
  128. + format_update_ranges(frs, s, offset, start, width);
  129. +}
  130. +
  131. +/* Draw list part of format. */
  132. +static void
  133. +format_draw_put_list(struct screen_write_ctx *octx,
  134. + u_int ocx, u_int ocy, u_int offset, u_int width, struct screen *list,
  135. + struct screen *list_left, struct screen *list_right, int focus_start,
  136. + int focus_end, struct format_ranges *frs)
  137. +{
  138. + u_int start, focus_centre;
  139. +
  140. + /* If there is enough space for the list, draw it entirely. */
  141. + if (width >= list->cx) {
  142. + format_draw_put(octx, ocx, ocy, list, frs, offset, 0, width);
  143. + return;
  144. + }
  145. +
  146. + /* The list needs to be trimmed. Try to keep the focus visible. */
  147. + focus_centre = focus_start + (focus_end - focus_start) / 2;
  148. + if (focus_centre < width / 2)
  149. + start = 0;
  150. + else
  151. + start = focus_centre - width / 2;
  152. + if (start + width > list->cx)
  153. + start = list->cx - width;
  154. +
  155. + /* Draw <> markers at either side if needed. */
  156. + if (start != 0 && width > list_left->cx) {
  157. + screen_write_cursormove(octx, ocx + offset, ocy, 0);
  158. + screen_write_fast_copy(octx, list_left, 0, 0, list_left->cx, 1);
  159. + offset += list_left->cx;
  160. + start += list_left->cx;
  161. + width -= list_left->cx;
  162. + }
  163. + if (start + width < list->cx && width > list_right->cx) {
  164. + screen_write_cursormove(octx, ocx + offset + width - 1, ocy, 0);
  165. + screen_write_fast_copy(octx, list_right, 0, 0, list_right->cx,
  166. + 1);
  167. + width -= list_right->cx;
  168. + }
  169. +
  170. + /* Draw the list screen itself. */
  171. + format_draw_put(octx, ocx, ocy, list, frs, offset, start, width);
  172. +}
  173. +
  174. +/* Draw format with no list. */
  175. +static void
  176. +format_draw_none(struct screen_write_ctx *octx, u_int available, u_int ocx,
  177. + u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
  178. + struct format_ranges *frs)
  179. +{
  180. + u_int width_left, width_centre, width_right;
  181. +
  182. + log_debug("%s", __func__);
  183. +
  184. + width_left = left->cx;
  185. + width_centre = centre->cx;
  186. + width_right = right->cx;
  187. +
  188. + /*
  189. + * Try to keep as much of the left and right as possible at the expense
  190. + * of the centre.
  191. + */
  192. + while (width_left + width_centre + width_right > available) {
  193. + if (width_centre > 0)
  194. + width_centre--;
  195. + else if (width_right > 0)
  196. + width_right--;
  197. + else
  198. + width_left--;
  199. + }
  200. +
  201. + /* Write left. */
  202. + format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left);
  203. +
  204. + /* Write right at available - width_right. */
  205. + format_draw_put(octx, ocx, ocy, right, frs,
  206. + available - width_right,
  207. + right->cx - width_right,
  208. + width_right);
  209. +
  210. + /*
  211. + * Write centre halfway between
  212. + * width_left
  213. + * and
  214. + * available - width_right.
  215. + */
  216. + format_draw_put(octx, ocx, ocy, centre, frs,
  217. + width_left
  218. + + ((available - width_right) - width_left) / 2
  219. + - width_centre / 2,
  220. + centre->cx / 2 - width_centre / 2,
  221. + width_centre);
  222. +}
  223. +
  224. +/* Draw format with list on the left. */
  225. +static void
  226. +format_draw_left(struct screen_write_ctx *octx, u_int available, u_int ocx,
  227. + u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
  228. + struct screen *list, struct screen *list_left, struct screen *list_right,
  229. + struct screen *after, int focus_start, int focus_end,
  230. + struct format_ranges *frs)
  231. +{
  232. + u_int width_left, width_centre, width_right;
  233. + u_int width_list, width_after;
  234. + struct screen_write_ctx ctx;
  235. +
  236. + log_debug("%s", __func__);
  237. +
  238. + width_left = left->cx;
  239. + width_centre = centre->cx;
  240. + width_right = right->cx;
  241. + width_list = list->cx;
  242. + width_after = after->cx;
  243. +
  244. + /*
  245. + * Trim first the centre, then the list, then the right, then after the
  246. + * list, then the left.
  247. + */
  248. + while (width_left +
  249. + width_centre +
  250. + width_right +
  251. + width_list +
  252. + width_after > available) {
  253. + if (width_centre > 0)
  254. + width_centre--;
  255. + else if (width_list > 0)
  256. + width_list--;
  257. + else if (width_right > 0)
  258. + width_right--;
  259. + else if (width_after > 0)
  260. + width_after--;
  261. + else
  262. + width_left--;
  263. + }
  264. +
  265. + /* If there is no list left, pass off to the no list function. */
  266. + if (width_list == 0) {
  267. + screen_write_start(&ctx, NULL, left);
  268. + screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1);
  269. + screen_write_stop(&ctx);
  270. +
  271. + format_draw_none(octx, available, ocx, ocy, left, centre,
  272. + right, frs);
  273. + return;
  274. + }
  275. +
  276. + /* Write left at 0. */
  277. + format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left);
  278. +
  279. + /* Write right at available - width_right. */
  280. + format_draw_put(octx, ocx, ocy, right, frs,
  281. + available - width_right,
  282. + right->cx - width_right,
  283. + width_right);
  284. +
  285. + /* Write after at width_left + width_list. */
  286. + format_draw_put(octx, ocx, ocy, after, frs,
  287. + width_left + width_list,
  288. + 0,
  289. + width_after);
  290. +
  291. + /*
  292. + * Write centre halfway between
  293. + * width_left + width_list + width_after
  294. + * and
  295. + * available - width_right.
  296. + */
  297. + format_draw_put(octx, ocx, ocy, centre, frs,
  298. + (width_left + width_list + width_after)
  299. + + ((available - width_right)
  300. + - (width_left + width_list + width_after)) / 2
  301. + - width_centre / 2,
  302. + centre->cx / 2 - width_centre / 2,
  303. + width_centre);
  304. +
  305. + /*
  306. + * The list now goes from
  307. + * width_left
  308. + * to
  309. + * width_left + width_list.
  310. + * If there is no focus given, keep the left in focus.
  311. + */
  312. + if (focus_start == -1 || focus_end == -1)
  313. + focus_start = focus_end = 0;
  314. + format_draw_put_list(octx, ocx, ocy, width_left, width_list, list,
  315. + list_left, list_right, focus_start, focus_end, frs);
  316. +}
  317. +
  318. +/* Draw format with list in the centre. */
  319. +static void
  320. +format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx,
  321. + u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
  322. + struct screen *list, struct screen *list_left, struct screen *list_right,
  323. + struct screen *after, int focus_start, int focus_end,
  324. + struct format_ranges *frs)
  325. +{
  326. + u_int width_left, width_centre, width_right;
  327. + u_int width_list, width_after, middle;
  328. + struct screen_write_ctx ctx;
  329. +
  330. + log_debug("%s", __func__);
  331. +
  332. + width_left = left->cx;
  333. + width_centre = centre->cx;
  334. + width_right = right->cx;
  335. + width_list = list->cx;
  336. + width_after = after->cx;
  337. +
  338. + /*
  339. + * Trim first the list, then after the list, then the centre, then the
  340. + * right, then the left.
  341. + */
  342. + while (width_left +
  343. + width_centre +
  344. + width_right +
  345. + width_list +
  346. + width_after > available) {
  347. + if (width_list > 0)
  348. + width_list--;
  349. + else if (width_after > 0)
  350. + width_after--;
  351. + else if (width_centre > 0)
  352. + width_centre--;
  353. + else if (width_right > 0)
  354. + width_right--;
  355. + else
  356. + width_left--;
  357. + }
  358. +
  359. + /* If there is no list left, pass off to the no list function. */
  360. + if (width_list == 0) {
  361. + screen_write_start(&ctx, NULL, centre);
  362. + screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1);
  363. + screen_write_stop(&ctx);
  364. +
  365. + format_draw_none(octx, available, ocx, ocy, left, centre,
  366. + right, frs);
  367. + return;
  368. + }
  369. +
  370. + /* Write left at 0. */
  371. + format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left);
  372. +
  373. + /* Write after at available - width_after. */
  374. + format_draw_put(octx, ocx, ocy, after, frs,
  375. + available - width_after,
  376. + after->cx - width_after,
  377. + width_after);
  378. +
  379. + /* Write right at available - width_right. */
  380. + format_draw_put(octx, ocx, ocy, right, frs,
  381. + available - width_right,
  382. + right->cx - width_right,
  383. + width_right);
  384. +
  385. + /*
  386. + * All three centre sections are offset from the middle of the
  387. + * available space.
  388. + */
  389. + middle = (width_left + ((available - width_right) - width_left) / 2);
  390. +
  391. + /*
  392. + * Write centre at
  393. + * middle - width_list / 2 - width_centre.
  394. + */
  395. + format_draw_put(octx, ocx, ocy, centre, frs,
  396. + middle - width_list / 2 - width_centre,
  397. + 0,
  398. + width_centre);
  399. +
  400. + /*
  401. + * Write after at
  402. + * middle + width_list / 2 - width_centre.
  403. + */
  404. + format_draw_put(octx, ocx, ocy, after, frs,
  405. + middle + width_list / 2,
  406. + 0,
  407. + width_after);
  408. +
  409. + /*
  410. + * The list now goes from
  411. + * middle - width_list / 2
  412. + * to
  413. + * middle + width_list / 2
  414. + * If there is no focus given, keep the centre in focus.
  415. + */
  416. + if (focus_start == -1 || focus_end == -1)
  417. + focus_start = focus_end = list->cx / 2;
  418. + format_draw_put_list(octx, ocx, ocy, middle - width_list / 2,
  419. + width_list, list, list_left, list_right, focus_start, focus_end,
  420. + frs);
  421. +}
  422. +
  423. +/* Draw format with list on the right. */
  424. +static void
  425. +format_draw_right(struct screen_write_ctx *octx, u_int available, u_int ocx,
  426. + u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
  427. + struct screen *list, struct screen *list_left, struct screen *list_right,
  428. + struct screen *after, int focus_start, int focus_end,
  429. + struct format_ranges *frs)
  430. +{
  431. + u_int width_left, width_centre, width_right;
  432. + u_int width_list, width_after;
  433. + struct screen_write_ctx ctx;
  434. +
  435. + log_debug("%s", __func__);
  436. +
  437. + width_left = left->cx;
  438. + width_centre = centre->cx;
  439. + width_right = right->cx;
  440. + width_list = list->cx;
  441. + width_after = after->cx;
  442. +
  443. + /*
  444. + * Trim first the centre, then the list, then the right, then
  445. + * after the list, then the left.
  446. + */
  447. + while (width_left +
  448. + width_centre +
  449. + width_right +
  450. + width_list +
  451. + width_after > available) {
  452. + if (width_centre > 0)
  453. + width_centre--;
  454. + else if (width_list > 0)
  455. + width_list--;
  456. + else if (width_right > 0)
  457. + width_right--;
  458. + else if (width_after > 0)
  459. + width_after--;
  460. + else
  461. + width_left--;
  462. + }
  463. +
  464. + /* If there is no list left, pass off to the no list function. */
  465. + if (width_list == 0) {
  466. + screen_write_start(&ctx, NULL, right);
  467. + screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1);
  468. + screen_write_stop(&ctx);
  469. +
  470. + format_draw_none(octx, available, ocx, ocy, left, centre,
  471. + right, frs);
  472. + return;
  473. + }
  474. +
  475. + /* Write left at 0. */
  476. + format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left);
  477. +
  478. + /* Write after at available - width_after. */
  479. + format_draw_put(octx, ocx, ocy, after, frs,
  480. + available - width_after,
  481. + after->cx - width_after,
  482. + width_after);
  483. +
  484. + /*
  485. + * Write right at
  486. + * available - width_right - width_list - width_after.
  487. + */
  488. + format_draw_put(octx, ocx, ocy, right, frs,
  489. + available - width_right - width_list - width_after,
  490. + 0,
  491. + width_right);
  492. +
  493. + /*
  494. + * Write centre halfway between
  495. + * width_left
  496. + * and
  497. + * available - width_right - width_list - width_after.
  498. + */
  499. + format_draw_put(octx, ocx, ocy, centre, frs,
  500. + width_left
  501. + + ((available - width_right - width_list - width_after)
  502. + - width_left) / 2
  503. + - width_centre / 2,
  504. + centre->cx / 2 - width_centre / 2,
  505. + width_centre);
  506. +
  507. + /*
  508. + * The list now goes from
  509. + * available - width_list - width_after
  510. + * to
  511. + * available - width_after
  512. + * If there is no focus given, keep the right in focus.
  513. + */
  514. + if (focus_start == -1 || focus_end == -1)
  515. + focus_start = focus_end = 0;
  516. + format_draw_put_list(octx, ocx, ocy, available - width_list -
  517. + width_after, width_list, list, list_left, list_right, focus_start,
  518. + focus_end, frs);
  519. +}
  520. +
  521. +/* Draw a format to a screen. */
  522. +void
  523. +format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
  524. + u_int available, const char *expanded, struct style_ranges *srs)
  525. +{
  526. + enum { LEFT,
  527. + CENTRE,
  528. + RIGHT,
  529. + LIST,
  530. + LIST_LEFT,
  531. + LIST_RIGHT,
  532. + AFTER,
  533. + TOTAL } current = LEFT, last = LEFT;
  534. + const char *names[] = { "LEFT",
  535. + "CENTRE",
  536. + "RIGHT",
  537. + "LIST",
  538. + "LIST_LEFT",
  539. + "LIST_RIGHT",
  540. + "AFTER" };
  541. + size_t size = strlen(expanded);
  542. + struct screen *os = octx->s, s[TOTAL];
  543. + struct screen_write_ctx ctx[TOTAL];
  544. + u_int ocx = os->cx, ocy = os->cy, i, width[TOTAL];
  545. + u_int map[] = { LEFT, LEFT, CENTRE, RIGHT };
  546. + int focus_start = -1, focus_end = -1;
  547. + int list_state = -1;
  548. + enum style_align list_align = STYLE_ALIGN_DEFAULT;
  549. + struct style sy;
  550. + struct utf8_data *ud = &sy.gc.data;
  551. + const char *cp, *end;
  552. + enum utf8_state more;
  553. + char *tmp;
  554. + struct format_range *fr = NULL, *fr1;
  555. + struct format_ranges frs;
  556. + struct style_range *sr;
  557. +
  558. + style_set(&sy, base);
  559. + TAILQ_INIT(&frs);
  560. +
  561. + /*
  562. + * We build three screens for left, right, centre alignment, one for
  563. + * the list, and one for anything after the list.
  564. + */
  565. + for (i = 0; i < TOTAL; i++) {
  566. + screen_init(&s[i], size, 1, 0);
  567. + screen_write_start(&ctx[i], NULL, &s[i]);
  568. + screen_write_clearendofline(&ctx[i], base->bg);
  569. + width[i] = 0;
  570. + }
  571. +
  572. + /*
  573. + * Walk the string and add to the corresponding screens,
  574. + * parsing styles as we go.
  575. + */
  576. + cp = expanded;
  577. + while (*cp != '\0') {
  578. + if (cp[0] != '#' || cp[1] != '[') {
  579. + /* See if this is a UTF-8 character. */
  580. + if ((more = utf8_open(ud, *cp)) == UTF8_MORE) {
  581. + while (*++cp != '\0' && more == UTF8_MORE)
  582. + more = utf8_append(ud, *cp);
  583. + if (more != UTF8_DONE)
  584. + cp -= ud->have;
  585. + }
  586. +
  587. + /* Not a UTF-8 character - ASCII or not valid. */
  588. + if (more != UTF8_DONE) {
  589. + if (*cp < 0x20 || *cp > 0x7e) {
  590. + /* Ignore nonprintable characters. */
  591. + cp++;
  592. + continue;
  593. + }
  594. + utf8_set(ud, *cp);
  595. + cp++;
  596. + }
  597. +
  598. + /* Draw the cell to th current screen. */
  599. + screen_write_cell(&ctx[current], &sy.gc);
  600. + width[current] += ud->width;
  601. + continue;
  602. + }
  603. +
  604. + /* This is a style. Work out where the end is and parse it. */
  605. + end = format_skip(cp + 2, "]");
  606. + if (end == NULL)
  607. + return;
  608. + tmp = xstrndup(cp + 2, end - (cp + 2));
  609. + if (style_parse(&sy, base, tmp) != 0) {
  610. + free(tmp);
  611. + return;
  612. + }
  613. + log_debug("style '%s' -> '%s'", tmp, style_tostring(&sy));
  614. + free(tmp);
  615. +
  616. + /* Check the list state. */
  617. + switch (sy.list) {
  618. + case STYLE_LIST_ON:
  619. + /*
  620. + * Entering the list, exiting a marker, or exiting the
  621. + * focus.
  622. + */
  623. + if (list_state != 0) {
  624. + if (fr != NULL) { /* abort any region */
  625. + free(fr);
  626. + fr = NULL;
  627. + }
  628. + list_state = 0;
  629. + list_align = sy.align;
  630. + }
  631. +
  632. + /* End the focus if started. */
  633. + if (focus_start != -1 && focus_end == -1)
  634. + focus_end = s[LIST].cx;
  635. +
  636. + current = LIST;
  637. + break;
  638. + case STYLE_LIST_FOCUS:
  639. + /* Entering the focus. */
  640. + if (list_state != 0) /* not inside the list */
  641. + break;
  642. + if (focus_start == -1) /* focus already started */
  643. + focus_start = s[LIST].cx;
  644. + break;
  645. + case STYLE_LIST_OFF:
  646. + /* Exiting or outside the list. */
  647. + if (list_state == 0) {
  648. + if (fr != NULL) { /* abort any region */
  649. + free(fr);
  650. + fr = NULL;
  651. + }
  652. + if (focus_start != -1 && focus_end == -1)
  653. + focus_end = s[LIST].cx;
  654. +
  655. + map[list_align] = AFTER;
  656. + if (list_align == STYLE_ALIGN_LEFT)
  657. + map[STYLE_ALIGN_DEFAULT] = AFTER;
  658. + list_state = 1;
  659. + }
  660. + current = map[sy.align];
  661. + break;
  662. + case STYLE_LIST_LEFT_MARKER:
  663. + /* Entering left marker. */
  664. + if (list_state != 0) /* not inside the list */
  665. + break;
  666. + if (s[LIST_LEFT].cx != 0) /* already have marker */
  667. + break;
  668. + if (fr != NULL) { /* abort any region */
  669. + free(fr);
  670. + fr = NULL;
  671. + }
  672. + if (focus_start != -1 && focus_end == -1)
  673. + focus_start = focus_end = -1;
  674. + current = LIST_LEFT;
  675. + break;
  676. + case STYLE_LIST_RIGHT_MARKER:
  677. + /* Entering right marker. */
  678. + if (list_state != 0) /* not inside the list */
  679. + break;
  680. + if (s[LIST_RIGHT].cx != 0) /* already have marker */
  681. + break;
  682. + if (fr != NULL) { /* abort any region */
  683. + free(fr);
  684. + fr = NULL;
  685. + }
  686. + if (focus_start != -1 && focus_end == -1)
  687. + focus_start = focus_end = -1;
  688. + current = LIST_RIGHT;
  689. + break;
  690. + }
  691. + if (current != last) {
  692. + log_debug("%s: change %s -> %s", __func__,
  693. + names[last], names[current]);
  694. + last = current;
  695. + }
  696. +
  697. + /*
  698. + * Check if the range style has changed and if so end the
  699. + * current range and start a new one if needed.
  700. + */
  701. + if (srs != NULL) {
  702. + if (fr != NULL && !format_is_type(fr, &sy)) {
  703. + if (s[current].cx != fr->start) {
  704. + fr->end = s[current].cx + 1;
  705. + TAILQ_INSERT_TAIL(&frs, fr, entry);
  706. + } else
  707. + free(fr);
  708. + fr = NULL;
  709. + }
  710. + if (fr == NULL && sy.range_type != STYLE_RANGE_NONE) {
  711. + fr = xcalloc(1, sizeof *fr);
  712. + fr->index = current;
  713. +
  714. + fr->s = &s[current];
  715. + fr->start = s[current].cx;
  716. +
  717. + fr->type = sy.range_type;
  718. + fr->argument = sy.range_argument;
  719. + }
  720. + }
  721. +
  722. + cp = end + 1;
  723. + }
  724. + free(fr);
  725. +
  726. + for (i = 0; i < TOTAL; i++)
  727. + log_debug("%s: width %s is %u", __func__, names[i], width[i]);
  728. + if (focus_start != -1 && focus_end != -1)
  729. + log_debug("focus is %d-%d", focus_start, focus_end);
  730. + TAILQ_FOREACH(fr, &frs, entry) {
  731. + log_debug("%s: range %d|%u is %s %u-%u", __func__, fr->type,
  732. + fr->argument, names[fr->index], fr->start, fr->end);
  733. + }
  734. +
  735. + /*
  736. + * Draw the screens. How they are arranged depends on where the list
  737. + * appearsq.
  738. + */
  739. + switch (list_align) {
  740. + case STYLE_ALIGN_DEFAULT:
  741. + /* No list. */
  742. + format_draw_none(octx, available, ocx, ocy, &s[LEFT],
  743. + &s[CENTRE], &s[RIGHT], &frs);
  744. + break;
  745. + case STYLE_ALIGN_LEFT:
  746. + /* List is part of the left. */
  747. + format_draw_left(octx, available, ocx, ocy, &s[LEFT],
  748. + &s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT],
  749. + &s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs);
  750. + break;
  751. + case STYLE_ALIGN_CENTRE:
  752. + /* List is part of the centre. */
  753. + format_draw_centre(octx, available, ocx, ocy, &s[LEFT],
  754. + &s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT],
  755. + &s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs);
  756. + break;
  757. + case STYLE_ALIGN_RIGHT:
  758. + /* List is part of the right. */
  759. + format_draw_right(octx, available, ocx, ocy, &s[LEFT],
  760. + &s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT],
  761. + &s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs);
  762. + break;
  763. + }
  764. +
  765. + /* Create ranges to return. */
  766. + TAILQ_FOREACH_SAFE(fr, &frs, entry, fr1) {
  767. + sr = xcalloc(1, sizeof *sr);
  768. + sr->type = fr->type;
  769. + sr->argument = fr->argument;
  770. + sr->start = fr->start;
  771. + sr->end = fr->end;
  772. + TAILQ_INSERT_TAIL(srs, sr, entry);
  773. +
  774. + log_debug("%s: range %d|%u at %u-%u", __func__, sr->type,
  775. + sr->argument, sr->start, sr->end);
  776. +
  777. + format_free_range(&frs, fr);
  778. + }
  779. +
  780. + /* Restore the original cursor position. */
  781. + screen_write_cursormove(octx, ocx, ocy, 0);
  782. +}
  783. +
  784. +/* Get width, taking #[] into account. */
  785. +u_int
  786. +format_width(const char *expanded)
  787. +{
  788. + const char *cp, *end;
  789. + u_int width = 0;
  790. + struct utf8_data ud;
  791. + enum utf8_state more;
  792. +
  793. + cp = expanded;
  794. + while (*cp != '\0') {
  795. + if (cp[0] == '#' && cp[1] == '[') {
  796. + end = format_skip(cp + 2, "]");
  797. + if (end == NULL)
  798. + return 0;
  799. + cp = end + 1;
  800. + } else if ((more = utf8_open(&ud, *cp)) == UTF8_MORE) {
  801. + while (*++cp != '\0' && more == UTF8_MORE)
  802. + more = utf8_append(&ud, *cp);
  803. + if (more == UTF8_DONE)
  804. + width += ud.width;
  805. + else
  806. + cp -= ud.have;
  807. + } else if (*cp > 0x1f && *cp < 0x7f) {
  808. + width++;
  809. + cp++;
  810. + }
  811. + }
  812. + return (width);
  813. +}
  814. +
  815. +/* Trim on the left, taking #[] into account. */
  816. +char *
  817. +format_trim_left(const char *expanded, u_int limit)
  818. +{
  819. + char *copy, *out;
  820. + const char *cp = expanded, *end;
  821. + u_int width = 0;
  822. + struct utf8_data ud;
  823. + enum utf8_state more;
  824. +
  825. + out = copy = xmalloc(strlen(expanded) + 1);
  826. + while (*cp != '\0') {
  827. + if (cp[0] == '#' && cp[1] == '[') {
  828. + end = format_skip(cp + 2, "]");
  829. + if (end == NULL)
  830. + break;
  831. + memcpy(out, cp, end + 1 - cp);
  832. + out += (end + 1 - cp);
  833. + cp = end + 1;
  834. + } else if ((more = utf8_open(&ud, *cp)) == UTF8_MORE) {
  835. + while (*++cp != '\0' && more == UTF8_MORE)
  836. + more = utf8_append(&ud, *cp);
  837. + if (more == UTF8_DONE) {
  838. + if (width + ud.width <= limit) {
  839. + memcpy(out, ud.data, ud.size);
  840. + out += ud.size;
  841. + }
  842. + width += ud.width;
  843. + } else
  844. + cp -= ud.have;
  845. + } else if (*cp > 0x1f && *cp < 0x7f) {
  846. + if (width + 1 <= limit)
  847. + *out++ = *cp;
  848. + width++;
  849. + cp++;
  850. + }
  851. + }
  852. + *out = '\0';
  853. + return (copy);
  854. +}
  855. +
  856. +/* Trim on the right, taking #[] into account. */
  857. +char *
  858. +format_trim_right(const char *expanded, u_int limit)
  859. +{
  860. + char *copy, *out;
  861. + const char *cp = expanded, *end;
  862. + u_int width = 0, total_width, skip;
  863. + struct utf8_data ud;
  864. + enum utf8_state more;
  865. +
  866. + total_width = format_width(expanded);
  867. + if (total_width <= limit)
  868. + return (xstrdup(expanded));
  869. + skip = total_width - limit;
  870. +
  871. + out = copy = xmalloc(strlen(expanded) + 1);
  872. + while (*cp != '\0') {
  873. + if (cp[0] == '#' && cp[1] == '[') {
  874. + end = format_skip(cp + 2, "]");
  875. + if (end == NULL)
  876. + break;
  877. + memcpy(out, cp, end + 1 - cp);
  878. + out += (end + 1 - cp);
  879. + cp = end + 1;
  880. + } else if ((more = utf8_open(&ud, *cp)) == UTF8_MORE) {
  881. + while (*++cp != '\0' && more == UTF8_MORE)
  882. + more = utf8_append(&ud, *cp);
  883. + if (more == UTF8_DONE) {
  884. + if (width >= skip) {
  885. + memcpy(out, ud.data, ud.size);
  886. + out += ud.size;
  887. + }
  888. + width += ud.width;
  889. + } else
  890. + cp -= ud.have;
  891. + } else if (*cp > 0x1f && *cp < 0x7f) {
  892. + if (width >= skip)
  893. + *out++ = *cp;
  894. + width++;
  895. + cp++;
  896. + }
  897. + }
  898. + *out = '\0';
  899. + return (copy);
  900. +}
  901. Index: format.c
  902. ===================================================================
  903. RCS file: /cvs/src/usr.bin/tmux/format.c,v
  904. retrieving revision 1.182
  905. diff -u -p -r1.182 format.c
  906. --- format.c 15 Mar 2019 15:02:25 -0000 1.182
  907. +++ format.c 17 Mar 2019 19:57:50 -0000
  908. @@ -936,7 +936,7 @@ found:
  909. }
  910.  
  911. /* Skip until end. */
  912. -static const char *
  913. +const char *
  914. format_skip(const char *s, const char *end)
  915. {
  916. int brackets = 0;
  917. @@ -1544,12 +1544,12 @@ done:
  918.  
  919. /* Truncate the value if needed. */
  920. if (limit > 0) {
  921. - new = utf8_trimcstr(value, limit);
  922. + new = format_trim_left(value, limit);
  923. format_log(ft, "applied length limit %d: %s", limit, new);
  924. free(value);
  925. value = new;
  926. } else if (limit < 0) {
  927. - new = utf8_rtrimcstr(value, -limit);
  928. + new = format_trim_right(value, -limit);
  929. format_log(ft, "applied length limit %d: %s", limit, new);
  930. free(value);
  931. value = new;
  932. Index: mode-tree.c
  933. ===================================================================
  934. RCS file: /cvs/src/usr.bin/tmux/mode-tree.c,v
  935. retrieving revision 1.26
  936. diff -u -p -r1.26 mode-tree.c
  937. --- mode-tree.c 12 Mar 2019 20:02:47 -0000 1.26
  938. +++ mode-tree.c 17 Mar 2019 19:57:50 -0000
  939. @@ -497,7 +497,7 @@ mode_tree_draw(struct mode_tree_data *mt
  940. struct options *oo = wp->window->options;
  941. struct screen_write_ctx ctx;
  942. struct grid_cell gc0, gc;
  943. - u_int w, h, i, j, sy, box_x, box_y;
  944. + u_int w, h, i, j, sy, box_x, box_y, width;
  945. char *text, *start, key[7];
  946. const char *tag, *symbol;
  947. size_t size, n;
  948. @@ -572,8 +572,9 @@ mode_tree_draw(struct mode_tree_data *mt
  949. tag = "*";
  950. else
  951. tag = "";
  952. - xasprintf(&text, "%-*s%s%s%s: %s", keylen, key, start,
  953. - mti->name, tag, mti->text);
  954. + xasprintf(&text, "%-*s%s%s%s: ", keylen, key, start, mti->name,
  955. + tag);
  956. + width = utf8_cstrwidth(text);
  957. free(start);
  958.  
  959. if (mti->tagged) {
  960. @@ -582,11 +583,13 @@ mode_tree_draw(struct mode_tree_data *mt
  961. }
  962.  
  963. if (i != mtd->current) {
  964. - screen_write_cnputs(&ctx, w, &gc0, "%s", text);
  965. screen_write_clearendofline(&ctx, 8);
  966. + screen_write_puts(&ctx, &gc0, "%s", text);
  967. + format_draw(&ctx, &gc0, w - width, mti->text, NULL);
  968. } else {
  969. - screen_write_cnputs(&ctx, w, &gc, "%s", text);
  970. screen_write_clearendofline(&ctx, gc.bg);
  971. + screen_write_puts(&ctx, &gc, "%s", text);
  972. + format_draw(&ctx, &gc, w - width, mti->text, NULL);
  973. }
  974. free(text);
  975.  
  976. Index: options-table.c
  977. ===================================================================
  978. RCS file: /cvs/src/usr.bin/tmux/options-table.c,v
  979. retrieving revision 1.98
  980. diff -u -p -r1.98 options-table.c
  981. --- options-table.c 25 Oct 2018 15:13:38 -0000 1.98
  982. +++ options-table.c 17 Mar 2019 19:57:50 -0000
  983. @@ -39,6 +39,9 @@ static const char *options_table_mode_ke
  984. static const char *options_table_clock_mode_style_list[] = {
  985. "12", "24", NULL
  986. };
  987. +static const char *options_table_status_list[] = {
  988. + "off", "on", "2", "3", "4", "5", NULL
  989. +};
  990. static const char *options_table_status_keys_list[] = {
  991. "emacs", "vi", NULL
  992. };
  993. @@ -64,6 +67,46 @@ static const char *options_table_window_
  994. "largest", "smallest", "manual", NULL
  995. };
  996.  
  997. +/* Status line format. */
  998. +#define OPTIONS_TABLE_STATUS_FORMAT1 \
  999. + "#[align=left range=left #{status-left-style}]" \
  1000. + "#{T;=/#{status-left-length}:status-left}#[norange default]" \
  1001. + "#[list=on align=#{status-justify}]" \
  1002. + "#[list=left-marker]<#[list=right-marker]>#[list=on]" \
  1003. + "#{W:" \
  1004. + "#[range=window|#{window_index}" \
  1005. + "#{?window_last_flag, #{window-status-last-style},}" \
  1006. + "#{?window_bell_flag," \
  1007. + " #{window-status-bell-style}," \
  1008. + "#{?window_activity_flag," \
  1009. + " #{window-status-activity-style},}" \
  1010. + "}" \
  1011. + "]" \
  1012. + "#{T:window-status-format}" \
  1013. + "#[norange default]" \
  1014. + "#{?window_end_flag,,#{window-status-separator}}" \
  1015. + "," \
  1016. + "#[range=window|#{window_index} list=focus" \
  1017. + "#{?window_last_flag, #{window-status-last-style},}" \
  1018. + "#{?window_bell_flag," \
  1019. + " #{window-status-bell-style}," \
  1020. + "#{?window_activity_flag," \
  1021. + " #{window-status-activity-style},}" \
  1022. + "}" \
  1023. + "]" \
  1024. + "#{T:window-status-current-format}" \
  1025. + "#[norange list=on default]" \
  1026. + "#{?window_end_flag,,#{window-status-separator}}" \
  1027. + "}" \
  1028. + "#[nolist align=right range=right #{status-right-style}]" \
  1029. + "#{T;=/#{status-right-length}:status-right}#[norange default]"
  1030. +#define OPTIONS_TABLE_STATUS_FORMAT2 \
  1031. + "#[align=centre]#{P:#{?pane_active,#[reverse],}" \
  1032. + "#{pane_index}[#{pane_width}x#{pane_height}]#[default] }"
  1033. +static const char *options_table_status_format_default[] = {
  1034. + OPTIONS_TABLE_STATUS_FORMAT1, OPTIONS_TABLE_STATUS_FORMAT2, NULL
  1035. +};
  1036. +
  1037. /* Top-level options. */
  1038. const struct options_table_entry options_table[] = {
  1039. { .name = "buffer-limit",
  1040. @@ -378,8 +421,9 @@ const struct options_table_entry options
  1041. },
  1042.  
  1043. { .name = "status",
  1044. - .type = OPTIONS_TABLE_FLAG,
  1045. + .type = OPTIONS_TABLE_CHOICE,
  1046. .scope = OPTIONS_TABLE_SESSION,
  1047. + .choices = options_table_status_list,
  1048. .default_num = 1
  1049. },
  1050.  
  1051. @@ -402,6 +446,12 @@ const struct options_table_entry options
  1052. .scope = OPTIONS_TABLE_SESSION,
  1053. .default_num = 0,
  1054. .style = "status-style"
  1055. + },
  1056. +
  1057. + { .name = "status-format",
  1058. + .type = OPTIONS_TABLE_ARRAY,
  1059. + .scope = OPTIONS_TABLE_SESSION,
  1060. + .default_arr = options_table_status_format_default,
  1061. },
  1062.  
  1063. { .name = "status-interval",
  1064. Index: screen-redraw.c
  1065. ===================================================================
  1066. RCS file: /cvs/src/usr.bin/tmux/screen-redraw.c,v
  1067. retrieving revision 1.58
  1068. diff -u -p -r1.58 screen-redraw.c
  1069. --- screen-redraw.c 16 Mar 2019 19:12:13 -0000 1.58
  1070. +++ screen-redraw.c 17 Mar 2019 19:57:50 -0000
  1071. @@ -274,8 +274,8 @@ screen_redraw_make_pane_status(struct cl
  1072. struct grid_cell gc;
  1073. const char *fmt;
  1074. struct format_tree *ft;
  1075. - char *out;
  1076. - size_t outlen;
  1077. + char *expanded;
  1078. + u_int width, i;
  1079. struct screen_write_ctx ctx;
  1080. struct screen old;
  1081.  
  1082. @@ -289,26 +289,26 @@ screen_redraw_make_pane_status(struct cl
  1083. ft = format_create(c, NULL, FORMAT_PANE|wp->id, 0);
  1084. format_defaults(ft, c, NULL, NULL, wp);
  1085.  
  1086. + expanded = format_expand_time(ft, fmt);
  1087. + wp->status_size = width = wp->sx - 4;
  1088. +
  1089. memcpy(&old, &wp->status_screen, sizeof old);
  1090. - screen_init(&wp->status_screen, wp->sx, 1, 0);
  1091. + screen_init(&wp->status_screen, width, 1, 0);
  1092. wp->status_screen.mode = 0;
  1093.  
  1094. - out = format_expand(ft, fmt);
  1095. - outlen = screen_write_cstrlen("%s", out);
  1096. - if (outlen > wp->sx - 4)
  1097. - outlen = wp->sx - 4;
  1098. - screen_resize(&wp->status_screen, outlen, 1, 0);
  1099. -
  1100. screen_write_start(&ctx, NULL, &wp->status_screen);
  1101. +
  1102. + gc.attr |= GRID_ATTR_CHARSET;
  1103. + for (i = 0; i < width; i++)
  1104. + screen_write_putc(&ctx, &gc, 'q');
  1105. + gc.attr &= ~GRID_ATTR_CHARSET;
  1106. +
  1107. screen_write_cursormove(&ctx, 0, 0, 0);
  1108. - screen_write_clearline(&ctx, 8);
  1109. - screen_write_cnputs(&ctx, outlen, &gc, "%s", out);
  1110. + format_draw(&ctx, &gc, width, expanded, NULL);
  1111. screen_write_stop(&ctx);
  1112.  
  1113. - free(out);
  1114. + free(expanded);
  1115. format_free(ft);
  1116. -
  1117. - wp->status_size = outlen;
  1118.  
  1119. if (grid_compare(wp->status_screen.grid, old.grid) == 0) {
  1120. screen_free(&old);
  1121. Index: screen-write.c
  1122. ===================================================================
  1123. RCS file: /cvs/src/usr.bin/tmux/screen-write.c,v
  1124. retrieving revision 1.148
  1125. diff -u -p -r1.148 screen-write.c
  1126. --- screen-write.c 14 Mar 2019 09:53:52 -0000 1.148
  1127. +++ screen-write.c 17 Mar 2019 19:57:50 -0000
  1128. @@ -169,41 +169,6 @@ screen_write_putc(struct screen_write_ct
  1129. screen_write_cell(ctx, &gc);
  1130. }
  1131.  
  1132. -/* Calculate string length, with embedded formatting. */
  1133. -size_t
  1134. -screen_write_cstrlen(const char *fmt, ...)
  1135. -{
  1136. - va_list ap;
  1137. - char *msg, *msg2, *ptr, *ptr2;
  1138. - size_t size;
  1139. -
  1140. - va_start(ap, fmt);
  1141. - xvasprintf(&msg, fmt, ap);
  1142. - va_end(ap);
  1143. - msg2 = xmalloc(strlen(msg) + 1);
  1144. -
  1145. - ptr = msg;
  1146. - ptr2 = msg2;
  1147. - while (*ptr != '\0') {
  1148. - if (ptr[0] == '#' && ptr[1] == '[') {
  1149. - while (*ptr != ']' && *ptr != '\0')
  1150. - ptr++;
  1151. - if (*ptr == ']')
  1152. - ptr++;
  1153. - continue;
  1154. - }
  1155. - *ptr2++ = *ptr++;
  1156. - }
  1157. - *ptr2 = '\0';
  1158. -
  1159. - size = screen_write_strlen("%s", msg2);
  1160. -
  1161. - free(msg);
  1162. - free(msg2);
  1163. -
  1164. - return (size);
  1165. -}
  1166. -
  1167. /* Calculate string length. */
  1168. size_t
  1169. screen_write_strlen(const char *fmt, ...)
  1170. @@ -314,78 +279,6 @@ screen_write_vnputs(struct screen_write_
  1171. else if (*ptr > 0x1f && *ptr < 0x7f) {
  1172. size++;
  1173. screen_write_putc(ctx, &gc, *ptr);
  1174. - }
  1175. - ptr++;
  1176. - }
  1177. - }
  1178. -
  1179. - free(msg);
  1180. -}
  1181. -
  1182. -/* Write string, similar to nputs, but with embedded formatting (#[]). */
  1183. -void
  1184. -screen_write_cnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
  1185. - const struct grid_cell *gcp, const char *fmt, ...)
  1186. -{
  1187. - struct style sy;
  1188. - struct utf8_data *ud = &sy.gc.data;
  1189. - va_list ap;
  1190. - char *msg;
  1191. - u_char *ptr, *last;
  1192. - size_t left, size = 0;
  1193. - enum utf8_state more;
  1194. -
  1195. - style_set(&sy, gcp);
  1196. -
  1197. - va_start(ap, fmt);
  1198. - xvasprintf(&msg, fmt, ap);
  1199. - va_end(ap);
  1200. -
  1201. - ptr = msg;
  1202. - while (*ptr != '\0') {
  1203. - if (ptr[0] == '#' && ptr[1] == '[') {
  1204. - ptr += 2;
  1205. - last = ptr + strcspn(ptr, "]");
  1206. - if (*last == '\0') {
  1207. - /* No ]. Not much point in doing anything. */
  1208. - break;
  1209. - }
  1210. - *last = '\0';
  1211. -
  1212. - style_parse(&sy, gcp, ptr);
  1213. - ptr = last + 1;
  1214. - continue;
  1215. - }
  1216. - if (*ptr > 0x7f && utf8_open(ud, *ptr) == UTF8_MORE) {
  1217. - ptr++;
  1218. -
  1219. - left = strlen(ptr);
  1220. - if (left < (size_t)ud->size - 1)
  1221. - break;
  1222. - while ((more = utf8_append(ud, *ptr)) == UTF8_MORE)
  1223. - ptr++;
  1224. - ptr++;
  1225. -
  1226. - if (more != UTF8_DONE)
  1227. - continue;
  1228. - if (maxlen > 0 && size + ud->width > (size_t)maxlen) {
  1229. - while (size < (size_t)maxlen) {
  1230. - screen_write_putc(ctx, &sy.gc, ' ');
  1231. - size++;
  1232. - }
  1233. - break;
  1234. - }
  1235. - size += ud->width;
  1236. - screen_write_cell(ctx, &sy.gc);
  1237. - } else {
  1238. - if (maxlen > 0 && size + 1 > (size_t)maxlen)
  1239. - break;
  1240. -
  1241. - if (*ptr == '\001')
  1242. - sy.gc.attr ^= GRID_ATTR_CHARSET;
  1243. - else if (*ptr > 0x1f && *ptr < 0x7f) {
  1244. - size++;
  1245. - screen_write_putc(ctx, &sy.gc, *ptr);
  1246. }
  1247. ptr++;
  1248. }
  1249. Index: server-client.c
  1250. ===================================================================
  1251. RCS file: /cvs/src/usr.bin/tmux/server-client.c,v
  1252. retrieving revision 1.271
  1253. diff -u -p -r1.271 server-client.c
  1254. --- server-client.c 16 Mar 2019 17:14:07 -0000 1.271
  1255. +++ server-client.c 17 Mar 2019 19:57:50 -0000
  1256. @@ -411,12 +411,13 @@ server_client_check_mouse(struct client
  1257. {
  1258. struct session *s = c->session;
  1259. struct mouse_event *m = &c->tty.mouse;
  1260. - struct window *w;
  1261. + struct winlink *wl;
  1262. struct window_pane *wp;
  1263. u_int x, y, b, sx, sy, px, py;
  1264. int flag;
  1265. key_code key;
  1266. struct timeval tv;
  1267. + struct style_range *sr;
  1268. enum { NOTYPE, MOVE, DOWN, UP, DRAG, WHEEL, DOUBLE, TRIPLE } type;
  1269. enum { NOWHERE, PANE, STATUS, STATUS_LEFT, STATUS_RIGHT, BORDER } where;
  1270.  
  1271. @@ -503,17 +504,29 @@ have_event:
  1272.  
  1273. /* Is this on the status line? */
  1274. m->statusat = status_at_line(c);
  1275. - if (m->statusat != -1 && y == (u_int)m->statusat) {
  1276. - if (x < c->status.left_size)
  1277. + if (m->statusat != -1 &&
  1278. + y >= (u_int)m->statusat &&
  1279. + y < m->statusat + status_line_size(c))
  1280. + sr = status_get_range(c, x, y - m->statusat);
  1281. + else
  1282. + sr = NULL;
  1283. + if (sr != NULL) {
  1284. + switch (sr->type) {
  1285. + case STYLE_RANGE_NONE:
  1286. + break;
  1287. + case STYLE_RANGE_LEFT:
  1288. where = STATUS_LEFT;
  1289. - else if (x > c->tty.sx - c->status.right_size)
  1290. + break;
  1291. + case STYLE_RANGE_RIGHT:
  1292. where = STATUS_RIGHT;
  1293. - else {
  1294. - w = status_get_window_at(c, x);
  1295. - if (w == NULL)
  1296. - return (KEYC_UNKNOWN);
  1297. - m->w = w->id;
  1298. - where = STATUS;
  1299. + break;
  1300. + case STYLE_RANGE_WINDOW:
  1301. + wl = winlink_find_by_index(&s->windows, sr->argument);
  1302. + if (wl != NULL) {
  1303. + m->w = wl->window->id;
  1304. + where = STATUS;
  1305. + }
  1306. + break;
  1307. }
  1308. }
  1309.  
  1310. Index: status.c
  1311. ===================================================================
  1312. RCS file: /cvs/src/usr.bin/tmux/status.c,v
  1313. retrieving revision 1.189
  1314. diff -u -p -r1.189 status.c
  1315. --- status.c 16 Mar 2019 19:12:13 -0000 1.189
  1316. +++ status.c 17 Mar 2019 19:57:50 -0000
  1317. @@ -29,14 +29,6 @@
  1318.  
  1319. #include "tmux.h"
  1320.  
  1321. -static char *status_redraw_get_left(struct client *, struct grid_cell *,
  1322. - size_t *);
  1323. -static char *status_redraw_get_right(struct client *, struct grid_cell *,
  1324. - size_t *);
  1325. -static char *status_print(struct client *, struct winlink *,
  1326. - struct grid_cell *);
  1327. -static char *status_replace(struct client *, struct winlink *,
  1328. - const char *);
  1329. static void status_message_callback(int, short, void *);
  1330. static void status_timer_callback(int, short, void *);
  1331.  
  1332. @@ -196,7 +188,8 @@ status_timer_start_all(void)
  1333. void
  1334. status_update_cache(struct session *s)
  1335. {
  1336. - if (!options_get_number(s->options, "status"))
  1337. + s->statuslines = options_get_number(s->options, "status");
  1338. + if (s->statuslines == 0)
  1339. s->statusat = -1;
  1340. else if (options_get_number(s->options, "status-position") == 0)
  1341. s->statusat = 0;
  1342. @@ -225,75 +218,35 @@ status_line_size(struct client *c)
  1343.  
  1344. if (c->flags & CLIENT_STATUSOFF)
  1345. return (0);
  1346. - if (s->statusat == -1)
  1347. - return (0);
  1348. - return (1);
  1349. + return (s->statuslines);
  1350. }
  1351.  
  1352. -/* Retrieve options for left string. */
  1353. -static char *
  1354. -status_redraw_get_left(struct client *c, struct grid_cell *gc, size_t *size)
  1355. +/* Get window at window list position. */
  1356. +struct style_range *
  1357. +status_get_range(struct client *c, u_int x, u_int y)
  1358. {
  1359. - struct session *s = c->session;
  1360. - const char *template;
  1361. - char *left;
  1362. - size_t leftlen;
  1363. -
  1364. - style_apply_update(gc, s->options, "status-left-style");
  1365. -
  1366. - template = options_get_string(s->options, "status-left");
  1367. - left = status_replace(c, NULL, template);
  1368. + struct status_line *sl = &c->status;
  1369. + struct style_range *sr;
  1370.  
  1371. - *size = options_get_number(s->options, "status-left-length");
  1372. - leftlen = screen_write_cstrlen("%s", left);
  1373. - if (leftlen < *size)
  1374. - *size = leftlen;
  1375. - return (left);
  1376. + if (y >= nitems(sl->entries))
  1377. + return (NULL);
  1378. + TAILQ_FOREACH(sr, &sl->entries[y].ranges, entry) {
  1379. + if (x >= sr->start && x < sr->end)
  1380. + return (sr);
  1381. + }
  1382. + return (NULL);
  1383. }
  1384.  
  1385. -/* Retrieve options for right string. */
  1386. -static char *
  1387. -status_redraw_get_right(struct client *c, struct grid_cell *gc, size_t *size)
  1388. +/* Free all ranges. */
  1389. +static void
  1390. +status_free_ranges(struct style_ranges *srs)
  1391. {
  1392. - struct session *s = c->session;
  1393. - const char *template;
  1394. - char *right;
  1395. - size_t rightlen;
  1396. -
  1397. - style_apply_update(gc, s->options, "status-right-style");
  1398. -
  1399. - template = options_get_string(s->options, "status-right");
  1400. - right = status_replace(c, NULL, template);
  1401. -
  1402. - *size = options_get_number(s->options, "status-right-length");
  1403. - rightlen = screen_write_cstrlen("%s", right);
  1404. - if (rightlen < *size)
  1405. - *size = rightlen;
  1406. - return (right);
  1407. -}
  1408. + struct style_range *sr, *sr1;
  1409.  
  1410. -/* Get window at window list position. */
  1411. -struct window *
  1412. -status_get_window_at(struct client *c, u_int x)
  1413. -{
  1414. - struct session *s = c->session;
  1415. - struct winlink *wl;
  1416. - struct options *oo;
  1417. - const char *sep;
  1418. - size_t seplen;
  1419. -
  1420. - x += c->status.window_list_offset;
  1421. - RB_FOREACH(wl, winlinks, &s->windows) {
  1422. - oo = wl->window->options;
  1423. -
  1424. - sep = options_get_string(oo, "window-status-separator");
  1425. - seplen = screen_write_cstrlen("%s", sep);
  1426. -
  1427. - if (x < wl->status_width)
  1428. - return (wl->window);
  1429. - x -= wl->status_width + seplen;
  1430. + TAILQ_FOREACH_SAFE(sr, srs, entry, sr1) {
  1431. + TAILQ_REMOVE(srs, sr, entry);
  1432. + free(sr);
  1433. }
  1434. - return (NULL);
  1435. }
  1436.  
  1437. /* Save old status line. */
  1438. @@ -327,6 +280,10 @@ void
  1439. status_init(struct client *c)
  1440. {
  1441. struct status_line *sl = &c->status;
  1442. + u_int i;
  1443. +
  1444. + for (i = 0; i < nitems(sl->entries); i++)
  1445. + TAILQ_INIT(&sl->entries[i].ranges);
  1446.  
  1447. screen_init(&sl->screen, c->tty.sx, 1, 0);
  1448. sl->active = &sl->screen;
  1449. @@ -337,6 +294,12 @@ void
  1450. status_free(struct client *c)
  1451. {
  1452. struct status_line *sl = &c->status;
  1453. + u_int i;
  1454. +
  1455. + for (i = 0; i < nitems(sl->entries); i++) {
  1456. + status_free_ranges(&sl->entries[i].ranges);
  1457. + free((void *)sl->entries[i].expanded);
  1458. + }
  1459.  
  1460. if (event_initialized(&sl->timer))
  1461. evtimer_del(&sl->timer);
  1462. @@ -352,19 +315,19 @@ status_free(struct client *c)
  1463. int
  1464. status_redraw(struct client *c)
  1465. {
  1466. - struct status_line *sl = &c->status;
  1467. - struct screen_write_ctx ctx;
  1468. - struct session *s = c->session;
  1469. - struct winlink *wl;
  1470. - struct screen old_screen, window_list;
  1471. - struct grid_cell stdgc, lgc, rgc, gc;
  1472. - struct options *oo;
  1473. - char *left, *right;
  1474. - const char *sep;
  1475. - u_int offset, needed, lines;
  1476. - u_int wlstart, wlwidth, wlavailable, wloffset, wlsize;
  1477. - size_t llen, rlen, seplen;
  1478. - int larrow, rarrow;
  1479. + struct status_line *sl = &c->status;
  1480. + struct status_line_entry *sle;
  1481. + struct session *s = c->session;
  1482. + struct screen_write_ctx ctx;
  1483. + struct grid_cell gc;
  1484. + u_int lines, i, width = c->tty.sx;
  1485. + int flags, force = 0, changed = 0;
  1486. + struct options_entry *o;
  1487. + struct format_tree *ft;
  1488. + const char *fmt;
  1489. + char *expanded;
  1490. +
  1491. + log_debug("%s enter", __func__);
  1492.  
  1493. /* Shouldn't get here if not the active screen. */
  1494. if (sl->active != &sl->screen)
  1495. @@ -374,257 +337,71 @@ status_redraw(struct client *c)
  1496. lines = status_line_size(c);
  1497. if (c->tty.sy == 0 || lines == 0)
  1498. return (1);
  1499. - left = right = NULL;
  1500. - larrow = rarrow = 0;
  1501.  
  1502. /* Set up default colour. */
  1503. - style_apply(&stdgc, s->options, "status-style");
  1504. -
  1505. - /* Create the target screen. */
  1506. - memcpy(&old_screen, sl->active, sizeof old_screen);
  1507. - screen_init(sl->active, c->tty.sx, lines, 0);
  1508. - screen_write_start(&ctx, NULL, sl->active);
  1509. - for (offset = 0; offset < lines * c->tty.sx; offset++)
  1510. - screen_write_putc(&ctx, &stdgc, ' ');
  1511. - screen_write_stop(&ctx);
  1512. -
  1513. - /* If the height is too small, blank status line. */
  1514. - if (c->tty.sy < lines)
  1515. - goto out;
  1516. -
  1517. - /* Work out left and right strings. */
  1518. - memcpy(&lgc, &stdgc, sizeof lgc);
  1519. - left = status_redraw_get_left(c, &lgc, &llen);
  1520. - memcpy(&rgc, &stdgc, sizeof rgc);
  1521. - right = status_redraw_get_right(c, &rgc, &rlen);
  1522. -
  1523. - /*
  1524. - * Figure out how much space we have for the window list. If there
  1525. - * isn't enough space, just show a blank status line.
  1526. - */
  1527. - needed = 0;
  1528. - if (llen != 0)
  1529. - needed += llen;
  1530. - if (rlen != 0)
  1531. - needed += rlen;
  1532. - if (c->tty.sx == 0 || c->tty.sx <= needed)
  1533. - goto out;
  1534. - wlavailable = c->tty.sx - needed;
  1535. -
  1536. - /* Calculate the total size needed for the window list. */
  1537. - wlstart = wloffset = wlwidth = 0;
  1538. - RB_FOREACH(wl, winlinks, &s->windows) {
  1539. - free(wl->status_text);
  1540. - memcpy(&wl->status_cell, &stdgc, sizeof wl->status_cell);
  1541. - wl->status_text = status_print(c, wl, &wl->status_cell);
  1542. - wl->status_width = screen_write_cstrlen("%s", wl->status_text);
  1543. -
  1544. - if (wl == s->curw)
  1545. - wloffset = wlwidth;
  1546. -
  1547. - oo = wl->window->options;
  1548. - sep = options_get_string(oo, "window-status-separator");
  1549. - seplen = screen_write_cstrlen("%s", sep);
  1550. - wlwidth += wl->status_width + seplen;
  1551. - }
  1552. -
  1553. - /* Create a new screen for the window list. */
  1554. - screen_init(&window_list, wlwidth, 1, 0);
  1555. -
  1556. - /* And draw the window list into it. */
  1557. - screen_write_start(&ctx, NULL, &window_list);
  1558. - RB_FOREACH(wl, winlinks, &s->windows) {
  1559. - screen_write_cnputs(&ctx, -1, &wl->status_cell, "%s",
  1560. - wl->status_text);
  1561. -
  1562. - oo = wl->window->options;
  1563. - sep = options_get_string(oo, "window-status-separator");
  1564. - screen_write_cnputs(&ctx, -1, &stdgc, "%s", sep);
  1565. - }
  1566. - screen_write_stop(&ctx);
  1567. -
  1568. - /* If there is enough space for the total width, skip to draw now. */
  1569. - if (wlwidth <= wlavailable)
  1570. - goto draw;
  1571. -
  1572. - /* Find size of current window text. */
  1573. - wlsize = s->curw->status_width;
  1574. -
  1575. - /*
  1576. - * If the current window is already on screen, good to draw from the
  1577. - * start and just leave off the end.
  1578. - */
  1579. - if (wloffset + wlsize < wlavailable) {
  1580. - if (wlavailable > 0) {
  1581. - rarrow = 1;
  1582. - wlavailable--;
  1583. - }
  1584. - wlwidth = wlavailable;
  1585. - } else {
  1586. - /*
  1587. - * Work out how many characters we need to omit from the
  1588. - * start. There are wlavailable characters to fill, and
  1589. - * wloffset + wlsize must be the last. So, the start character
  1590. - * is wloffset + wlsize - wlavailable.
  1591. - */
  1592. - if (wlavailable > 0) {
  1593. - larrow = 1;
  1594. - wlavailable--;
  1595. - }
  1596. -
  1597. - wlstart = wloffset + wlsize - wlavailable;
  1598. - if (wlavailable > 0 && wlwidth > wlstart + wlavailable + 1) {
  1599. - rarrow = 1;
  1600. - wlstart++;
  1601. - wlavailable--;
  1602. - }
  1603. - wlwidth = wlavailable;
  1604. - }
  1605. -
  1606. - /* Bail if anything is now too small too. */
  1607. - if (wlwidth == 0 || wlavailable == 0) {
  1608. - screen_free(&window_list);
  1609. - goto out;
  1610. + style_apply(&gc, s->options, "status-style");
  1611. + if (!grid_cells_equal(&gc, &sl->style)) {
  1612. + force = 1;
  1613. + memcpy(&sl->style, &gc, sizeof sl->style);
  1614. + }
  1615. +
  1616. + /* Resize the target screen. */
  1617. + if (screen_size_x(&sl->screen) != width ||
  1618. + screen_size_y(&sl->screen) != lines) {
  1619. + if (screen_size_x(&sl->screen) != width)
  1620. + force = 1;
  1621. + screen_resize(&sl->screen, width, lines, 0);
  1622. + changed = 1;
  1623. }
  1624. + screen_write_start(&ctx, NULL, &sl->screen);
  1625.  
  1626. - /*
  1627. - * Now the start position is known, work out the state of the left and
  1628. - * right arrows.
  1629. - */
  1630. - offset = 0;
  1631. - RB_FOREACH(wl, winlinks, &s->windows) {
  1632. - if (wl->flags & WINLINK_ALERTFLAGS &&
  1633. - larrow == 1 && offset < wlstart)
  1634. - larrow = -1;
  1635. + /* Create format tree. */
  1636. + flags = FORMAT_STATUS;
  1637. + if (c->flags & CLIENT_STATUSFORCE)
  1638. + flags |= FORMAT_FORCE;
  1639. + ft = format_create(c, NULL, FORMAT_NONE, flags);
  1640. + format_defaults(ft, c, NULL, NULL, NULL);
  1641.  
  1642. - offset += wl->status_width;
  1643. + /* Write the status lines. */
  1644. + o = options_get(s->options, "status-format");
  1645. + if (o == NULL)
  1646. + screen_write_clearscreen(&ctx, gc.bg);
  1647. + else {
  1648. + for (i = 0; i < lines; i++) {
  1649. + screen_write_cursormove(&ctx, 0, i, 0);
  1650. +
  1651. + fmt = options_array_get(o, i);
  1652. + if (fmt == NULL) {
  1653. + screen_write_clearline(&ctx, gc.bg);
  1654. + continue;
  1655. + }
  1656. + sle = &sl->entries[i];
  1657.  
  1658. - if (wl->flags & WINLINK_ALERTFLAGS &&
  1659. - rarrow == 1 && offset > wlstart + wlwidth)
  1660. - rarrow = -1;
  1661. - }
  1662. + expanded = format_expand_time(ft, fmt);
  1663. + if (!force &&
  1664. + sle->expanded != NULL &&
  1665. + strcmp(expanded, sle->expanded) == 0) {
  1666. + free(expanded);
  1667. + continue;
  1668. + }
  1669. + changed = 1;
  1670.  
  1671. -draw:
  1672. - /* Begin drawing. */
  1673. - screen_write_start(&ctx, NULL, sl->active);
  1674. + screen_write_clearline(&ctx, gc.bg);
  1675. + status_free_ranges(&sle->ranges);
  1676. + format_draw(&ctx, &gc, width, expanded, &sle->ranges);
  1677.  
  1678. - /* Draw the left string and arrow. */
  1679. - screen_write_cursormove(&ctx, 0, 0, 0);
  1680. - if (llen != 0)
  1681. - screen_write_cnputs(&ctx, llen, &lgc, "%s", left);
  1682. - if (larrow != 0) {
  1683. - memcpy(&gc, &stdgc, sizeof gc);
  1684. - if (larrow == -1)
  1685. - gc.attr ^= GRID_ATTR_REVERSE;
  1686. - screen_write_putc(&ctx, &gc, '<');
  1687. - }
  1688. -
  1689. - /* Draw the right string and arrow. */
  1690. - if (rarrow != 0) {
  1691. - screen_write_cursormove(&ctx, c->tty.sx - rlen - 1, 0, 0);
  1692. - memcpy(&gc, &stdgc, sizeof gc);
  1693. - if (rarrow == -1)
  1694. - gc.attr ^= GRID_ATTR_REVERSE;
  1695. - screen_write_putc(&ctx, &gc, '>');
  1696. - } else
  1697. - screen_write_cursormove(&ctx, c->tty.sx - rlen, 0, 0);
  1698. - if (rlen != 0)
  1699. - screen_write_cnputs(&ctx, rlen, &rgc, "%s", right);
  1700. -
  1701. - /* Figure out the offset for the window list. */
  1702. - if (llen != 0)
  1703. - wloffset = llen;
  1704. - else
  1705. - wloffset = 0;
  1706. - if (wlwidth < wlavailable) {
  1707. - switch (options_get_number(s->options, "status-justify")) {
  1708. - case 1: /* centred */
  1709. - wloffset += (wlavailable - wlwidth) / 2;
  1710. - break;
  1711. - case 2: /* right */
  1712. - wloffset += (wlavailable - wlwidth);
  1713. - break;
  1714. + free(sle->expanded);
  1715. + sle->expanded = expanded;
  1716. }
  1717. }
  1718. - if (larrow != 0)
  1719. - wloffset++;
  1720. -
  1721. - /* Copy the window list. */
  1722. - sl->window_list_offset = -wloffset + wlstart;
  1723. - screen_write_cursormove(&ctx, wloffset, 0, 0);
  1724. - screen_write_fast_copy(&ctx, &window_list, wlstart, 0, wlwidth, 1);
  1725. - screen_free(&window_list);
  1726. -
  1727. - /* Save left and right size. */
  1728. - sl->left_size = llen;
  1729. - sl->right_size = rlen;
  1730. -
  1731. screen_write_stop(&ctx);
  1732.  
  1733. -out:
  1734. - free(left);
  1735. - free(right);
  1736. -
  1737. - if (grid_compare(sl->active->grid, old_screen.grid) == 0) {
  1738. - screen_free(&old_screen);
  1739. - return (0);
  1740. - }
  1741. - screen_free(&old_screen);
  1742. - return (1);
  1743. -}
  1744. -
  1745. -/* Replace special sequences in fmt. */
  1746. -static char *
  1747. -status_replace(struct client *c, struct winlink *wl, const char *fmt)
  1748. -{
  1749. - struct format_tree *ft;
  1750. - char *expanded;
  1751. - u_int tag;
  1752. -
  1753. - if (fmt == NULL)
  1754. - return (xstrdup(""));
  1755. -
  1756. - if (wl != NULL)
  1757. - tag = FORMAT_WINDOW|wl->window->id;
  1758. - else
  1759. - tag = FORMAT_NONE;
  1760. - if (c->flags & CLIENT_STATUSFORCE)
  1761. - ft = format_create(c, NULL, tag, FORMAT_STATUS|FORMAT_FORCE);
  1762. - else
  1763. - ft = format_create(c, NULL, tag, FORMAT_STATUS);
  1764. - format_defaults(ft, c, NULL, wl, NULL);
  1765. -
  1766. - expanded = format_expand_time(ft, fmt);
  1767. -
  1768. + /* Free the format tree. */
  1769. format_free(ft);
  1770. - return (expanded);
  1771. -}
  1772. -
  1773. -/* Return winlink status line entry and adjust gc as necessary. */
  1774. -static char *
  1775. -status_print(struct client *c, struct winlink *wl, struct grid_cell *gc)
  1776. -{
  1777. - struct options *oo = wl->window->options;
  1778. - struct session *s = c->session;
  1779. - const char *fmt;
  1780. - char *text;
  1781.  
  1782. - style_apply_update(gc, oo, "window-status-style");
  1783. - fmt = options_get_string(oo, "window-status-format");
  1784. - if (wl == s->curw) {
  1785. - style_apply_update(gc, oo, "window-status-current-style");
  1786. - fmt = options_get_string(oo, "window-status-current-format");
  1787. - }
  1788. - if (wl == TAILQ_FIRST(&s->lastw))
  1789. - style_apply_update(gc, oo, "window-status-last-style");
  1790. -
  1791. - if (wl->flags & WINLINK_BELL)
  1792. - style_apply_update(gc, oo, "window-status-bell-style");
  1793. - else if (wl->flags & (WINLINK_ACTIVITY|WINLINK_SILENCE))
  1794. - style_apply_update(gc, oo, "window-status-activity-style");
  1795. -
  1796. - text = status_replace(c, wl, fmt);
  1797. - return (text);
  1798. + /* Return if the status line has changed. */
  1799. + log_debug("%s exit: force=%d, changed=%d", __func__, force, changed);
  1800. + return (force || changed);
  1801. }
  1802.  
  1803. /* Set a status line message. */
  1804. @@ -704,7 +481,7 @@ status_message_redraw(struct client *c)
  1805. lines = status_line_size(c);
  1806. if (lines <= 1)
  1807. lines = 1;
  1808. - screen_init(sl->active, c->tty.sx, 1, 0);
  1809. + screen_init(sl->active, c->tty.sx, lines, 0);
  1810.  
  1811. len = screen_write_strlen("%s", c->message_string);
  1812. if (len > c->tty.sx)
  1813. @@ -713,8 +490,9 @@ status_message_redraw(struct client *c)
  1814. style_apply(&gc, s->options, "message-style");
  1815.  
  1816. screen_write_start(&ctx, NULL, sl->active);
  1817. - screen_write_cursormove(&ctx, 0, 0, 0);
  1818. - for (offset = 0; offset < lines * c->tty.sx; offset++)
  1819. + screen_write_fast_copy(&ctx, &sl->screen, 0, 0, c->tty.sx, lines - 1);
  1820. + screen_write_cursormove(&ctx, 0, lines - 1, 0);
  1821. + for (offset = 0; offset < c->tty.sx; offset++)
  1822. screen_write_putc(&ctx, &gc, ' ');
  1823. screen_write_cursormove(&ctx, 0, lines - 1, 0);
  1824. screen_write_nputs(&ctx, len, &gc, "%s", c->message_string);
  1825. @@ -864,12 +642,13 @@ status_prompt_redraw(struct client *c)
  1826. start = c->tty.sx;
  1827.  
  1828. screen_write_start(&ctx, NULL, sl->active);
  1829. - screen_write_cursormove(&ctx, 0, 0, 0);
  1830. - for (offset = 0; offset < lines * c->tty.sx; offset++)
  1831. + screen_write_fast_copy(&ctx, &sl->screen, 0, 0, c->tty.sx, lines - 1);
  1832. + screen_write_cursormove(&ctx, 0, lines - 1, 0);
  1833. + for (offset = 0; offset < c->tty.sx; offset++)
  1834. screen_write_putc(&ctx, &gc, ' ');
  1835. - screen_write_cursormove(&ctx, 0, 0, 0);
  1836. + screen_write_cursormove(&ctx, 0, lines - 1, 0);
  1837. screen_write_nputs(&ctx, start, &gc, "%s", c->prompt_string);
  1838. - screen_write_cursormove(&ctx, start, 0, 0);
  1839. + screen_write_cursormove(&ctx, start, lines - 1, 0);
  1840.  
  1841. left = c->tty.sx - start;
  1842. if (left == 0)
  1843. Index: style.c
  1844. ===================================================================
  1845. RCS file: /cvs/src/usr.bin/tmux/style.c,v
  1846. retrieving revision 1.17
  1847. diff -u -p -r1.17 style.c
  1848. --- style.c 14 Mar 2019 21:46:08 -0000 1.17
  1849. +++ style.c 17 Mar 2019 19:57:50 -0000
  1850. @@ -19,6 +19,8 @@
  1851.  
  1852. #include <sys/types.h>
  1853.  
  1854. +#include <ctype.h>
  1855. +#include <stdlib.h>
  1856. #include <string.h>
  1857.  
  1858. #include "tmux.h"
  1859. @@ -28,7 +30,12 @@
  1860.  
  1861. /* Default style. */
  1862. static struct style style_default = {
  1863. - { 0, 0, 8, 8, { { ' ' }, 0, 1, 1 } }
  1864. + { 0, 0, 8, 8, { { ' ' }, 0, 1, 1 } },
  1865. +
  1866. + STYLE_ALIGN_DEFAULT,
  1867. + STYLE_LIST_OFF,
  1868. +
  1869. + STYLE_RANGE_NONE, 0
  1870. };
  1871.  
  1872. /*
  1873. @@ -40,8 +47,8 @@ int
  1874. style_parse(struct style *sy, const struct grid_cell *base, const char *in)
  1875. {
  1876. struct style saved;
  1877. - const char delimiters[] = " ,";
  1878. - char tmp[32];
  1879. + const char delimiters[] = " ,", *cp;
  1880. + char tmp[256], *found;
  1881. int value;
  1882. size_t end;
  1883.  
  1884. @@ -68,6 +75,60 @@ style_parse(struct style *sy, const stru
  1885. sy->gc.bg = base->bg;
  1886. sy->gc.attr = base->attr;
  1887. sy->gc.flags = base->flags;
  1888. + } else if (strcasecmp(tmp, "nolist") == 0)
  1889. + sy->list = STYLE_LIST_OFF;
  1890. + else if (strncasecmp(tmp, "list=", 5) == 0) {
  1891. + if (strcasecmp(tmp + 5, "on") == 0)
  1892. + sy->list = STYLE_LIST_ON;
  1893. + else if (strcasecmp(tmp + 5, "focus") == 0)
  1894. + sy->list = STYLE_LIST_FOCUS;
  1895. + else if (strcasecmp(tmp + 5, "left-marker") == 0)
  1896. + sy->list = STYLE_LIST_LEFT_MARKER;
  1897. + else if (strcasecmp(tmp + 5, "right-marker") == 0)
  1898. + sy->list = STYLE_LIST_RIGHT_MARKER;
  1899. + else
  1900. + goto error;
  1901. + } else if (strcasecmp(tmp, "norange") == 0) {
  1902. + sy->range_type = style_default.range_type;
  1903. + sy->range_argument = style_default.range_type;
  1904. + } else if (end > 6 && strncasecmp(tmp, "range=", 6) == 0) {
  1905. + found = strchr(tmp + 6, '|');
  1906. + if (found != NULL) {
  1907. + *found++ = '\0';
  1908. + if (*found == '\0')
  1909. + goto error;
  1910. + for (cp = found; *cp != '\0'; cp++) {
  1911. + if (!isdigit((u_char)*cp))
  1912. + goto error;
  1913. + }
  1914. + }
  1915. + if (strcasecmp(tmp + 6, "left") == 0) {
  1916. + if (found != NULL)
  1917. + goto error;
  1918. + sy->range_type = STYLE_RANGE_LEFT;
  1919. + sy->range_argument = 0;
  1920. + } else if (strcasecmp(tmp + 6, "right") == 0) {
  1921. + if (found != NULL)
  1922. + goto error;
  1923. + sy->range_type = STYLE_RANGE_RIGHT;
  1924. + sy->range_argument = 0;
  1925. + } else if (strcasecmp(tmp + 6, "window") == 0) {
  1926. + if (found == NULL)
  1927. + goto error;
  1928. + sy->range_type = STYLE_RANGE_WINDOW;
  1929. + sy->range_argument = atoi(found);
  1930. + }
  1931. + } else if (strcasecmp(tmp, "noalign") == 0)
  1932. + sy->align = style_default.align;
  1933. + else if (end > 6 && strncasecmp(tmp, "align=", 6) == 0) {
  1934. + if (strcasecmp(tmp + 6, "left") == 0)
  1935. + sy->align = STYLE_ALIGN_LEFT;
  1936. + else if (strcasecmp(tmp + 6, "centre") == 0)
  1937. + sy->align = STYLE_ALIGN_CENTRE;
  1938. + else if (strcasecmp(tmp + 6, "right") == 0)
  1939. + sy->align = STYLE_ALIGN_RIGHT;
  1940. + else
  1941. + goto error;
  1942. } else if (end > 3 && strncasecmp(tmp + 1, "g=", 2) == 0) {
  1943. if ((value = colour_fromstring(tmp + 3)) == -1)
  1944. goto error;
  1945. @@ -111,11 +172,49 @@ style_tostring(struct style *sy)
  1946. {
  1947. struct grid_cell *gc = &sy->gc;
  1948. int off = 0;
  1949. - const char *comma = "";
  1950. + const char *comma = "", *tmp;
  1951. static char s[256];
  1952. + char b[16];
  1953.  
  1954. *s = '\0';
  1955.  
  1956. + if (sy->list != STYLE_LIST_OFF) {
  1957. + if (sy->list == STYLE_LIST_ON)
  1958. + tmp = "on";
  1959. + else if (sy->list == STYLE_LIST_FOCUS)
  1960. + tmp = "focus";
  1961. + else if (sy->list == STYLE_LIST_LEFT_MARKER)
  1962. + tmp = "left-marker";
  1963. + else if (sy->list == STYLE_LIST_RIGHT_MARKER)
  1964. + tmp = "right-marker";
  1965. + off += xsnprintf(s + off, sizeof s - off, "%slist=%s", comma,
  1966. + tmp);
  1967. + comma = ",";
  1968. + }
  1969. + if (sy->range_type != STYLE_RANGE_NONE) {
  1970. + if (sy->range_type == STYLE_RANGE_LEFT)
  1971. + tmp = "left";
  1972. + else if (sy->range_type == STYLE_RANGE_RIGHT)
  1973. + tmp = "right";
  1974. + else if (sy->range_type == STYLE_RANGE_WINDOW) {
  1975. + snprintf(b, sizeof b, "window|%u", sy->range_argument);
  1976. + tmp = b;
  1977. + }
  1978. + off += xsnprintf(s + off, sizeof s - off, "%srange=%s", comma,
  1979. + tmp);
  1980. + comma = ",";
  1981. + }
  1982. + if (sy->align != STYLE_ALIGN_DEFAULT) {
  1983. + if (sy->align == STYLE_ALIGN_LEFT)
  1984. + tmp = "left";
  1985. + else if (sy->align == STYLE_ALIGN_CENTRE)
  1986. + tmp = "centre";
  1987. + else if (sy->align == STYLE_ALIGN_RIGHT)
  1988. + tmp = "right";
  1989. + off += xsnprintf(s + off, sizeof s - off, "%salign=%s", comma,
  1990. + tmp);
  1991. + comma = ",";
  1992. + }
  1993. if (gc->fg != 8) {
  1994. off += xsnprintf(s + off, sizeof s - off, "%sfg=%s", comma,
  1995. colour_tostring(gc->fg));
  1996. @@ -180,7 +279,7 @@ style_copy(struct style *dst, struct sty
  1997. memcpy(dst, src, sizeof *dst);
  1998. }
  1999.  
  2000. -/* Check if two styles are the same. */
  2001. +/* Check if two styles are (visibly) the same. */
  2002. int
  2003. style_equal(struct style *sy1, struct style *sy2)
  2004. {
  2005. @@ -192,6 +291,8 @@ style_equal(struct style *sy1, struct st
  2006. if (gc1->bg != gc2->bg)
  2007. return (0);
  2008. if ((gc1->attr & STYLE_ATTR_MASK) != (gc2->attr & STYLE_ATTR_MASK))
  2009. + return (0);
  2010. + if (sy1->align != sy2->align)
  2011. return (0);
  2012. return (1);
  2013. }
  2014. Index: tmux.1
  2015. ===================================================================
  2016. RCS file: /cvs/src/usr.bin/tmux/tmux.1,v
  2017. retrieving revision 1.623
  2018. diff -u -p -r1.623 tmux.1
  2019. --- tmux.1 17 Mar 2019 19:33:12 -0000 1.623
  2020. +++ tmux.1 17 Mar 2019 19:57:51 -0000
  2021. @@ -251,6 +251,7 @@ client.
  2022. .It !
  2023. Break the current pane out of the window.
  2024. .It \&"
  2025. +.\" "
  2026. Split the current pane into two, top and bottom.
  2027. .It #
  2028. List all paste buffers.
  2029. @@ -2838,9 +2839,22 @@ is on.
  2030. The values are the same as those for
  2031. .Ic activity-action .
  2032. .It Xo Ic status
  2033. -.Op Ic on | off
  2034. +.Op Ic off | on | 2 | 3 | 4 | 5
  2035. .Xc
  2036. -Show or hide the status line.
  2037. +Show or hide the status line or specify its size.
  2038. +Using
  2039. +.Ic on
  2040. +gives a status line one row in height;
  2041. +.Ic 2 ,
  2042. +.Ic 3 ,
  2043. +.Ic 4
  2044. +or
  2045. +.Ic 5
  2046. +more rows.
  2047. +.It Ic status-format[] Ar format
  2048. +Specify the format to be used for each line of the status line.
  2049. +The default builds the top status line from the various individual status
  2050. +options below.
  2051. .It Ic status-interval Ar interval
  2052. Update the status line every
  2053. .Ar interval
  2054. @@ -3872,8 +3886,9 @@ for the terminal default colour; or a he
  2055. Set the background colour.
  2056. .It Ic none
  2057. Set no attributes (turn off any active attributes).
  2058. -.It Xo Ic bright (or
  2059. -.Ic bold )
  2060. +.It Xo Ic bright
  2061. +(or
  2062. +.Ic bold ) ,
  2063. .Ic dim ,
  2064. .Ic underscore ,
  2065. .Ic blink ,
  2066. @@ -3890,6 +3905,54 @@ Set an attribute.
  2067. Any of the attributes may be prefixed with
  2068. .Ql no
  2069. to unset.
  2070. +.It Xo Ic align=left
  2071. +(or
  2072. +.Ic noalign ) ,
  2073. +.Ic align=centre ,
  2074. +.Ic align=right
  2075. +.Xc
  2076. +Align text to the left, centre or right of the available space if appropriate.
  2077. +.It Xo Ic list=on ,
  2078. +.Ic list=focus ,
  2079. +.Ic list=left-marker ,
  2080. +.Ic list=right=marker
  2081. +.Ic nolist
  2082. +.Xc
  2083. +Mark the position of the various window list components in the
  2084. +.Ic status-format
  2085. +option:
  2086. +.Ic list=on
  2087. +marks the start of the list;
  2088. +.Ic list=focus
  2089. +is the part of the list that should be kept in focus if the entire list won't fit
  2090. +in the available space (typically the current window);
  2091. +.Ic list=left-marker
  2092. +and
  2093. +.Ic list=right-marker
  2094. +mark the text to be used to mark that text has been trimmed from the left or
  2095. +right of the list if there is not enough space.
  2096. +.It Xo Ic range=left ,
  2097. +.Ic range=right ,
  2098. +.Ic range=window|X ,
  2099. +.Ic norange
  2100. +.Xc
  2101. +Mark a range in the
  2102. +. Ic status-format
  2103. +option.
  2104. +.Ic range=left
  2105. +and
  2106. +.Ic range=right
  2107. +are the text used for the
  2108. +.Ql StatusLeft
  2109. +and
  2110. +.Ql StatusRight
  2111. +mouse keys.
  2112. +.Ic range=window|X
  2113. +is the range for a window passed to the
  2114. +.Ql Status
  2115. +mouse key, where
  2116. +.Ql X
  2117. +is a window index.
  2118. .El
  2119. .Pp
  2120. Examples are:
  2121. Index: tmux.h
  2122. ===================================================================
  2123. RCS file: /cvs/src/usr.bin/tmux/tmux.h,v
  2124. retrieving revision 1.871
  2125. diff -u -p -r1.871 tmux.h
  2126. --- tmux.h 16 Mar 2019 19:12:13 -0000 1.871
  2127. +++ tmux.h 17 Mar 2019 19:57:51 -0000
  2128. @@ -634,9 +634,50 @@ struct grid {
  2129. struct grid_line *linedata;
  2130. };
  2131.  
  2132. +/* Style alignment. */
  2133. +enum style_align {
  2134. + STYLE_ALIGN_DEFAULT,
  2135. + STYLE_ALIGN_LEFT,
  2136. + STYLE_ALIGN_CENTRE,
  2137. + STYLE_ALIGN_RIGHT
  2138. +};
  2139. +
  2140. +/* Style list. */
  2141. +enum style_list {
  2142. + STYLE_LIST_OFF,
  2143. + STYLE_LIST_ON,
  2144. + STYLE_LIST_FOCUS,
  2145. + STYLE_LIST_LEFT_MARKER,
  2146. + STYLE_LIST_RIGHT_MARKER,
  2147. +};
  2148. +
  2149. +/* Style range. */
  2150. +enum style_range_type {
  2151. + STYLE_RANGE_NONE,
  2152. + STYLE_RANGE_LEFT,
  2153. + STYLE_RANGE_RIGHT,
  2154. + STYLE_RANGE_WINDOW
  2155. +};
  2156. +struct style_range {
  2157. + enum style_range_type type;
  2158. + u_int argument;
  2159. +
  2160. + u_int start;
  2161. + u_int end; /* not included */
  2162. +
  2163. + TAILQ_ENTRY(style_range) entry;
  2164. +};
  2165. +TAILQ_HEAD(style_ranges, style_range);
  2166. +
  2167. /* Style option. */
  2168. struct style {
  2169. - struct grid_cell gc;
  2170. + struct grid_cell gc;
  2171. +
  2172. + enum style_align align;
  2173. + enum style_list list;
  2174. +
  2175. + enum style_range_type range_type;
  2176. + u_int range_argument;
  2177. };
  2178.  
  2179. /* Hook data structures. */
  2180. @@ -867,10 +908,6 @@ struct winlink {
  2181. struct session *session;
  2182. struct window *window;
  2183.  
  2184. - size_t status_width;
  2185. - struct grid_cell status_cell;
  2186. - char *status_text;
  2187. -
  2188. int flags;
  2189. #define WINLINK_BELL 0x1
  2190. #define WINLINK_ACTIVITY 0x2
  2191. @@ -952,6 +989,7 @@ struct session {
  2192. struct winlinks windows;
  2193.  
  2194. int statusat;
  2195. + u_int statuslines;
  2196.  
  2197. struct hooks *hooks;
  2198. struct options *options;
  2199. @@ -996,7 +1034,9 @@ struct mouse_event {
  2200. int valid;
  2201.  
  2202. key_code key;
  2203. +
  2204. int statusat;
  2205. + u_int statuslines;
  2206.  
  2207. u_int x;
  2208. u_int y;
  2209. @@ -1311,17 +1351,20 @@ struct cmd_entry {
  2210. };
  2211.  
  2212. /* Status line. */
  2213. +#define STATUS_LINES_LIMIT 5
  2214. +struct status_line_entry {
  2215. + char *expanded;
  2216. + struct style_ranges ranges;
  2217. +};
  2218. struct status_line {
  2219. - struct event timer;
  2220. -
  2221. - struct screen screen;
  2222. - struct screen *active;
  2223. - int references;
  2224. + struct event timer;
  2225.  
  2226. - int window_list_offset;
  2227. + struct screen screen;
  2228. + struct screen *active;
  2229. + int references;
  2230.  
  2231. - u_int left_size;
  2232. - u_int right_size;
  2233. + struct grid_cell style;
  2234. + struct status_line_entry entries[STATUS_LINES_LIMIT];
  2235. };
  2236.  
  2237. /* Client connection. */
  2238. @@ -1580,6 +1623,7 @@ char *paste_make_sample(struct paste_bu
  2239. #define FORMAT_PANE 0x80000000U
  2240. #define FORMAT_WINDOW 0x40000000U
  2241. struct format_tree;
  2242. +const char *format_skip(const char *s, const char *end);
  2243. int format_true(const char *);
  2244. struct format_tree *format_create(struct client *, struct cmdq_item *, int,
  2245. int);
  2246. @@ -1600,6 +1644,14 @@ void format_defaults_paste_buffer(stru
  2247. struct paste_buffer *);
  2248. void format_lost_client(struct client *);
  2249.  
  2250. +/* format-draw.c */
  2251. +void format_draw(struct screen_write_ctx *,
  2252. + const struct grid_cell *, u_int, const char *,
  2253. + struct style_ranges *);
  2254. +u_int format_width(const char *);
  2255. +char *format_trim_left(const char *, u_int);
  2256. +char *format_trim_right(const char *, u_int);
  2257. +
  2258. /* hooks.c */
  2259. struct hook;
  2260. struct hooks *hooks_get(struct session *);
  2261. @@ -1971,7 +2023,7 @@ void status_timer_start_all(void);
  2262. void status_update_cache(struct session *);
  2263. int status_at_line(struct client *);
  2264. u_int status_line_size(struct client *);
  2265. -struct window *status_get_window_at(struct client *, u_int);
  2266. +struct style_range *status_get_range(struct client *, u_int, u_int);
  2267. void status_init(struct client *);
  2268. void status_free(struct client *);
  2269. int status_redraw(struct client *);
  2270. @@ -2071,9 +2123,6 @@ void screen_write_start(struct screen_w
  2271. struct screen *);
  2272. void screen_write_stop(struct screen_write_ctx *);
  2273. void screen_write_reset(struct screen_write_ctx *);
  2274. -size_t printflike(1, 2) screen_write_cstrlen(const char *, ...);
  2275. -void printflike(4, 5) screen_write_cnputs(struct screen_write_ctx *,
  2276. - ssize_t, const struct grid_cell *, const char *, ...);
  2277. size_t printflike(1, 2) screen_write_strlen(const char *, ...);
  2278. void printflike(3, 4) screen_write_puts(struct screen_write_ctx *,
  2279. const struct grid_cell *, const char *, ...);
  2280. @@ -2409,8 +2458,6 @@ u_int utf8_strwidth(const struct utf8_
  2281. struct utf8_data *utf8_fromcstr(const char *);
  2282. char *utf8_tocstr(struct utf8_data *);
  2283. u_int utf8_cstrwidth(const char *);
  2284. -char *utf8_rtrimcstr(const char *, u_int);
  2285. -char *utf8_trimcstr(const char *, u_int);
  2286. char *utf8_padcstr(const char *, u_int);
  2287.  
  2288. /* procname.c */
  2289. Index: utf8.c
  2290. ===================================================================
  2291. RCS file: /cvs/src/usr.bin/tmux/utf8.c,v
  2292. retrieving revision 1.39
  2293. diff -u -p -r1.39 utf8.c
  2294. --- utf8.c 4 Jun 2017 09:02:57 -0000 1.39
  2295. +++ utf8.c 17 Mar 2019 19:57:51 -0000
  2296. @@ -383,66 +383,6 @@ utf8_cstrwidth(const char *s)
  2297. return (width);
  2298. }
  2299.  
  2300. -/* Trim UTF-8 string to width. Caller frees. */
  2301. -char *
  2302. -utf8_trimcstr(const char *s, u_int width)
  2303. -{
  2304. - struct utf8_data *tmp, *next;
  2305. - char *out;
  2306. - u_int at;
  2307. -
  2308. - tmp = utf8_fromcstr(s);
  2309. -
  2310. - at = 0;
  2311. - for (next = tmp; next->size != 0; next++) {
  2312. - if (at + next->width > width) {
  2313. - next->size = 0;
  2314. - break;
  2315. - }
  2316. - at += next->width;
  2317. - }
  2318. -
  2319. - out = utf8_tocstr(tmp);
  2320. - free(tmp);
  2321. - return (out);
  2322. -}
  2323. -
  2324. -/* Trim UTF-8 string to width. Caller frees. */
  2325. -char *
  2326. -utf8_rtrimcstr(const char *s, u_int width)
  2327. -{
  2328. - struct utf8_data *tmp, *next, *end;
  2329. - char *out;
  2330. - u_int at;
  2331. -
  2332. - tmp = utf8_fromcstr(s);
  2333. -
  2334. - for (end = tmp; end->size != 0; end++)
  2335. - /* nothing */;
  2336. - if (end == tmp) {
  2337. - free(tmp);
  2338. - return (xstrdup(""));
  2339. - }
  2340. - next = end - 1;
  2341. -
  2342. - at = 0;
  2343. - for (;;) {
  2344. - if (at + next->width > width) {
  2345. - next++;
  2346. - break;
  2347. - }
  2348. - at += next->width;
  2349. -
  2350. - if (next == tmp)
  2351. - break;
  2352. - next--;
  2353. - }
  2354. -
  2355. - out = utf8_tocstr(next);
  2356. - free(tmp);
  2357. - return (out);
  2358. -}
  2359. -
  2360. /* Pad UTF-8 string to width. Caller frees. */
  2361. char *
  2362. utf8_padcstr(const char *s, u_int width)
  2363. Index: window.c
  2364. ===================================================================
  2365. RCS file: /cvs/src/usr.bin/tmux/window.c,v
  2366. retrieving revision 1.221
  2367. diff -u -p -r1.221 window.c
  2368. --- window.c 14 Mar 2019 09:53:52 -0000 1.221
  2369. +++ window.c 17 Mar 2019 19:57:51 -0000
  2370. @@ -206,7 +206,6 @@ winlink_remove(struct winlinks *wwl, str
  2371. }
  2372.  
  2373. RB_REMOVE(winlinks, wwl, wl);
  2374. - free(wl->status_text);
  2375. free(wl);
  2376. }
  2377.  
  2378. @@ -825,7 +824,6 @@ window_pane_create(struct window *w, u_i
  2379. wp->pipe_event = NULL;
  2380.  
  2381. wp->saved_grid = NULL;
  2382. -
  2383. style_set(&wp->style, &grid_default_cell);
  2384.  
  2385. screen_init(&wp->base, sx, sy, hlimit);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement