Extend the modifiers allowed before formats: as well as the existing

#{=10:...}  length limit, add #{t:...} to convert a time_t format to a
string, #{b:...} for basename and #{d:...} for dirname. Remove all the
foo_string time formats as they can now be replaced by "t:", for example
#{window_activity_string} becomes #{t:window_activity}.
This commit is contained in:
nicm 2015-10-25 22:29:17 +00:00
parent 3faa51a0ca
commit e65306d8e7
5 changed files with 168 additions and 106 deletions

View File

@ -31,7 +31,7 @@
"#{client_tty}: #{session_name} " \ "#{client_tty}: #{session_name} " \
"[#{client_width}x#{client_height} #{client_termname}]" \ "[#{client_width}x#{client_height} #{client_termname}]" \
"#{?client_utf8, (utf8),}#{?client_readonly, (ro),} " \ "#{?client_utf8, (utf8),}#{?client_readonly, (ro),} " \
"(last used #{client_activity_string})" "(last used #{t:client_activity})"
enum cmd_retval cmd_choose_client_exec(struct cmd *, struct cmd_q *); enum cmd_retval cmd_choose_client_exec(struct cmd *, struct cmd_q *);

View File

@ -30,7 +30,7 @@
#define LIST_SESSIONS_TEMPLATE \ #define LIST_SESSIONS_TEMPLATE \
"#{session_name}: #{session_windows} windows " \ "#{session_name}: #{session_windows} windows " \
"(created #{session_created_string}) " \ "(created #{t:session_created}) " \
"[#{session_width}x#{session_height}]" \ "[#{session_width}x#{session_height}]" \
"#{?session_grouped, (group ,}" \ "#{?session_grouped, (group ,}" \
"#{session_group}#{?session_grouped,),}" \ "#{session_group}#{?session_grouped,),}" \

243
format.c
View File

@ -21,6 +21,7 @@
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <libgen.h>
#include <netdb.h> #include <netdb.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
@ -52,7 +53,9 @@ 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_history_bytes(struct format_tree *, struct format_entry *);
void format_cb_pane_tabs(struct format_tree *, struct format_entry *); void format_cb_pane_tabs(struct format_tree *, struct format_entry *);
char *format_find(struct format_tree *, const char *, int);
void format_add_cb(struct format_tree *, const char *, format_cb); void format_add_cb(struct format_tree *, const char *, format_cb);
void format_add_tv(struct format_tree *, const char *, struct timeval *);
int format_replace(struct format_tree *, const char *, size_t, char **, int format_replace(struct format_tree *, const char *, size_t, char **,
size_t *, size_t *); size_t *, size_t *);
char *format_time_string(time_t); char *format_time_string(time_t);
@ -90,10 +93,16 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
return (strcmp(fj1->cmd, fj2->cmd)); return (strcmp(fj1->cmd, fj2->cmd));
} }
/* Format modifiers. */
#define FORMAT_TIMESTRING 0x1
#define FORMAT_BASENAME 0x2
#define FORMAT_DIRNAME 0x4
/* Entry in format tree. */ /* Entry in format tree. */
struct format_entry { struct format_entry {
char *key; char *key;
char *value; char *value;
time_t t;
format_cb cb; format_cb cb;
RB_ENTRY(format_entry) entry; RB_ENTRY(format_entry) entry;
}; };
@ -503,12 +512,37 @@ format_add(struct format_tree *ft, const char *key, const char *fmt, ...)
} }
fe->cb = NULL; fe->cb = NULL;
fe->t = 0;
va_start(ap, fmt); va_start(ap, fmt);
xvasprintf(&fe->value, fmt, ap); xvasprintf(&fe->value, fmt, ap);
va_end(ap); va_end(ap);
} }
/* Add a key and time. */
void
format_add_tv(struct format_tree *ft, const char *key, struct timeval *tv)
{
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->key);
free(fe);
free(fe_now->value);
fe = fe_now;
}
fe->cb = NULL;
fe->t = tv->tv_sec;
fe->value = NULL;
}
/* Add a key and function. */ /* Add a key and function. */
void void
format_add_cb(struct format_tree *ft, const char *key, format_cb cb) format_add_cb(struct format_tree *ft, const char *key, format_cb cb)
@ -528,57 +562,99 @@ format_add_cb(struct format_tree *ft, const char *key, format_cb cb)
} }
fe->cb = cb; fe->cb = cb;
fe->t = 0;
fe->value = NULL; fe->value = NULL;
} }
/* Find a format entry. */ /* Find a format entry. */
const char * char *
format_find(struct format_tree *ft, const char *key) format_find(struct format_tree *ft, const char *key, int modifiers)
{ {
struct format_entry *fe, fe_find; struct format_entry *fe, fe_find;
struct options_entry *o; struct options_entry *o;
struct environ_entry *envent; struct environ_entry *envent;
static char s[16]; static char s[64];
const char *found;
char *copy, *saved;
o = options_find(&global_options, key); found = NULL;
if (o == NULL && ft->w != NULL)
o = options_find(&ft->w->options, key); if (~modifiers & FORMAT_TIMESTRING) {
if (o == NULL) o = options_find(&global_options, key);
o = options_find(&global_w_options, key); if (o == NULL && ft->w != NULL)
if (o == NULL && ft->s != NULL) o = options_find(&ft->w->options, key);
o = options_find(&ft->s->options, key); if (o == NULL)
if (o == NULL) o = options_find(&global_w_options, key);
o = options_find(&global_s_options, key); if (o == NULL && ft->s != NULL)
if (o != NULL) { o = options_find(&ft->s->options, key);
switch (o->type) { if (o == NULL)
case OPTIONS_STRING: o = options_find(&global_s_options, key);
return (o->str); if (o != NULL) {
case OPTIONS_NUMBER: switch (o->type) {
xsnprintf(s, sizeof s, "%lld", o->num); case OPTIONS_STRING:
return (s); found = o->str;
case OPTIONS_STYLE: goto found;
return (style_tostring(&o->style)); case OPTIONS_NUMBER:
xsnprintf(s, sizeof s, "%lld", o->num);
found = s;
goto found;
case OPTIONS_STYLE:
found = style_tostring(&o->style);
goto found;
}
} }
} }
fe_find.key = (char *) key; fe_find.key = (char *) key;
fe = RB_FIND(format_entry_tree, &ft->tree, &fe_find); fe = RB_FIND(format_entry_tree, &ft->tree, &fe_find);
if (fe != NULL) { if (fe != NULL) {
if (modifiers & FORMAT_TIMESTRING) {
if (fe->t == 0)
return (NULL);
ctime_r(&fe->t, s);
s[strcspn(s, "\n")] = '\0';
found = s;
goto found;
}
if (fe->t != 0) {
xsnprintf(s, sizeof s, "%lld", (long long)fe->t);
found = s;
goto found;
}
if (fe->value == NULL && fe->cb != NULL) if (fe->value == NULL && fe->cb != NULL)
fe->cb(ft, fe); fe->cb(ft, fe);
return (fe->value); found = fe->value;
goto found;
} }
envent = NULL; if (~modifiers & FORMAT_TIMESTRING) {
if (ft->s != NULL) envent = NULL;
envent = environ_find(&ft->s->environ, key); if (ft->s != NULL)
if (envent == NULL) envent = environ_find(&ft->s->environ, key);
envent = environ_find(&global_environ, key); if (envent == NULL)
if (envent != NULL) envent = environ_find(&global_environ, key);
return (envent->value); if (envent != NULL) {
found = envent->value;
goto found;
}
}
return (NULL); return (NULL);
found:
copy = xstrdup(found);
if (modifiers & FORMAT_BASENAME) {
saved = copy;
copy = xstrdup(basename(saved));
free(saved);
}
if (modifiers & FORMAT_DIRNAME) {
saved = copy;
copy = xstrdup(dirname(saved));
free(saved);
}
return (copy);
} }
/* /*
@ -589,10 +665,10 @@ int
format_replace(struct format_tree *ft, const char *key, size_t keylen, format_replace(struct format_tree *ft, const char *key, size_t keylen,
char **buf, size_t *len, size_t *off) char **buf, size_t *len, size_t *off)
{ {
char *copy, *copy0, *endptr, *ptr, *saved, *trimmed; char *copy, *copy0, *endptr, *ptr, *saved, *trimmed, *value;
const char *value;
size_t valuelen; size_t valuelen;
u_long limit = 0; u_long limit = 0;
int modifiers = 0;
/* Make a copy of the key. */ /* Make a copy of the key. */
copy0 = copy = xmalloc(keylen + 1); copy0 = copy = xmalloc(keylen + 1);
@ -600,24 +676,34 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
copy[keylen] = '\0'; copy[keylen] = '\0';
/* Is there a length limit or whatnot? */ /* Is there a length limit or whatnot? */
if (!isalpha((u_char) *copy) && *copy != '@' && *copy != '?') { switch (copy[0]) {
while (*copy != ':' && *copy != '\0') { case '=':
switch (*copy) { errno = 0;
case '=': limit = strtoul(copy + 1, &endptr, 10);
errno = 0; if (errno == ERANGE && limit == ULONG_MAX)
limit = strtoul(copy + 1, &endptr, 10); break;
if (errno == ERANGE && limit == ULONG_MAX) if (*endptr != ':')
goto fail; break;
copy = endptr; copy = endptr + 1;
break; break;
default: case 'b':
copy++; if (copy[1] != ':')
break; break;
} modifiers |= FORMAT_BASENAME;
} copy += 2;
if (*copy != ':') break;
goto fail; case 'd':
copy++; if (copy[1] != ':')
break;
modifiers |= FORMAT_DIRNAME;
copy += 2;
break;
case 't':
if (copy[1] != ':')
break;
modifiers |= FORMAT_TIMESTRING;
copy += 2;
break;
} }
/* /*
@ -630,7 +716,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
goto fail; goto fail;
*ptr = '\0'; *ptr = '\0';
value = format_find(ft, copy + 1); value = saved = format_find(ft, copy + 1, modifiers);
if (value != NULL && *value != '\0' && if (value != NULL && *value != '\0' &&
(value[0] != '0' || value[1] != '\0')) { (value[0] != '0' || value[1] != '\0')) {
value = ptr + 1; value = ptr + 1;
@ -644,13 +730,13 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
goto fail; goto fail;
value = ptr + 1; value = ptr + 1;
} }
saved = format_expand(ft, value); value = format_expand(ft, value);
value = saved; free(saved);
saved = value;
} else { } else {
value = format_find(ft, copy); saved = value = format_find(ft, copy, modifiers);
if (value == NULL) if (value == NULL)
value = ""; saved = value = xstrdup("");
saved = NULL;
} }
/* Truncate the value if needed. */ /* Truncate the value if needed. */
@ -820,18 +906,6 @@ format_expand(struct format_tree *ft, const char *fmt)
return (buf); return (buf);
} }
/* Get time as a string. */
char *
format_time_string(time_t t)
{
char *tim;
tim = ctime(&t);
*strchr(tim, '\n') = '\0';
return (tim);
}
/* Set defaults for any of arguments that are not NULL. */ /* Set defaults for any of arguments that are not NULL. */
void void
format_defaults(struct format_tree *ft, struct client *c, struct session *s, format_defaults(struct format_tree *ft, struct client *c, struct session *s,
@ -859,7 +933,6 @@ void
format_defaults_session(struct format_tree *ft, struct session *s) format_defaults_session(struct format_tree *ft, struct session *s)
{ {
struct session_group *sg; struct session_group *sg;
time_t t;
ft->s = s; ft->s = s;
@ -874,20 +947,9 @@ format_defaults_session(struct format_tree *ft, struct session *s)
if (sg != NULL) if (sg != NULL)
format_add(ft, "session_group", "%u", session_group_index(sg)); format_add(ft, "session_group", "%u", session_group_index(sg));
t = s->creation_time.tv_sec; format_add_tv(ft, "session_created", &s->creation_time);
format_add(ft, "session_created", "%lld", (long long) t); format_add_tv(ft, "session_last_attached", &s->last_attached_time);
format_add(ft, "session_created_string", "%s", format_time_string(t)); format_add_tv(ft, "session_activity", &s->activity_time);
t = s->last_attached_time.tv_sec;
if (t != 0) { /* zero if never attached */
format_add(ft, "session_last_attached", "%lld", (long long) t);
format_add(ft, "session_last_attached_string", "%s",
format_time_string(t));
}
t = s->activity_time.tv_sec;
format_add(ft, "session_activity", "%lld", (long long) t);
format_add(ft, "session_activity_string", "%s", format_time_string(t));
format_add(ft, "session_attached", "%u", s->attached); format_add(ft, "session_attached", "%u", s->attached);
format_add(ft, "session_many_attached", "%d", s->attached > 1); format_add(ft, "session_many_attached", "%d", s->attached > 1);
@ -900,7 +962,6 @@ void
format_defaults_client(struct format_tree *ft, struct client *c) format_defaults_client(struct format_tree *ft, struct client *c)
{ {
struct session *s; struct session *s;
time_t t;
if (ft->s == NULL) if (ft->s == NULL)
ft->s = c->session; ft->s = c->session;
@ -915,13 +976,8 @@ format_defaults_client(struct format_tree *ft, struct client *c)
format_add(ft, "client_control_mode", "%d", format_add(ft, "client_control_mode", "%d",
!!(c->flags & CLIENT_CONTROL)); !!(c->flags & CLIENT_CONTROL));
t = c->creation_time.tv_sec; format_add_tv(ft, "client_created", &c->creation_time);
format_add(ft, "client_created", "%lld", (long long) t); format_add_tv(ft, "client_activity", &c->activity_time);
format_add(ft, "client_created_string", "%s", format_time_string(t));
t = c->activity_time.tv_sec;
format_add(ft, "client_activity", "%lld", (long long) t);
format_add(ft, "client_activity_string", "%s", format_time_string(t));
if (strcmp(c->keytable->name, "root") == 0) if (strcmp(c->keytable->name, "root") == 0)
format_add(ft, "client_prefix", "%d", 0); format_add(ft, "client_prefix", "%d", 0);
@ -951,14 +1007,9 @@ format_defaults_client(struct format_tree *ft, struct client *c)
void void
format_defaults_window(struct format_tree *ft, struct window *w) format_defaults_window(struct format_tree *ft, struct window *w)
{ {
time_t t;
ft->w = w; ft->w = w;
t = w->activity_time.tv_sec; format_add_tv(ft, "window_activity", &w->activity_time);
format_add(ft, "window_activity", "%lld", (long long) t);
format_add(ft, "window_activity_string", "%s", format_time_string(t));
format_add(ft, "window_id", "@%u", w->id); format_add(ft, "window_id", "@%u", w->id);
format_add(ft, "window_name", "%s", w->name); format_add(ft, "window_name", "%s", w->name);
format_add(ft, "window_width", "%u", w->sx); format_add(ft, "window_width", "%u", w->sx);

26
tmux.1
View File

@ -3319,12 +3319,31 @@ if
is enabled, or is enabled, or
.Ql no .Ql no
if not. if not.
.Pp
A limit may be placed on the length of the resultant string by prefixing it A limit may be placed on the length of the resultant string by prefixing it
by an by an
.Ql = , .Ql = ,
a number and a colon, so a number and a colon, so
.Ql #{=10:pane_title} .Ql #{=10:pane_title}
will include at most the first 10 characters of the pane title. will include at most the first 10 characters of the pane title.
Prefixing a time variable with
.Ql t:
will convert it to a string, so if
.Ql #{window_activity}
gives
.Ql 1445765102,
.Ql #{t:window_activity}
gives
.Ql Sun Oct 25 09:25:02 2015 .
The
.Ql b:
and
.Ql d:
prefixes are
.Xr basename 3
and
.Xr dirname 3
of the variable respectively.
.Pp .Pp
In addition, the first line of a shell command's output may be inserted using In addition, the first line of a shell command's output may be inserted using
.Ql #() . .Ql #() .
@ -3352,9 +3371,7 @@ The following variables are available, where appropriate:
.It Li "buffer_sample" Ta "" Ta "Sample of start of buffer" .It Li "buffer_sample" Ta "" Ta "Sample of start of buffer"
.It Li "buffer_size" Ta "" Ta "Size of the specified buffer in bytes" .It Li "buffer_size" Ta "" Ta "Size of the specified buffer in bytes"
.It Li "client_activity" Ta "" Ta "Integer time client last had activity" .It Li "client_activity" Ta "" Ta "Integer time client last had activity"
.It Li "client_activity_string" Ta "" Ta "String time client last had activity"
.It Li "client_created" Ta "" Ta "Integer time client created" .It Li "client_created" Ta "" Ta "Integer time client created"
.It Li "client_created_string" Ta "" Ta "String time client created"
.It Li "client_control_mode" Ta "" Ta "1 if client is in control mode" .It Li "client_control_mode" Ta "" Ta "1 if client is in control mode"
.It Li "client_height" Ta "" Ta "Height of client" .It Li "client_height" Ta "" Ta "Height of client"
.It Li "client_key_table" Ta "" Ta "Current key table" .It Li "client_key_table" Ta "" Ta "Current key table"
@ -3410,11 +3427,8 @@ The following variables are available, where appropriate:
.It Li "session_alerts" Ta "" Ta "List of window indexes with alerts" .It Li "session_alerts" Ta "" Ta "List of window indexes with alerts"
.It Li "session_attached" Ta "" Ta "Number of clients session is attached to" .It Li "session_attached" Ta "" Ta "Number of clients session is attached to"
.It Li "session_activity" Ta "" Ta "Integer time of session last activity" .It Li "session_activity" Ta "" Ta "Integer time of session last activity"
.It Li "session_activity_string" Ta "" Ta "String time of session last activity"
.It Li "session_created" Ta "" Ta "Integer time session created" .It Li "session_created" Ta "" Ta "Integer time session created"
.It Li "session_created_string" Ta "" Ta "String time session created"
.It Li "session_last_attached" Ta "" Ta "Integer time session last attached" .It Li "session_last_attached" Ta "" Ta "Integer time session last attached"
.It Li "session_last_attached_string" Ta "" Ta "String time session last attached"
.It Li "session_group" Ta "" Ta "Number of session group" .It Li "session_group" Ta "" Ta "Number of session group"
.It Li "session_grouped" Ta "" Ta "1 if session in a group" .It Li "session_grouped" Ta "" Ta "1 if session in a group"
.It Li "session_height" Ta "" Ta "Height of session" .It Li "session_height" Ta "" Ta "Height of session"
@ -3424,9 +3438,7 @@ The following variables are available, where appropriate:
.It Li "session_width" Ta "" Ta "Width of session" .It Li "session_width" Ta "" Ta "Width of session"
.It Li "session_windows" Ta "" Ta "Number of windows in session" .It Li "session_windows" Ta "" Ta "Number of windows in session"
.It Li "window_activity" Ta "" Ta "Integer time of window last activity" .It Li "window_activity" Ta "" Ta "Integer time of window last activity"
.It Li "window_activity_string" Ta "" Ta "String time of window last activity"
.It Li "window_active" Ta "" Ta "1 if window active" .It Li "window_active" Ta "" Ta "1 if window active"
.It Li "window_activity_flag" Ta "" Ta "1 if window has activity alert"
.It Li "window_bell_flag" Ta "" Ta "1 if window has bell" .It Li "window_bell_flag" Ta "" Ta "1 if window has bell"
.It Li "window_find_matches" Ta "" Ta "Matched data from the find-window" .It Li "window_find_matches" Ta "" Ta "Matched data from the find-window"
.It Li "window_flags" Ta "#F" Ta "Window flags" .It Li "window_flags" Ta "#F" Ta "Window flags"

1
tmux.h
View File

@ -1453,7 +1453,6 @@ struct format_tree *format_create_flags(int);
void format_free(struct format_tree *); void format_free(struct format_tree *);
void printflike(3, 4) format_add(struct format_tree *, const char *, void printflike(3, 4) format_add(struct format_tree *, const char *,
const char *, ...); const char *, ...);
const char *format_find(struct format_tree *, const char *);
char *format_expand_time(struct format_tree *, const char *, time_t); char *format_expand_time(struct format_tree *, const char *, time_t);
char *format_expand(struct format_tree *, const char *); char *format_expand(struct format_tree *, const char *);
void format_defaults(struct format_tree *, struct client *, void format_defaults(struct format_tree *, struct client *,