diff --git a/cmd-list-panes.c b/cmd-list-panes.c index a131053e..723c7039 100644 --- a/cmd-list-panes.c +++ b/cmd-list-panes.c @@ -28,15 +28,16 @@ int cmd_list_panes_exec(struct cmd *, struct cmd_ctx *); -void cmd_list_panes_server(struct cmd_ctx *); -void cmd_list_panes_session(struct session *, struct cmd_ctx *, int); -void cmd_list_panes_window( +void cmd_list_panes_server(struct cmd *, struct cmd_ctx *); +void cmd_list_panes_session( + struct cmd *, struct session *, struct cmd_ctx *, int); +void cmd_list_panes_window(struct cmd *, struct session *, struct winlink *, struct cmd_ctx *, int); const struct cmd_entry cmd_list_panes_entry = { "list-panes", "lsp", - "ast:", 0, 0, - "[-as] [-t target]", + "asF:t:", 0, 0, + "[-as] [-F format] [-t target]", 0, NULL, NULL, @@ -51,87 +52,92 @@ cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx) struct winlink *wl; if (args_has(args, 'a')) - cmd_list_panes_server(ctx); + cmd_list_panes_server(self, ctx); else if (args_has(args, 's')) { s = cmd_find_session(ctx, args_get(args, 't'), 0); if (s == NULL) return (-1); - cmd_list_panes_session(s, ctx, 1); + cmd_list_panes_session(self, s, ctx, 1); } else { wl = cmd_find_window(ctx, args_get(args, 't'), &s); if (wl == NULL) return (-1); - cmd_list_panes_window(s, wl, ctx, 0); + cmd_list_panes_window(self, s, wl, ctx, 0); } return (0); } void -cmd_list_panes_server(struct cmd_ctx *ctx) +cmd_list_panes_server(struct cmd *self, struct cmd_ctx *ctx) { struct session *s; RB_FOREACH(s, sessions, &sessions) - cmd_list_panes_session(s, ctx, 2); + cmd_list_panes_session(self, s, ctx, 2); } void -cmd_list_panes_session(struct session *s, struct cmd_ctx *ctx, int type) +cmd_list_panes_session( + struct cmd *self, struct session *s, struct cmd_ctx *ctx, int type) { struct winlink *wl; RB_FOREACH(wl, winlinks, &s->windows) - cmd_list_panes_window(s, wl, ctx, type); + cmd_list_panes_window(self, s, wl, ctx, type); } void -cmd_list_panes_window( +cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl, struct cmd_ctx *ctx, int type) { + struct args *args = self->args; struct window_pane *wp; - struct grid *gd; - struct grid_line *gl; - u_int i, n; - unsigned long long size; + u_int n; + struct format_tree *ft; + const char *template; + char *line; + + template = args_get(args, 'F'); + if (template == NULL) { + switch (type) { + case 0: + template = "#{line}: " + "[#{pane_width}x#{pane_height}] [history " + "#{history_size}/#{history_limit}, " + "#{history_bytes} bytes] #{pane_id}" + "#{?pane_active, (active),}#{?pane_dead, (dead),}"; + break; + case 1: + template = "#{window_index}.#{line}: " + "[#{pane_width}x#{pane_height}] [history " + "#{history_size}/#{history_limit}, " + "#{history_bytes} bytes] #{pane_id}" + "#{?pane_active, (active),}#{?pane_dead, (dead),}"; + break; + case 2: + template = "#{session_name}:#{window_index}.#{line}: " + "[#{pane_width}x#{pane_height}] [history " + "#{history_size}/#{history_limit}, " + "#{history_bytes} bytes] #{pane_id}" + "#{?pane_active, (active),}#{?pane_dead, (dead),}"; + break; + } + } n = 0; TAILQ_FOREACH(wp, &wl->window->panes, entry) { - gd = wp->base.grid; + ft = format_create(); + format_add(ft, "line", "%u", n); + format_session(ft, s); + format_winlink(ft, s, wl); + format_window_pane(ft, wp); - size = 0; - for (i = 0; i < gd->hsize; i++) { - gl = &gd->linedata[i]; - size += gl->cellsize * sizeof *gl->celldata; - size += gl->utf8size * sizeof *gl->utf8data; - } - size += gd->hsize * sizeof *gd->linedata; + line = format_expand(ft, template); + ctx->print(ctx, "%s", line); + xfree(line); - switch (type) { - case 0: - ctx->print(ctx, - "%u: [%ux%u] [history %u/%u, %llu bytes] %%%u%s%s", - n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size, - wp->id, wp == wp->window->active ? " (active)" : "", - wp->fd == -1 ? " (dead)" : ""); - break; - case 1: - ctx->print(ctx, - "%d.%u: [%ux%u] [history %u/%u, %llu bytes] " - "%%%u%s%s", wl->idx, - n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size, - wp->id, wp == wp->window->active ? " (active)" : "", - wp->fd == -1 ? " (dead)" : ""); - break; - case 2: - ctx->print(ctx, - "%s:%d.%u: [%ux%u] [history %u/%u, %llu bytes] " - "%%%u%s%s", s->name, wl->idx, - n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size, - wp->id, wp == wp->window->active ? " (active)" : "", - wp->fd == -1 ? " (dead)" : ""); - break; - } + format_free(ft); n++; } } diff --git a/cmd-list-sessions.c b/cmd-list-sessions.c index 5791800c..1ddc574d 100644 --- a/cmd-list-sessions.c +++ b/cmd-list-sessions.c @@ -31,40 +31,45 @@ int cmd_list_sessions_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_list_sessions_entry = { "list-sessions", "ls", - "", 0, 0, - "", + "F:", 0, 0, + "[-F format]", 0, NULL, NULL, cmd_list_sessions_exec }; -/* ARGSUSED */ int -cmd_list_sessions_exec(unused struct cmd *self, struct cmd_ctx *ctx) +cmd_list_sessions_exec(struct cmd *self, struct cmd_ctx *ctx) { + struct args *args = self->args; struct session *s; - struct session_group *sg; - char *tim, tmp[64]; - u_int idx; - time_t t; + u_int n; + struct format_tree *ft; + const char *template; + char *line; + template = args_get(args, 'F'); + if (template == NULL) { + template = "#{session_name}: #{session_windows} windows " + "(created #{session_created_string}) [#{session_width}x" + "#{session_height}]#{?session_grouped, (group ,}" + "#{session_group}#{?session_grouped,),}" + "#{?session_attached, (attached),}"; + } + + n = 0; RB_FOREACH(s, sessions, &sessions) { - sg = session_group_find(s); - if (sg == NULL) - *tmp = '\0'; - else { - idx = session_group_index(sg); - xsnprintf(tmp, sizeof tmp, " (group %u)", idx); - } + ft = format_create(); + format_add(ft, "line", "%u", n); + format_session(ft, s); - t = s->creation_time.tv_sec; - tim = ctime(&t); - *strchr(tim, '\n') = '\0'; + line = format_expand(ft, template); + ctx->print(ctx, "%s", line); + xfree(line); - ctx->print(ctx, "%s: %u windows (created %s) [%ux%u]%s%s", - s->name, winlink_count(&s->windows), tim, s->sx, s->sy, - tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)"); + format_free(ft); + n++; } return (0); diff --git a/cmd-list-windows.c b/cmd-list-windows.c index 0bfe94ed..1b34b1c2 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -28,13 +28,14 @@ int cmd_list_windows_exec(struct cmd *, struct cmd_ctx *); -void cmd_list_windows_server(struct cmd_ctx *); -void cmd_list_windows_session(struct session *, struct cmd_ctx *, int); +void cmd_list_windows_server(struct cmd *, struct cmd_ctx *); +void cmd_list_windows_session( + struct cmd *, struct session *, struct cmd_ctx *, int); const struct cmd_entry cmd_list_windows_entry = { "list-windows", "lsw", - "at:", 0, 0, - "[-a] " CMD_TARGET_SESSION_USAGE, + "aF:t:", 0, 0, + "[-a] [-F format] " CMD_TARGET_SESSION_USAGE, 0, NULL, NULL, @@ -48,45 +49,69 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) struct session *s; if (args_has(args, 'a')) - cmd_list_windows_server(ctx); + cmd_list_windows_server(self, ctx); else { s = cmd_find_session(ctx, args_get(args, 't'), 0); if (s == NULL) return (-1); - cmd_list_windows_session(s, ctx, 0); + cmd_list_windows_session(self, s, ctx, 0); } return (0); } void -cmd_list_windows_server(struct cmd_ctx *ctx) +cmd_list_windows_server(struct cmd *self, struct cmd_ctx *ctx) { struct session *s; RB_FOREACH(s, sessions, &sessions) - cmd_list_windows_session(s, ctx, 1); + cmd_list_windows_session(self, s, ctx, 1); } void -cmd_list_windows_session(struct session *s, struct cmd_ctx *ctx, int type) +cmd_list_windows_session( + struct cmd *self, struct session *s, struct cmd_ctx *ctx, int type) { - struct winlink *wl; - char *layout; + struct args *args = self->args; + struct winlink *wl; + u_int n; + struct format_tree *ft; + const char *template; + char *line; - RB_FOREACH(wl, winlinks, &s->windows) { - layout = layout_dump(wl->window); - if (type) { - ctx->print(ctx, "%s:%d: %s [%ux%u] [layout %s]%s", - s->name, wl->idx, wl->window->name, wl->window->sx, - wl->window->sy, layout, - wl == s->curw ? " (active)" : ""); - } else { - ctx->print(ctx, "%d: %s [%ux%u] [layout %s]%s", - wl->idx, wl->window->name, wl->window->sx, - wl->window->sy, layout, - wl == s->curw ? " (active)" : ""); + template = args_get(args, 'F'); + if (template == NULL) { + switch (type) { + case 0: + template = "#{window_index}: " + "#{window_name} " + "[#{window_width}x#{window_height}] " + "[layout #{window_layout}]" + "#{?window_active, (active),}"; + break; + case 1: + template = "#{session_name):#{window_index}: " + "#{window_name} " + "[#{window_width}x#{window_height}] " + "[layout #{window_layout}]" + "#{?window_active, (active),}"; + break; } - xfree(layout); + } + + n = 0; + RB_FOREACH(wl, winlinks, &s->windows) { + ft = format_create(); + format_add(ft, "line", "%u", n); + format_session(ft, s); + format_winlink(ft, s, wl); + + line = format_expand(ft, template); + ctx->print(ctx, "%s", line); + xfree(line); + + format_free(ft); + n++; } } diff --git a/format.c b/format.c new file mode 100644 index 00000000..2924c8c0 --- /dev/null +++ b/format.c @@ -0,0 +1,346 @@ +/* $Id$ */ + +/* + * Copyright (c) 2011 Nicholas Marriott + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include + +#include "tmux.h" + +/* + * Build a list of key-value pairs and use them to expand #{key} entries in a + * string. + */ + +int format_replace(struct format_tree *, + const char *, size_t, char **, size_t *, size_t *); + +/* Format key-value replacement entry. */ +RB_GENERATE(format_tree, format_entry, entry, format_cmp); + +/* Format tree comparison function. */ +int +format_cmp(struct format_entry *fe1, struct format_entry *fe2) +{ + return (strcmp(fe1->key, fe2->key)); +} + +/* Single-character aliases. */ +const char *format_aliases[26] = { + NULL, /* A */ + NULL, /* B */ + NULL, /* C */ + "pane_id", /* D */ + NULL, /* E */ + "window_flags", /* F */ + NULL, /* G */ + "host", /* H */ + "window_index", /* I */ + NULL, /* J */ + NULL, /* K */ + NULL, /* L */ + NULL, /* M */ + NULL, /* N */ + NULL, /* O */ + "pane_index", /* P */ + NULL, /* Q */ + NULL, /* R */ + "session_name", /* S */ + "pane_title", /* T */ + NULL, /* U */ + NULL, /* V */ + "window_name", /* W */ + NULL, /* X */ + NULL, /* Y */ + NULL /* Z */ +}; + +/* Create a new tree. */ +struct format_tree * +format_create(void) +{ + struct format_tree *ft; + char host[MAXHOSTNAMELEN]; + + ft = xmalloc(sizeof *ft); + RB_INIT(ft); + + if (gethostname(host, sizeof host) == 0) + format_add(ft, "host", "%s", host); + + return (ft); +} + +/* Free a tree. */ +void +format_free(struct format_tree *ft) +{ + struct format_entry *fe, *fe_next; + + fe_next = RB_MIN(format_tree, ft); + while (fe_next != NULL) { + fe = fe_next; + fe_next = RB_NEXT(format_tree, ft, fe); + + RB_REMOVE(format_tree, ft, fe); + xfree(fe->value); + xfree(fe->key); + xfree(fe); + } + + xfree (ft); +} + +/* Add a key-value pair. */ +void +format_add(struct format_tree *ft, const char *key, const char *fmt, ...) +{ + struct format_entry *fe; + va_list ap; + + fe = xmalloc(sizeof *fe); + fe->key = xstrdup(key); + + va_start(ap, fmt); + xvasprintf(&fe->value, fmt, ap); + va_end(ap); + + RB_INSERT(format_tree, ft, fe); +} + +/* Find a format entry. */ +const char * +format_find(struct format_tree *ft, const char *key) +{ + struct format_entry *fe, fe_find; + + fe_find.key = (char *) key; + fe = RB_FIND(format_tree, ft, &fe_find); + if (fe == NULL) + return (NULL); + return (fe->value); +} + +/* + * Replace a key/value pair in buffer. #{blah} is expanded directly, + * #{?blah,a,b} is replace with a if blah exists and is nonzero else b. + */ +int +format_replace(struct format_tree *ft, + const char *key, size_t keylen, char **buf, size_t *len, size_t *off) +{ + char *copy, *ptr; + const char *value; + size_t valuelen; + + /* Make a copy of the key. */ + copy = xmalloc(keylen + 1); + memcpy(copy, key, keylen); + copy[keylen] = '\0'; + + /* + * Is this a conditional? If so, check it exists and extract either the + * first or second element. If not, look up the key directly. + */ + if (*copy == '?') { + ptr = strchr(copy, ','); + if (ptr == NULL) + goto fail; + *ptr = '\0'; + + value = format_find(ft, copy + 1); + if (value != NULL && (value[0] != '0' || value[1] != '\0')) { + value = ptr + 1; + ptr = strchr(value, ','); + if (ptr == NULL) + goto fail; + *ptr = '\0'; + } else { + ptr = strchr(ptr + 1, ','); + if (ptr == NULL) + goto fail; + value = ptr + 1; + } + } else { + value = format_find(ft, copy); + if (value == NULL) + value = ""; + } + valuelen = strlen(value); + + /* Expand the buffer and copy in the value. */ + while (*len - *off < valuelen + 1) { + *buf = xrealloc(*buf, 2, *len); + *len *= 2; + } + memcpy(*buf + *off, value, valuelen); + *off += valuelen; + + xfree(copy); + return (0); + +fail: + xfree(copy); + return (-1); +} + +/* Expand keys in a template. */ +char * +format_expand(struct format_tree *ft, const char *fmt) +{ + char *buf, *ptr; + const char *s; + size_t off, len, n; + int ch; + + len = 64; + buf = xmalloc(len); + off = 0; + + while (*fmt != '\0') { + if (*fmt != '#') { + while (len - off < 2) { + buf = xrealloc(buf, 2, len); + len *= 2; + } + buf[off++] = *fmt++; + continue; + } + fmt++; + + ch = (u_char) *fmt++; + switch (ch) { + case '{': + ptr = strchr(fmt, '}'); + if (ptr == NULL) + break; + n = ptr - fmt; + + if (format_replace(ft, fmt, n, &buf, &len, &off) != 0) + break; + fmt += n + 1; + continue; + default: + if (ch >= 'A' && ch <= 'Z') { + s = format_aliases[ch - 'A']; + if (s != NULL) { + n = strlen(s); + if (format_replace ( + ft, s, n, &buf, &len, &off) != 0) + break; + continue; + } + } + while (len - off < 2) { + buf = xrealloc(buf, 2, len); + len *= 2; + } + buf[off++] = ch; + continue; + } + + break; + } + buf[off] = '\0'; + + return (buf); +} + +/* Set default format keys for a session. */ +void +format_session(struct format_tree *ft, struct session *s) +{ + struct session_group *sg; + char *tim; + time_t t; + + format_add(ft, "session_name", "%s", s->name); + format_add(ft, "session_windows", "%u", winlink_count(&s->windows)); + format_add(ft, "session_width", "%u", s->sx); + format_add(ft, "session_height", "%u", s->sy); + + sg = session_group_find(s); + format_add(ft, "session_grouped", "%d", sg != NULL); + if (sg != NULL) + format_add(ft, "session_group", "%u", session_group_index(sg)); + + t = s->creation_time.tv_sec; + format_add(ft, "session_created", "%ld", (long) t); + tim = ctime(&t); + *strchr(tim, '\n') = '\0'; + format_add(ft, "session_created_string", "%s", tim); + + if (s->flags & SESSION_UNATTACHED) + format_add(ft, "session_attached", "%d", 0); + else + format_add(ft, "session_attached", "%d", 1); +} + +/* Set default format keys for a winlink. */ +void +format_winlink(struct format_tree *ft, struct session *s, struct winlink *wl) +{ + struct window *w = wl->window; + char *layout, *flags; + + layout = layout_dump(w); + flags = window_printable_flags(s, wl); + + format_add(ft, "window_index", "%d", wl->idx); + format_add(ft, "window_name", "%s", w->name); + format_add(ft, "window_width", "%u", w->sx); + format_add(ft, "window_height", "%u", w->sy); + format_add(ft, "window_flags", "%s", flags); + format_add(ft, "window_layout", "%s", layout); + format_add(ft, "window_active", "%d", wl == s->curw); + + xfree(flags); + xfree(layout); +} + +/* Set default format keys for a window pane. */ +void +format_window_pane(struct format_tree *ft, struct window_pane *wp) +{ + struct grid *gd = wp->base.grid; + struct grid_line *gl; + unsigned long long size; + u_int i; + + size = 0; + for (i = 0; i < gd->hsize; i++) { + gl = &gd->linedata[i]; + size += gl->cellsize * sizeof *gl->celldata; + size += gl->utf8size * sizeof *gl->utf8data; + } + size += gd->hsize * sizeof *gd->linedata; + + format_add(ft, "pane_width", "%u", wp->sx); + format_add(ft, "pane_height", "%u", wp->sy); + format_add(ft, "pane_title", "%s", wp->base.title); + format_add(ft, "history_size", "%u", gd->hsize); + format_add(ft, "history_limit", "%u", gd->hlimit); + format_add(ft, "history_bytes", "%llu", size); + format_add(ft, "pane_id", "%%%u", wp->id); + format_add(ft, "pane_active", "%d", wp == wp->window->active); + format_add(ft, "pane_dead", "%d", wp->fd == -1); +} diff --git a/tmux.1 b/tmux.1 index 1607621f..9ba3bc24 100644 --- a/tmux.1 +++ b/tmux.1 @@ -14,7 +14,7 @@ .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: August 24 2011 $ +.Dd $Mdocdate: August 26 2011 $ .Dt TMUX 1 .Os .Sh NAME @@ -621,6 +621,7 @@ is specified, list only clients connected to that session. List the syntax of all commands supported by .Nm . .It Ic list-sessions +.Op Fl F Ar format .D1 (alias: Ic ls ) List all sessions managed by the server. .It Ic lock-client Op Fl t Ar target-client @@ -630,6 +631,11 @@ Lock see the .Ic lock-server command. +For the meaning of the +.Fl F +flag, see the +.Sx FORMATS +section. .It Ic lock-session Op Fl t Ar target-session .D1 (alias: Ic locks ) Lock all clients attached to @@ -1151,6 +1157,7 @@ If is given, the newly linked window is not selected. .It Xo Ic list-panes .Op Fl as +.Op Fl F Ar format .Op Fl t Ar target .Xc .D1 (alias: Ic lsp ) @@ -1169,6 +1176,7 @@ If neither is given, is a window (or the current window). .It Xo Ic list-windows .Op Fl a +.Op Fl F Ar format .Op Fl t Ar target-session .Xc .D1 (alias: Ic lsw ) @@ -1177,6 +1185,11 @@ If is given, list all windows on the server. Otherwise, list windows in the current session or in .Ar target-session . +For the meaning of the +.Fl F +flag, see the +.Sx FORMATS +section. .It Xo Ic move-window .Op Fl dk .Op Fl s Ar src-window @@ -2539,6 +2552,70 @@ or the global window options if .Fl g is used. .El +.Sh FORMATS +The +.Ic list-sessions , +.Ic list-windows +and +.Ic list-panes +commands accept the +.Fl F +flag with a +.Ar format +argument. +This is a string which controls the output format of the command. +Special character sequences are replaced as documented under the +.Ic status-left +option and an additional long form is accepted. +Replacement variables are enclosed in +.Ql #{ +and +.Ql } , +for example +.Ql #{session_name} +is equivalent to +.Ql #S . +Conditionals are also accepted by prefixing with +.Ql ? +and separating two alternatives with a comma; +if the specified variable exists and is not zero, the first alternative +is chosen, otherwise the second is used. For example +.Ql #{?session_attached,attached,not attached} +will include the string +.Ql attached +if the session is attached and the string +.Ql not attached +if it is unattached. +.Pp +The following variables are available, where appropriate: +.Bl -column "session_created_string" "Replaced with" -offset indent +.It Sy "Variable name" Ta Sy "Replaced with" +.It Li "host" Ta "Hostname of local host" +.It Li "line" Ta "Line number in the list" +.It Li "pane_active" Ta "1 if active pane" +.It Li "pane_dead" Ta "1 if pane is dead" +.It Li "pane_height" Ta "Height of pane" +.It Li "pane_id" Ta "Unique pane id" +.It Li "pane_title" Ta "Title of pane" +.It Li "pane_width" Ta "Width of pane" +.It Li "session_attached" Ta "1 if session attached" +.It Li "session_created" Ta "Integer time session created" +.It Li "session_created_string" Ta "String time session created" +.It Li "session_group" Ta "Number of session group" +.It Li "session_grouped" Ta "1 if session in a group" +.It Li "session_height" Ta "Height of session" +.It Li "session_name" Ta "Name of session" +.It Li "session_width" Ta "Width of session" +.It Li "session_windows" Ta "Number of windows in session" +.It Li "window_active" Ta "1 if window active" +.It Li "window_flags" Ta "Window flags" +.It Li "window_height" Ta "Height of window" +.It Li "window_index" Ta "Index of window" +.It Li "window_layout" Ta "Window layout description" +.It Li "window_name" Ta "Name of window" +.It Li "window_width" Ta "Width of window" +.El +.Pp .Sh ENVIRONMENT When the server is started, .Nm diff --git a/tmux.h b/tmux.h index 4458813b..74add288 100644 --- a/tmux.h +++ b/tmux.h @@ -1299,6 +1299,15 @@ struct options_table_entry { long long default_num; }; +/* Tree of format entries. */ +struct format_entry { + char *key; + char *value; + + RB_ENTRY(format_entry) entry; +}; +RB_HEAD(format_tree, format_entry); + /* List of configuration causes. */ ARRAY_DECL(causelist, char *); @@ -1341,6 +1350,20 @@ extern struct causelist cfg_causes; void printflike2 cfg_add_cause(struct causelist *, const char *, ...); int load_cfg(const char *, struct cmd_ctx *, struct causelist *); +/* format.c */ +int format_cmp(struct format_entry *, struct format_entry *); +RB_PROTOTYPE(format_tree, format_entry, entry, format_cmp); +struct format_tree *format_create(void); +void format_free(struct format_tree *); +void format_add( + struct format_tree *, const char *, const char *, ...); +const char *format_find(struct format_tree *, const char *); +char *format_expand(struct format_tree *, const char *); +void format_session(struct format_tree *, struct session *); +void format_winlink( + struct format_tree *, struct session *, struct winlink *); +void format_window_pane(struct format_tree *, struct window_pane *); + /* mode-key.c */ extern const struct mode_key_table mode_key_tables[]; extern struct mode_key_tree mode_key_tree_vi_edit;