mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 00:56:10 +00:00 
			
		
		
		
	Sync OpenBSD patchset 953:
Add initial framework for more powerful formatting of command output and
use it for list-{panes,windows,sessions}. This allows more descriptive
replacements (such as #{session_name}) and conditionals.
Later this will be used for status_replace and list-keys and other
places.
			
			
This commit is contained in:
		
							
								
								
									
										106
									
								
								cmd-list-panes.c
									
									
									
									
									
								
							
							
						
						
									
										106
									
								
								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++;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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++;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										346
									
								
								format.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										346
									
								
								format.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,346 @@
 | 
			
		||||
/* $Id$ */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2011 Nicholas Marriott <nicm@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 <netdb.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										79
									
								
								tmux.1
									
									
									
									
									
								
							
							
						
						
									
										79
									
								
								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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										23
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								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;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user