On Mon, Feb 21, 2011 at 07:25:32PM -0800, Felix Rosencrantz wrote: > > What would be really nice would be a way to represent their output in a > > general internal form that could be output nicely, eg we translate a > > window into a list of key,value pairs such as: > > > > [index=7, name=abc, width=159, height=48, layout=3fdf,159x48,0,0] > That would work for me.
Please try this against CVS HEAD. - Only lsp, lsw, ls at the moment. - Only stuff that was already there so eg no pane_title yet. - Use -F to specify an alternate format. For example: $ ./tmux lsw -F '#{window_index},#{window_name},#{window_active}' 0,ksh,1 1,ksh,0 2,ksh,0 - Ultimately will want similar for choose-*, lsb and so on. Also would be nice to use this for status-*, display but that'll need some twiddling for backwards compatibility. Index: Makefile.am =================================================================== RCS file: /cvsroot/tmux/tmux/Makefile.am,v retrieving revision 1.10 diff -u -p -r1.10 Makefile.am --- Makefile.am 14 Feb 2011 20:39:40 -0000 1.10 +++ Makefile.am 28 Mar 2011 22:43:20 -0000 @@ -140,6 +140,7 @@ dist_tmux_SOURCES = \ cmd.c \ colour.c \ environ.c \ + format.c \ grid-utf8.c \ grid-view.c \ grid.c \ Index: cmd-list-panes.c =================================================================== RCS file: /cvsroot/tmux/tmux/cmd-list-panes.c,v retrieving revision 1.7 diff -u -p -r1.7 cmd-list-panes.c --- cmd-list-panes.c 7 Jan 2011 14:45:34 -0000 1.7 +++ cmd-list-panes.c 28 Mar 2011 22:43:20 -0000 @@ -30,8 +30,8 @@ int cmd_list_panes_exec(struct cmd *, st const struct cmd_entry cmd_list_panes_entry = { "list-panes", "lsp", - "t:", 0, 0, - CMD_TARGET_WINDOW_USAGE, + "F:t:", 0, 0, + "[-F format] " CMD_TARGET_WINDOW_USAGE, 0, NULL, NULL, @@ -44,30 +44,35 @@ cmd_list_panes_exec(struct cmd *self, st struct args *args = self->args; struct winlink *wl; struct window_pane *wp; - struct grid *gd; - struct grid_line *gl; - u_int i, n; - unsigned long long size; + struct session *s; + u_int n; + struct format_tree *ft; + const char *template; + char *line; - if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) + if ((wl = cmd_find_window(ctx, args_get(args, 't'), &s)) == NULL) return (-1); + template = args_get(args, 'F'); + if (template == NULL) { + template = "#{line}: [#{pane_width}x#{pane_height}] [history " + "#{history_size}/#{history_limit}, #{history_bytes} bytes]" + "#{?pane_active, (active),}#{?pane_dead, (dead),}"; + } + 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); + + line = format_expand(ft, template); + ctx->print(ctx, "%s", line); + xfree(line); - 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; - - ctx->print(ctx, "%u: [%ux%u] [history %u/%u, %llu bytes]%s%s", - n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size, - wp == wp->window->active ? " (active)" : "", - wp->fd == -1 ? " (dead)" : ""); + format_free(ft); n++; } Index: cmd-list-sessions.c =================================================================== RCS file: /cvsroot/tmux/tmux/cmd-list-sessions.c,v retrieving revision 1.27 diff -u -p -r1.27 cmd-list-sessions.c --- cmd-list-sessions.c 7 Jan 2011 14:45:34 -0000 1.27 +++ cmd-list-sessions.c 28 Mar 2011 22:43:20 -0000 @@ -31,40 +31,45 @@ int cmd_list_sessions_exec(struct cmd *, 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); - } - - t = s->creation_time.tv_sec; - tim = ctime(&t); - *strchr(tim, '\n') = '\0'; - - 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)"); + ft = format_create(); + format_add(ft, "line", "%u", n); + format_session(ft, s); + + line = format_expand(ft, template); + ctx->print(ctx, "%s", line); + xfree(line); + + format_free(ft); + n++; } return (0); Index: cmd-list-windows.c =================================================================== RCS file: /cvsroot/tmux/tmux/cmd-list-windows.c,v retrieving revision 1.45 diff -u -p -r1.45 cmd-list-windows.c --- cmd-list-windows.c 7 Jan 2011 14:45:34 -0000 1.45 +++ cmd-list-windows.c 28 Mar 2011 22:43:20 -0000 @@ -30,8 +30,8 @@ int cmd_list_windows_exec(struct cmd *, const struct cmd_entry cmd_list_windows_entry = { "list-windows", "lsw", - "t:", 0, 0, - CMD_TARGET_SESSION_USAGE, + "F:t:", 0, 0, + "[-F format] " CMD_TARGET_SESSION_USAGE, 0, NULL, NULL, @@ -41,20 +41,37 @@ const struct cmd_entry cmd_list_windows_ int cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) { - struct args *args = self->args; - struct session *s; - struct winlink *wl; - char *layout; + struct args *args = self->args; + struct session *s; + struct winlink *wl; + u_int n; + struct format_tree *ft; + const char *template; + char *line; if ((s = cmd_find_session(ctx, args_get(args, 't'))) == NULL) return (-1); + template = args_get(args, 'F'); + if (template == NULL) { + template = "#{window_index}: #{window_name} " + "[#{window_width}x#{window_height}] " + "[layout #{window_layout}]#{?window_active, (active),}"; + } + + n = 0; RB_FOREACH(wl, winlinks, &s->windows) { - layout = layout_dump(wl->window); - 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)" : ""); - xfree(layout); + 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++; } return (0); Index: format.c =================================================================== RCS file: format.c diff -N format.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ format.c 28 Mar 2011 22:43:21 -0000 @@ -0,0 +1,277 @@ +/* $Id: tmux.h,v 1.612 2011/03/19 23:30:37 tcunha Exp $ */ + +/* + * Copyright (c) 2011 Nicholas Marriott <n...@users.sourceforge.net> + * + * 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 <sys/types.h> + +#include <stdarg.h> +#include <string.h> + +#include "tmux.h" + +/* + * Code to 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 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)); +} + +/* Create a new tree. */ +struct format_tree * +format_create(void) +{ + struct format_tree *ft; + + ft = xmalloc(sizeof *ft); + RB_INIT(ft); + + 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); + } +} + +/* 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 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; + size_t off, len, n; + + len = 64; + buf = xmalloc(len); + off = 0; + + while (*fmt != '\0') { + if (fmt[0] == '#' && fmt[1] == '{') { + fmt += 2; + + 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; + } + + while (len - off < 2) { + buf = xrealloc(buf, 2, len); + len *= 2; + } + buf[off++] = *fmt++; + } + 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; + + layout = layout_dump(w); + + 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_layout", "%s", layout); + format_add(ft, "window_active", "%d", wl == s->curw); + + 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, "history_size", "%u", gd->hsize); + format_add(ft, "history_limit", "%u", gd->hlimit); + format_add(ft, "history_bytes", "%llu", size); + format_add(ft, "pane_active", "%d", wp == wp->window->active); + format_add(ft, "pane_dead", "%d", wp->fd == -1); +} Index: tmux.h =================================================================== RCS file: /cvsroot/tmux/tmux/tmux.h,v retrieving revision 1.612 diff -u -p -r1.612 tmux.h --- tmux.h 19 Mar 2011 23:30:37 -0000 1.612 +++ tmux.h 28 Mar 2011 22:43:21 -0000 @@ -1273,6 +1273,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 *); @@ -1315,6 +1324,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; ------------------------------------------------------------------------------ Create and publish websites with WebMatrix Use the most popular FREE web apps or write code yourself; WebMatrix provides all the features you need to develop and publish your website. http://p.sf.net/sfu/ms-webmatrix-sf _______________________________________________ tmux-users mailing list tmux-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tmux-users