aboutsummaryrefslogtreecommitdiff
path: root/format.c
diff options
context:
space:
mode:
Diffstat (limited to 'format.c')
-rw-r--r--format.c224
1 files changed, 205 insertions, 19 deletions
diff --git a/format.c b/format.c
index 9af6e0a0..8041f728 100644
--- a/format.c
+++ b/format.c
@@ -24,6 +24,7 @@
#include <fnmatch.h>
#include <libgen.h>
#include <math.h>
+#include <pwd.h>
#include <regex.h>
#include <stdarg.h>
#include <stdlib.h>
@@ -101,6 +102,7 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
#define FORMAT_WINDOW_NAME 0x4000
#define FORMAT_SESSION_NAME 0x8000
#define FORMAT_CHARACTER 0x10000
+#define FORMAT_COLOUR 0x20000
/* Limit on recursion. */
#define FORMAT_LOOP_LIMIT 100
@@ -390,7 +392,7 @@ format_job_get(struct format_expand_state *es, const char *cmd)
if (force && fj->job != NULL)
job_free(fj->job);
if (force || (fj->job == NULL && fj->last != t)) {
- fj->job = job_run(expanded, 0, NULL, NULL,
+ fj->job = job_run(expanded, 0, NULL, NULL, NULL,
server_client_get_cwd(ft->client, NULL), format_job_update,
format_job_complete, NULL, fj, JOB_NOWAIT, -1, -1);
if (fj->job == NULL) {
@@ -799,6 +801,20 @@ format_cb_start_command(struct format_tree *ft)
return (cmd_stringify_argv(wp->argc, wp->argv));
}
+/* Callback for pane_start_path. */
+static void *
+format_cb_start_path(struct format_tree *ft)
+{
+ struct window_pane *wp = ft->wp;
+
+ if (wp == NULL)
+ return (NULL);
+
+ if (wp->cwd == NULL)
+ return (xstrdup(""));
+ return (xstrdup(wp->cwd));
+}
+
/* Callback for pane_current_command. */
static void *
format_cb_current_command(struct format_tree *ft)
@@ -1129,6 +1145,25 @@ format_cb_mouse_word(struct format_tree *ft)
return (format_grid_word(gd, x, gd->hsize + y));
}
+/* Callback for mouse_hyperlink. */
+static void *
+format_cb_mouse_hyperlink(struct format_tree *ft)
+{
+ struct window_pane *wp;
+ struct grid *gd;
+ u_int x, y;
+
+ if (!ft->m.valid)
+ return (NULL);
+ wp = cmd_mouse_pane(&ft->m, NULL, NULL);
+ if (wp == NULL)
+ return (NULL);
+ if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0)
+ return (NULL);
+ gd = wp->base.grid;
+ return (format_grid_hyperlink(gd, x, gd->hsize + y, wp->screen));
+}
+
/* Callback for mouse_line. */
static void *
format_cb_mouse_line(struct format_tree *ft)
@@ -1386,6 +1421,35 @@ format_cb_client_tty(struct format_tree *ft)
return (NULL);
}
+/* Callback for client_uid. */
+static void *
+format_cb_client_uid(struct format_tree *ft)
+{
+ uid_t uid;
+
+ if (ft->c != NULL) {
+ uid = proc_get_peer_uid(ft->c->peer);
+ if (uid != (uid_t)-1)
+ return (format_printf("%ld", (long)uid));
+ }
+ return (NULL);
+}
+
+/* Callback for client_user. */
+static void *
+format_cb_client_user(struct format_tree *ft)
+{
+ uid_t uid;
+ struct passwd *pw;
+
+ if (ft->c != NULL) {
+ uid = proc_get_peer_uid(ft->c->peer);
+ if (uid != (uid_t)-1 && (pw = getpwuid(uid)) != NULL)
+ return (xstrdup(pw->pw_name));
+ }
+ return (NULL);
+}
+
/* Callback for client_utf8. */
static void *
format_cb_client_utf8(struct format_tree *ft)
@@ -1649,6 +1713,13 @@ format_cb_mouse_y(struct format_tree *ft)
return (NULL);
}
+/* Callback for next_session_id. */
+static void *
+format_cb_next_session_id(__unused struct format_tree *ft)
+{
+ return (format_printf("$%u", next_session_id));
+}
+
/* Callback for origin_flag. */
static void *
format_cb_origin_flag(struct format_tree *ft)
@@ -1718,6 +1789,23 @@ format_cb_pane_dead(struct format_tree *ft)
return (NULL);
}
+/* Callback for pane_dead_signal. */
+static void *
+format_cb_pane_dead_signal(struct format_tree *ft)
+{
+ struct window_pane *wp = ft->wp;
+ const char *name;
+
+ if (wp != NULL) {
+ if ((wp->flags & PANE_STATUSREADY) && WIFSIGNALED(wp->status)) {
+ name = sig2name(WTERMSIG(wp->status));
+ return (format_printf("%s", name));
+ }
+ return (NULL);
+ }
+ return (NULL);
+}
+
/* Callback for pane_dead_status. */
static void *
format_cb_pane_dead_status(struct format_tree *ft)
@@ -1732,6 +1820,20 @@ format_cb_pane_dead_status(struct format_tree *ft)
return (NULL);
}
+/* Callback for pane_dead_time. */
+static void *
+format_cb_pane_dead_time(struct format_tree *ft)
+{
+ struct window_pane *wp = ft->wp;
+
+ if (wp != NULL) {
+ if (wp->flags & PANE_STATUSDRAWN)
+ return (&wp->dead_time);
+ return (NULL);
+ }
+ return (NULL);
+}
+
/* Callback for pane_format. */
static void *
format_cb_pane_format(struct format_tree *ft)
@@ -2513,6 +2615,24 @@ format_cb_tree_mode_format(__unused struct format_tree *ft)
return (xstrdup(window_tree_mode.default_format));
}
+/* Callback for uid. */
+static void *
+format_cb_uid(__unused struct format_tree *ft)
+{
+ return (format_printf("%ld", (long)getuid()));
+}
+
+/* Callback for user. */
+static void *
+format_cb_user(__unused struct format_tree *ft)
+{
+ struct passwd *pw;
+
+ if ((pw = getpwuid(getuid())) != NULL)
+ return (xstrdup(pw->pw_name));
+ return (NULL);
+}
+
/* Format table type. */
enum format_table_type {
FORMAT_TABLE_STRING,
@@ -2619,6 +2739,12 @@ static const struct format_table_entry format_table[] = {
{ "client_tty", FORMAT_TABLE_STRING,
format_cb_client_tty
},
+ { "client_uid", FORMAT_TABLE_STRING,
+ format_cb_client_uid
+ },
+ { "client_user", FORMAT_TABLE_STRING,
+ format_cb_client_user
+ },
{ "client_utf8", FORMAT_TABLE_STRING,
format_cb_client_utf8
},
@@ -2682,6 +2808,9 @@ static const struct format_table_entry format_table[] = {
{ "mouse_button_flag", FORMAT_TABLE_STRING,
format_cb_mouse_button_flag
},
+ { "mouse_hyperlink", FORMAT_TABLE_STRING,
+ format_cb_mouse_hyperlink
+ },
{ "mouse_line", FORMAT_TABLE_STRING,
format_cb_mouse_line
},
@@ -2706,6 +2835,9 @@ static const struct format_table_entry format_table[] = {
{ "mouse_y", FORMAT_TABLE_STRING,
format_cb_mouse_y
},
+ { "next_session_id", FORMAT_TABLE_STRING,
+ format_cb_next_session_id
+ },
{ "origin_flag", FORMAT_TABLE_STRING,
format_cb_origin_flag
},
@@ -2739,9 +2871,15 @@ static const struct format_table_entry format_table[] = {
{ "pane_dead", FORMAT_TABLE_STRING,
format_cb_pane_dead
},
+ { "pane_dead_signal", FORMAT_TABLE_STRING,
+ format_cb_pane_dead_signal
+ },
{ "pane_dead_status", FORMAT_TABLE_STRING,
format_cb_pane_dead_status
},
+ { "pane_dead_time", FORMAT_TABLE_TIME,
+ format_cb_pane_dead_time
+ },
{ "pane_fg", FORMAT_TABLE_STRING,
format_cb_pane_fg
},
@@ -2796,6 +2934,9 @@ static const struct format_table_entry format_table[] = {
{ "pane_start_command", FORMAT_TABLE_STRING,
format_cb_start_command
},
+ { "pane_start_path", FORMAT_TABLE_STRING,
+ format_cb_start_path
+ },
{ "pane_synchronized", FORMAT_TABLE_STRING,
format_cb_pane_synchronized
},
@@ -2895,6 +3036,12 @@ static const struct format_table_entry format_table[] = {
{ "tree_mode_format", FORMAT_TABLE_STRING,
format_cb_tree_mode_format
},
+ { "uid", FORMAT_TABLE_STRING,
+ format_cb_uid
+ },
+ { "user", FORMAT_TABLE_STRING,
+ format_cb_user
+ },
{ "version", FORMAT_TABLE_STRING,
format_cb_version
},
@@ -3262,12 +3409,12 @@ format_quote_style(const char *s)
}
/* Make a prettier time. */
-static char *
-format_pretty_time(time_t t)
+char *
+format_pretty_time(time_t t, int seconds)
{
struct tm now_tm, tm;
time_t now, age;
- char s[6];
+ char s[9];
time(&now);
if (now < t)
@@ -3279,7 +3426,10 @@ format_pretty_time(time_t t)
/* Last 24 hours. */
if (age < 24 * 3600) {
- strftime(s, sizeof s, "%H:%M", &tm);
+ if (seconds)
+ strftime(s, sizeof s, "%H:%M:%S", &tm);
+ else
+ strftime(s, sizeof s, "%H:%M", &tm);
return (xstrdup(s));
}
@@ -3384,7 +3534,7 @@ found:
if (t == 0)
return (NULL);
if (modifiers & FORMAT_PRETTY)
- found = format_pretty_time(t);
+ found = format_pretty_time(t, 0);
else {
if (time_format != NULL) {
localtime_r(&t, &tm);
@@ -3414,12 +3564,12 @@ found:
}
if (modifiers & FORMAT_QUOTE_SHELL) {
saved = found;
- found = xstrdup(format_quote_shell(saved));
+ found = format_quote_shell(saved);
free(saved);
}
if (modifiers & FORMAT_QUOTE_STYLE) {
saved = found;
- found = xstrdup(format_quote_style(saved));
+ found = format_quote_style(saved);
free(saved);
}
return (found);
@@ -3555,7 +3705,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
/*
* Modifiers are a ; separated list of the forms:
- * l,m,C,a,b,d,n,t,w,q,E,T,S,W,P,<,>
+ * l,m,C,a,b,c,d,n,t,w,q,E,T,S,W,P,<,>
* =a
* =/a
* =/a/
@@ -3572,7 +3722,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
cp++;
/* Check single character modifiers with no arguments. */
- if (strchr("labdnwETSWP<>", cp[0]) != NULL &&
+ if (strchr("labcdnwETSWP<>", cp[0]) != NULL &&
format_is_end(cp[1])) {
format_add_modifier(&list, count, cp, 1, NULL, 0);
cp++;
@@ -4052,10 +4202,10 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
const char *errstr, *copy, *cp, *marker = NULL;
const char *time_format = NULL;
char *copy0, *condition, *found, *new;
- char *value, *left, *right, c;
+ char *value, *left, *right;
size_t valuelen;
int modifiers = 0, limit = 0, width = 0;
- int j;
+ int j, c;
struct format_modifier *list, *cmp = NULL, *search = NULL;
struct format_modifier **sub = NULL, *mexp = NULL, *fm;
u_int i, count, nsub = 0;
@@ -4126,6 +4276,9 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
case 'b':
modifiers |= FORMAT_BASENAME;
break;
+ case 'c':
+ modifiers |= FORMAT_COLOUR;
+ break;
case 'd':
modifiers |= FORMAT_DIRNAME;
break;
@@ -4201,6 +4354,18 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
goto done;
}
+ /* Is this a colour? */
+ if (modifiers & FORMAT_COLOUR) {
+ new = format_expand1(es, copy);
+ c = colour_fromstring(new);
+ if (c == -1 || (c = colour_force_rgb(c)) == -1)
+ value = xstrdup("");
+ else
+ xasprintf(&value, "%06x", c & 0xffffff);
+ free(new);
+ goto done;
+ }
+
/* Is this a loop, comparison or condition? */
if (modifiers & FORMAT_SESSIONS) {
value = format_loop_sessions(es, copy);
@@ -4463,7 +4628,7 @@ format_expand1(struct format_expand_state *es, const char *fmt)
{
struct format_tree *ft = es->ft;
char *buf, *out, *name;
- const char *ptr, *s;
+ const char *ptr, *s, *style_end = NULL;
size_t off, len, n, outlen;
int ch, brackets;
char expanded[8192];
@@ -4558,18 +4723,20 @@ format_expand1(struct format_expand_state *es, const char *fmt)
break;
fmt += n + 1;
continue;
+ case '[':
case '#':
/*
* If ##[ (with two or more #s), then it is a style and
* can be left for format_draw to handle.
*/
- ptr = fmt;
- n = 2;
+ ptr = fmt - (ch == '[');
+ n = 2 - (ch == '[');
while (*ptr == '#') {
ptr++;
n++;
}
if (*ptr == '[') {
+ style_end = format_skip(fmt - 2, "]");
format_log(es, "found #*%zu[", n);
while (len - off < n + 2) {
buf = xreallocarray(buf, 2, len);
@@ -4592,10 +4759,12 @@ format_expand1(struct format_expand_state *es, const char *fmt)
continue;
default:
s = NULL;
- if (ch >= 'A' && ch <= 'Z')
- s = format_upper[ch - 'A'];
- else if (ch >= 'a' && ch <= 'z')
- s = format_lower[ch - 'a'];
+ if (fmt > style_end) { /* skip inside #[] */
+ if (ch >= 'A' && ch <= 'Z')
+ s = format_upper[ch - 'A'];
+ else if (ch >= 'a' && ch <= 'z')
+ s = format_lower[ch - 'a'];
+ }
if (s == NULL) {
while (len - off < 3) {
buf = xreallocarray(buf, 2, len);
@@ -4917,3 +5086,20 @@ format_grid_line(struct grid *gd, u_int y)
}
return (s);
}
+
+/* Return hyperlink at given coordinates. Caller frees. */
+char *
+format_grid_hyperlink(struct grid *gd, u_int x, u_int y, struct screen* s)
+{
+ const char *uri;
+ struct grid_cell gc;
+
+ grid_get_cell(gd, x, y, &gc);
+ if (gc.flags & GRID_FLAG_PADDING)
+ return (NULL);
+ if (s->hyperlinks == NULL || gc.link == 0)
+ return (NULL);
+ if (!hyperlinks_get(s->hyperlinks, gc.link, &uri, NULL, NULL))
+ return (NULL);
+ return (xstrdup(uri));
+}