diff options
Diffstat (limited to 'format.c')
-rw-r--r-- | format.c | 287 |
1 files changed, 247 insertions, 40 deletions
@@ -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)); |