aboutsummaryrefslogtreecommitdiff
path: root/format.c
diff options
context:
space:
mode:
Diffstat (limited to 'format.c')
-rw-r--r--format.c287
1 files changed, 247 insertions, 40 deletions
diff --git a/format.c b/format.c
index 79e99b61..97fcb81f 100644
--- a/format.c
+++ b/format.c
@@ -23,6 +23,7 @@
#include <errno.h>
#include <fnmatch.h>
#include <libgen.h>
+#include <math.h>
#include <regex.h>
#include <stdarg.h>
#include <stdlib.h>
@@ -49,7 +50,6 @@ static void format_add_tv(struct format_tree *, const char *,
struct timeval *);
static int format_replace(struct format_tree *, const char *, size_t,
char **, size_t *, size_t *);
-
static void format_defaults_session(struct format_tree *,
struct session *);
static void format_defaults_client(struct format_tree *, struct client *);
@@ -100,6 +100,7 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
#define FORMAT_SESSIONS 0x80
#define FORMAT_WINDOWS 0x100
#define FORMAT_PANES 0x200
+#define FORMAT_PRETTY 0x400
/* Limit on recursion. */
#define FORMAT_LOOP_LIMIT 10
@@ -354,7 +355,7 @@ format_job_get(struct format_tree *ft, const char *cmd)
if (force || (fj->job == NULL && fj->last != t)) {
fj->job = job_run(expanded, NULL,
server_client_get_cwd(ft->client, NULL), format_job_update,
- format_job_complete, NULL, fj, JOB_NOWAIT);
+ format_job_complete, NULL, fj, JOB_NOWAIT, -1, -1);
if (fj->job == NULL) {
free(fj->out);
xasprintf(&fj->out, "<'%s' didn't start>", fj->cmd);
@@ -900,11 +901,12 @@ static void
format_cb_pane_at_top(struct format_tree *ft, struct format_entry *fe)
{
struct window_pane *wp = ft->wp;
- struct window *w = wp->window;
+ struct window *w;
int status, flag;
if (wp == NULL)
return;
+ w = wp->window;
status = options_get_number(w->options, "pane-border-status");
if (status == PANE_STATUS_TOP)
@@ -919,11 +921,12 @@ static void
format_cb_pane_at_bottom(struct format_tree *ft, struct format_entry *fe)
{
struct window_pane *wp = ft->wp;
- struct window *w = wp->window;
+ struct window *w;
int status, flag;
if (wp == NULL)
return;
+ w = wp->window;
status = options_get_number(w->options, "pane-border-status");
if (status == PANE_STATUS_BOTTOM)
@@ -952,7 +955,7 @@ format_cb_cursor_character(struct format_tree *ft, struct format_entry *fe)
char *
format_grid_word(struct grid *gd, u_int x, u_int y)
{
- struct grid_line *gl;
+ const struct grid_line *gl;
struct grid_cell gc;
const char *ws;
struct utf8_data *ud = NULL;
@@ -963,7 +966,6 @@ format_grid_word(struct grid *gd, u_int x, u_int y)
ws = options_get_string(global_s_options, "word-separators");
- y = gd->hsize + y;
for (;;) {
grid_get_cell(gd, x, y, &gc);
if (gc.flags & GRID_FLAG_PADDING)
@@ -976,7 +978,7 @@ format_grid_word(struct grid *gd, u_int x, u_int y)
if (x == 0) {
if (y == 0)
break;
- gl = &gd->linedata[y - 1];
+ gl = grid_peek_line(gd, y - 1);
if (~gl->flags & GRID_LINE_WRAPPED)
break;
y--;
@@ -992,7 +994,7 @@ format_grid_word(struct grid *gd, u_int x, u_int y)
if (end == 0 || x == end - 1) {
if (y == gd->hsize + gd->sy - 1)
break;
- gl = &gd->linedata[y];
+ gl = grid_peek_line(gd, y);
if (~gl->flags & GRID_LINE_WRAPPED)
break;
y++;
@@ -1024,6 +1026,7 @@ static void
format_cb_mouse_word(struct format_tree *ft, struct format_entry *fe)
{
struct window_pane *wp;
+ struct grid *gd;
u_int x, y;
char *s;
@@ -1032,12 +1035,19 @@ format_cb_mouse_word(struct format_tree *ft, struct format_entry *fe)
wp = cmd_mouse_pane(&ft->m, NULL, NULL);
if (wp == NULL)
return;
- if (!TAILQ_EMPTY (&wp->modes))
- return;
if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0)
return;
- s = format_grid_word(wp->base.grid, x, y);
+ if (!TAILQ_EMPTY(&wp->modes)) {
+ if (TAILQ_FIRST(&wp->modes)->mode == &window_copy_mode ||
+ TAILQ_FIRST(&wp->modes)->mode == &window_view_mode)
+ s = window_copy_get_word(wp, x, y);
+ else
+ s = NULL;
+ } else {
+ gd = wp->base.grid;
+ s = format_grid_word(gd, x, gd->hsize + y);
+ }
if (s != NULL)
fe->value = s;
}
@@ -1052,7 +1062,6 @@ format_grid_line(struct grid *gd, u_int y)
size_t size = 0;
char *s = NULL;
- y = gd->hsize + y;
for (x = 0; x < grid_line_length(gd, y); x++) {
grid_get_cell(gd, x, y, &gc);
if (gc.flags & GRID_FLAG_PADDING)
@@ -1074,6 +1083,7 @@ static void
format_cb_mouse_line(struct format_tree *ft, struct format_entry *fe)
{
struct window_pane *wp;
+ struct grid *gd;
u_int x, y;
char *s;
@@ -1082,18 +1092,25 @@ format_cb_mouse_line(struct format_tree *ft, struct format_entry *fe)
wp = cmd_mouse_pane(&ft->m, NULL, NULL);
if (wp == NULL)
return;
- if (!TAILQ_EMPTY (&wp->modes))
- return;
if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0)
return;
- s = format_grid_line(wp->base.grid, y);
+ if (!TAILQ_EMPTY(&wp->modes)) {
+ if (TAILQ_FIRST(&wp->modes)->mode == &window_copy_mode ||
+ TAILQ_FIRST(&wp->modes)->mode == &window_view_mode)
+ s = window_copy_get_line(wp, y);
+ else
+ s = NULL;
+ } else {
+ gd = wp->base.grid;
+ s = format_grid_line(gd, gd->hsize + y);
+ }
if (s != NULL)
fe->value = s;
}
-/* Merge a format tree. */
-static void
+/* Merge one format tree into another. */
+void
format_merge(struct format_tree *ft, struct format_tree *from)
{
struct format_entry *fe;
@@ -1108,19 +1125,13 @@ format_merge(struct format_tree *ft, struct format_tree *from)
static void
format_create_add_item(struct format_tree *ft, struct cmdq_item *item)
{
- struct mouse_event *m;
+ struct key_event *event = cmdq_get_event(item);
+ struct mouse_event *m = &event->m;
struct window_pane *wp;
u_int x, y;
- if (item->cmd != NULL)
- format_add(ft, "command", "%s", item->cmd->entry->name);
-
- if (item->shared == NULL)
- return;
- if (item->shared->formats != NULL)
- format_merge(ft, item->shared->formats);
+ cmdq_merge_formats(item, ft);
- m = &item->shared->mouse;
if (m->valid && ((wp = cmd_mouse_pane(m, NULL, NULL)) != NULL)) {
format_add(ft, "mouse_pane", "%%%u", wp->id);
if (cmd_mouse_at(wp, m, &x, &y, 0) == 0) {
@@ -1312,6 +1323,53 @@ format_quote(const char *s)
return (out);
}
+/* Make a prettier time. */
+static char *
+format_pretty_time(time_t t)
+{
+ struct tm now_tm, tm;
+ time_t now;
+ char s[6];
+ int y, m, d;
+
+ time(&now);
+ if (now < t)
+ now = t;
+ localtime_r(&now, &now_tm);
+ localtime_r(&t, &tm);
+
+ y = now_tm.tm_year - 1;
+ if (tm.tm_year < y ||
+ (tm.tm_year == y &&
+ (tm.tm_mon <= now_tm.tm_mon || tm.tm_mday <= now_tm.tm_mday))) {
+ /* Last year. */
+ strftime(s, sizeof s, "%h%y", &tm);
+ return (xstrdup(s));
+ }
+ if (now_tm.tm_mon == 0)
+ m = 11;
+ else
+ m = now_tm.tm_mon - 1;
+ if (tm.tm_mon < m || (tm.tm_mon == m && tm.tm_mday < now_tm.tm_mday)) {
+ /* Last month. */
+ strftime(s, sizeof s, "%d%b", &tm);
+ return (xstrdup(s));
+ }
+ if (now_tm.tm_mday == 0)
+ d = 31;
+ else
+ d = now_tm.tm_mday - 1;
+ if (tm.tm_mday < d ||
+ (tm.tm_mday == d && tm.tm_mday < now_tm.tm_mday)) {
+ /* This day. */
+ strftime(s, sizeof s, "%a%d", &tm);
+ return (xstrdup(s));
+ }
+ /* Today. */
+ strftime(s, sizeof s, "%H:%M", &tm);
+ return (xstrdup(s));
+}
+
/* Find a format entry. */
static char *
format_find(struct format_tree *ft, const char *key, int modifiers)
@@ -1348,9 +1406,13 @@ format_find(struct format_tree *ft, const char *key, int modifiers)
if (modifiers & FORMAT_TIMESTRING) {
if (fe->t == 0)
return (NULL);
- ctime_r(&fe->t, s);
- s[strcspn(s, "\n")] = '\0';
- found = xstrdup(s);
+ if (modifiers & FORMAT_PRETTY)
+ found = format_pretty_time(fe->t);
+ else {
+ ctime_r(&fe->t, s);
+ s[strcspn(s, "\n")] = '\0';
+ found = xstrdup(s);
+ }
goto found;
}
if (fe->t != 0) {
@@ -1522,7 +1584,7 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
cp++;
/* Check single character modifiers with no arguments. */
- if (strchr("lbdtqETSWP<>", cp[0]) != NULL &&
+ if (strchr("lbdqETSWP<>", cp[0]) != NULL &&
format_is_end(cp[1])) {
format_add_modifier(&list, count, cp, 1, NULL, 0);
cp++;
@@ -1543,7 +1605,7 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
}
/* Now try single character with arguments. */
- if (strchr("mCs=p", cp[0]) == NULL)
+ if (strchr("mCst=pe", cp[0]) == NULL)
break;
c = cp[0];
@@ -1601,7 +1663,7 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
return (NULL);
}
*s = cp + 1;
- return list;
+ return (list);
}
/* Match against an fnmatch(3) pattern or regular expression. */
@@ -1799,6 +1861,108 @@ format_loop_panes(struct format_tree *ft, const char *fmt)
return (value);
}
+static char *
+format_replace_expression(struct format_modifier *mexp, struct format_tree *ft,
+ const char *copy)
+{
+ int argc = mexp->argc;
+ const char *errstr;
+ char *endch, *value, *left = NULL, *right = NULL;
+ int use_fp = 0;
+ u_int prec = 0;
+ double mleft, mright, result;
+ enum { ADD, SUBTRACT, MULTIPLY, DIVIDE, MODULUS } operator;
+
+ if (strcmp(mexp->argv[0], "+") == 0)
+ operator = ADD;
+ else if (strcmp(mexp->argv[0], "-") == 0)
+ operator = SUBTRACT;
+ else if (strcmp(mexp->argv[0], "*") == 0)
+ operator = MULTIPLY;
+ else if (strcmp(mexp->argv[0], "/") == 0)
+ operator = DIVIDE;
+ else if (strcmp(mexp->argv[0], "%") == 0 ||
+ strcmp(mexp->argv[0], "m") == 0)
+ operator = MODULUS;
+ else {
+ format_log(ft, "expression has no valid operator: '%s'",
+ mexp->argv[0]);
+ goto fail;
+ }
+
+ /* The second argument may be flags. */
+ if (argc >= 2 && strchr(mexp->argv[1], 'f') != NULL) {
+ use_fp = 1;
+ prec = 2;
+ }
+
+ /* The third argument may be precision. */
+ if (argc >= 3) {
+ prec = strtonum(mexp->argv[2], INT_MIN, INT_MAX, &errstr);
+ if (errstr != NULL) {
+ format_log (ft, "expression precision %s: %s", errstr,
+ mexp->argv[2]);
+ goto fail;
+ }
+ }
+
+ if (format_choose(ft, copy, &left, &right, 1) != 0) {
+ format_log(ft, "expression syntax error");
+ goto fail;
+ }
+
+ mleft = strtod(left, &endch);
+ if (*endch != '\0') {
+ format_log(ft, "expression left side is invalid: %s", left);
+ goto fail;
+ }
+
+ mright = strtod(right, &endch);
+ if (*endch != '\0') {
+ format_log(ft, "expression right side is invalid: %s", right);
+ goto fail;
+ }
+
+ if (!use_fp) {
+ mleft = (long long)mleft;
+ mright = (long long)mright;
+ }
+ format_log(ft, "expression left side is: %.*f", prec, mleft);
+ format_log(ft, "expression right side is: %.*f", prec, mright);
+
+ switch (operator) {
+ case ADD:
+ result = mleft + mright;
+ break;
+ case SUBTRACT:
+ result = mleft - mright;
+ break;
+ case MULTIPLY:
+ result = mleft * mright;
+ break;
+ case DIVIDE:
+ result = mleft / mright;
+ break;
+ case MODULUS:
+ result = fmod(mleft, mright);
+ break;
+ }
+ if (use_fp)
+ xasprintf(&value, "%.*f", prec, result);
+ else
+ xasprintf(&value, "%.*f", prec, (double)(long long)result);
+ format_log(ft, "expression result is %s", value);
+
+ free(right);
+ free(left);
+ return (value);
+
+fail:
+ free(right);
+ free(left);
+ return (NULL);
+}
+
/* Replace a key. */
static int
format_replace(struct format_tree *ft, const char *key, size_t keylen,
@@ -1811,7 +1975,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
size_t valuelen;
int modifiers = 0, limit = 0, width = 0, j;
struct format_modifier *list, *fm, *cmp = NULL, *search = NULL;
- struct format_modifier **sub = NULL;
+ struct format_modifier **sub = NULL, *mexp = NULL;
u_int i, count, nsub = 0;
/* Make a copy of the key. */
@@ -1863,6 +2027,11 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
if (errptr != NULL)
width = 0;
break;
+ case 'e':
+ if (fm->argc < 1 || fm->argc > 3)
+ break;
+ mexp = fm;
+ break;
case 'l':
modifiers |= FORMAT_LITERAL;
break;
@@ -1874,6 +2043,10 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
break;
case 't':
modifiers |= FORMAT_TIMESTRING;
+ if (fm->argc < 1)
+ break;
+ if (strchr(fm->argv[0], 'p') != NULL)
+ modifiers |= FORMAT_PRETTY;
break;
case 'q':
modifiers |= FORMAT_QUOTE;
@@ -2039,6 +2212,10 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
free(condition);
free(found);
+ } else if (mexp != NULL) {
+ value = format_replace_expression(mexp, ft, copy);
+ if (value == NULL)
+ value = xstrdup("");
} else {
/* Neither: look up directly. */
value = format_find(ft, copy, modifiers);
@@ -2296,7 +2473,7 @@ format_single(struct cmdq_item *item, const char *fmt, struct client *c,
char *expanded;
if (item != NULL)
- ft = format_create(item->client, item, FORMAT_NONE, 0);
+ ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
else
ft = format_create(NULL, item, FORMAT_NONE, 0);
format_defaults(ft, c, s, wl, wp);
@@ -2306,11 +2483,23 @@ format_single(struct cmdq_item *item, const char *fmt, struct client *c,
return (expanded);
}
+/* Expand a single string using target. */
+char *
+format_single_from_target(struct cmdq_item *item, const char *fmt)
+{
+ struct cmd_find_state *target = cmdq_get_target(item);
+ struct client *tc = cmdq_get_target_client(item);
+
+ return (format_single(item, fmt, tc, target->s, target->wl, target->wp));
+}
+
/* Set defaults for any of arguments that are not NULL. */
void
format_defaults(struct format_tree *ft, struct client *c, struct session *s,
struct winlink *wl, struct window_pane *wp)
{
+ struct paste_buffer *pb;
+
if (c != NULL && c->name != NULL)
log_debug("%s: c=%s", __func__, c->name);
else
@@ -2350,6 +2539,10 @@ format_defaults(struct format_tree *ft, struct client *c, struct session *s,
format_defaults_winlink(ft, wl);
if (wp != NULL)
format_defaults_pane(ft, wp);
+
+ pb = paste_get_top (NULL);
+ if (pb != NULL)
+ format_defaults_paste_buffer(ft, pb);
}
/* Set default format keys for a session. */
@@ -2361,6 +2554,7 @@ format_defaults_session(struct format_tree *ft, struct session *s)
ft->s = s;
format_add(ft, "session_name", "%s", s->name);
+ format_add(ft, "session_path", "%s", s->cwd);
format_add(ft, "session_windows", "%u", winlink_count(&s->windows));
format_add(ft, "session_id", "$%u", s->id);
@@ -2391,6 +2585,11 @@ format_defaults_session(struct format_tree *ft, struct session *s)
format_add_cb(ft, "session_alerts", format_cb_session_alerts);
format_add_cb(ft, "session_stack", format_cb_session_stack);
+
+ if (server_check_marked() && marked_pane.s == s)
+ format_add(ft, "session_marked", "1");
+ else
+ format_add(ft, "session_marked", "0");
}
/* Set default format keys for a client. */
@@ -2415,8 +2614,11 @@ format_defaults_client(struct format_tree *ft, struct client *c)
format_add(ft, "client_control_mode", "%d",
!!(c->flags & CLIENT_CONTROL));
- if (tty->term_name != NULL)
- format_add(ft, "client_termname", "%s", tty->term_name);
+ format_add(ft, "client_termname", "%s", c->term_name);
+ format_add(ft, "client_termfeatures", "%s",
+ tty_get_features(c->term_features));
+ if (c->term_type != NULL)
+ format_add(ft, "client_termtype", "%s", c->term_type);
format_add_tv(ft, "client_created", &c->creation_time);
format_add_tv(ft, "client_activity", &c->activity_time);
@@ -2431,7 +2633,7 @@ format_defaults_client(struct format_tree *ft, struct client *c)
format_add(ft, "client_prefix", "%d", 1);
format_add(ft, "client_key_table", "%s", c->keytable->name);
- if (tty->flags & TTY_UTF8)
+ if (c->flags & CLIENT_UTF8)
format_add(ft, "client_utf8", "%d", 1);
else
format_add(ft, "client_utf8", "%d", 0);
@@ -2552,6 +2754,9 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp)
format_add(ft, "history_limit", "%u", gd->hlimit);
format_add_cb(ft, "history_bytes", format_cb_history_bytes);
+ format_add(ft, "pane_written", "%zu", wp->written);
+ format_add(ft, "pane_skipped", "%zu", wp->skipped);
+
if (window_pane_index(wp, &idx) != 0)
fatalx("index not found");
format_add(ft, "pane_index", "%u", idx);
@@ -2614,9 +2819,11 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp)
format_add(ft, "scroll_region_upper", "%u", wp->base.rupper);
format_add(ft, "scroll_region_lower", "%u", wp->base.rlower);
- format_add(ft, "alternate_on", "%d", wp->saved_grid ? 1 : 0);
- format_add(ft, "alternate_saved_x", "%u", wp->saved_cx);
- format_add(ft, "alternate_saved_y", "%u", wp->saved_cy);
+ format_add(ft, "alternate_on", "%d", wp->base.saved_grid != NULL);
+ if (wp->base.saved_cx != UINT_MAX)
+ format_add(ft, "alternate_saved_x", "%u", wp->base.saved_cx);
+ if (wp->base.saved_cy != UINT_MAX)
+ format_add(ft, "alternate_saved_y", "%u", wp->base.saved_cy);
format_add(ft, "cursor_flag", "%d",
!!(wp->base.mode & MODE_CURSOR));