4 * Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
38 * Build a list of key-value pairs and use them to expand #{key} entries in a
42 struct format_expand_state
;
44 static char *format_job_get(struct format_expand_state
*, const char *);
45 static char *format_expand1(struct format_expand_state
*, const char *);
46 static int format_replace(struct format_expand_state
*, const char *,
47 size_t, char **, size_t *, size_t *);
48 static void format_defaults_session(struct format_tree
*,
50 static void format_defaults_client(struct format_tree
*, struct client
*);
51 static void format_defaults_winlink(struct format_tree
*,
54 /* Entry in format job tree. */
56 struct client
*client
;
68 RB_ENTRY(format_job
) entry
;
71 /* Format job tree. */
72 static int format_job_cmp(struct format_job
*, struct format_job
*);
73 static RB_HEAD(format_job_tree
, format_job
) format_jobs
= RB_INITIALIZER();
74 RB_GENERATE_STATIC(format_job_tree
, format_job
, entry
, format_job_cmp
);
76 /* Format job tree comparison function. */
78 format_job_cmp(struct format_job
*fj1
, struct format_job
*fj2
)
80 if (fj1
->tag
< fj2
->tag
)
82 if (fj1
->tag
> fj2
->tag
)
84 return (strcmp(fj1
->cmd
, fj2
->cmd
));
87 /* Format modifiers. */
88 #define FORMAT_TIMESTRING 0x1
89 #define FORMAT_BASENAME 0x2
90 #define FORMAT_DIRNAME 0x4
91 #define FORMAT_QUOTE_SHELL 0x8
92 #define FORMAT_LITERAL 0x10
93 #define FORMAT_EXPAND 0x20
94 #define FORMAT_EXPANDTIME 0x40
95 #define FORMAT_SESSIONS 0x80
96 #define FORMAT_WINDOWS 0x100
97 #define FORMAT_PANES 0x200
98 #define FORMAT_PRETTY 0x400
99 #define FORMAT_LENGTH 0x800
100 #define FORMAT_WIDTH 0x1000
101 #define FORMAT_QUOTE_STYLE 0x2000
102 #define FORMAT_WINDOW_NAME 0x4000
103 #define FORMAT_SESSION_NAME 0x8000
104 #define FORMAT_CHARACTER 0x10000
105 #define FORMAT_COLOUR 0x20000
107 /* Limit on recursion. */
108 #define FORMAT_LOOP_LIMIT 100
110 /* Format expand flags. */
111 #define FORMAT_EXPAND_TIME 0x1
112 #define FORMAT_EXPAND_NOJOBS 0x2
114 /* Entry in format tree. */
115 struct format_entry
{
120 RB_ENTRY(format_entry
) entry
;
132 enum format_type type
;
138 struct window_pane
*wp
;
139 struct paste_buffer
*pb
;
141 struct cmdq_item
*item
;
142 struct client
*client
;
146 struct mouse_event m
;
148 RB_HEAD(format_entry_tree
, format_entry
) tree
;
150 static int format_entry_cmp(struct format_entry
*, struct format_entry
*);
151 RB_GENERATE_STATIC(format_entry_tree
, format_entry
, entry
, format_entry_cmp
);
153 /* Format expand state. */
154 struct format_expand_state
{
155 struct format_tree
*ft
;
162 /* Format modifier. */
163 struct format_modifier
{
171 /* Format entry tree comparison function. */
173 format_entry_cmp(struct format_entry
*fe1
, struct format_entry
*fe2
)
175 return (strcmp(fe1
->key
, fe2
->key
));
178 /* Single-character uppercase aliases. */
179 static const char *format_upper
[] = {
185 "window_flags", /* F */
188 "window_index", /* I */
195 "pane_index", /* P */
198 "session_name", /* S */
199 "pane_title", /* T */
202 "window_name", /* W */
208 /* Single-character lowercase aliases. */
209 static const char *format_lower
[] = {
217 "host_short", /* h */
238 /* Is logging enabled? */
240 format_logging(struct format_tree
*ft
)
242 return (log_get_level() != 0 || (ft
->flags
& FORMAT_VERBOSE
));
245 /* Log a message if verbose. */
246 static void printflike(3, 4)
247 format_log1(struct format_expand_state
*es
, const char *from
, const char *fmt
,
250 struct format_tree
*ft
= es
->ft
;
253 static const char spaces
[] = " ";
255 if (!format_logging(ft
))
259 xvasprintf(&s
, fmt
, ap
);
262 log_debug("%s: %s", from
, s
);
263 if (ft
->item
!= NULL
&& (ft
->flags
& FORMAT_VERBOSE
))
264 cmdq_print(ft
->item
, "#%.*s%s", es
->loop
, spaces
, s
);
268 #define format_log(es, fmt, ...) format_log1(es, __func__, fmt, ##__VA_ARGS__)
270 /* Copy expand state. */
272 format_copy_state(struct format_expand_state
*to
,
273 struct format_expand_state
*from
, int flags
)
276 to
->loop
= from
->loop
;
277 to
->time
= from
->time
;
278 memcpy(&to
->tm
, &from
->tm
, sizeof to
->tm
);
279 to
->flags
= from
->flags
|flags
;
282 /* Format job update callback. */
284 format_job_update(struct job
*job
)
286 struct format_job
*fj
= job_get_data(job
);
287 struct evbuffer
*evb
= job_get_event(job
)->input
;
288 char *line
= NULL
, *next
;
291 while ((next
= evbuffer_readline(evb
)) != NULL
) {
302 log_debug("%s: %p %s: %s", __func__
, fj
, fj
->cmd
, fj
->out
);
305 if (fj
->status
&& fj
->last
!= t
) {
306 if (fj
->client
!= NULL
)
307 server_status_client(fj
->client
);
312 /* Format job complete callback. */
314 format_job_complete(struct job
*job
)
316 struct format_job
*fj
= job_get_data(job
);
317 struct evbuffer
*evb
= job_get_event(job
)->input
;
324 if ((line
= evbuffer_readline(evb
)) == NULL
) {
325 len
= EVBUFFER_LENGTH(evb
);
326 buf
= xmalloc(len
+ 1);
328 memcpy(buf
, EVBUFFER_DATA(evb
), len
);
333 log_debug("%s: %p %s: %s", __func__
, fj
, fj
->cmd
, buf
);
335 if (*buf
!= '\0' || !fj
->updated
) {
342 if (fj
->client
!= NULL
)
343 server_status_client(fj
->client
);
350 format_job_get(struct format_expand_state
*es
, const char *cmd
)
352 struct format_tree
*ft
= es
->ft
;
353 struct format_job_tree
*jobs
;
354 struct format_job fj0
, *fj
;
358 struct format_expand_state next
;
360 if (ft
->client
== NULL
)
362 else if (ft
->client
->jobs
!= NULL
)
363 jobs
= ft
->client
->jobs
;
365 jobs
= ft
->client
->jobs
= xmalloc(sizeof *ft
->client
->jobs
);
371 if ((fj
= RB_FIND(format_job_tree
, jobs
, &fj0
)) == NULL
) {
372 fj
= xcalloc(1, sizeof *fj
);
373 fj
->client
= ft
->client
;
375 fj
->cmd
= xstrdup(cmd
);
377 RB_INSERT(format_job_tree
, jobs
, fj
);
380 format_copy_state(&next
, es
, FORMAT_EXPAND_NOJOBS
);
381 next
.flags
&= ~FORMAT_EXPAND_TIME
;
383 expanded
= format_expand1(&next
, cmd
);
384 if (fj
->expanded
== NULL
|| strcmp(expanded
, fj
->expanded
) != 0) {
385 free((void *)fj
->expanded
);
386 fj
->expanded
= xstrdup(expanded
);
389 force
= (ft
->flags
& FORMAT_FORCE
);
392 if (force
&& fj
->job
!= NULL
)
394 if (force
|| (fj
->job
== NULL
&& fj
->last
!= t
)) {
395 fj
->job
= job_run(expanded
, 0, NULL
, NULL
, NULL
,
396 server_client_get_cwd(ft
->client
, NULL
), format_job_update
,
397 format_job_complete
, NULL
, fj
, JOB_NOWAIT
, -1, -1);
398 if (fj
->job
== NULL
) {
400 xasprintf(&fj
->out
, "<'%s' didn't start>", fj
->cmd
);
404 } else if (fj
->job
!= NULL
&& (t
- fj
->last
) > 1 && fj
->out
== NULL
)
405 xasprintf(&fj
->out
, "<'%s' not ready>", fj
->cmd
);
408 if (ft
->flags
& FORMAT_STATUS
)
411 return (xstrdup(""));
412 return (format_expand1(&next
, fj
->out
));
415 /* Remove old jobs. */
417 format_job_tidy(struct format_job_tree
*jobs
, int force
)
419 struct format_job
*fj
, *fj1
;
423 RB_FOREACH_SAFE(fj
, format_job_tree
, jobs
, fj1
) {
424 if (!force
&& (fj
->last
> now
|| now
- fj
->last
< 3600))
426 RB_REMOVE(format_job_tree
, jobs
, fj
);
428 log_debug("%s: %s", __func__
, fj
->cmd
);
433 free((void *)fj
->expanded
);
434 free((void *)fj
->cmd
);
441 /* Tidy old jobs for all clients. */
443 format_tidy_jobs(void)
447 format_job_tidy(&format_jobs
, 0);
448 TAILQ_FOREACH(c
, &clients
, entry
) {
450 format_job_tidy(c
->jobs
, 0);
454 /* Remove old jobs for client. */
456 format_lost_client(struct client
*c
)
459 format_job_tidy(c
->jobs
, 1);
463 /* Wrapper for asprintf. */
464 static char * printflike(1, 2)
465 format_printf(const char *fmt
, ...)
471 xvasprintf(&s
, fmt
, ap
);
476 /* Callback for host. */
478 format_cb_host(__unused
struct format_tree
*ft
)
480 char host
[HOST_NAME_MAX
+ 1];
482 if (gethostname(host
, sizeof host
) != 0)
483 return (xstrdup(""));
484 return (xstrdup(host
));
487 /* Callback for host_short. */
489 format_cb_host_short(__unused
struct format_tree
*ft
)
491 char host
[HOST_NAME_MAX
+ 1], *cp
;
493 if (gethostname(host
, sizeof host
) != 0)
494 return (xstrdup(""));
495 if ((cp
= strchr(host
, '.')) != NULL
)
497 return (xstrdup(host
));
500 /* Callback for pid. */
502 format_cb_pid(__unused
struct format_tree
*ft
)
506 xasprintf(&value
, "%ld", (long)getpid());
510 /* Callback for session_attached_list. */
512 format_cb_session_attached_list(struct format_tree
*ft
)
514 struct session
*s
= ft
->s
;
516 struct evbuffer
*buffer
;
523 buffer
= evbuffer_new();
525 fatalx("out of memory");
527 TAILQ_FOREACH(loop
, &clients
, entry
) {
528 if (loop
->session
== s
) {
529 if (EVBUFFER_LENGTH(buffer
) > 0)
530 evbuffer_add(buffer
, ",", 1);
531 evbuffer_add_printf(buffer
, "%s", loop
->name
);
535 if ((size
= EVBUFFER_LENGTH(buffer
)) != 0)
536 xasprintf(&value
, "%.*s", size
, EVBUFFER_DATA(buffer
));
537 evbuffer_free(buffer
);
541 /* Callback for session_alerts. */
543 format_cb_session_alerts(struct format_tree
*ft
)
545 struct session
*s
= ft
->s
;
547 char alerts
[1024], tmp
[16];
553 RB_FOREACH(wl
, winlinks
, &s
->windows
) {
554 if ((wl
->flags
& WINLINK_ALERTFLAGS
) == 0)
556 xsnprintf(tmp
, sizeof tmp
, "%u", wl
->idx
);
559 strlcat(alerts
, ",", sizeof alerts
);
560 strlcat(alerts
, tmp
, sizeof alerts
);
561 if (wl
->flags
& WINLINK_ACTIVITY
)
562 strlcat(alerts
, "#", sizeof alerts
);
563 if (wl
->flags
& WINLINK_BELL
)
564 strlcat(alerts
, "!", sizeof alerts
);
565 if (wl
->flags
& WINLINK_SILENCE
)
566 strlcat(alerts
, "~", sizeof alerts
);
568 return (xstrdup(alerts
));
571 /* Callback for session_stack. */
573 format_cb_session_stack(struct format_tree
*ft
)
575 struct session
*s
= ft
->s
;
577 char result
[1024], tmp
[16];
582 xsnprintf(result
, sizeof result
, "%u", s
->curw
->idx
);
583 TAILQ_FOREACH(wl
, &s
->lastw
, sentry
) {
584 xsnprintf(tmp
, sizeof tmp
, "%u", wl
->idx
);
587 strlcat(result
, ",", sizeof result
);
588 strlcat(result
, tmp
, sizeof result
);
590 return (xstrdup(result
));
593 /* Callback for window_stack_index. */
595 format_cb_window_stack_index(struct format_tree
*ft
)
607 TAILQ_FOREACH(wl
, &s
->lastw
, sentry
) {
613 return (xstrdup("0"));
614 xasprintf(&value
, "%u", idx
);
618 /* Callback for window_linked_sessions_list. */
620 format_cb_window_linked_sessions_list(struct format_tree
*ft
)
624 struct evbuffer
*buffer
;
632 buffer
= evbuffer_new();
634 fatalx("out of memory");
636 TAILQ_FOREACH(wl
, &w
->winlinks
, wentry
) {
637 if (EVBUFFER_LENGTH(buffer
) > 0)
638 evbuffer_add(buffer
, ",", 1);
639 evbuffer_add_printf(buffer
, "%s", wl
->session
->name
);
642 if ((size
= EVBUFFER_LENGTH(buffer
)) != 0)
643 xasprintf(&value
, "%.*s", size
, EVBUFFER_DATA(buffer
));
644 evbuffer_free(buffer
);
648 /* Callback for window_active_sessions. */
650 format_cb_window_active_sessions(struct format_tree
*ft
)
661 TAILQ_FOREACH(wl
, &w
->winlinks
, wentry
) {
662 if (wl
->session
->curw
== wl
)
666 xasprintf(&value
, "%u", n
);
670 /* Callback for window_active_sessions_list. */
672 format_cb_window_active_sessions_list(struct format_tree
*ft
)
676 struct evbuffer
*buffer
;
684 buffer
= evbuffer_new();
686 fatalx("out of memory");
688 TAILQ_FOREACH(wl
, &w
->winlinks
, wentry
) {
689 if (wl
->session
->curw
== wl
) {
690 if (EVBUFFER_LENGTH(buffer
) > 0)
691 evbuffer_add(buffer
, ",", 1);
692 evbuffer_add_printf(buffer
, "%s", wl
->session
->name
);
696 if ((size
= EVBUFFER_LENGTH(buffer
)) != 0)
697 xasprintf(&value
, "%.*s", size
, EVBUFFER_DATA(buffer
));
698 evbuffer_free(buffer
);
702 /* Callback for window_active_clients. */
704 format_cb_window_active_clients(struct format_tree
*ft
)
708 struct session
*client_session
;
716 TAILQ_FOREACH(loop
, &clients
, entry
) {
717 client_session
= loop
->session
;
718 if (client_session
== NULL
)
721 if (w
== client_session
->curw
->window
)
725 xasprintf(&value
, "%u", n
);
729 /* Callback for window_active_clients_list. */
731 format_cb_window_active_clients_list(struct format_tree
*ft
)
735 struct session
*client_session
;
736 struct evbuffer
*buffer
;
744 buffer
= evbuffer_new();
746 fatalx("out of memory");
748 TAILQ_FOREACH(loop
, &clients
, entry
) {
749 client_session
= loop
->session
;
750 if (client_session
== NULL
)
753 if (w
== client_session
->curw
->window
) {
754 if (EVBUFFER_LENGTH(buffer
) > 0)
755 evbuffer_add(buffer
, ",", 1);
756 evbuffer_add_printf(buffer
, "%s", loop
->name
);
760 if ((size
= EVBUFFER_LENGTH(buffer
)) != 0)
761 xasprintf(&value
, "%.*s", size
, EVBUFFER_DATA(buffer
));
762 evbuffer_free(buffer
);
766 /* Callback for window_layout. */
768 format_cb_window_layout(struct format_tree
*ft
)
770 struct window
*w
= ft
->w
;
775 if (w
->saved_layout_root
!= NULL
)
776 return (layout_dump(w
->saved_layout_root
));
777 return (layout_dump(w
->layout_root
));
780 /* Callback for window_visible_layout. */
782 format_cb_window_visible_layout(struct format_tree
*ft
)
784 struct window
*w
= ft
->w
;
789 return (layout_dump(w
->layout_root
));
792 /* Callback for pane_start_command. */
794 format_cb_start_command(struct format_tree
*ft
)
796 struct window_pane
*wp
= ft
->wp
;
801 return (cmd_stringify_argv(wp
->argc
, wp
->argv
));
804 /* Callback for pane_current_command. */
806 format_cb_current_command(struct format_tree
*ft
)
808 struct window_pane
*wp
= ft
->wp
;
811 if (wp
== NULL
|| wp
->shell
== NULL
)
814 cmd
= osdep_get_name(wp
->fd
, wp
->tty
);
815 if (cmd
== NULL
|| *cmd
== '\0') {
817 cmd
= cmd_stringify_argv(wp
->argc
, wp
->argv
);
818 if (cmd
== NULL
|| *cmd
== '\0') {
820 cmd
= xstrdup(wp
->shell
);
823 value
= parse_window_name(cmd
);
828 /* Callback for pane_current_path. */
830 format_cb_current_path(struct format_tree
*ft
)
832 struct window_pane
*wp
= ft
->wp
;
838 cwd
= osdep_get_cwd(wp
->fd
);
841 return (xstrdup(cwd
));
844 /* Callback for history_bytes. */
846 format_cb_history_bytes(struct format_tree
*ft
)
848 struct window_pane
*wp
= ft
->wp
;
850 struct grid_line
*gl
;
859 for (i
= 0; i
< gd
->hsize
+ gd
->sy
; i
++) {
860 gl
= grid_get_line(gd
, i
);
861 size
+= gl
->cellsize
* sizeof *gl
->celldata
;
862 size
+= gl
->extdsize
* sizeof *gl
->extddata
;
864 size
+= (gd
->hsize
+ gd
->sy
) * sizeof *gl
;
866 xasprintf(&value
, "%zu", size
);
870 /* Callback for history_all_bytes. */
872 format_cb_history_all_bytes(struct format_tree
*ft
)
874 struct window_pane
*wp
= ft
->wp
;
876 struct grid_line
*gl
;
877 u_int i
, lines
, cells
= 0, extended_cells
= 0;
884 lines
= gd
->hsize
+ gd
->sy
;
885 for (i
= 0; i
< lines
; i
++) {
886 gl
= grid_get_line(gd
, i
);
887 cells
+= gl
->cellsize
;
888 extended_cells
+= gl
->extdsize
;
891 xasprintf(&value
, "%u,%zu,%u,%zu,%u,%zu", lines
,
892 lines
* sizeof *gl
, cells
, cells
* sizeof *gl
->celldata
,
893 extended_cells
, extended_cells
* sizeof *gl
->extddata
);
897 /* Callback for pane_tabs. */
899 format_cb_pane_tabs(struct format_tree
*ft
)
901 struct window_pane
*wp
= ft
->wp
;
902 struct evbuffer
*buffer
;
910 buffer
= evbuffer_new();
912 fatalx("out of memory");
913 for (i
= 0; i
< wp
->base
.grid
->sx
; i
++) {
914 if (!bit_test(wp
->base
.tabs
, i
))
917 if (EVBUFFER_LENGTH(buffer
) > 0)
918 evbuffer_add(buffer
, ",", 1);
919 evbuffer_add_printf(buffer
, "%u", i
);
921 if ((size
= EVBUFFER_LENGTH(buffer
)) != 0)
922 xasprintf(&value
, "%.*s", size
, EVBUFFER_DATA(buffer
));
923 evbuffer_free(buffer
);
927 /* Callback for pane_fg. */
929 format_cb_pane_fg(struct format_tree
*ft
)
931 struct window_pane
*wp
= ft
->wp
;
937 tty_default_colours(&gc
, wp
);
938 return (xstrdup(colour_tostring(gc
.fg
)));
941 /* Callback for pane_bg. */
943 format_cb_pane_bg(struct format_tree
*ft
)
945 struct window_pane
*wp
= ft
->wp
;
951 tty_default_colours(&gc
, wp
);
952 return (xstrdup(colour_tostring(gc
.bg
)));
955 /* Callback for session_group_list. */
957 format_cb_session_group_list(struct format_tree
*ft
)
959 struct session
*s
= ft
->s
;
960 struct session_group
*sg
;
961 struct session
*loop
;
962 struct evbuffer
*buffer
;
968 sg
= session_group_contains(s
);
972 buffer
= evbuffer_new();
974 fatalx("out of memory");
976 TAILQ_FOREACH(loop
, &sg
->sessions
, gentry
) {
977 if (EVBUFFER_LENGTH(buffer
) > 0)
978 evbuffer_add(buffer
, ",", 1);
979 evbuffer_add_printf(buffer
, "%s", loop
->name
);
982 if ((size
= EVBUFFER_LENGTH(buffer
)) != 0)
983 xasprintf(&value
, "%.*s", size
, EVBUFFER_DATA(buffer
));
984 evbuffer_free(buffer
);
988 /* Callback for session_group_attached_list. */
990 format_cb_session_group_attached_list(struct format_tree
*ft
)
992 struct session
*s
= ft
->s
, *client_session
, *session_loop
;
993 struct session_group
*sg
;
995 struct evbuffer
*buffer
;
1001 sg
= session_group_contains(s
);
1005 buffer
= evbuffer_new();
1007 fatalx("out of memory");
1009 TAILQ_FOREACH(loop
, &clients
, entry
) {
1010 client_session
= loop
->session
;
1011 if (client_session
== NULL
)
1013 TAILQ_FOREACH(session_loop
, &sg
->sessions
, gentry
) {
1014 if (session_loop
== client_session
){
1015 if (EVBUFFER_LENGTH(buffer
) > 0)
1016 evbuffer_add(buffer
, ",", 1);
1017 evbuffer_add_printf(buffer
, "%s", loop
->name
);
1022 if ((size
= EVBUFFER_LENGTH(buffer
)) != 0)
1023 xasprintf(&value
, "%.*s", size
, EVBUFFER_DATA(buffer
));
1024 evbuffer_free(buffer
);
1028 /* Callback for pane_in_mode. */
1030 format_cb_pane_in_mode(struct format_tree
*ft
)
1032 struct window_pane
*wp
= ft
->wp
;
1034 struct window_mode_entry
*wme
;
1040 TAILQ_FOREACH(wme
, &wp
->modes
, entry
)
1042 xasprintf(&value
, "%u", n
);
1046 /* Callback for pane_at_top. */
1048 format_cb_pane_at_top(struct format_tree
*ft
)
1050 struct window_pane
*wp
= ft
->wp
;
1059 status
= options_get_number(w
->options
, "pane-border-status");
1060 if (status
== PANE_STATUS_TOP
)
1061 flag
= (wp
->yoff
== 1);
1063 flag
= (wp
->yoff
== 0);
1064 xasprintf(&value
, "%d", flag
);
1068 /* Callback for pane_at_bottom. */
1070 format_cb_pane_at_bottom(struct format_tree
*ft
)
1072 struct window_pane
*wp
= ft
->wp
;
1081 status
= options_get_number(w
->options
, "pane-border-status");
1082 if (status
== PANE_STATUS_BOTTOM
)
1083 flag
= (wp
->yoff
+ wp
->sy
== w
->sy
- 1);
1085 flag
= (wp
->yoff
+ wp
->sy
== w
->sy
);
1086 xasprintf(&value
, "%d", flag
);
1090 /* Callback for cursor_character. */
1092 format_cb_cursor_character(struct format_tree
*ft
)
1094 struct window_pane
*wp
= ft
->wp
;
1095 struct grid_cell gc
;
1101 grid_view_get_cell(wp
->base
.grid
, wp
->base
.cx
, wp
->base
.cy
, &gc
);
1102 if (~gc
.flags
& GRID_FLAG_PADDING
)
1103 xasprintf(&value
, "%.*s", (int)gc
.data
.size
, gc
.data
.data
);
1107 /* Callback for mouse_word. */
1109 format_cb_mouse_word(struct format_tree
*ft
)
1111 struct window_pane
*wp
;
1118 wp
= cmd_mouse_pane(&ft
->m
, NULL
, NULL
);
1121 if (cmd_mouse_at(wp
, &ft
->m
, &x
, &y
, 0) != 0)
1124 if (!TAILQ_EMPTY(&wp
->modes
)) {
1125 if (TAILQ_FIRST(&wp
->modes
)->mode
== &window_copy_mode
||
1126 TAILQ_FIRST(&wp
->modes
)->mode
== &window_view_mode
)
1127 return (s
= window_copy_get_word(wp
, x
, y
));
1131 return (format_grid_word(gd
, x
, gd
->hsize
+ y
));
1134 /* Callback for mouse_line. */
1136 format_cb_mouse_line(struct format_tree
*ft
)
1138 struct window_pane
*wp
;
1144 wp
= cmd_mouse_pane(&ft
->m
, NULL
, NULL
);
1147 if (cmd_mouse_at(wp
, &ft
->m
, &x
, &y
, 0) != 0)
1150 if (!TAILQ_EMPTY(&wp
->modes
)) {
1151 if (TAILQ_FIRST(&wp
->modes
)->mode
== &window_copy_mode
||
1152 TAILQ_FIRST(&wp
->modes
)->mode
== &window_view_mode
)
1153 return (window_copy_get_line(wp
, y
));
1157 return (format_grid_line(gd
, gd
->hsize
+ y
));
1160 /* Callback for alternate_on. */
1162 format_cb_alternate_on(struct format_tree
*ft
)
1164 if (ft
->wp
!= NULL
) {
1165 if (ft
->wp
->base
.saved_grid
!= NULL
)
1166 return (xstrdup("1"));
1167 return (xstrdup("0"));
1172 /* Callback for alternate_saved_x. */
1174 format_cb_alternate_saved_x(struct format_tree
*ft
)
1177 return (format_printf("%u", ft
->wp
->base
.saved_cx
));
1181 /* Callback for alternate_saved_y. */
1183 format_cb_alternate_saved_y(struct format_tree
*ft
)
1186 return (format_printf("%u", ft
->wp
->base
.saved_cy
));
1190 /* Callback for buffer_name. */
1192 format_cb_buffer_name(struct format_tree
*ft
)
1195 return (xstrdup(paste_buffer_name(ft
->pb
)));
1199 /* Callback for buffer_sample. */
1201 format_cb_buffer_sample(struct format_tree
*ft
)
1204 return (paste_make_sample(ft
->pb
));
1208 /* Callback for buffer_size. */
1210 format_cb_buffer_size(struct format_tree
*ft
)
1214 if (ft
->pb
!= NULL
) {
1215 paste_buffer_data(ft
->pb
, &size
);
1216 return (format_printf("%zu", size
));
1221 /* Callback for client_cell_height. */
1223 format_cb_client_cell_height(struct format_tree
*ft
)
1225 if (ft
->c
!= NULL
&& (ft
->c
->tty
.flags
& TTY_STARTED
))
1226 return (format_printf("%u", ft
->c
->tty
.ypixel
));
1230 /* Callback for client_cell_width. */
1232 format_cb_client_cell_width(struct format_tree
*ft
)
1234 if (ft
->c
!= NULL
&& (ft
->c
->tty
.flags
& TTY_STARTED
))
1235 return (format_printf("%u", ft
->c
->tty
.xpixel
));
1239 /* Callback for client_control_mode. */
1241 format_cb_client_control_mode(struct format_tree
*ft
)
1243 if (ft
->c
!= NULL
) {
1244 if (ft
->c
->flags
& CLIENT_CONTROL
)
1245 return (xstrdup("1"));
1246 return (xstrdup("0"));
1251 /* Callback for client_discarded. */
1253 format_cb_client_discarded(struct format_tree
*ft
)
1256 return (format_printf("%zu", ft
->c
->discarded
));
1260 /* Callback for client_flags. */
1262 format_cb_client_flags(struct format_tree
*ft
)
1265 return (xstrdup(server_client_get_flags(ft
->c
)));
1269 /* Callback for client_height. */
1271 format_cb_client_height(struct format_tree
*ft
)
1273 if (ft
->c
!= NULL
&& (ft
->c
->tty
.flags
& TTY_STARTED
))
1274 return (format_printf("%u", ft
->c
->tty
.sy
));
1278 /* Callback for client_key_table. */
1280 format_cb_client_key_table(struct format_tree
*ft
)
1283 return (xstrdup(ft
->c
->keytable
->name
));
1287 /* Callback for client_last_session. */
1289 format_cb_client_last_session(struct format_tree
*ft
)
1291 if (ft
->c
!= NULL
&&
1292 ft
->c
->last_session
!= NULL
&&
1293 session_alive(ft
->c
->last_session
))
1294 return (xstrdup(ft
->c
->last_session
->name
));
1298 /* Callback for client_name. */
1300 format_cb_client_name(struct format_tree
*ft
)
1303 return (xstrdup(ft
->c
->name
));
1307 /* Callback for client_pid. */
1309 format_cb_client_pid(struct format_tree
*ft
)
1312 return (format_printf("%ld", (long)ft
->c
->pid
));
1316 /* Callback for client_prefix. */
1318 format_cb_client_prefix(struct format_tree
*ft
)
1322 if (ft
->c
!= NULL
) {
1323 name
= server_client_get_key_table(ft
->c
);
1324 if (strcmp(ft
->c
->keytable
->name
, name
) == 0)
1325 return (xstrdup("0"));
1326 return (xstrdup("1"));
1331 /* Callback for client_readonly. */
1333 format_cb_client_readonly(struct format_tree
*ft
)
1335 if (ft
->c
!= NULL
) {
1336 if (ft
->c
->flags
& CLIENT_READONLY
)
1337 return (xstrdup("1"));
1338 return (xstrdup("0"));
1343 /* Callback for client_session. */
1345 format_cb_client_session(struct format_tree
*ft
)
1347 if (ft
->c
!= NULL
&& ft
->c
->session
!= NULL
)
1348 return (xstrdup(ft
->c
->session
->name
));
1352 /* Callback for client_termfeatures. */
1354 format_cb_client_termfeatures(struct format_tree
*ft
)
1357 return (xstrdup(tty_get_features(ft
->c
->term_features
)));
1361 /* Callback for client_termname. */
1363 format_cb_client_termname(struct format_tree
*ft
)
1366 return (xstrdup(ft
->c
->term_name
));
1370 /* Callback for client_termtype. */
1372 format_cb_client_termtype(struct format_tree
*ft
)
1374 if (ft
->c
!= NULL
) {
1375 if (ft
->c
->term_type
== NULL
)
1376 return (xstrdup(""));
1377 return (xstrdup(ft
->c
->term_type
));
1382 /* Callback for client_tty. */
1384 format_cb_client_tty(struct format_tree
*ft
)
1387 return (xstrdup(ft
->c
->ttyname
));
1391 /* Callback for client_uid. */
1393 format_cb_client_uid(struct format_tree
*ft
)
1397 if (ft
->c
!= NULL
) {
1398 uid
= proc_get_peer_uid(ft
->c
->peer
);
1399 if (uid
!= (uid_t
)-1)
1400 return (format_printf("%ld", (long)uid
));
1405 /* Callback for client_user. */
1407 format_cb_client_user(struct format_tree
*ft
)
1412 if (ft
->c
!= NULL
) {
1413 uid
= proc_get_peer_uid(ft
->c
->peer
);
1414 if (uid
!= (uid_t
)-1 && (pw
= getpwuid(uid
)) != NULL
)
1415 return (xstrdup(pw
->pw_name
));
1420 /* Callback for client_utf8. */
1422 format_cb_client_utf8(struct format_tree
*ft
)
1424 if (ft
->c
!= NULL
) {
1425 if (ft
->c
->flags
& CLIENT_UTF8
)
1426 return (xstrdup("1"));
1427 return (xstrdup("0"));
1432 /* Callback for client_width. */
1434 format_cb_client_width(struct format_tree
*ft
)
1437 return (format_printf("%u", ft
->c
->tty
.sx
));
1441 /* Callback for client_written. */
1443 format_cb_client_written(struct format_tree
*ft
)
1446 return (format_printf("%zu", ft
->c
->written
));
1450 /* Callback for config_files. */
1452 format_cb_config_files(__unused
struct format_tree
*ft
)
1459 for (i
= 0; i
< cfg_nfiles
; i
++) {
1460 n
= strlen(cfg_files
[i
]) + 1;
1461 s
= xrealloc(s
, slen
+ n
+ 1);
1462 slen
+= xsnprintf(s
+ slen
, n
+ 1, "%s,", cfg_files
[i
]);
1465 return (xstrdup(""));
1470 /* Callback for cursor_flag. */
1472 format_cb_cursor_flag(struct format_tree
*ft
)
1474 if (ft
->wp
!= NULL
) {
1475 if (ft
->wp
->base
.mode
& MODE_CURSOR
)
1476 return (xstrdup("1"));
1477 return (xstrdup("0"));
1482 /* Callback for cursor_x. */
1484 format_cb_cursor_x(struct format_tree
*ft
)
1487 return (format_printf("%u", ft
->wp
->base
.cx
));
1491 /* Callback for cursor_y. */
1493 format_cb_cursor_y(struct format_tree
*ft
)
1496 return (format_printf("%u", ft
->wp
->base
.cy
));
1500 /* Callback for history_limit. */
1502 format_cb_history_limit(struct format_tree
*ft
)
1505 return (format_printf("%u", ft
->wp
->base
.grid
->hlimit
));
1509 /* Callback for history_size. */
1511 format_cb_history_size(struct format_tree
*ft
)
1514 return (format_printf("%u", ft
->wp
->base
.grid
->hsize
));
1518 /* Callback for insert_flag. */
1520 format_cb_insert_flag(struct format_tree
*ft
)
1522 if (ft
->wp
!= NULL
) {
1523 if (ft
->wp
->base
.mode
& MODE_INSERT
)
1524 return (xstrdup("1"));
1525 return (xstrdup("0"));
1530 /* Callback for keypad_cursor_flag. */
1532 format_cb_keypad_cursor_flag(struct format_tree
*ft
)
1534 if (ft
->wp
!= NULL
) {
1535 if (ft
->wp
->base
.mode
& MODE_KCURSOR
)
1536 return (xstrdup("1"));
1537 return (xstrdup("0"));
1542 /* Callback for keypad_flag. */
1544 format_cb_keypad_flag(struct format_tree
*ft
)
1546 if (ft
->wp
!= NULL
) {
1547 if (ft
->wp
->base
.mode
& MODE_KKEYPAD
)
1548 return (xstrdup("1"));
1549 return (xstrdup("0"));
1554 /* Callback for mouse_all_flag. */
1556 format_cb_mouse_all_flag(struct format_tree
*ft
)
1558 if (ft
->wp
!= NULL
) {
1559 if (ft
->wp
->base
.mode
& MODE_MOUSE_ALL
)
1560 return (xstrdup("1"));
1561 return (xstrdup("0"));
1566 /* Callback for mouse_any_flag. */
1568 format_cb_mouse_any_flag(struct format_tree
*ft
)
1570 if (ft
->wp
!= NULL
) {
1571 if (ft
->wp
->base
.mode
& ALL_MOUSE_MODES
)
1572 return (xstrdup("1"));
1573 return (xstrdup("0"));
1578 /* Callback for mouse_button_flag. */
1580 format_cb_mouse_button_flag(struct format_tree
*ft
)
1582 if (ft
->wp
!= NULL
) {
1583 if (ft
->wp
->base
.mode
& MODE_MOUSE_BUTTON
)
1584 return (xstrdup("1"));
1585 return (xstrdup("0"));
1590 /* Callback for mouse_pane. */
1592 format_cb_mouse_pane(struct format_tree
*ft
)
1594 struct window_pane
*wp
;
1597 wp
= cmd_mouse_pane(&ft
->m
, NULL
, NULL
);
1599 return (format_printf("%%%u", wp
->id
));
1605 /* Callback for mouse_sgr_flag. */
1607 format_cb_mouse_sgr_flag(struct format_tree
*ft
)
1609 if (ft
->wp
!= NULL
) {
1610 if (ft
->wp
->base
.mode
& MODE_MOUSE_SGR
)
1611 return (xstrdup("1"));
1612 return (xstrdup("0"));
1617 /* Callback for mouse_standard_flag. */
1619 format_cb_mouse_standard_flag(struct format_tree
*ft
)
1621 if (ft
->wp
!= NULL
) {
1622 if (ft
->wp
->base
.mode
& MODE_MOUSE_STANDARD
)
1623 return (xstrdup("1"));
1624 return (xstrdup("0"));
1629 /* Callback for mouse_utf8_flag. */
1631 format_cb_mouse_utf8_flag(struct format_tree
*ft
)
1633 if (ft
->wp
!= NULL
) {
1634 if (ft
->wp
->base
.mode
& MODE_MOUSE_UTF8
)
1635 return (xstrdup("1"));
1636 return (xstrdup("0"));
1641 /* Callback for mouse_x. */
1643 format_cb_mouse_x(struct format_tree
*ft
)
1645 struct window_pane
*wp
;
1650 wp
= cmd_mouse_pane(&ft
->m
, NULL
, NULL
);
1651 if (wp
!= NULL
&& cmd_mouse_at(wp
, &ft
->m
, &x
, &y
, 0) == 0)
1652 return (format_printf("%u", x
));
1653 if (ft
->c
!= NULL
&& (ft
->c
->tty
.flags
& TTY_STARTED
)) {
1654 if (ft
->m
.statusat
== 0 && ft
->m
.y
< ft
->m
.statuslines
)
1655 return (format_printf("%u", ft
->m
.x
));
1656 if (ft
->m
.statusat
> 0 && ft
->m
.y
>= (u_int
)ft
->m
.statusat
)
1657 return (format_printf("%u", ft
->m
.x
));
1662 /* Callback for mouse_y. */
1664 format_cb_mouse_y(struct format_tree
*ft
)
1666 struct window_pane
*wp
;
1671 wp
= cmd_mouse_pane(&ft
->m
, NULL
, NULL
);
1672 if (wp
!= NULL
&& cmd_mouse_at(wp
, &ft
->m
, &x
, &y
, 0) == 0)
1673 return (format_printf("%u", y
));
1674 if (ft
->c
!= NULL
&& (ft
->c
->tty
.flags
& TTY_STARTED
)) {
1675 if (ft
->m
.statusat
== 0 && ft
->m
.y
< ft
->m
.statuslines
)
1676 return (format_printf("%u", ft
->m
.y
));
1677 if (ft
->m
.statusat
> 0 && ft
->m
.y
>= (u_int
)ft
->m
.statusat
)
1678 return (format_printf("%u", ft
->m
.y
- ft
->m
.statusat
));
1683 /* Callback for next_session_id. */
1685 format_cb_next_session_id(__unused
struct format_tree
*ft
)
1687 return (format_printf("$%u", next_session_id
));
1690 /* Callback for origin_flag. */
1692 format_cb_origin_flag(struct format_tree
*ft
)
1694 if (ft
->wp
!= NULL
) {
1695 if (ft
->wp
->base
.mode
& MODE_ORIGIN
)
1696 return (xstrdup("1"));
1697 return (xstrdup("0"));
1702 /* Callback for pane_active. */
1704 format_cb_pane_active(struct format_tree
*ft
)
1706 if (ft
->wp
!= NULL
) {
1707 if (ft
->wp
== ft
->wp
->window
->active
)
1708 return (xstrdup("1"));
1709 return (xstrdup("0"));
1714 /* Callback for pane_at_left. */
1716 format_cb_pane_at_left(struct format_tree
*ft
)
1718 if (ft
->wp
!= NULL
) {
1719 if (ft
->wp
->xoff
== 0)
1720 return (xstrdup("1"));
1721 return (xstrdup("0"));
1726 /* Callback for pane_at_right. */
1728 format_cb_pane_at_right(struct format_tree
*ft
)
1730 if (ft
->wp
!= NULL
) {
1731 if (ft
->wp
->xoff
+ ft
->wp
->sx
== ft
->wp
->window
->sx
)
1732 return (xstrdup("1"));
1733 return (xstrdup("0"));
1738 /* Callback for pane_bottom. */
1740 format_cb_pane_bottom(struct format_tree
*ft
)
1743 return (format_printf("%u", ft
->wp
->yoff
+ ft
->wp
->sy
- 1));
1747 /* Callback for pane_dead. */
1749 format_cb_pane_dead(struct format_tree
*ft
)
1751 if (ft
->wp
!= NULL
) {
1752 if (ft
->wp
->fd
== -1)
1753 return (xstrdup("1"));
1754 return (xstrdup("0"));
1759 /* Callback for pane_dead_signal. */
1761 format_cb_pane_dead_signal(struct format_tree
*ft
)
1763 struct window_pane
*wp
= ft
->wp
;
1767 if ((wp
->flags
& PANE_STATUSREADY
) && WIFSIGNALED(wp
->status
)) {
1768 name
= sig2name(WTERMSIG(wp
->status
));
1769 return (format_printf("%s", name
));
1776 /* Callback for pane_dead_status. */
1778 format_cb_pane_dead_status(struct format_tree
*ft
)
1780 struct window_pane
*wp
= ft
->wp
;
1783 if ((wp
->flags
& PANE_STATUSREADY
) && WIFEXITED(wp
->status
))
1784 return (format_printf("%d", WEXITSTATUS(wp
->status
)));
1790 /* Callback for pane_dead_time. */
1792 format_cb_pane_dead_time(struct format_tree
*ft
)
1794 struct window_pane
*wp
= ft
->wp
;
1797 if (wp
->flags
& PANE_STATUSDRAWN
)
1798 return (&wp
->dead_time
);
1804 /* Callback for pane_format. */
1806 format_cb_pane_format(struct format_tree
*ft
)
1808 if (ft
->type
== FORMAT_TYPE_PANE
)
1809 return (xstrdup("1"));
1810 return (xstrdup("0"));
1813 /* Callback for pane_height. */
1815 format_cb_pane_height(struct format_tree
*ft
)
1818 return (format_printf("%u", ft
->wp
->sy
));
1822 /* Callback for pane_id. */
1824 format_cb_pane_id(struct format_tree
*ft
)
1827 return (format_printf("%%%u", ft
->wp
->id
));
1831 /* Callback for pane_index. */
1833 format_cb_pane_index(struct format_tree
*ft
)
1837 if (ft
->wp
!= NULL
&& window_pane_index(ft
->wp
, &idx
) == 0)
1838 return (format_printf("%u", idx
));
1842 /* Callback for pane_input_off. */
1844 format_cb_pane_input_off(struct format_tree
*ft
)
1846 if (ft
->wp
!= NULL
) {
1847 if (ft
->wp
->flags
& PANE_INPUTOFF
)
1848 return (xstrdup("1"));
1849 return (xstrdup("0"));
1854 /* Callback for pane_last. */
1856 format_cb_pane_last(struct format_tree
*ft
)
1858 if (ft
->wp
!= NULL
) {
1859 if (ft
->wp
== ft
->wp
->window
->last
)
1860 return (xstrdup("1"));
1861 return (xstrdup("0"));
1866 /* Callback for pane_left. */
1868 format_cb_pane_left(struct format_tree
*ft
)
1871 return (format_printf("%u", ft
->wp
->xoff
));
1875 /* Callback for pane_marked. */
1877 format_cb_pane_marked(struct format_tree
*ft
)
1879 if (ft
->wp
!= NULL
) {
1880 if (server_check_marked() && marked_pane
.wp
== ft
->wp
)
1881 return (xstrdup("1"));
1882 return (xstrdup("0"));
1887 /* Callback for pane_marked_set. */
1889 format_cb_pane_marked_set(struct format_tree
*ft
)
1891 if (ft
->wp
!= NULL
) {
1892 if (server_check_marked())
1893 return (xstrdup("1"));
1894 return (xstrdup("0"));
1899 /* Callback for pane_mode. */
1901 format_cb_pane_mode(struct format_tree
*ft
)
1903 struct window_mode_entry
*wme
;
1905 if (ft
->wp
!= NULL
) {
1906 wme
= TAILQ_FIRST(&ft
->wp
->modes
);
1908 return (xstrdup(wme
->mode
->name
));
1914 /* Callback for pane_path. */
1916 format_cb_pane_path(struct format_tree
*ft
)
1918 if (ft
->wp
!= NULL
) {
1919 if (ft
->wp
->base
.path
== NULL
)
1920 return (xstrdup(""));
1921 return (xstrdup(ft
->wp
->base
.path
));
1926 /* Callback for pane_pid. */
1928 format_cb_pane_pid(struct format_tree
*ft
)
1931 return (format_printf("%ld", (long)ft
->wp
->pid
));
1935 /* Callback for pane_pipe. */
1937 format_cb_pane_pipe(struct format_tree
*ft
)
1939 if (ft
->wp
!= NULL
) {
1940 if (ft
->wp
->pipe_fd
!= -1)
1941 return (xstrdup("1"));
1942 return (xstrdup("0"));
1947 /* Callback for pane_right. */
1949 format_cb_pane_right(struct format_tree
*ft
)
1952 return (format_printf("%u", ft
->wp
->xoff
+ ft
->wp
->sx
- 1));
1956 /* Callback for pane_search_string. */
1958 format_cb_pane_search_string(struct format_tree
*ft
)
1960 if (ft
->wp
!= NULL
) {
1961 if (ft
->wp
->searchstr
== NULL
)
1962 return (xstrdup(""));
1963 return (xstrdup(ft
->wp
->searchstr
));
1968 /* Callback for pane_synchronized. */
1970 format_cb_pane_synchronized(struct format_tree
*ft
)
1972 if (ft
->wp
!= NULL
) {
1973 if (options_get_number(ft
->wp
->options
, "synchronize-panes"))
1974 return (xstrdup("1"));
1975 return (xstrdup("0"));
1980 /* Callback for pane_title. */
1982 format_cb_pane_title(struct format_tree
*ft
)
1985 return (xstrdup(ft
->wp
->base
.title
));
1989 /* Callback for pane_top. */
1991 format_cb_pane_top(struct format_tree
*ft
)
1994 return (format_printf("%u", ft
->wp
->yoff
));
1998 /* Callback for pane_tty. */
2000 format_cb_pane_tty(struct format_tree
*ft
)
2003 return (xstrdup(ft
->wp
->tty
));
2007 /* Callback for pane_width. */
2009 format_cb_pane_width(struct format_tree
*ft
)
2012 return (format_printf("%u", ft
->wp
->sx
));
2016 /* Callback for scroll_region_lower. */
2018 format_cb_scroll_region_lower(struct format_tree
*ft
)
2021 return (format_printf("%u", ft
->wp
->base
.rlower
));
2025 /* Callback for scroll_region_upper. */
2027 format_cb_scroll_region_upper(struct format_tree
*ft
)
2030 return (format_printf("%u", ft
->wp
->base
.rupper
));
2034 /* Callback for session_attached. */
2036 format_cb_session_attached(struct format_tree
*ft
)
2039 return (format_printf("%u", ft
->s
->attached
));
2043 /* Callback for session_format. */
2045 format_cb_session_format(struct format_tree
*ft
)
2047 if (ft
->type
== FORMAT_TYPE_SESSION
)
2048 return (xstrdup("1"));
2049 return (xstrdup("0"));
2052 /* Callback for session_group. */
2054 format_cb_session_group(struct format_tree
*ft
)
2056 struct session_group
*sg
;
2058 if (ft
->s
!= NULL
&& (sg
= session_group_contains(ft
->s
)) != NULL
)
2059 return (xstrdup(sg
->name
));
2063 /* Callback for session_group_attached. */
2065 format_cb_session_group_attached(struct format_tree
*ft
)
2067 struct session_group
*sg
;
2069 if (ft
->s
!= NULL
&& (sg
= session_group_contains(ft
->s
)) != NULL
)
2070 return (format_printf("%u", session_group_attached_count (sg
)));
2074 /* Callback for session_group_many_attached. */
2076 format_cb_session_group_many_attached(struct format_tree
*ft
)
2078 struct session_group
*sg
;
2080 if (ft
->s
!= NULL
&& (sg
= session_group_contains(ft
->s
)) != NULL
) {
2081 if (session_group_attached_count (sg
) > 1)
2082 return (xstrdup("1"));
2083 return (xstrdup("0"));
2088 /* Callback for session_group_size. */
2090 format_cb_session_group_size(struct format_tree
*ft
)
2092 struct session_group
*sg
;
2094 if (ft
->s
!= NULL
&& (sg
= session_group_contains(ft
->s
)) != NULL
)
2095 return (format_printf("%u", session_group_count (sg
)));
2099 /* Callback for session_grouped. */
2101 format_cb_session_grouped(struct format_tree
*ft
)
2103 if (ft
->s
!= NULL
) {
2104 if (session_group_contains(ft
->s
) != NULL
)
2105 return (xstrdup("1"));
2106 return (xstrdup("0"));
2111 /* Callback for session_id. */
2113 format_cb_session_id(struct format_tree
*ft
)
2116 return (format_printf("$%u", ft
->s
->id
));
2120 /* Callback for session_many_attached. */
2122 format_cb_session_many_attached(struct format_tree
*ft
)
2124 if (ft
->s
!= NULL
) {
2125 if (ft
->s
->attached
> 1)
2126 return (xstrdup("1"));
2127 return (xstrdup("0"));
2132 /* Callback for session_marked. */
2134 format_cb_session_marked(struct format_tree
*ft
)
2136 if (ft
->s
!= NULL
) {
2137 if (server_check_marked() && marked_pane
.s
== ft
->s
)
2138 return (xstrdup("1"));
2139 return (xstrdup("0"));
2144 /* Callback for session_name. */
2146 format_cb_session_name(struct format_tree
*ft
)
2149 return (xstrdup(ft
->s
->name
));
2153 /* Callback for session_path. */
2155 format_cb_session_path(struct format_tree
*ft
)
2158 return (xstrdup(ft
->s
->cwd
));
2162 /* Callback for session_windows. */
2164 format_cb_session_windows(struct format_tree
*ft
)
2167 return (format_printf("%u", winlink_count(&ft
->s
->windows
)));
2171 /* Callback for socket_path. */
2173 format_cb_socket_path(__unused
struct format_tree
*ft
)
2175 return (xstrdup(socket_path
));
2178 /* Callback for version. */
2180 format_cb_version(__unused
struct format_tree
*ft
)
2182 return (xstrdup(getversion()));
2185 /* Callback for active_window_index. */
2187 format_cb_active_window_index(struct format_tree
*ft
)
2190 return (format_printf("%u", ft
->s
->curw
->idx
));
2194 /* Callback for last_window_index. */
2196 format_cb_last_window_index(struct format_tree
*ft
)
2200 if (ft
->s
!= NULL
) {
2201 wl
= RB_MAX(winlinks
, &ft
->s
->windows
);
2202 return (format_printf("%u", wl
->idx
));
2207 /* Callback for window_active. */
2209 format_cb_window_active(struct format_tree
*ft
)
2211 if (ft
->wl
!= NULL
) {
2212 if (ft
->wl
== ft
->wl
->session
->curw
)
2213 return (xstrdup("1"));
2214 return (xstrdup("0"));
2219 /* Callback for window_activity_flag. */
2221 format_cb_window_activity_flag(struct format_tree
*ft
)
2223 if (ft
->wl
!= NULL
) {
2224 if (ft
->wl
->flags
& WINLINK_ACTIVITY
)
2225 return (xstrdup("1"));
2226 return (xstrdup("0"));
2231 /* Callback for window_bell_flag. */
2233 format_cb_window_bell_flag(struct format_tree
*ft
)
2235 if (ft
->wl
!= NULL
) {
2236 if (ft
->wl
->flags
& WINLINK_BELL
)
2237 return (xstrdup("1"));
2238 return (xstrdup("0"));
2243 /* Callback for window_bigger. */
2245 format_cb_window_bigger(struct format_tree
*ft
)
2247 u_int ox
, oy
, sx
, sy
;
2249 if (ft
->c
!= NULL
) {
2250 if (tty_window_offset(&ft
->c
->tty
, &ox
, &oy
, &sx
, &sy
))
2251 return (xstrdup("1"));
2252 return (xstrdup("0"));
2257 /* Callback for window_cell_height. */
2259 format_cb_window_cell_height(struct format_tree
*ft
)
2262 return (format_printf("%u", ft
->w
->ypixel
));
2266 /* Callback for window_cell_width. */
2268 format_cb_window_cell_width(struct format_tree
*ft
)
2271 return (format_printf("%u", ft
->w
->xpixel
));
2275 /* Callback for window_end_flag. */
2277 format_cb_window_end_flag(struct format_tree
*ft
)
2279 if (ft
->wl
!= NULL
) {
2280 if (ft
->wl
== RB_MAX(winlinks
, &ft
->wl
->session
->windows
))
2281 return (xstrdup("1"));
2282 return (xstrdup("0"));
2287 /* Callback for window_flags. */
2289 format_cb_window_flags(struct format_tree
*ft
)
2292 return (xstrdup(window_printable_flags(ft
->wl
, 1)));
2296 /* Callback for window_format. */
2298 format_cb_window_format(struct format_tree
*ft
)
2300 if (ft
->type
== FORMAT_TYPE_WINDOW
)
2301 return (xstrdup("1"));
2302 return (xstrdup("0"));
2305 /* Callback for window_height. */
2307 format_cb_window_height(struct format_tree
*ft
)
2310 return (format_printf("%u", ft
->w
->sy
));
2314 /* Callback for window_id. */
2316 format_cb_window_id(struct format_tree
*ft
)
2319 return (format_printf("@%u", ft
->w
->id
));
2323 /* Callback for window_index. */
2325 format_cb_window_index(struct format_tree
*ft
)
2328 return (format_printf("%d", ft
->wl
->idx
));
2332 /* Callback for window_last_flag. */
2334 format_cb_window_last_flag(struct format_tree
*ft
)
2336 if (ft
->wl
!= NULL
) {
2337 if (ft
->wl
== TAILQ_FIRST(&ft
->wl
->session
->lastw
))
2338 return (xstrdup("1"));
2339 return (xstrdup("0"));
2344 /* Callback for window_linked. */
2346 format_cb_window_linked(struct format_tree
*ft
)
2348 if (ft
->wl
!= NULL
) {
2349 if (session_is_linked(ft
->wl
->session
, ft
->wl
->window
))
2350 return (xstrdup("1"));
2351 return (xstrdup("0"));
2356 /* Callback for window_linked_sessions. */
2358 format_cb_window_linked_sessions(struct format_tree
*ft
)
2361 return (format_printf("%u", ft
->wl
->window
->references
));
2365 /* Callback for window_marked_flag. */
2367 format_cb_window_marked_flag(struct format_tree
*ft
)
2369 if (ft
->wl
!= NULL
) {
2370 if (server_check_marked() && marked_pane
.wl
== ft
->wl
)
2371 return (xstrdup("1"));
2372 return (xstrdup("0"));
2377 /* Callback for window_name. */
2379 format_cb_window_name(struct format_tree
*ft
)
2382 return (format_printf("%s", ft
->w
->name
));
2386 /* Callback for window_offset_x. */
2388 format_cb_window_offset_x(struct format_tree
*ft
)
2390 u_int ox
, oy
, sx
, sy
;
2392 if (ft
->c
!= NULL
) {
2393 if (tty_window_offset(&ft
->c
->tty
, &ox
, &oy
, &sx
, &sy
))
2394 return (format_printf("%u", ox
));
2400 /* Callback for window_offset_y. */
2402 format_cb_window_offset_y(struct format_tree
*ft
)
2404 u_int ox
, oy
, sx
, sy
;
2406 if (ft
->c
!= NULL
) {
2407 if (tty_window_offset(&ft
->c
->tty
, &ox
, &oy
, &sx
, &sy
))
2408 return (format_printf("%u", oy
));
2414 /* Callback for window_panes. */
2416 format_cb_window_panes(struct format_tree
*ft
)
2419 return (format_printf("%u", window_count_panes(ft
->w
)));
2423 /* Callback for window_raw_flags. */
2425 format_cb_window_raw_flags(struct format_tree
*ft
)
2428 return (xstrdup(window_printable_flags(ft
->wl
, 0)));
2432 /* Callback for window_silence_flag. */
2434 format_cb_window_silence_flag(struct format_tree
*ft
)
2436 if (ft
->wl
!= NULL
) {
2437 if (ft
->wl
->flags
& WINLINK_SILENCE
)
2438 return (xstrdup("1"));
2439 return (xstrdup("0"));
2444 /* Callback for window_start_flag. */
2446 format_cb_window_start_flag(struct format_tree
*ft
)
2448 if (ft
->wl
!= NULL
) {
2449 if (ft
->wl
== RB_MIN(winlinks
, &ft
->wl
->session
->windows
))
2450 return (xstrdup("1"));
2451 return (xstrdup("0"));
2456 /* Callback for window_width. */
2458 format_cb_window_width(struct format_tree
*ft
)
2461 return (format_printf("%u", ft
->w
->sx
));
2465 /* Callback for window_zoomed_flag. */
2467 format_cb_window_zoomed_flag(struct format_tree
*ft
)
2469 if (ft
->w
!= NULL
) {
2470 if (ft
->w
->flags
& WINDOW_ZOOMED
)
2471 return (xstrdup("1"));
2472 return (xstrdup("0"));
2477 /* Callback for wrap_flag. */
2479 format_cb_wrap_flag(struct format_tree
*ft
)
2481 if (ft
->wp
!= NULL
) {
2482 if (ft
->wp
->base
.mode
& MODE_WRAP
)
2483 return (xstrdup("1"));
2484 return (xstrdup("0"));
2489 /* Callback for buffer_created. */
2491 format_cb_buffer_created(struct format_tree
*ft
)
2493 static struct timeval tv
;
2495 if (ft
->pb
!= NULL
) {
2497 tv
.tv_sec
= paste_buffer_created(ft
->pb
);
2503 /* Callback for client_activity. */
2505 format_cb_client_activity(struct format_tree
*ft
)
2508 return (&ft
->c
->activity_time
);
2512 /* Callback for client_created. */
2514 format_cb_client_created(struct format_tree
*ft
)
2517 return (&ft
->c
->creation_time
);
2521 /* Callback for session_activity. */
2523 format_cb_session_activity(struct format_tree
*ft
)
2526 return (&ft
->s
->activity_time
);
2530 /* Callback for session_created. */
2532 format_cb_session_created(struct format_tree
*ft
)
2535 return (&ft
->s
->creation_time
);
2539 /* Callback for session_last_attached. */
2541 format_cb_session_last_attached(struct format_tree
*ft
)
2544 return (&ft
->s
->last_attached_time
);
2548 /* Callback for start_time. */
2550 format_cb_start_time(__unused
struct format_tree
*ft
)
2552 return (&start_time
);
2555 /* Callback for window_activity. */
2557 format_cb_window_activity(struct format_tree
*ft
)
2560 return (&ft
->w
->activity_time
);
2564 /* Callback for buffer_mode_format, */
2566 format_cb_buffer_mode_format(__unused
struct format_tree
*ft
)
2568 return (xstrdup(window_buffer_mode
.default_format
));
2571 /* Callback for client_mode_format, */
2573 format_cb_client_mode_format(__unused
struct format_tree
*ft
)
2575 return (xstrdup(window_client_mode
.default_format
));
2578 /* Callback for tree_mode_format, */
2580 format_cb_tree_mode_format(__unused
struct format_tree
*ft
)
2582 return (xstrdup(window_tree_mode
.default_format
));
2585 /* Callback for uid. */
2587 format_cb_uid(__unused
struct format_tree
*ft
)
2589 return (format_printf("%ld", (long)getuid()));
2592 /* Callback for user. */
2594 format_cb_user(__unused
struct format_tree
*ft
)
2598 if ((pw
= getpwuid(getuid())) != NULL
)
2599 return (xstrdup(pw
->pw_name
));
2603 /* Format table type. */
2604 enum format_table_type
{
2605 FORMAT_TABLE_STRING
,
2609 /* Format table entry. */
2610 struct format_table_entry
{
2612 enum format_table_type type
;
2617 * Format table. Default format variables (that are almost always in the tree
2618 * and where the value is expanded by a callback in this file) are listed here.
2619 * Only variables which are added by the caller go into the tree.
2621 static const struct format_table_entry format_table
[] = {
2622 { "active_window_index", FORMAT_TABLE_STRING
,
2623 format_cb_active_window_index
2625 { "alternate_on", FORMAT_TABLE_STRING
,
2626 format_cb_alternate_on
2628 { "alternate_saved_x", FORMAT_TABLE_STRING
,
2629 format_cb_alternate_saved_x
2631 { "alternate_saved_y", FORMAT_TABLE_STRING
,
2632 format_cb_alternate_saved_y
2634 { "buffer_created", FORMAT_TABLE_TIME
,
2635 format_cb_buffer_created
2637 { "buffer_mode_format", FORMAT_TABLE_STRING
,
2638 format_cb_buffer_mode_format
2640 { "buffer_name", FORMAT_TABLE_STRING
,
2641 format_cb_buffer_name
2643 { "buffer_sample", FORMAT_TABLE_STRING
,
2644 format_cb_buffer_sample
2646 { "buffer_size", FORMAT_TABLE_STRING
,
2647 format_cb_buffer_size
2649 { "client_activity", FORMAT_TABLE_TIME
,
2650 format_cb_client_activity
2652 { "client_cell_height", FORMAT_TABLE_STRING
,
2653 format_cb_client_cell_height
2655 { "client_cell_width", FORMAT_TABLE_STRING
,
2656 format_cb_client_cell_width
2658 { "client_control_mode", FORMAT_TABLE_STRING
,
2659 format_cb_client_control_mode
2661 { "client_created", FORMAT_TABLE_TIME
,
2662 format_cb_client_created
2664 { "client_discarded", FORMAT_TABLE_STRING
,
2665 format_cb_client_discarded
2667 { "client_flags", FORMAT_TABLE_STRING
,
2668 format_cb_client_flags
2670 { "client_height", FORMAT_TABLE_STRING
,
2671 format_cb_client_height
2673 { "client_key_table", FORMAT_TABLE_STRING
,
2674 format_cb_client_key_table
2676 { "client_last_session", FORMAT_TABLE_STRING
,
2677 format_cb_client_last_session
2679 { "client_mode_format", FORMAT_TABLE_STRING
,
2680 format_cb_client_mode_format
2682 { "client_name", FORMAT_TABLE_STRING
,
2683 format_cb_client_name
2685 { "client_pid", FORMAT_TABLE_STRING
,
2686 format_cb_client_pid
2688 { "client_prefix", FORMAT_TABLE_STRING
,
2689 format_cb_client_prefix
2691 { "client_readonly", FORMAT_TABLE_STRING
,
2692 format_cb_client_readonly
2694 { "client_session", FORMAT_TABLE_STRING
,
2695 format_cb_client_session
2697 { "client_termfeatures", FORMAT_TABLE_STRING
,
2698 format_cb_client_termfeatures
2700 { "client_termname", FORMAT_TABLE_STRING
,
2701 format_cb_client_termname
2703 { "client_termtype", FORMAT_TABLE_STRING
,
2704 format_cb_client_termtype
2706 { "client_tty", FORMAT_TABLE_STRING
,
2707 format_cb_client_tty
2709 { "client_uid", FORMAT_TABLE_STRING
,
2710 format_cb_client_uid
2712 { "client_user", FORMAT_TABLE_STRING
,
2713 format_cb_client_user
2715 { "client_utf8", FORMAT_TABLE_STRING
,
2716 format_cb_client_utf8
2718 { "client_width", FORMAT_TABLE_STRING
,
2719 format_cb_client_width
2721 { "client_written", FORMAT_TABLE_STRING
,
2722 format_cb_client_written
2724 { "config_files", FORMAT_TABLE_STRING
,
2725 format_cb_config_files
2727 { "cursor_character", FORMAT_TABLE_STRING
,
2728 format_cb_cursor_character
2730 { "cursor_flag", FORMAT_TABLE_STRING
,
2731 format_cb_cursor_flag
2733 { "cursor_x", FORMAT_TABLE_STRING
,
2736 { "cursor_y", FORMAT_TABLE_STRING
,
2739 { "history_all_bytes", FORMAT_TABLE_STRING
,
2740 format_cb_history_all_bytes
2742 { "history_bytes", FORMAT_TABLE_STRING
,
2743 format_cb_history_bytes
2745 { "history_limit", FORMAT_TABLE_STRING
,
2746 format_cb_history_limit
2748 { "history_size", FORMAT_TABLE_STRING
,
2749 format_cb_history_size
2751 { "host", FORMAT_TABLE_STRING
,
2754 { "host_short", FORMAT_TABLE_STRING
,
2755 format_cb_host_short
2757 { "insert_flag", FORMAT_TABLE_STRING
,
2758 format_cb_insert_flag
2760 { "keypad_cursor_flag", FORMAT_TABLE_STRING
,
2761 format_cb_keypad_cursor_flag
2763 { "keypad_flag", FORMAT_TABLE_STRING
,
2764 format_cb_keypad_flag
2766 { "last_window_index", FORMAT_TABLE_STRING
,
2767 format_cb_last_window_index
2769 { "mouse_all_flag", FORMAT_TABLE_STRING
,
2770 format_cb_mouse_all_flag
2772 { "mouse_any_flag", FORMAT_TABLE_STRING
,
2773 format_cb_mouse_any_flag
2775 { "mouse_button_flag", FORMAT_TABLE_STRING
,
2776 format_cb_mouse_button_flag
2778 { "mouse_line", FORMAT_TABLE_STRING
,
2779 format_cb_mouse_line
2781 { "mouse_pane", FORMAT_TABLE_STRING
,
2782 format_cb_mouse_pane
2784 { "mouse_sgr_flag", FORMAT_TABLE_STRING
,
2785 format_cb_mouse_sgr_flag
2787 { "mouse_standard_flag", FORMAT_TABLE_STRING
,
2788 format_cb_mouse_standard_flag
2790 { "mouse_utf8_flag", FORMAT_TABLE_STRING
,
2791 format_cb_mouse_utf8_flag
2793 { "mouse_word", FORMAT_TABLE_STRING
,
2794 format_cb_mouse_word
2796 { "mouse_x", FORMAT_TABLE_STRING
,
2799 { "mouse_y", FORMAT_TABLE_STRING
,
2802 { "next_session_id", FORMAT_TABLE_STRING
,
2803 format_cb_next_session_id
2805 { "origin_flag", FORMAT_TABLE_STRING
,
2806 format_cb_origin_flag
2808 { "pane_active", FORMAT_TABLE_STRING
,
2809 format_cb_pane_active
2811 { "pane_at_bottom", FORMAT_TABLE_STRING
,
2812 format_cb_pane_at_bottom
2814 { "pane_at_left", FORMAT_TABLE_STRING
,
2815 format_cb_pane_at_left
2817 { "pane_at_right", FORMAT_TABLE_STRING
,
2818 format_cb_pane_at_right
2820 { "pane_at_top", FORMAT_TABLE_STRING
,
2821 format_cb_pane_at_top
2823 { "pane_bg", FORMAT_TABLE_STRING
,
2826 { "pane_bottom", FORMAT_TABLE_STRING
,
2827 format_cb_pane_bottom
2829 { "pane_current_command", FORMAT_TABLE_STRING
,
2830 format_cb_current_command
2832 { "pane_current_path", FORMAT_TABLE_STRING
,
2833 format_cb_current_path
2835 { "pane_dead", FORMAT_TABLE_STRING
,
2838 { "pane_dead_signal", FORMAT_TABLE_STRING
,
2839 format_cb_pane_dead_signal
2841 { "pane_dead_status", FORMAT_TABLE_STRING
,
2842 format_cb_pane_dead_status
2844 { "pane_dead_time", FORMAT_TABLE_TIME
,
2845 format_cb_pane_dead_time
2847 { "pane_fg", FORMAT_TABLE_STRING
,
2850 { "pane_format", FORMAT_TABLE_STRING
,
2851 format_cb_pane_format
2853 { "pane_height", FORMAT_TABLE_STRING
,
2854 format_cb_pane_height
2856 { "pane_id", FORMAT_TABLE_STRING
,
2859 { "pane_in_mode", FORMAT_TABLE_STRING
,
2860 format_cb_pane_in_mode
2862 { "pane_index", FORMAT_TABLE_STRING
,
2863 format_cb_pane_index
2865 { "pane_input_off", FORMAT_TABLE_STRING
,
2866 format_cb_pane_input_off
2868 { "pane_last", FORMAT_TABLE_STRING
,
2871 { "pane_left", FORMAT_TABLE_STRING
,
2874 { "pane_marked", FORMAT_TABLE_STRING
,
2875 format_cb_pane_marked
2877 { "pane_marked_set", FORMAT_TABLE_STRING
,
2878 format_cb_pane_marked_set
2880 { "pane_mode", FORMAT_TABLE_STRING
,
2883 { "pane_path", FORMAT_TABLE_STRING
,
2886 { "pane_pid", FORMAT_TABLE_STRING
,
2889 { "pane_pipe", FORMAT_TABLE_STRING
,
2892 { "pane_right", FORMAT_TABLE_STRING
,
2893 format_cb_pane_right
2895 { "pane_search_string", FORMAT_TABLE_STRING
,
2896 format_cb_pane_search_string
2898 { "pane_start_command", FORMAT_TABLE_STRING
,
2899 format_cb_start_command
2901 { "pane_synchronized", FORMAT_TABLE_STRING
,
2902 format_cb_pane_synchronized
2904 { "pane_tabs", FORMAT_TABLE_STRING
,
2907 { "pane_title", FORMAT_TABLE_STRING
,
2908 format_cb_pane_title
2910 { "pane_top", FORMAT_TABLE_STRING
,
2913 { "pane_tty", FORMAT_TABLE_STRING
,
2916 { "pane_width", FORMAT_TABLE_STRING
,
2917 format_cb_pane_width
2919 { "pid", FORMAT_TABLE_STRING
,
2922 { "scroll_region_lower", FORMAT_TABLE_STRING
,
2923 format_cb_scroll_region_lower
2925 { "scroll_region_upper", FORMAT_TABLE_STRING
,
2926 format_cb_scroll_region_upper
2928 { "session_activity", FORMAT_TABLE_TIME
,
2929 format_cb_session_activity
2931 { "session_alerts", FORMAT_TABLE_STRING
,
2932 format_cb_session_alerts
2934 { "session_attached", FORMAT_TABLE_STRING
,
2935 format_cb_session_attached
2937 { "session_attached_list", FORMAT_TABLE_STRING
,
2938 format_cb_session_attached_list
2940 { "session_created", FORMAT_TABLE_TIME
,
2941 format_cb_session_created
2943 { "session_format", FORMAT_TABLE_STRING
,
2944 format_cb_session_format
2946 { "session_group", FORMAT_TABLE_STRING
,
2947 format_cb_session_group
2949 { "session_group_attached", FORMAT_TABLE_STRING
,
2950 format_cb_session_group_attached
2952 { "session_group_attached_list", FORMAT_TABLE_STRING
,
2953 format_cb_session_group_attached_list
2955 { "session_group_list", FORMAT_TABLE_STRING
,
2956 format_cb_session_group_list
2958 { "session_group_many_attached", FORMAT_TABLE_STRING
,
2959 format_cb_session_group_many_attached
2961 { "session_group_size", FORMAT_TABLE_STRING
,
2962 format_cb_session_group_size
2964 { "session_grouped", FORMAT_TABLE_STRING
,
2965 format_cb_session_grouped
2967 { "session_id", FORMAT_TABLE_STRING
,
2968 format_cb_session_id
2970 { "session_last_attached", FORMAT_TABLE_TIME
,
2971 format_cb_session_last_attached
2973 { "session_many_attached", FORMAT_TABLE_STRING
,
2974 format_cb_session_many_attached
2976 { "session_marked", FORMAT_TABLE_STRING
,
2977 format_cb_session_marked
,
2979 { "session_name", FORMAT_TABLE_STRING
,
2980 format_cb_session_name
2982 { "session_path", FORMAT_TABLE_STRING
,
2983 format_cb_session_path
2985 { "session_stack", FORMAT_TABLE_STRING
,
2986 format_cb_session_stack
2988 { "session_windows", FORMAT_TABLE_STRING
,
2989 format_cb_session_windows
2991 { "socket_path", FORMAT_TABLE_STRING
,
2992 format_cb_socket_path
2994 { "start_time", FORMAT_TABLE_TIME
,
2995 format_cb_start_time
2997 { "tree_mode_format", FORMAT_TABLE_STRING
,
2998 format_cb_tree_mode_format
3000 { "uid", FORMAT_TABLE_STRING
,
3003 { "user", FORMAT_TABLE_STRING
,
3006 { "version", FORMAT_TABLE_STRING
,
3009 { "window_active", FORMAT_TABLE_STRING
,
3010 format_cb_window_active
3012 { "window_active_clients", FORMAT_TABLE_STRING
,
3013 format_cb_window_active_clients
3015 { "window_active_clients_list", FORMAT_TABLE_STRING
,
3016 format_cb_window_active_clients_list
3018 { "window_active_sessions", FORMAT_TABLE_STRING
,
3019 format_cb_window_active_sessions
3021 { "window_active_sessions_list", FORMAT_TABLE_STRING
,
3022 format_cb_window_active_sessions_list
3024 { "window_activity", FORMAT_TABLE_TIME
,
3025 format_cb_window_activity
3027 { "window_activity_flag", FORMAT_TABLE_STRING
,
3028 format_cb_window_activity_flag
3030 { "window_bell_flag", FORMAT_TABLE_STRING
,
3031 format_cb_window_bell_flag
3033 { "window_bigger", FORMAT_TABLE_STRING
,
3034 format_cb_window_bigger
3036 { "window_cell_height", FORMAT_TABLE_STRING
,
3037 format_cb_window_cell_height
3039 { "window_cell_width", FORMAT_TABLE_STRING
,
3040 format_cb_window_cell_width
3042 { "window_end_flag", FORMAT_TABLE_STRING
,
3043 format_cb_window_end_flag
3045 { "window_flags", FORMAT_TABLE_STRING
,
3046 format_cb_window_flags
3048 { "window_format", FORMAT_TABLE_STRING
,
3049 format_cb_window_format
3051 { "window_height", FORMAT_TABLE_STRING
,
3052 format_cb_window_height
3054 { "window_id", FORMAT_TABLE_STRING
,
3057 { "window_index", FORMAT_TABLE_STRING
,
3058 format_cb_window_index
3060 { "window_last_flag", FORMAT_TABLE_STRING
,
3061 format_cb_window_last_flag
3063 { "window_layout", FORMAT_TABLE_STRING
,
3064 format_cb_window_layout
3066 { "window_linked", FORMAT_TABLE_STRING
,
3067 format_cb_window_linked
3069 { "window_linked_sessions", FORMAT_TABLE_STRING
,
3070 format_cb_window_linked_sessions
3072 { "window_linked_sessions_list", FORMAT_TABLE_STRING
,
3073 format_cb_window_linked_sessions_list
3075 { "window_marked_flag", FORMAT_TABLE_STRING
,
3076 format_cb_window_marked_flag
3078 { "window_name", FORMAT_TABLE_STRING
,
3079 format_cb_window_name
3081 { "window_offset_x", FORMAT_TABLE_STRING
,
3082 format_cb_window_offset_x
3084 { "window_offset_y", FORMAT_TABLE_STRING
,
3085 format_cb_window_offset_y
3087 { "window_panes", FORMAT_TABLE_STRING
,
3088 format_cb_window_panes
3090 { "window_raw_flags", FORMAT_TABLE_STRING
,
3091 format_cb_window_raw_flags
3093 { "window_silence_flag", FORMAT_TABLE_STRING
,
3094 format_cb_window_silence_flag
3096 { "window_stack_index", FORMAT_TABLE_STRING
,
3097 format_cb_window_stack_index
3099 { "window_start_flag", FORMAT_TABLE_STRING
,
3100 format_cb_window_start_flag
3102 { "window_visible_layout", FORMAT_TABLE_STRING
,
3103 format_cb_window_visible_layout
3105 { "window_width", FORMAT_TABLE_STRING
,
3106 format_cb_window_width
3108 { "window_zoomed_flag", FORMAT_TABLE_STRING
,
3109 format_cb_window_zoomed_flag
3111 { "wrap_flag", FORMAT_TABLE_STRING
,
3116 /* Compare format table entries. */
3118 format_table_compare(const void *key0
, const void *entry0
)
3120 const char *key
= key0
;
3121 const struct format_table_entry
*entry
= entry0
;
3123 return (strcmp(key
, entry
->key
));
3126 /* Get a format callback. */
3127 static struct format_table_entry
*
3128 format_table_get(const char *key
)
3130 return (bsearch(key
, format_table
, nitems(format_table
),
3131 sizeof *format_table
, format_table_compare
));
3134 /* Merge one format tree into another. */
3136 format_merge(struct format_tree
*ft
, struct format_tree
*from
)
3138 struct format_entry
*fe
;
3140 RB_FOREACH(fe
, format_entry_tree
, &from
->tree
) {
3141 if (fe
->value
!= NULL
)
3142 format_add(ft
, fe
->key
, "%s", fe
->value
);
3146 /* Get format pane. */
3147 struct window_pane
*
3148 format_get_pane(struct format_tree
*ft
)
3153 /* Add item bits to tree. */
3155 format_create_add_item(struct format_tree
*ft
, struct cmdq_item
*item
)
3157 struct key_event
*event
= cmdq_get_event(item
);
3158 struct mouse_event
*m
= &event
->m
;
3160 cmdq_merge_formats(item
, ft
);
3161 memcpy(&ft
->m
, m
, sizeof ft
->m
);
3164 /* Create a new tree. */
3165 struct format_tree
*
3166 format_create(struct client
*c
, struct cmdq_item
*item
, int tag
, int flags
)
3168 struct format_tree
*ft
;
3170 ft
= xcalloc(1, sizeof *ft
);
3175 ft
->client
->references
++;
3183 format_create_add_item(ft
, item
);
3190 format_free(struct format_tree
*ft
)
3192 struct format_entry
*fe
, *fe1
;
3194 RB_FOREACH_SAFE(fe
, format_entry_tree
, &ft
->tree
, fe1
) {
3195 RB_REMOVE(format_entry_tree
, &ft
->tree
, fe
);
3201 if (ft
->client
!= NULL
)
3202 server_client_unref(ft
->client
);
3206 /* Log each format. */
3208 format_log_debug_cb(const char *key
, const char *value
, void *arg
)
3210 const char *prefix
= arg
;
3212 log_debug("%s: %s=%s", prefix
, key
, value
);
3215 /* Log a format tree. */
3217 format_log_debug(struct format_tree
*ft
, const char *prefix
)
3219 format_each(ft
, format_log_debug_cb
, (void *)prefix
);
3222 /* Walk each format. */
3224 format_each(struct format_tree
*ft
, void (*cb
)(const char *, const char *,
3227 const struct format_table_entry
*fte
;
3228 struct format_entry
*fe
;
3234 for (i
= 0; i
< nitems(format_table
); i
++) {
3235 fte
= &format_table
[i
];
3237 value
= fte
->cb(ft
);
3240 if (fte
->type
== FORMAT_TABLE_TIME
) {
3242 xsnprintf(s
, sizeof s
, "%lld", (long long)tv
->tv_sec
);
3243 cb(fte
->key
, s
, arg
);
3245 cb(fte
->key
, value
, arg
);
3249 RB_FOREACH(fe
, format_entry_tree
, &ft
->tree
) {
3250 if (fe
->time
!= 0) {
3251 xsnprintf(s
, sizeof s
, "%lld", (long long)fe
->time
);
3252 cb(fe
->key
, s
, arg
);
3254 if (fe
->value
== NULL
&& fe
->cb
!= NULL
) {
3255 fe
->value
= fe
->cb(ft
);
3256 if (fe
->value
== NULL
)
3257 fe
->value
= xstrdup("");
3259 cb(fe
->key
, fe
->value
, arg
);
3264 /* Add a key-value pair. */
3266 format_add(struct format_tree
*ft
, const char *key
, const char *fmt
, ...)
3268 struct format_entry
*fe
;
3269 struct format_entry
*fe_now
;
3272 fe
= xmalloc(sizeof *fe
);
3273 fe
->key
= xstrdup(key
);
3275 fe_now
= RB_INSERT(format_entry_tree
, &ft
->tree
, fe
);
3276 if (fe_now
!= NULL
) {
3279 free(fe_now
->value
);
3287 xvasprintf(&fe
->value
, fmt
, ap
);
3291 /* Add a key and time. */
3293 format_add_tv(struct format_tree
*ft
, const char *key
, struct timeval
*tv
)
3295 struct format_entry
*fe
, *fe_now
;
3297 fe
= xmalloc(sizeof *fe
);
3298 fe
->key
= xstrdup(key
);
3300 fe_now
= RB_INSERT(format_entry_tree
, &ft
->tree
, fe
);
3301 if (fe_now
!= NULL
) {
3304 free(fe_now
->value
);
3309 fe
->time
= tv
->tv_sec
;
3314 /* Add a key and function. */
3316 format_add_cb(struct format_tree
*ft
, const char *key
, format_cb cb
)
3318 struct format_entry
*fe
;
3319 struct format_entry
*fe_now
;
3321 fe
= xmalloc(sizeof *fe
);
3322 fe
->key
= xstrdup(key
);
3324 fe_now
= RB_INSERT(format_entry_tree
, &ft
->tree
, fe
);
3325 if (fe_now
!= NULL
) {
3328 free(fe_now
->value
);
3338 /* Quote shell special characters in string. */
3340 format_quote_shell(const char *s
)
3345 at
= out
= xmalloc(strlen(s
) * 2 + 1);
3346 for (cp
= s
; *cp
!= '\0'; cp
++) {
3347 if (strchr("|&;<>()$`\\\"'*?[# =%", *cp
) != NULL
)
3355 /* Quote #s in string. */
3357 format_quote_style(const char *s
)
3362 at
= out
= xmalloc(strlen(s
) * 2 + 1);
3363 for (cp
= s
; *cp
!= '\0'; cp
++) {
3372 /* Make a prettier time. */
3374 format_pretty_time(time_t t
)
3376 struct tm now_tm
, tm
;
3385 localtime_r(&now
, &now_tm
);
3386 localtime_r(&t
, &tm
);
3388 /* Last 24 hours. */
3389 if (age
< 24 * 3600) {
3390 strftime(s
, sizeof s
, "%H:%M", &tm
);
3391 return (xstrdup(s
));
3394 /* This month or last 28 days. */
3395 if ((tm
.tm_year
== now_tm
.tm_year
&& tm
.tm_mon
== now_tm
.tm_mon
) ||
3396 age
< 28 * 24 * 3600) {
3397 strftime(s
, sizeof s
, "%a%d", &tm
);
3398 return (xstrdup(s
));
3401 /* Last 12 months. */
3402 if ((tm
.tm_year
== now_tm
.tm_year
&& tm
.tm_mon
< now_tm
.tm_mon
) ||
3403 (tm
.tm_year
== now_tm
.tm_year
- 1 && tm
.tm_mon
> now_tm
.tm_mon
)) {
3404 strftime(s
, sizeof s
, "%d%b", &tm
);
3405 return (xstrdup(s
));
3408 /* Older than that. */
3409 strftime(s
, sizeof s
, "%h%y", &tm
);
3410 return (xstrdup(s
));
3413 /* Find a format entry. */
3415 format_find(struct format_tree
*ft
, const char *key
, int modifiers
,
3416 const char *time_format
)
3418 struct format_table_entry
*fte
;
3420 struct format_entry
*fe
, fe_find
;
3421 struct environ_entry
*envent
;
3422 struct options_entry
*o
;
3424 char *found
= NULL
, *saved
, s
[512];
3429 o
= options_parse_get(global_options
, key
, &idx
, 0);
3430 if (o
== NULL
&& ft
->wp
!= NULL
)
3431 o
= options_parse_get(ft
->wp
->options
, key
, &idx
, 0);
3432 if (o
== NULL
&& ft
->w
!= NULL
)
3433 o
= options_parse_get(ft
->w
->options
, key
, &idx
, 0);
3435 o
= options_parse_get(global_w_options
, key
, &idx
, 0);
3436 if (o
== NULL
&& ft
->s
!= NULL
)
3437 o
= options_parse_get(ft
->s
->options
, key
, &idx
, 0);
3439 o
= options_parse_get(global_s_options
, key
, &idx
, 0);
3441 found
= options_to_string(o
, idx
, 1);
3445 fte
= format_table_get(key
);
3447 value
= fte
->cb(ft
);
3448 if (fte
->type
== FORMAT_TABLE_TIME
&& value
!= NULL
)
3449 t
= ((struct timeval
*)value
)->tv_sec
;
3454 fe_find
.key
= (char *)key
;
3455 fe
= RB_FIND(format_entry_tree
, &ft
->tree
, &fe_find
);
3457 if (fe
->time
!= 0) {
3461 if (fe
->value
== NULL
&& fe
->cb
!= NULL
) {
3462 fe
->value
= fe
->cb(ft
);
3463 if (fe
->value
== NULL
)
3464 fe
->value
= xstrdup("");
3466 found
= xstrdup(fe
->value
);
3470 if (~modifiers
& FORMAT_TIMESTRING
) {
3473 envent
= environ_find(ft
->s
->environ
, key
);
3475 envent
= environ_find(global_environ
, key
);
3476 if (envent
!= NULL
&& envent
->value
!= NULL
) {
3477 found
= xstrdup(envent
->value
);
3485 if (modifiers
& FORMAT_TIMESTRING
) {
3486 if (t
== 0 && found
!= NULL
) {
3487 t
= strtonum(found
, 0, INT64_MAX
, &errstr
);
3494 if (modifiers
& FORMAT_PRETTY
)
3495 found
= format_pretty_time(t
);
3497 if (time_format
!= NULL
) {
3498 localtime_r(&t
, &tm
);
3499 strftime(s
, sizeof s
, time_format
, &tm
);
3502 s
[strcspn(s
, "\n")] = '\0';
3510 xasprintf(&found
, "%lld", (long long)t
);
3511 else if (found
== NULL
)
3513 if (modifiers
& FORMAT_BASENAME
) {
3515 found
= xstrdup(basename(saved
));
3518 if (modifiers
& FORMAT_DIRNAME
) {
3520 found
= xstrdup(dirname(saved
));
3523 if (modifiers
& FORMAT_QUOTE_SHELL
) {
3525 found
= xstrdup(format_quote_shell(saved
));
3528 if (modifiers
& FORMAT_QUOTE_STYLE
) {
3530 found
= xstrdup(format_quote_style(saved
));
3536 /* Remove escaped characters from string. */
3538 format_strip(const char *s
)
3543 cp
= out
= xmalloc(strlen(s
) + 1);
3544 for (; *s
!= '\0'; s
++) {
3545 if (*s
== '#' && s
[1] == '{')
3547 if (*s
== '#' && strchr(",#{}:", s
[1]) != NULL
) {
3560 /* Skip until end. */
3562 format_skip(const char *s
, const char *end
)
3566 for (; *s
!= '\0'; s
++) {
3567 if (*s
== '#' && s
[1] == '{')
3569 if (*s
== '#' && strchr(",#{}:", s
[1]) != NULL
) {
3575 if (strchr(end
, *s
) != NULL
&& brackets
== 0)
3583 /* Return left and right alternatives separated by commas. */
3585 format_choose(struct format_expand_state
*es
, const char *s
, char **left
,
3586 char **right
, int expand
)
3589 char *left0
, *right0
;
3591 cp
= format_skip(s
, ",");
3594 left0
= xstrndup(s
, cp
- s
);
3595 right0
= xstrdup(cp
+ 1);
3598 *left
= format_expand1(es
, left0
);
3600 *right
= format_expand1(es
, right0
);
3611 format_true(const char *s
)
3613 if (s
!= NULL
&& *s
!= '\0' && (s
[0] != '0' || s
[1] != '\0'))
3618 /* Check if modifier end. */
3620 format_is_end(char c
)
3622 return (c
== ';' || c
== ':');
3625 /* Add to modifier list. */
3627 format_add_modifier(struct format_modifier
**list
, u_int
*count
,
3628 const char *c
, size_t n
, char **argv
, int argc
)
3630 struct format_modifier
*fm
;
3632 *list
= xreallocarray(*list
, (*count
) + 1, sizeof **list
);
3633 fm
= &(*list
)[(*count
)++];
3635 memcpy(fm
->modifier
, c
, n
);
3636 fm
->modifier
[n
] = '\0';
3643 /* Free modifier list. */
3645 format_free_modifiers(struct format_modifier
*list
, u_int count
)
3649 for (i
= 0; i
< count
; i
++)
3650 cmd_free_argv(list
[i
].argc
, list
[i
].argv
);
3654 /* Build modifier list. */
3655 static struct format_modifier
*
3656 format_build_modifiers(struct format_expand_state
*es
, const char **s
,
3659 const char *cp
= *s
, *end
;
3660 struct format_modifier
*list
= NULL
;
3661 char c
, last
[] = "X;:", **argv
, *value
;
3665 * Modifiers are a ; separated list of the forms:
3666 * l,m,C,a,b,c,d,n,t,w,q,E,T,S,W,P,<,>
3677 while (*cp
!= '\0' && *cp
!= ':') {
3678 /* Skip any separator character. */
3682 /* Check single character modifiers with no arguments. */
3683 if (strchr("labcdnwETSWP<>", cp
[0]) != NULL
&&
3684 format_is_end(cp
[1])) {
3685 format_add_modifier(&list
, count
, cp
, 1, NULL
, 0);
3690 /* Then try double character with no arguments. */
3691 if ((memcmp("||", cp
, 2) == 0 ||
3692 memcmp("&&", cp
, 2) == 0 ||
3693 memcmp("!=", cp
, 2) == 0 ||
3694 memcmp("==", cp
, 2) == 0 ||
3695 memcmp("<=", cp
, 2) == 0 ||
3696 memcmp(">=", cp
, 2) == 0) &&
3697 format_is_end(cp
[2])) {
3698 format_add_modifier(&list
, count
, cp
, 2, NULL
, 0);
3703 /* Now try single character with arguments. */
3704 if (strchr("mCNst=peq", cp
[0]) == NULL
)
3708 /* No arguments provided. */
3709 if (format_is_end(cp
[1])) {
3710 format_add_modifier(&list
, count
, cp
, 1, NULL
, 0);
3717 /* Single argument with no wrapper character. */
3718 if (!ispunct(cp
[1]) || cp
[1] == '-') {
3719 end
= format_skip(cp
+ 1, ":;");
3723 argv
= xcalloc(1, sizeof *argv
);
3724 value
= xstrndup(cp
+ 1, end
- (cp
+ 1));
3725 argv
[0] = format_expand1(es
, value
);
3729 format_add_modifier(&list
, count
, &c
, 1, argv
, argc
);
3734 /* Multiple arguments with a wrapper character. */
3738 if (cp
[0] == last
[0] && format_is_end(cp
[1])) {
3742 end
= format_skip(cp
+ 1, last
);
3747 argv
= xreallocarray(argv
, argc
+ 1, sizeof *argv
);
3748 value
= xstrndup(cp
, end
- cp
);
3749 argv
[argc
++] = format_expand1(es
, value
);
3753 } while (!format_is_end(cp
[0]));
3754 format_add_modifier(&list
, count
, &c
, 1, argv
, argc
);
3757 format_free_modifiers(list
, *count
);
3765 /* Match against an fnmatch(3) pattern or regular expression. */
3767 format_match(struct format_modifier
*fm
, const char *pattern
, const char *text
)
3775 if (strchr(s
, 'r') == NULL
) {
3776 if (strchr(s
, 'i') != NULL
)
3777 flags
|= FNM_CASEFOLD
;
3778 if (fnmatch(pattern
, text
, flags
) != 0)
3779 return (xstrdup("0"));
3781 flags
= REG_EXTENDED
|REG_NOSUB
;
3782 if (strchr(s
, 'i') != NULL
)
3784 if (regcomp(&r
, pattern
, flags
) != 0)
3785 return (xstrdup("0"));
3786 if (regexec(&r
, text
, 0, NULL
, 0) != 0) {
3788 return (xstrdup("0"));
3792 return (xstrdup("1"));
3795 /* Perform substitution in string. */
3797 format_sub(struct format_modifier
*fm
, const char *text
, const char *pattern
,
3801 int flags
= REG_EXTENDED
;
3803 if (fm
->argc
>= 3 && strchr(fm
->argv
[2], 'i') != NULL
)
3805 value
= regsub(pattern
, with
, text
, flags
);
3807 return (xstrdup(text
));
3811 /* Search inside pane. */
3813 format_search(struct format_modifier
*fm
, struct window_pane
*wp
, const char *s
)
3815 int ignore
= 0, regex
= 0;
3818 if (fm
->argc
>= 1) {
3819 if (strchr(fm
->argv
[0], 'i') != NULL
)
3821 if (strchr(fm
->argv
[0], 'r') != NULL
)
3824 xasprintf(&value
, "%u", window_pane_search(wp
, s
, regex
, ignore
));
3828 /* Does session name exist? */
3830 format_session_name(struct format_expand_state
*es
, const char *fmt
)
3835 name
= format_expand1(es
, fmt
);
3836 RB_FOREACH(s
, sessions
, &sessions
) {
3837 if (strcmp(s
->name
, name
) == 0) {
3839 return (xstrdup("1"));
3843 return (xstrdup("0"));
3846 /* Loop over sessions. */
3848 format_loop_sessions(struct format_expand_state
*es
, const char *fmt
)
3850 struct format_tree
*ft
= es
->ft
;
3851 struct client
*c
= ft
->client
;
3852 struct cmdq_item
*item
= ft
->item
;
3853 struct format_tree
*nft
;
3854 struct format_expand_state next
;
3855 char *expanded
, *value
;
3859 value
= xcalloc(1, 1);
3862 RB_FOREACH(s
, sessions
, &sessions
) {
3863 format_log(es
, "session loop: $%u", s
->id
);
3864 nft
= format_create(c
, item
, FORMAT_NONE
, ft
->flags
);
3865 format_defaults(nft
, ft
->c
, s
, NULL
, NULL
);
3866 format_copy_state(&next
, es
, 0);
3868 expanded
= format_expand1(&next
, fmt
);
3869 format_free(next
.ft
);
3871 valuelen
+= strlen(expanded
);
3872 value
= xrealloc(value
, valuelen
);
3874 strlcat(value
, expanded
, valuelen
);
3881 /* Does window name exist? */
3883 format_window_name(struct format_expand_state
*es
, const char *fmt
)
3885 struct format_tree
*ft
= es
->ft
;
3889 if (ft
->s
== NULL
) {
3890 format_log(es
, "window name but no session");
3894 name
= format_expand1(es
, fmt
);
3895 RB_FOREACH(wl
, winlinks
, &ft
->s
->windows
) {
3896 if (strcmp(wl
->window
->name
, name
) == 0) {
3898 return (xstrdup("1"));
3902 return (xstrdup("0"));
3905 /* Loop over windows. */
3907 format_loop_windows(struct format_expand_state
*es
, const char *fmt
)
3909 struct format_tree
*ft
= es
->ft
;
3910 struct client
*c
= ft
->client
;
3911 struct cmdq_item
*item
= ft
->item
;
3912 struct format_tree
*nft
;
3913 struct format_expand_state next
;
3914 char *all
, *active
, *use
, *expanded
, *value
;
3919 if (ft
->s
== NULL
) {
3920 format_log(es
, "window loop but no session");
3924 if (format_choose(es
, fmt
, &all
, &active
, 0) != 0) {
3929 value
= xcalloc(1, 1);
3932 RB_FOREACH(wl
, winlinks
, &ft
->s
->windows
) {
3934 format_log(es
, "window loop: %u @%u", wl
->idx
, w
->id
);
3935 if (active
!= NULL
&& wl
== ft
->s
->curw
)
3939 nft
= format_create(c
, item
, FORMAT_WINDOW
|w
->id
, ft
->flags
);
3940 format_defaults(nft
, ft
->c
, ft
->s
, wl
, NULL
);
3941 format_copy_state(&next
, es
, 0);
3943 expanded
= format_expand1(&next
, use
);
3946 valuelen
+= strlen(expanded
);
3947 value
= xrealloc(value
, valuelen
);
3949 strlcat(value
, expanded
, valuelen
);
3959 /* Loop over panes. */
3961 format_loop_panes(struct format_expand_state
*es
, const char *fmt
)
3963 struct format_tree
*ft
= es
->ft
;
3964 struct client
*c
= ft
->client
;
3965 struct cmdq_item
*item
= ft
->item
;
3966 struct format_tree
*nft
;
3967 struct format_expand_state next
;
3968 char *all
, *active
, *use
, *expanded
, *value
;
3970 struct window_pane
*wp
;
3972 if (ft
->w
== NULL
) {
3973 format_log(es
, "pane loop but no window");
3977 if (format_choose(es
, fmt
, &all
, &active
, 0) != 0) {
3982 value
= xcalloc(1, 1);
3985 TAILQ_FOREACH(wp
, &ft
->w
->panes
, entry
) {
3986 format_log(es
, "pane loop: %%%u", wp
->id
);
3987 if (active
!= NULL
&& wp
== ft
->w
->active
)
3991 nft
= format_create(c
, item
, FORMAT_PANE
|wp
->id
, ft
->flags
);
3992 format_defaults(nft
, ft
->c
, ft
->s
, ft
->wl
, wp
);
3993 format_copy_state(&next
, es
, 0);
3995 expanded
= format_expand1(&next
, use
);
3998 valuelen
+= strlen(expanded
);
3999 value
= xrealloc(value
, valuelen
);
4001 strlcat(value
, expanded
, valuelen
);
4012 format_replace_expression(struct format_modifier
*mexp
,
4013 struct format_expand_state
*es
, const char *copy
)
4015 int argc
= mexp
->argc
;
4017 char *endch
, *value
, *left
= NULL
, *right
= NULL
;
4020 double mleft
, mright
, result
;
4031 LESS_THAN_EQUAL
} operator;
4033 if (strcmp(mexp
->argv
[0], "+") == 0)
4035 else if (strcmp(mexp
->argv
[0], "-") == 0)
4036 operator = SUBTRACT
;
4037 else if (strcmp(mexp
->argv
[0], "*") == 0)
4038 operator = MULTIPLY
;
4039 else if (strcmp(mexp
->argv
[0], "/") == 0)
4041 else if (strcmp(mexp
->argv
[0], "%") == 0 ||
4042 strcmp(mexp
->argv
[0], "m") == 0)
4044 else if (strcmp(mexp
->argv
[0], "==") == 0)
4046 else if (strcmp(mexp
->argv
[0], "!=") == 0)
4047 operator = NOT_EQUAL
;
4048 else if (strcmp(mexp
->argv
[0], ">") == 0)
4049 operator = GREATER_THAN
;
4050 else if (strcmp(mexp
->argv
[0], "<") == 0)
4051 operator = LESS_THAN
;
4052 else if (strcmp(mexp
->argv
[0], ">=") == 0)
4053 operator = GREATER_THAN_EQUAL
;
4054 else if (strcmp(mexp
->argv
[0], "<=") == 0)
4055 operator = LESS_THAN_EQUAL
;
4057 format_log(es
, "expression has no valid operator: '%s'",
4062 /* The second argument may be flags. */
4063 if (argc
>= 2 && strchr(mexp
->argv
[1], 'f') != NULL
) {
4068 /* The third argument may be precision. */
4070 prec
= strtonum(mexp
->argv
[2], INT_MIN
, INT_MAX
, &errstr
);
4071 if (errstr
!= NULL
) {
4072 format_log(es
, "expression precision %s: %s", errstr
,
4078 if (format_choose(es
, copy
, &left
, &right
, 1) != 0) {
4079 format_log(es
, "expression syntax error");
4083 mleft
= strtod(left
, &endch
);
4084 if (*endch
!= '\0') {
4085 format_log(es
, "expression left side is invalid: %s", left
);
4089 mright
= strtod(right
, &endch
);
4090 if (*endch
!= '\0') {
4091 format_log(es
, "expression right side is invalid: %s", right
);
4096 mleft
= (long long)mleft
;
4097 mright
= (long long)mright
;
4099 format_log(es
, "expression left side is: %.*f", prec
, mleft
);
4100 format_log(es
, "expression right side is: %.*f", prec
, mright
);
4104 result
= mleft
+ mright
;
4107 result
= mleft
- mright
;
4110 result
= mleft
* mright
;
4113 result
= mleft
/ mright
;
4116 result
= fmod(mleft
, mright
);
4119 result
= fabs(mleft
- mright
) < 1e-9;
4122 result
= fabs(mleft
- mright
) > 1e-9;
4125 result
= (mleft
> mright
);
4127 case GREATER_THAN_EQUAL
:
4128 result
= (mleft
>= mright
);
4131 result
= (mleft
< mright
);
4133 case LESS_THAN_EQUAL
:
4134 result
= (mleft
<= mright
);
4138 xasprintf(&value
, "%.*f", prec
, result
);
4140 xasprintf(&value
, "%.*f", prec
, (double)(long long)result
);
4141 format_log(es
, "expression result is %s", value
);
4153 /* Replace a key. */
4155 format_replace(struct format_expand_state
*es
, const char *key
, size_t keylen
,
4156 char **buf
, size_t *len
, size_t *off
)
4158 struct format_tree
*ft
= es
->ft
;
4159 struct window_pane
*wp
= ft
->wp
;
4160 const char *errstr
, *copy
, *cp
, *marker
= NULL
;
4161 const char *time_format
= NULL
;
4162 char *copy0
, *condition
, *found
, *new;
4163 char *value
, *left
, *right
;
4165 int modifiers
= 0, limit
= 0, width
= 0;
4167 struct format_modifier
*list
, *cmp
= NULL
, *search
= NULL
;
4168 struct format_modifier
**sub
= NULL
, *mexp
= NULL
, *fm
;
4169 u_int i
, count
, nsub
= 0;
4170 struct format_expand_state next
;
4172 /* Make a copy of the key. */
4173 copy
= copy0
= xstrndup(key
, keylen
);
4175 /* Process modifier list. */
4176 list
= format_build_modifiers(es
, ©
, &count
);
4177 for (i
= 0; i
< count
; i
++) {
4179 if (format_logging(ft
)) {
4180 format_log(es
, "modifier %u is %s", i
, fm
->modifier
);
4181 for (j
= 0; j
< fm
->argc
; j
++) {
4182 format_log(es
, "modifier %u argument %d: %s", i
,
4186 if (fm
->size
== 1) {
4187 switch (fm
->modifier
[0]) {
4199 sub
= xreallocarray(sub
, nsub
+ 1, sizeof *sub
);
4205 limit
= strtonum(fm
->argv
[0], INT_MIN
, INT_MAX
,
4209 if (fm
->argc
>= 2 && fm
->argv
[1] != NULL
)
4210 marker
= fm
->argv
[1];
4215 width
= strtonum(fm
->argv
[0], INT_MIN
, INT_MAX
,
4221 modifiers
|= FORMAT_WIDTH
;
4224 if (fm
->argc
< 1 || fm
->argc
> 3)
4229 modifiers
|= FORMAT_LITERAL
;
4232 modifiers
|= FORMAT_CHARACTER
;
4235 modifiers
|= FORMAT_BASENAME
;
4238 modifiers
|= FORMAT_COLOUR
;
4241 modifiers
|= FORMAT_DIRNAME
;
4244 modifiers
|= FORMAT_LENGTH
;
4247 modifiers
|= FORMAT_TIMESTRING
;
4250 if (strchr(fm
->argv
[0], 'p') != NULL
)
4251 modifiers
|= FORMAT_PRETTY
;
4252 else if (fm
->argc
>= 2 &&
4253 strchr(fm
->argv
[0], 'f') != NULL
)
4254 time_format
= format_strip(fm
->argv
[1]);
4258 modifiers
|= FORMAT_QUOTE_SHELL
;
4259 else if (strchr(fm
->argv
[0], 'e') != NULL
||
4260 strchr(fm
->argv
[0], 'h') != NULL
)
4261 modifiers
|= FORMAT_QUOTE_STYLE
;
4264 modifiers
|= FORMAT_EXPAND
;
4267 modifiers
|= FORMAT_EXPANDTIME
;
4271 strchr(fm
->argv
[0], 'w') != NULL
)
4272 modifiers
|= FORMAT_WINDOW_NAME
;
4273 else if (strchr(fm
->argv
[0], 's') != NULL
)
4274 modifiers
|= FORMAT_SESSION_NAME
;
4277 modifiers
|= FORMAT_SESSIONS
;
4280 modifiers
|= FORMAT_WINDOWS
;
4283 modifiers
|= FORMAT_PANES
;
4286 } else if (fm
->size
== 2) {
4287 if (strcmp(fm
->modifier
, "||") == 0 ||
4288 strcmp(fm
->modifier
, "&&") == 0 ||
4289 strcmp(fm
->modifier
, "==") == 0 ||
4290 strcmp(fm
->modifier
, "!=") == 0 ||
4291 strcmp(fm
->modifier
, ">=") == 0 ||
4292 strcmp(fm
->modifier
, "<=") == 0)
4297 /* Is this a literal string? */
4298 if (modifiers
& FORMAT_LITERAL
) {
4299 value
= xstrdup(copy
);
4303 /* Is this a character? */
4304 if (modifiers
& FORMAT_CHARACTER
) {
4305 new = format_expand1(es
, copy
);
4306 c
= strtonum(new, 32, 126, &errstr
);
4308 value
= xstrdup("");
4310 xasprintf(&value
, "%c", c
);
4315 /* Is this a colour? */
4316 if (modifiers
& FORMAT_COLOUR
) {
4317 new = format_expand1(es
, copy
);
4318 c
= colour_fromstring(new);
4319 if (c
== -1 || (c
= colour_force_rgb(c
)) == -1)
4320 value
= xstrdup("");
4322 xasprintf(&value
, "%06x", c
& 0xffffff);
4327 /* Is this a loop, comparison or condition? */
4328 if (modifiers
& FORMAT_SESSIONS
) {
4329 value
= format_loop_sessions(es
, copy
);
4332 } else if (modifiers
& FORMAT_WINDOWS
) {
4333 value
= format_loop_windows(es
, copy
);
4336 } else if (modifiers
& FORMAT_PANES
) {
4337 value
= format_loop_panes(es
, copy
);
4340 } else if (modifiers
& FORMAT_WINDOW_NAME
) {
4341 value
= format_window_name(es
, copy
);
4344 } else if (modifiers
& FORMAT_SESSION_NAME
) {
4345 value
= format_session_name(es
, copy
);
4348 } else if (search
!= NULL
) {
4349 /* Search in pane. */
4350 new = format_expand1(es
, copy
);
4352 format_log(es
, "search '%s' but no pane", new);
4353 value
= xstrdup("0");
4355 format_log(es
, "search '%s' pane %%%u", new, wp
->id
);
4356 value
= format_search(search
, wp
, new);
4359 } else if (cmp
!= NULL
) {
4360 /* Comparison of left and right. */
4361 if (format_choose(es
, copy
, &left
, &right
, 1) != 0) {
4362 format_log(es
, "compare %s syntax error: %s",
4363 cmp
->modifier
, copy
);
4366 format_log(es
, "compare %s left is: %s", cmp
->modifier
, left
);
4367 format_log(es
, "compare %s right is: %s", cmp
->modifier
, right
);
4369 if (strcmp(cmp
->modifier
, "||") == 0) {
4370 if (format_true(left
) || format_true(right
))
4371 value
= xstrdup("1");
4373 value
= xstrdup("0");
4374 } else if (strcmp(cmp
->modifier
, "&&") == 0) {
4375 if (format_true(left
) && format_true(right
))
4376 value
= xstrdup("1");
4378 value
= xstrdup("0");
4379 } else if (strcmp(cmp
->modifier
, "==") == 0) {
4380 if (strcmp(left
, right
) == 0)
4381 value
= xstrdup("1");
4383 value
= xstrdup("0");
4384 } else if (strcmp(cmp
->modifier
, "!=") == 0) {
4385 if (strcmp(left
, right
) != 0)
4386 value
= xstrdup("1");
4388 value
= xstrdup("0");
4389 } else if (strcmp(cmp
->modifier
, "<") == 0) {
4390 if (strcmp(left
, right
) < 0)
4391 value
= xstrdup("1");
4393 value
= xstrdup("0");
4394 } else if (strcmp(cmp
->modifier
, ">") == 0) {
4395 if (strcmp(left
, right
) > 0)
4396 value
= xstrdup("1");
4398 value
= xstrdup("0");
4399 } else if (strcmp(cmp
->modifier
, "<=") == 0) {
4400 if (strcmp(left
, right
) <= 0)
4401 value
= xstrdup("1");
4403 value
= xstrdup("0");
4404 } else if (strcmp(cmp
->modifier
, ">=") == 0) {
4405 if (strcmp(left
, right
) >= 0)
4406 value
= xstrdup("1");
4408 value
= xstrdup("0");
4409 } else if (strcmp(cmp
->modifier
, "m") == 0)
4410 value
= format_match(cmp
, left
, right
);
4414 } else if (*copy
== '?') {
4415 /* Conditional: check first and choose second or third. */
4416 cp
= format_skip(copy
+ 1, ",");
4418 format_log(es
, "condition syntax error: %s", copy
+ 1);
4421 condition
= xstrndup(copy
+ 1, cp
- (copy
+ 1));
4422 format_log(es
, "condition is: %s", condition
);
4424 found
= format_find(ft
, condition
, modifiers
, time_format
);
4425 if (found
== NULL
) {
4427 * If the condition not found, try to expand it. If
4428 * the expansion doesn't have any effect, then assume
4431 found
= format_expand1(es
, condition
);
4432 if (strcmp(found
, condition
) == 0) {
4434 found
= xstrdup("");
4436 "condition '%s' not found; assuming false",
4440 format_log(es
, "condition '%s' found: %s", condition
,
4444 if (format_choose(es
, cp
+ 1, &left
, &right
, 0) != 0) {
4445 format_log(es
, "condition '%s' syntax error: %s",
4450 if (format_true(found
)) {
4451 format_log(es
, "condition '%s' is true", condition
);
4452 value
= format_expand1(es
, left
);
4454 format_log(es
, "condition '%s' is false", condition
);
4455 value
= format_expand1(es
, right
);
4462 } else if (mexp
!= NULL
) {
4463 value
= format_replace_expression(mexp
, es
, copy
);
4465 value
= xstrdup("");
4467 if (strstr(copy
, "#{") != 0) {
4468 format_log(es
, "expanding inner format '%s'", copy
);
4469 value
= format_expand1(es
, copy
);
4471 value
= format_find(ft
, copy
, modifiers
, time_format
);
4472 if (value
== NULL
) {
4473 format_log(es
, "format '%s' not found", copy
);
4474 value
= xstrdup("");
4476 format_log(es
, "format '%s' found: %s", copy
,
4483 /* Expand again if required. */
4484 if (modifiers
& FORMAT_EXPAND
) {
4485 new = format_expand1(es
, value
);
4488 } else if (modifiers
& FORMAT_EXPANDTIME
) {
4489 format_copy_state(&next
, es
, FORMAT_EXPAND_TIME
);
4490 new = format_expand1(&next
, value
);
4495 /* Perform substitution if any. */
4496 for (i
= 0; i
< nsub
; i
++) {
4497 left
= format_expand1(es
, sub
[i
]->argv
[0]);
4498 right
= format_expand1(es
, sub
[i
]->argv
[1]);
4499 new = format_sub(sub
[i
], value
, left
, right
);
4500 format_log(es
, "substitute '%s' to '%s': %s", left
, right
, new);
4507 /* Truncate the value if needed. */
4509 new = format_trim_left(value
, limit
);
4510 if (marker
!= NULL
&& strcmp(new, value
) != 0) {
4512 xasprintf(&value
, "%s%s", new, marker
);
4517 format_log(es
, "applied length limit %d: %s", limit
, value
);
4518 } else if (limit
< 0) {
4519 new = format_trim_right(value
, -limit
);
4520 if (marker
!= NULL
&& strcmp(new, value
) != 0) {
4522 xasprintf(&value
, "%s%s", marker
, new);
4527 format_log(es
, "applied length limit %d: %s", limit
, value
);
4530 /* Pad the value if needed. */
4532 new = utf8_padcstr(value
, width
);
4535 format_log(es
, "applied padding width %d: %s", width
, value
);
4536 } else if (width
< 0) {
4537 new = utf8_rpadcstr(value
, -width
);
4540 format_log(es
, "applied padding width %d: %s", width
, value
);
4543 /* Replace with the length or width if needed. */
4544 if (modifiers
& FORMAT_LENGTH
) {
4545 xasprintf(&new, "%zu", strlen(value
));
4548 format_log(es
, "replacing with length: %s", new);
4550 if (modifiers
& FORMAT_WIDTH
) {
4551 xasprintf(&new, "%u", format_width(value
));
4554 format_log(es
, "replacing with width: %s", new);
4557 /* Expand the buffer and copy in the value. */
4558 valuelen
= strlen(value
);
4559 while (*len
- *off
< valuelen
+ 1) {
4560 *buf
= xreallocarray(*buf
, 2, *len
);
4563 memcpy(*buf
+ *off
, value
, valuelen
);
4566 format_log(es
, "replaced '%s' with '%s'", copy0
, value
);
4570 format_free_modifiers(list
, count
);
4575 format_log(es
, "failed %s", copy0
);
4578 format_free_modifiers(list
, count
);
4583 /* Expand keys in a template. */
4585 format_expand1(struct format_expand_state
*es
, const char *fmt
)
4587 struct format_tree
*ft
= es
->ft
;
4588 char *buf
, *out
, *name
;
4589 const char *ptr
, *s
;
4590 size_t off
, len
, n
, outlen
;
4592 char expanded
[8192];
4594 if (fmt
== NULL
|| *fmt
== '\0')
4595 return (xstrdup(""));
4597 if (es
->loop
== FORMAT_LOOP_LIMIT
) {
4598 format_log(es
, "reached loop limit (%u)", FORMAT_LOOP_LIMIT
);
4599 return (xstrdup(""));
4603 format_log(es
, "expanding format: %s", fmt
);
4605 if ((es
->flags
& FORMAT_EXPAND_TIME
) && strchr(fmt
, '%') != NULL
) {
4606 if (es
->time
== 0) {
4607 es
->time
= time(NULL
);
4608 localtime_r(&es
->time
, &es
->tm
);
4610 if (strftime(expanded
, sizeof expanded
, fmt
, &es
->tm
) == 0) {
4611 format_log(es
, "format is too long");
4612 return (xstrdup(""));
4614 if (format_logging(ft
) && strcmp(expanded
, fmt
) != 0)
4615 format_log(es
, "after time expanded: %s", expanded
);
4623 while (*fmt
!= '\0') {
4625 while (len
- off
< 2) {
4626 buf
= xreallocarray(buf
, 2, len
);
4629 buf
[off
++] = *fmt
++;
4634 ch
= (u_char
)*fmt
++;
4638 for (ptr
= fmt
; *ptr
!= '\0'; ptr
++) {
4641 if (*ptr
== ')' && --brackets
== 0)
4644 if (*ptr
!= ')' || brackets
!= 0)
4648 name
= xstrndup(fmt
, n
);
4649 format_log(es
, "found #(): %s", name
);
4651 if ((ft
->flags
& FORMAT_NOJOBS
) ||
4652 (es
->flags
& FORMAT_EXPAND_NOJOBS
)) {
4654 format_log(es
, "#() is disabled");
4656 out
= format_job_get(es
, name
);
4657 format_log(es
, "#() result: %s", out
);
4661 outlen
= strlen(out
);
4662 while (len
- off
< outlen
+ 1) {
4663 buf
= xreallocarray(buf
, 2, len
);
4666 memcpy(buf
+ off
, out
, outlen
);
4674 ptr
= format_skip((char *)fmt
- 2, "}");
4679 format_log(es
, "found #{}: %.*s", (int)n
, fmt
);
4680 if (format_replace(es
, fmt
, n
, &buf
, &len
, &off
) != 0)
4686 * If ##[ (with two or more #s), then it is a style and
4687 * can be left for format_draw to handle.
4691 while (*ptr
== '#') {
4696 format_log(es
, "found #*%zu[", n
);
4697 while (len
- off
< n
+ 2) {
4698 buf
= xreallocarray(buf
, 2, len
);
4701 memcpy(buf
+ off
, fmt
- 2, n
+ 1);
4709 format_log(es
, "found #%c", ch
);
4710 while (len
- off
< 2) {
4711 buf
= xreallocarray(buf
, 2, len
);
4718 if (ch
>= 'A' && ch
<= 'Z')
4719 s
= format_upper
[ch
- 'A'];
4720 else if (ch
>= 'a' && ch
<= 'z')
4721 s
= format_lower
[ch
- 'a'];
4723 while (len
- off
< 3) {
4724 buf
= xreallocarray(buf
, 2, len
);
4732 format_log(es
, "found #%c: %s", ch
, s
);
4733 if (format_replace(es
, s
, n
, &buf
, &len
, &off
) != 0)
4742 format_log(es
, "result is: %s", buf
);
4748 /* Expand keys in a template, passing through strftime first. */
4750 format_expand_time(struct format_tree
*ft
, const char *fmt
)
4752 struct format_expand_state es
;
4754 memset(&es
, 0, sizeof es
);
4756 es
.flags
= FORMAT_EXPAND_TIME
;
4757 return (format_expand1(&es
, fmt
));
4760 /* Expand keys in a template. */
4762 format_expand(struct format_tree
*ft
, const char *fmt
)
4764 struct format_expand_state es
;
4766 memset(&es
, 0, sizeof es
);
4769 return (format_expand1(&es
, fmt
));
4772 /* Expand a single string. */
4774 format_single(struct cmdq_item
*item
, const char *fmt
, struct client
*c
,
4775 struct session
*s
, struct winlink
*wl
, struct window_pane
*wp
)
4777 struct format_tree
*ft
;
4780 ft
= format_create_defaults(item
, c
, s
, wl
, wp
);
4781 expanded
= format_expand(ft
, fmt
);
4786 /* Expand a single string using state. */
4788 format_single_from_state(struct cmdq_item
*item
, const char *fmt
,
4789 struct client
*c
, struct cmd_find_state
*fs
)
4791 return (format_single(item
, fmt
, c
, fs
->s
, fs
->wl
, fs
->wp
));
4794 /* Expand a single string using target. */
4796 format_single_from_target(struct cmdq_item
*item
, const char *fmt
)
4798 struct client
*tc
= cmdq_get_target_client(item
);
4800 return (format_single_from_state(item
, fmt
, tc
, cmdq_get_target(item
)));
4803 /* Create and add defaults. */
4804 struct format_tree
*
4805 format_create_defaults(struct cmdq_item
*item
, struct client
*c
,
4806 struct session
*s
, struct winlink
*wl
, struct window_pane
*wp
)
4808 struct format_tree
*ft
;
4811 ft
= format_create(cmdq_get_client(item
), item
, FORMAT_NONE
, 0);
4813 ft
= format_create(NULL
, item
, FORMAT_NONE
, 0);
4814 format_defaults(ft
, c
, s
, wl
, wp
);
4818 /* Create and add defaults using state. */
4819 struct format_tree
*
4820 format_create_from_state(struct cmdq_item
*item
, struct client
*c
,
4821 struct cmd_find_state
*fs
)
4823 return (format_create_defaults(item
, c
, fs
->s
, fs
->wl
, fs
->wp
));
4826 /* Create and add defaults using target. */
4827 struct format_tree
*
4828 format_create_from_target(struct cmdq_item
*item
)
4830 struct client
*tc
= cmdq_get_target_client(item
);
4832 return (format_create_from_state(item
, tc
, cmdq_get_target(item
)));
4835 /* Set defaults for any of arguments that are not NULL. */
4837 format_defaults(struct format_tree
*ft
, struct client
*c
, struct session
*s
,
4838 struct winlink
*wl
, struct window_pane
*wp
)
4840 struct paste_buffer
*pb
;
4842 if (c
!= NULL
&& c
->name
!= NULL
)
4843 log_debug("%s: c=%s", __func__
, c
->name
);
4845 log_debug("%s: c=none", __func__
);
4847 log_debug("%s: s=$%u", __func__
, s
->id
);
4849 log_debug("%s: s=none", __func__
);
4851 log_debug("%s: wl=%u", __func__
, wl
->idx
);
4853 log_debug("%s: wl=none", __func__
);
4855 log_debug("%s: wp=%%%u", __func__
, wp
->id
);
4857 log_debug("%s: wp=none", __func__
);
4859 if (c
!= NULL
&& s
!= NULL
&& c
->session
!= s
)
4860 log_debug("%s: session does not match", __func__
);
4863 ft
->type
= FORMAT_TYPE_PANE
;
4864 else if (wl
!= NULL
)
4865 ft
->type
= FORMAT_TYPE_WINDOW
;
4867 ft
->type
= FORMAT_TYPE_SESSION
;
4869 ft
->type
= FORMAT_TYPE_UNKNOWN
;
4871 if (s
== NULL
&& c
!= NULL
)
4873 if (wl
== NULL
&& s
!= NULL
)
4875 if (wp
== NULL
&& wl
!= NULL
)
4876 wp
= wl
->window
->active
;
4879 format_defaults_client(ft
, c
);
4881 format_defaults_session(ft
, s
);
4883 format_defaults_winlink(ft
, wl
);
4885 format_defaults_pane(ft
, wp
);
4887 pb
= paste_get_top(NULL
);
4889 format_defaults_paste_buffer(ft
, pb
);
4892 /* Set default format keys for a session. */
4894 format_defaults_session(struct format_tree
*ft
, struct session
*s
)
4899 /* Set default format keys for a client. */
4901 format_defaults_client(struct format_tree
*ft
, struct client
*c
)
4908 /* Set default format keys for a window. */
4910 format_defaults_window(struct format_tree
*ft
, struct window
*w
)
4915 /* Set default format keys for a winlink. */
4917 format_defaults_winlink(struct format_tree
*ft
, struct winlink
*wl
)
4920 format_defaults_window(ft
, wl
->window
);
4924 /* Set default format keys for a window pane. */
4926 format_defaults_pane(struct format_tree
*ft
, struct window_pane
*wp
)
4928 struct window_mode_entry
*wme
;
4931 format_defaults_window(ft
, wp
->window
);
4934 wme
= TAILQ_FIRST(&wp
->modes
);
4935 if (wme
!= NULL
&& wme
->mode
->formats
!= NULL
)
4936 wme
->mode
->formats(wme
, ft
);
4939 /* Set default format keys for paste buffer. */
4941 format_defaults_paste_buffer(struct format_tree
*ft
, struct paste_buffer
*pb
)
4946 /* Return word at given coordinates. Caller frees. */
4948 format_grid_word(struct grid
*gd
, u_int x
, u_int y
)
4950 const struct grid_line
*gl
;
4951 struct grid_cell gc
;
4953 struct utf8_data
*ud
= NULL
;
4959 ws
= options_get_string(global_s_options
, "word-separators");
4962 grid_get_cell(gd
, x
, y
, &gc
);
4963 if (gc
.flags
& GRID_FLAG_PADDING
)
4965 if (utf8_cstrhas(ws
, &gc
.data
) ||
4966 (gc
.data
.size
== 1 && *gc
.data
.data
== ' ')) {
4974 gl
= grid_peek_line(gd
, y
- 1);
4975 if (~gl
->flags
& GRID_LINE_WRAPPED
)
4978 x
= grid_line_length(gd
, y
);
4986 end
= grid_line_length(gd
, y
);
4987 if (end
== 0 || x
== end
- 1) {
4988 if (y
== gd
->hsize
+ gd
->sy
- 1)
4990 gl
= grid_peek_line(gd
, y
);
4991 if (~gl
->flags
& GRID_LINE_WRAPPED
)
5000 grid_get_cell(gd
, x
, y
, &gc
);
5001 if (gc
.flags
& GRID_FLAG_PADDING
)
5003 if (utf8_cstrhas(ws
, &gc
.data
) ||
5004 (gc
.data
.size
== 1 && *gc
.data
.data
== ' '))
5007 ud
= xreallocarray(ud
, size
+ 2, sizeof *ud
);
5008 memcpy(&ud
[size
++], &gc
.data
, sizeof *ud
);
5012 s
= utf8_tocstr(ud
);
5018 /* Return line at given coordinates. Caller frees. */
5020 format_grid_line(struct grid
*gd
, u_int y
)
5022 struct grid_cell gc
;
5023 struct utf8_data
*ud
= NULL
;
5028 for (x
= 0; x
< grid_line_length(gd
, y
); x
++) {
5029 grid_get_cell(gd
, x
, y
, &gc
);
5030 if (gc
.flags
& GRID_FLAG_PADDING
)
5033 ud
= xreallocarray(ud
, size
+ 2, sizeof *ud
);
5034 memcpy(&ud
[size
++], &gc
.data
, sizeof *ud
);
5038 s
= utf8_tocstr(ud
);