aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--alerts.c (renamed from server-window.c)167
-rw-r--r--arguments.c6
-rw-r--r--cmd-choose-buffer.c4
-rw-r--r--cmd-paste-buffer.c33
-rw-r--r--cmd-save-buffer.c23
-rw-r--r--cmd-set-buffer.c39
-rw-r--r--cmd-set-option.c6
-rw-r--r--cmd-show-environment.c2
-rw-r--r--cmd-swap-pane.c2
-rw-r--r--format.c352
-rw-r--r--input.c9
-rw-r--r--layout-set.c6
-rw-r--r--log.c9
-rw-r--r--names.c65
-rw-r--r--paste.c63
-rw-r--r--screen.c8
-rw-r--r--server-client.c8
-rw-r--r--server.c3
-rw-r--r--session.c1
-rw-r--r--status.c16
-rw-r--r--tmux.c4
-rw-r--r--tmux.h75
-rw-r--r--window-copy.c32
-rw-r--r--window.c47
-rw-r--r--xterm-keys.c2
26 files changed, 595 insertions, 389 deletions
diff --git a/Makefile.am b/Makefile.am
index 3173ba99..e9a6bd33 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -57,6 +57,7 @@ endif
# List of sources.
dist_tmux_SOURCES = \
+ alerts.c \
arguments.c \
attributes.c \
cfg.c \
@@ -156,7 +157,6 @@ dist_tmux_SOURCES = \
screen.c \
server-client.c \
server-fn.c \
- server-window.c \
server.c \
session.c \
signal.c \
diff --git a/server-window.c b/alerts.c
index c96c2602..cfdd30e3 100644
--- a/server-window.c
+++ b/alerts.c
@@ -1,7 +1,7 @@
/* $OpenBSD$ */
/*
- * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
+ * Copyright (c) 2015 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
@@ -19,42 +19,133 @@
#include <sys/types.h>
#include <event.h>
-#include <stdlib.h>
-#include <unistd.h>
#include "tmux.h"
-int server_window_check_bell(struct session *, struct winlink *);
-int server_window_check_activity(struct session *, struct winlink *);
-int server_window_check_silence(struct session *, struct winlink *);
-void ring_bell(struct session *);
+int alerts_fired;
+
+void alerts_timer(int, short, void *);
+int alerts_enabled(struct window *, int);
+void alerts_callback(int, short, void *);
+void alerts_reset(struct window *);
+
+int alerts_check_bell(struct session *, struct winlink *);
+int alerts_check_activity(struct session *, struct winlink *);
+int alerts_check_silence(struct session *, struct winlink *);
+void alerts_ring_bell(struct session *);
+
+void
+alerts_timer(unused int fd, unused short events, void *arg)
+{
+ struct window *w = arg;
+
+ log_debug("@%u alerts timer expired", w->id);
+ alerts_reset(w);
+ alerts_queue(w, WINDOW_SILENCE);
+}
-/* Window functions that need to happen every loop. */
void
-server_window_loop(void)
+alerts_callback(unused int fd, unused short events, unused void *arg)
{
struct window *w;
struct session *s;
struct winlink *wl;
+ int flags, alerts;
RB_FOREACH(w, windows, &windows) {
RB_FOREACH(s, sessions, &sessions) {
RB_FOREACH(wl, winlinks, &s->windows) {
if (wl->window != w)
continue;
+ flags = w->flags;
- if (server_window_check_bell(s, wl) ||
- server_window_check_activity(s, wl) ||
- server_window_check_silence(s, wl))
+ alerts = alerts_check_bell(s, wl);
+ alerts |= alerts_check_activity(s, wl);
+ alerts |= alerts_check_silence(s, wl);
+ if (alerts != 0)
server_status_session(s);
+
+ log_debug("%s:%d @%u alerts check, alerts %#x, "
+ "flags %#x", s->name, wl->idx, w->id,
+ alerts, flags);
}
}
}
+ alerts_fired = 0;
}
-/* Check for bell in window. */
int
-server_window_check_bell(struct session *s, struct winlink *wl)
+alerts_enabled(struct window *w, int flags)
+{
+ struct session *s;
+
+ if (flags & WINDOW_ACTIVITY) {
+ if (options_get_number(&w->options, "monitor-activity"))
+ return (1);
+ }
+ if (flags & WINDOW_SILENCE) {
+ if (options_get_number(&w->options, "monitor-silence") != 0)
+ return (1);
+ }
+ if (~flags & WINDOW_BELL)
+ return (0);
+ RB_FOREACH(s, sessions, &sessions) {
+ if (!session_has(s, w))
+ continue;
+ if (options_get_number(&s->options, "bell-action") != BELL_NONE)
+ return (1);
+ }
+ return (0);
+}
+
+void
+alerts_reset_all(void)
+{
+ struct window *w;
+
+ RB_FOREACH(w, windows, &windows)
+ alerts_reset(w);
+}
+
+void
+alerts_reset(struct window *w)
+{
+ struct timeval tv;
+
+ w->flags &= ~WINDOW_SILENCE;
+ event_del(&w->alerts_timer);
+
+ timerclear(&tv);
+ tv.tv_sec = options_get_number(&w->options, "monitor-silence");
+
+ log_debug("@%u alerts timer reset %u", w->id, (u_int)tv.tv_sec);
+ if (tv.tv_sec != 0)
+ event_add(&w->alerts_timer, &tv);
+}
+
+void
+alerts_queue(struct window *w, int flags)
+{
+ if (!event_initialized(&w->alerts_timer))
+ evtimer_set(&w->alerts_timer, alerts_timer, w);
+
+ if (w->flags & flags)
+ return;
+ w->flags |= flags;
+ log_debug("@%u alerts flags added %#x", w->id, flags);
+
+ if (!alerts_fired && alerts_enabled(w, flags)) {
+ log_debug("alerts check queued (by @%u)", w->id);
+ event_once(-1, EV_TIMEOUT, alerts_callback, NULL, NULL);
+ alerts_fired = 1;
+ }
+
+ if (flags & WINDOW_ACTIVITY)
+ alerts_reset(w);
+}
+
+int
+alerts_check_bell(struct session *s, struct winlink *wl)
{
struct client *c;
struct window *w = wl->window;
@@ -69,10 +160,11 @@ server_window_check_bell(struct session *s, struct winlink *wl)
if (s->curw->window == w)
w->flags &= ~WINDOW_BELL;
- visual = options_get_number(&s->options, "visual-bell");
action = options_get_number(&s->options, "bell-action");
if (action == BELL_NONE)
return (0);
+
+ visual = options_get_number(&s->options, "visual-bell");
TAILQ_FOREACH(c, &clients, entry) {
if (c->session != s || c->flags & CLIENT_CONTROL)
continue;
@@ -92,12 +184,11 @@ server_window_check_bell(struct session *s, struct winlink *wl)
status_message_set(c, "Bell in window %d", wl->idx);
}
- return (1);
+ return (WINDOW_BELL);
}
-/* Check for activity in window. */
int
-server_window_check_activity(struct session *s, struct winlink *wl)
+alerts_check_activity(struct session *s, struct winlink *wl)
{
struct client *c;
struct window *w = wl->window;
@@ -114,7 +205,7 @@ server_window_check_activity(struct session *s, struct winlink *wl)
return (0);
if (options_get_number(&s->options, "bell-on-alert"))
- ring_bell(s);
+ alerts_ring_bell(s);
wl->flags |= WINLINK_ACTIVITY;
if (options_get_number(&s->options, "visual-activity")) {
@@ -125,45 +216,28 @@ server_window_check_activity(struct session *s, struct winlink *wl)
}
}
- return (1);
+ return (WINDOW_ACTIVITY);
}
-/* Check for silence in window. */
int
-server_window_check_silence(struct session *s, struct winlink *wl)
+alerts_check_silence(struct session *s, struct winlink *wl)
{
struct client *c;
struct window *w = wl->window;
- struct timeval timer;
- int silence_interval, timer_difference;
-
- if (!(w->flags & WINDOW_SILENCE) || wl->flags & WINLINK_SILENCE)
- return (0);
- if (s->curw == wl && !(s->flags & SESSION_UNATTACHED)) {
- /*
- * Reset the timer for this window if we've focused it. We
- * don't want the timer tripping as soon as we've switched away
- * from this window.
- */
- if (gettimeofday(&w->silence_timer, NULL) != 0)
- fatal("gettimeofday failed");
+ if (s->curw->window == w)
+ w->flags &= ~WINDOW_SILENCE;
+ if (!(w->flags & WINDOW_SILENCE) || wl->flags & WINLINK_SILENCE)
return (0);
- }
-
- silence_interval = options_get_number(&w->options, "monitor-silence");
- if (silence_interval == 0)
+ if (s->curw == wl && !(s->flags & SESSION_UNATTACHED))
return (0);
- if (gettimeofday(&timer, NULL) != 0)
- fatal("gettimeofday");
- timer_difference = timer.tv_sec - w->silence_timer.tv_sec;
- if (timer_difference <= silence_interval)
+ if (options_get_number(&w->options, "monitor-silence") == 0)
return (0);
if (options_get_number(&s->options, "bell-on-alert"))
- ring_bell(s);
+ alerts_ring_bell(s);
wl->flags |= WINLINK_SILENCE;
if (options_get_number(&s->options, "visual-silence")) {
@@ -174,12 +248,11 @@ server_window_check_silence(struct session *s, struct winlink *wl)
}
}
- return (1);
+ return (WINDOW_SILENCE);
}
-/* Ring terminal bell. */
void
-ring_bell(struct session *s)
+alerts_ring_bell(struct session *s)
{
struct client *c;
diff --git a/arguments.c b/arguments.c
index ca6cc760..9f080f52 100644
--- a/arguments.c
+++ b/arguments.c
@@ -28,6 +28,12 @@
* Manipulate command arguments.
*/
+struct args_entry {
+ u_char flag;
+ char *value;
+ RB_ENTRY(args_entry) entry;
+};
+
struct args_entry *args_find(struct args *, u_char);
RB_GENERATE(args_tree, args_entry, entry, args_cmp);
diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c
index af178976..b4590306 100644
--- a/cmd-choose-buffer.c
+++ b/cmd-choose-buffer.c
@@ -65,7 +65,7 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR);
utf8flag = options_get_number(&wl->window->options, "utf8");
- if (paste_get_top() == NULL)
+ if (paste_get_top(NULL) == NULL)
return (CMD_RETURN_NORMAL);
if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
@@ -85,7 +85,7 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
cdata->ft_template = xstrdup(template);
format_defaults_paste_buffer(cdata->ft, pb, utf8flag);
- xasprintf(&action_data, "%s", pb->name);
+ xasprintf(&action_data, "%s", paste_buffer_name(pb));
cdata->command = cmd_template_replace(action, action_data, 1);
free(action_data);
diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c
index 5d91aeff..5027a4f8 100644
--- a/cmd-paste-buffer.c
+++ b/cmd-paste-buffer.c
@@ -47,7 +47,9 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
struct window_pane *wp;
struct session *s;
struct paste_buffer *pb;
- const char *sepstr, *bufname;
+ const char *sepstr, *bufname, *bufdata, *bufend, *line;
+ size_t seplen, bufsize;
+ int bracket = args_has(args, 'p');
if (cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp) == NULL)
return (CMD_RETURN_ERROR);
@@ -57,7 +59,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
bufname = args_get(args, 'b');
if (bufname == NULL)
- pb = paste_get_top();
+ pb = paste_get_top(NULL);
else {
pb = paste_get_name(bufname);
if (pb == NULL) {
@@ -66,7 +68,7 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
}
}
- if (pb != NULL) {
+ if (pb != NULL && ~wp->flags & PANE_INPUTOFF) {
sepstr = args_get(args, 's');
if (sepstr == NULL) {
if (args_has(args, 'r'))
@@ -74,10 +76,31 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
else
sepstr = "\r";
}
- paste_send_pane(pb, wp, sepstr, args_has(args, 'p'));
+ seplen = strlen(sepstr);
+
+ if (bracket && (wp->screen->mode & MODE_BRACKETPASTE))
+ bufferevent_write(wp->event, "\033[200~", 6);
+
+ bufdata = paste_buffer_data(pb, &bufsize);
+ bufend = bufdata + bufsize;
+
+ for (;;) {
+ line = memchr(bufdata, '\n', bufend - bufdata);
+ if (line == NULL)
+ break;
+
+ bufferevent_write(wp->event, bufdata, line - bufdata);
+ bufferevent_write(wp->event, sepstr, seplen);
+
+ bufdata = line + 1;
+ }
+ if (bufdata != bufend)
+ bufferevent_write(wp->event, bufdata, bufend - bufdata);
+
+ if (bracket && (wp->screen->mode & MODE_BRACKETPASTE))
+ bufferevent_write(wp->event, "\033[201~", 6);
}
- /* Delete the buffer if -d. */
if (args_has(args, 'd')) {
if (bufname == NULL)
paste_free_top();
diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c
index 86e302ae..1e020934 100644
--- a/cmd-save-buffer.c
+++ b/cmd-save-buffer.c
@@ -56,14 +56,14 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
struct client *c = cmdq->client;
struct session *s;
struct paste_buffer *pb;
- const char *path, *bufname;
- char *start, *end, *msg;
- size_t size, used, msglen;
+ const char *path, *bufname, *bufdata, *start, *end;
+ char *msg;
+ size_t size, used, msglen, bufsize;
int cwd, fd;
FILE *f;
if (!args_has(args, 'b')) {
- if ((pb = paste_get_top()) == NULL) {
+ if ((pb = paste_get_top(NULL)) == NULL) {
cmdq_error(cmdq, "no buffers");
return (CMD_RETURN_ERROR);
}
@@ -75,6 +75,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_ERROR);
}
}
+ bufdata = paste_buffer_data(pb, &bufsize);
if (self->entry == &cmd_show_buffer_entry)
path = "-";
@@ -113,7 +114,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
cmdq_error(cmdq, "%s: %s", path, strerror(errno));
return (CMD_RETURN_ERROR);
}
- if (fwrite(pb->data, 1, pb->size, f) != pb->size) {
+ if (fwrite(bufdata, 1, bufsize, f) != bufsize) {
cmdq_error(cmdq, "%s: fwrite error", path);
fclose(f);
return (CMD_RETURN_ERROR);
@@ -123,25 +124,25 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
return (CMD_RETURN_NORMAL);
do_stdout:
- evbuffer_add(c->stdout_data, pb->data, pb->size);
+ evbuffer_add(c->stdout_data, bufdata, bufsize);
server_push_stdout(c);
return (CMD_RETURN_NORMAL);
do_print:
- if (pb->size > (INT_MAX / 4) - 1) {
+ if (bufsize > (INT_MAX / 4) - 1) {
cmdq_error(cmdq, "buffer too big");
return (CMD_RETURN_ERROR);
}
msg = NULL;
used = 0;
- while (used != pb->size) {
- start = pb->data + used;
- end = memchr(start, '\n', pb->size - used);
+ while (used != bufsize) {
+ start = bufdata + used;
+ end = memchr(start, '\n', bufsize - used);
if (end != NULL)
size = end - start;
else
- size = pb->size - used;
+ size = bufsize - used;
msglen = size * 4 + 1;
msg = xrealloc(msg, msglen);
diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c
index 0ec362b3..4fa7ca11 100644
--- a/cmd-set-buffer.c
+++ b/cmd-set-buffer.c
@@ -42,9 +42,9 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
{
struct args *args = self->args;
struct paste_buffer *pb;
- char *pdata, *cause;
- const char *bufname;
- size_t psize, newsize;
+ char *bufdata, *cause;
+ const char *bufname, *olddata;
+ size_t bufsize, newsize;
bufname = NULL;
@@ -58,12 +58,11 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
bufname = args_get(args, 'b');
if (bufname == NULL) {
- pb = paste_get_top();
+ pb = paste_get_top(&bufname);
if (pb == NULL) {
cmdq_error(cmdq, "no buffer");
return (CMD_RETURN_ERROR);
}
- bufname = pb->name;
}
if (paste_rename(bufname, args_get(args, 'n'), &cause) != 0) {
@@ -79,37 +78,33 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq)
cmdq_error(cmdq, "no data specified");
return (CMD_RETURN_ERROR);
}
-
- psize = 0;
- pdata = NULL;
-
pb = NULL;
+ bufsize = 0;
+ bufdata = NULL;
+
if ((newsize = strlen(args->argv[0])) == 0)
return (CMD_RETURN_NORMAL);
if (args_has(args, 'b')) {
bufname = args_get(args, 'b');
pb = paste_get_name(bufname);
- } else if (args_has(args, 'a')) {
- pb = paste_get_top();
- if (pb != NULL)
- bufname = pb->name;
- }
+ } else if (args_has(args, 'a'))
+ pb = paste_get_top(&bufname);
if (args_has(args, 'a') && pb != NULL) {
- psize = pb->size;
- pdata = xmalloc(psize);
- memcpy(pdata, pb->data, psize);
+ olddata = paste_buffer_data(pb, &bufsize);
+ bufdata = xmalloc(bufsize);
+ memcpy(bufdata, olddata, bufsize);
}
- pdata = xrealloc(pdata, psize + newsize);
- memcpy(pdata + psize, args->argv[0], newsize);
- psize += newsize;
+ bufdata = xrealloc(bufdata, bufsize + newsize);
+ memcpy(bufdata + bufsize, args->argv[0], newsize);
+ bufsize += newsize;
- if (paste_set(pdata, psize, bufname, &cause) != 0) {
+ if (paste_set(bufdata, bufsize, bufname, &cause) != 0) {
cmdq_error(cmdq, "%s", cause);
- free(pdata);
+ free(bufdata);
free(cause);
return (CMD_RETURN_ERROR);
}
diff --git a/cmd-set-option.c b/cmd-set-option.c
index 56ca91e0..98ab2513 100644
--- a/cmd-set-option.c
+++ b/cmd-set-option.c
@@ -180,14 +180,14 @@ cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq)
if (strcmp(oe->name, "automatic-rename") == 0) {
RB_FOREACH(w, windows, &windows) {
if (options_get_number(&w->options, "automatic-rename"))
- queue_window_name(w);
- else if (event_initialized(&w->name_timer))
- evtimer_del(&w->name_timer);
+ w->active->flags |= PANE_CHANGED;
}
}
if (strcmp(oe->name, "status") == 0 ||
strcmp(oe->name, "status-interval") == 0)
status_timer_start_all();
+ if (strcmp(oe->name, "monitor-silence") == 0)
+ alerts_reset_all();
/* Update sizes and redraw. May not need it but meh. */
recalculate_sizes();
diff --git a/cmd-show-environment.c b/cmd-show-environment.c
index a61cf3f4..af24d91b 100644
--- a/cmd-show-environment.c
+++ b/cmd-show-environment.c
@@ -56,7 +56,7 @@ cmd_show_environment_escape(struct environ_entry *envent)
}
*out = '\0';
- return ret;
+ return (ret);
}
void
diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c
index c4751c36..dc2b7246 100644
--- a/cmd-swap-pane.c
+++ b/cmd-swap-pane.c
@@ -58,12 +58,10 @@ cmd_swap_pane_exec(struct cmd *self, struct cmd_q *cmdq)
src_wp = TAILQ_NEXT(dst_wp, entry);
if (src_wp == NULL)
src_wp = TAILQ_FIRST(&dst_w->panes);
- src_wl = dst_wl;
} else if (args_has(self->args, 'U')) {
src_wp = TAILQ_PREV(dst_wp, window_panes, entry);
if (src_wp == NULL)
src_wp = TAILQ_LAST(&dst_w->panes, window_panes);
- src_wl = dst_wl;
} else {
src_wl = cmd_find_pane_marked(cmdq, NULL, NULL,
&src_wp);
diff --git a/format.c b/format.c
index 9cacbd98..5f31fa86 100644
--- a/format.c
+++ b/format.c
@@ -36,14 +36,27 @@
* string.
*/
+struct format_entry;
+typedef void (*format_cb)(struct format_tree *, struct format_entry *);
+
void format_job_callback(struct job *);
const char *format_job_get(struct format_tree *, const char *);
void format_job_timer(int, short, void *);
+void format_cb_host(struct format_tree *, struct format_entry *);
+void format_cb_host_short(struct format_tree *, struct format_entry *);
+void format_cb_pid(struct format_tree *, struct format_entry *);
+void format_cb_session_alerts(struct format_tree *, struct format_entry *);
+void format_cb_window_layout(struct format_tree *, struct format_entry *);
+void format_cb_start_command(struct format_tree *, struct format_entry *);
+void format_cb_current_command(struct format_tree *, struct format_entry *);
+void format_cb_history_bytes(struct format_tree *, struct format_entry *);
+void format_cb_pane_tabs(struct format_tree *, struct format_entry *);
+
+void format_add_cb(struct format_tree *, const char *, format_cb);
int format_replace(struct format_tree *, const char *, size_t, char **,
size_t *, size_t *);
char *format_time_string(time_t);
-char *format_get_command(struct window_pane *);
void format_defaults_pane_tabs(struct format_tree *, struct window_pane *);
void format_defaults_session(struct format_tree *, struct session *);
@@ -80,18 +93,19 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
/* Entry in format tree. */
struct format_entry {
- char *key;
- char *value;
-
- RB_ENTRY(format_entry) entry;
+ char *key;
+ char *value;
+ format_cb cb;
+ RB_ENTRY(format_entry) entry;
};
/* Format entry tree. */
struct format_tree {
- struct window *w;
- struct session *s;
+ struct window *w;
+ struct session *s;
+ struct window_pane *wp;
- int status;
+ int status;
RB_HEAD(format_entry_tree, format_entry) tree;
};
@@ -258,6 +272,170 @@ format_job_timer(unused int fd, unused short events, unused void *arg)
evtimer_add(&format_job_event, &tv);
}
+/* Callback for host. */
+void
+format_cb_host(unused struct format_tree *ft, struct format_entry *fe)
+{
+ char host[HOST_NAME_MAX + 1];
+
+ if (gethostname(host, sizeof host) != 0)
+ fe->value = xstrdup("");
+ else
+ fe->value = xstrdup(host);
+}
+
+/* Callback for host_short. */
+void
+format_cb_host_short(unused struct format_tree *ft, struct format_entry *fe)
+{
+ char host[HOST_NAME_MAX + 1], *cp;
+
+ if (gethostname(host, sizeof host) != 0)
+ fe->value = xstrdup("");
+ else {
+ if ((cp = strchr(host, '.')) != NULL)
+ *cp = '\0';
+ fe->value = xstrdup(host);
+ }
+}
+
+/* Callback for pid. */
+void
+format_cb_pid(unused struct format_tree *ft, struct format_entry *fe)
+{
+ xasprintf(&fe->value, "%ld", (long)getpid());
+}
+
+/* Callback for session_alerts. */
+void
+format_cb_session_alerts(struct format_tree *ft, struct format_entry *fe)
+{
+ struct session *s = ft->s;
+ struct winlink *wl;
+ char alerts[256], tmp[16];
+
+ if (s == NULL)
+ return;
+
+ *alerts = '\0';
+ RB_FOREACH(wl, winlinks, &s->windows) {
+ if ((wl->flags & WINLINK_ALERTFLAGS) == 0)
+ continue;
+ xsnprintf(tmp, sizeof tmp, "%u", wl->idx);
+
+ if (*alerts != '\0')
+ strlcat(alerts, ",", sizeof alerts);
+ strlcat(alerts, tmp, sizeof alerts);
+ if (wl->flags & WINLINK_ACTIVITY)
+ strlcat(alerts, "#", sizeof alerts);
+ if (wl->flags & WINLINK_BELL)
+ strlcat(alerts, "!", sizeof alerts);
+ if (wl->flags & WINLINK_SILENCE)
+ strlcat(alerts, "~", sizeof alerts);
+ }
+ fe->value = xstrdup(alerts);
+}
+
+/* Callback for window_layout. */
+void
+format_cb_window_layout(struct format_tree *ft, struct format_entry *fe)
+{
+ struct window *w = ft->w;
+
+ if (w == NULL)
+ return;
+
+ if (w->saved_layout_root != NULL)
+ fe->value = layout_dump(w->saved_layout_root);
+ else
+ fe->value = layout_dump(w->layout_root);
+}
+
+/* Callback for pane_start_command. */
+void
+format_cb_start_command(struct format_tree *ft, struct format_entry *fe)
+{
+ struct window_pane *wp = ft->wp;
+
+ if (wp == NULL)
+ return;
+
+ fe->value = cmd_stringify_argv(wp->argc, wp->argv);
+}
+
+/* Callback for pane_current_command. */
+void
+format_cb_current_command(struct format_tree *ft, struct format_entry *fe)
+{
+ struct window_pane *wp = ft->wp;
+ char *cmd;
+
+ if (wp == NULL)
+ return;
+
+ cmd = get_proc_name(wp->fd, wp->tty);
+ if (cmd == NULL || *cmd == '\0') {
+ free(cmd);
+ cmd = cmd_stringify_argv(wp->argc, wp->argv);
+ if (cmd == NULL || *cmd == '\0') {
+ free(cmd);
+ cmd = xstrdup(wp->shell);
+ }
+ }
+ fe->value = parse_window_name(cmd);
+ free(cmd);
+}
+
+/* Callback for history_bytes. */
+void
+format_cb_history_bytes(struct format_tree *ft, struct format_entry *fe)
+{
+ struct window_pane *wp = ft->wp;
+ struct grid *gd;
+ struct grid_line *gl;
+ unsigned long long size;
+ u_int i;
+
+ if (wp == NULL)
+ return;
+ gd = wp->base.grid;
+
+ size = 0;
+ for (i = 0; i < gd->hsize; i++) {
+ gl = &gd->linedata[i];
+ size += gl->cellsize * sizeof *gl->celldata;
+ }
+ size += gd->hsize * sizeof *gd->linedata;
+
+ xasprintf(&fe->value, "%llu", size);
+}
+
+/* Callback for pane_tabs. */
+void
+format_cb_pane_tabs(struct format_tree *ft, struct format_entry *fe)
+{
+ struct window_pane *wp = ft->wp;
+ struct evbuffer *buffer;
+ u_int i;
+ int size;
+
+ if (wp == NULL)
+ return;
+
+ buffer = evbuffer_new();
+ for (i = 0; i < wp->base.grid->sx; i++) {
+ if (!bit_test(wp->base.tabs, i))
+ continue;
+
+ if (EVBUFFER_LENGTH(buffer) > 0)
+ evbuffer_add(buffer, ",", 1);
+ evbuffer_add_printf(buffer, "%u", i);
+ }
+ size = EVBUFFER_LENGTH(buffer);
+ xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer));
+ evbuffer_free(buffer);
+}
+
/* Create a new tree. */
struct format_tree *
format_create(void)
@@ -270,7 +448,6 @@ struct format_tree *
format_create_status(int status)
{
struct format_tree *ft;
- char host[HOST_NAME_MAX + 1], *ptr;
if (!event_initialized(&format_job_event)) {
evtimer_set(&format_job_event, format_job_timer, NULL);
@@ -281,13 +458,9 @@ format_create_status(int status)
RB_INIT(&ft->tree);
ft->status = status;
- if (gethostname(host, sizeof host) == 0) {
- format_add(ft, "host", "%s", host);
- if ((ptr = strchr(host, '.')) != NULL)
- *ptr = '\0';
- format_add(ft, "host_short", "%s", host);
- }
- format_add(ft, "pid", "%ld", (long) getpid());
+ format_add_cb(ft, "host", format_cb_host);
+ format_add_cb(ft, "host_short", format_cb_host_short);
+ format_add_cb(ft, "pid", format_cb_pid);
return (ft);
}
@@ -319,17 +492,42 @@ format_add(struct format_tree *ft, const char *key, const char *fmt, ...)
fe = xmalloc(sizeof *fe);
fe->key = xstrdup(key);
+ fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe);
+ if (fe_now != NULL) {
+ free(fe->key);
+ free(fe);
+ free(fe_now->value);
+ fe = fe_now;
+ }
+
+ fe->cb = NULL;
+
va_start(ap, fmt);
xvasprintf(&fe->value, fmt, ap);
va_end(ap);
+}
+
+/* Add a key and function. */
+void
+format_add_cb(struct format_tree *ft, const char *key, format_cb cb)
+{
+ struct format_entry *fe;
+ struct format_entry *fe_now;
+
+ fe = xmalloc(sizeof *fe);
+ fe->key = xstrdup(key);
fe_now = RB_INSERT(format_entry_tree, &ft->tree, fe);
if (fe_now != NULL) {
- free(fe_now->value);
- fe_now->value = fe->value;
free(fe->key);
free(fe);
+ free(fe_now->value);
+ fe = fe_now;
}
+
+ fe->cb = cb;
+
+ fe->value = NULL;
}
/* Find a format entry. */
@@ -364,8 +562,11 @@ format_find(struct format_tree *ft, const char *key)
fe_find.key = (char *) key;
fe = RB_FIND(format_entry_tree, &ft->tree, &fe_find);
- if (fe != NULL)
+ if (fe != NULL) {
+ if (fe->value == NULL && fe->cb != NULL)
+ fe->cb(ft, fe);
return (fe->value);
+ }
envent = NULL;
if (ft->s != NULL)
@@ -507,7 +708,7 @@ char *
format_expand(struct format_tree *ft, const char *fmt)
{
char *buf, *tmp, *cmd;
- const char *ptr, *s;
+ const char *ptr, *s, *saved = fmt;
size_t off, len, n, slen;
int ch, brackets;
@@ -611,29 +812,10 @@ format_expand(struct format_tree *ft, const char *fmt)
}
buf[off] = '\0';
+ log_debug("format '%s' -> '%s'", saved, buf);
return (buf);
}
-/* Get command name for format. */
-char *
-format_get_command(struct window_pane *wp)
-{
- char *cmd, *out;
-
- cmd = osdep_get_name(wp->fd, wp->tty);
- if (cmd == NULL || *cmd == '\0') {
- free(cmd);
- cmd = cmd_stringify_argv(wp->argc, wp->argv);
- if (cmd == NULL || *cmd == '\0') {
- free(cmd);
- cmd = xstrdup(wp->shell);
- }
- }
- out = parse_window_name(cmd);
- free(cmd);
- return (out);
-}
-
/* Get time as a string. */
char *
format_time_string(time_t t)
@@ -674,8 +856,6 @@ format_defaults_session(struct format_tree *ft, struct session *s)
{
struct session_group *sg;
time_t t;
- struct winlink *wl;
- char alerts[256], tmp[16];
ft->s = s;
@@ -701,23 +881,7 @@ format_defaults_session(struct format_tree *ft, struct session *s)
format_add(ft, "session_attached", "%u", s->attached);
format_add(ft, "session_many_attached", "%d", s->attached > 1);
- *alerts = '\0';
- RB_FOREACH (wl, winlinks, &s->windows) {
- if ((wl->flags & WINLINK_ALERTFLAGS) == 0)
- continue;
- xsnprintf(tmp, sizeof tmp, "%u", wl->idx);
-
- if (*alerts != '\0')
- strlcat(alerts, ",", sizeof alerts);
- strlcat(alerts, tmp, sizeof alerts);
- if (wl->flags & WINLINK_ACTIVITY)
- strlcat(alerts, "#", sizeof alerts);
- if (wl->flags & WINLINK_BELL)
- strlcat(alerts, "!", sizeof alerts);
- if (wl->flags & WINLINK_SILENCE)
- strlcat(alerts, "~", sizeof alerts);
- }
- format_add(ft, "session_alerts", "%s", alerts);
+ format_add_cb(ft, "session_alerts", format_cb_session_alerts);
}
/* Set default format keys for a client. */
@@ -776,16 +940,10 @@ format_defaults_client(struct format_tree *ft, struct client *c)
void
format_defaults_window(struct format_tree *ft, struct window *w)
{
- char *layout;
time_t t;
ft->w = w;
- if (w->saved_layout_root != NULL)
- layout = layout_dump(w->saved_layout_root);
- else