In order that people can use formats like #D in #() in the status line
authornicm <nicm@openbsd.org>
Mon, 1 May 2017 12:20:55 +0000 (12:20 +0000)
committernicm <nicm@openbsd.org>
Mon, 1 May 2017 12:20:55 +0000 (12:20 +0000)
and not have to wait for an update when they change pane, we allow
commands to run more than once a second if the expanded form
changes. Unfortunately this can mean them being run far too often
(pretty much continually) when multiple clients exist, because some
formats (including #D) will always differ between clients.

To avoid this, give each client its own tree of jobs which means that
the same command will be different instances for each client - similar
to how we have the tag to separate commands for different panes.

GitHub issue 889; test case reported by Paul Johnson.

17 files changed:
usr.bin/tmux/cfg.c
usr.bin/tmux/cmd-display-message.c
usr.bin/tmux/cmd-list-buffers.c
usr.bin/tmux/cmd-list-clients.c
usr.bin/tmux/cmd-list-keys.c
usr.bin/tmux/cmd-list-panes.c
usr.bin/tmux/cmd-list-sessions.c
usr.bin/tmux/cmd-list-windows.c
usr.bin/tmux/cmd-pipe-pane.c
usr.bin/tmux/cmd-queue.c
usr.bin/tmux/format.c
usr.bin/tmux/names.c
usr.bin/tmux/screen-redraw.c
usr.bin/tmux/server-client.c
usr.bin/tmux/status.c
usr.bin/tmux/tmux.h
usr.bin/tmux/window-choose.c

index b9f6ab0..6257930 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cfg.c,v 1.58 2017/04/25 14:46:23 nicm Exp $ */
+/* $OpenBSD: cfg.c,v 1.59 2017/05/01 12:20:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -148,7 +148,8 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int quiet)
                                    line);
                                continue;
                        }
-                       ft = format_create(NULL, FORMAT_NONE, FORMAT_NOJOBS);
+                       ft = format_create(NULL, NULL, FORMAT_NONE,
+                           FORMAT_NOJOBS);
 
                        s = p + 3;
                        while (isspace((u_char)*s))
index afb3a48..c4aa322 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-display-message.c,v 1.41 2017/04/22 10:22:39 nicm Exp $ */
+/* $OpenBSD: cmd-display-message.c,v 1.42 2017/05/01 12:20:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -73,7 +73,7 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
        if (template == NULL)
                template = DISPLAY_MESSAGE_TEMPLATE;
 
-       ft = format_create(item, FORMAT_NONE, 0);
+       ft = format_create(item->client, item, FORMAT_NONE, 0);
        format_defaults(ft, c, s, wl, wp);
 
        msg = format_expand_time(ft, template, time(NULL));
index 56efd29..95d109d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-list-buffers.c,v 1.34 2017/02/03 11:57:27 nicm Exp $ */
+/* $OpenBSD: cmd-list-buffers.c,v 1.35 2017/05/01 12:20:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -57,7 +57,7 @@ cmd_list_buffers_exec(struct cmd *self, struct cmdq_item *item)
 
        pb = NULL;
        while ((pb = paste_walk(pb)) != NULL) {
-               ft = format_create(item, FORMAT_NONE, 0);
+               ft = format_create(item->client, item, FORMAT_NONE, 0);
                format_defaults_paste_buffer(ft, pb);
 
                line = format_expand(ft, template);
index 3d489a0..83b7fcb 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-list-clients.c,v 1.33 2017/04/22 10:22:39 nicm Exp $ */
+/* $OpenBSD: cmd-list-clients.c,v 1.34 2017/05/01 12:20:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -72,7 +72,7 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
                if (c->session == NULL || (s != NULL && s != c->session))
                        continue;
 
-               ft = format_create(item, FORMAT_NONE, 0);
+               ft = format_create(item->client, item, FORMAT_NONE, 0);
                format_add(ft, "line", "%u", idx);
                format_defaults(ft, c, NULL, NULL, NULL);
 
index aab3c77..919571f 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-list-keys.c,v 1.43 2017/04/21 14:01:19 nicm Exp $ */
+/* $OpenBSD: cmd-list-keys.c,v 1.44 2017/05/01 12:20:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -144,7 +144,7 @@ cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
                    "#{command_list_usage}";
        }
 
-       ft = format_create(item, FORMAT_NONE, 0);
+       ft = format_create(item->client, item, FORMAT_NONE, 0);
        format_defaults(ft, NULL, NULL, NULL, NULL);
 
        for (entryp = cmd_table; *entryp != NULL; entryp++) {
index 1f81dee..6a9f99e 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-list-panes.c,v 1.32 2017/04/22 10:22:39 nicm Exp $ */
+/* $OpenBSD: cmd-list-panes.c,v 1.33 2017/05/01 12:20:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -123,7 +123,7 @@ cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
 
        n = 0;
        TAILQ_FOREACH(wp, &wl->window->panes, entry) {
-               ft = format_create(item, FORMAT_NONE, 0);
+               ft = format_create(item->client, item, FORMAT_NONE, 0);
                format_add(ft, "line", "%u", n);
                format_defaults(ft, NULL, s, wl, wp);
 
index 9e3bc65..dc51059 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-list-sessions.c,v 1.28 2017/02/03 11:57:27 nicm Exp $ */
+/* $OpenBSD: cmd-list-sessions.c,v 1.29 2017/05/01 12:20:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -65,7 +65,7 @@ cmd_list_sessions_exec(struct cmd *self, struct cmdq_item *item)
 
        n = 0;
        RB_FOREACH(s, sessions, &sessions) {
-               ft = format_create(item, FORMAT_NONE, 0);
+               ft = format_create(item->client, item, FORMAT_NONE, 0);
                format_add(ft, "line", "%u", n);
                format_defaults(ft, NULL, s, NULL, NULL);
 
index fa4572a..4eebbbc 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-list-windows.c,v 1.42 2017/04/22 10:22:39 nicm Exp $ */
+/* $OpenBSD: cmd-list-windows.c,v 1.43 2017/05/01 12:20:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -86,7 +86,7 @@ cmd_list_windows_session(struct cmd *self, struct session *s,
 {
        struct args             *args = self->args;
        struct winlink          *wl;
-       u_int                   n;
+       u_int                    n;
        struct format_tree      *ft;
        const char              *template;
        char                    *line;
@@ -105,7 +105,7 @@ cmd_list_windows_session(struct cmd *self, struct session *s,
 
        n = 0;
        RB_FOREACH(wl, winlinks, &s->windows) {
-               ft = format_create(item, FORMAT_NONE, 0);
+               ft = format_create(item->client, item, FORMAT_NONE, 0);
                format_add(ft, "line", "%u", n);
                format_defaults(ft, NULL, s, wl, NULL);
 
index 7ed9284..1f0a795 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-pipe-pane.c,v 1.41 2017/04/22 10:22:39 nicm Exp $ */
+/* $OpenBSD: cmd-pipe-pane.c,v 1.42 2017/05/01 12:20:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -90,7 +90,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
        }
 
        /* Expand the command. */
-       ft = format_create(item, FORMAT_NONE, 0);
+       ft = format_create(item->client, item, FORMAT_NONE, 0);
        format_defaults(ft, c, s, wl, wp);
        cmd = format_expand_time(ft, args->argv[0], time(NULL));
        format_free(ft);
index 0abda7b..68109e5 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-queue.c,v 1.54 2017/04/22 10:22:39 nicm Exp $ */
+/* $OpenBSD: cmd-queue.c,v 1.55 2017/05/01 12:20:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2013 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -299,7 +299,7 @@ cmdq_format(struct cmdq_item *item, const char *key, const char *fmt, ...)
        va_end(ap);
 
        if (shared->formats == NULL)
-               shared->formats = format_create(NULL, FORMAT_NONE, 0);
+               shared->formats = format_create(NULL, NULL, FORMAT_NONE, 0);
        format_add(shared->formats, key, "%s", value);
 
        free(value);
index f5bd279..8e06ede 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: format.c,v 1.130 2017/04/21 14:01:19 nicm Exp $ */
+/* $OpenBSD: format.c,v 1.131 2017/05/01 12:20:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -76,6 +76,7 @@ static void    format_defaults_winlink(struct format_tree *,
 
 /* Entry in format job tree. */
 struct format_job {
+       struct client           *client;
        u_int                    tag;
        const char              *cmd;
        const char              *expanded;
@@ -128,6 +129,7 @@ struct format_tree {
        struct session          *s;
        struct window_pane      *wp;
 
+       struct client           *client;
        u_int                    tag;
        int                      flags;
 
@@ -236,7 +238,6 @@ format_job_complete(struct job *job)
        struct format_job       *fj = job->data;
        char                    *line, *buf;
        size_t                   len;
-       struct client           *c;
 
        fj->job = NULL;
 
@@ -258,8 +259,8 @@ format_job_complete(struct job *job)
                free(buf);
 
        if (fj->status) {
-               TAILQ_FOREACH(c, &clients, entry)
-                   server_status_client(c);
+               if (fj->client != NULL)
+                       server_status_client(fj->client);
                fj->status = 0;
        }
 }
@@ -268,22 +269,33 @@ format_job_complete(struct job *job)
 static char *
 format_job_get(struct format_tree *ft, const char *cmd)
 {
+       struct format_job_tree  *jobs;
        struct format_job        fj0, *fj;
        time_t                   t;
        char                    *expanded;
        int                      force;
 
+       if (ft->client == NULL)
+               jobs = &format_jobs;
+       else if (ft->client->jobs != NULL)
+               jobs = ft->client->jobs;
+       else {
+               jobs = ft->client->jobs = xmalloc(sizeof *ft->client->jobs);
+               RB_INIT(jobs);
+       }
+
        fj0.tag = ft->tag;
        fj0.cmd = cmd;
-       if ((fj = RB_FIND(format_job_tree, &format_jobs, &fj0)) == NULL) {
+       if ((fj = RB_FIND(format_job_tree, jobs, &fj0)) == NULL) {
                fj = xcalloc(1, sizeof *fj);
+               fj->client = ft->client;
                fj->tag = ft->tag;
                fj->cmd = xstrdup(cmd);
                fj->expanded = NULL;
 
                xasprintf(&fj->out, "<'%s' not ready>", fj->cmd);
 
-               RB_INSERT(format_job_tree, &format_jobs, fj);
+               RB_INSERT(format_job_tree, jobs, fj);
        }
 
        expanded = format_expand(ft, cmd);
@@ -314,17 +326,16 @@ format_job_get(struct format_tree *ft, const char *cmd)
 
 /* Remove old jobs. */
 static void
-format_job_timer(__unused int fd, __unused short events, __unused void *arg)
+format_job_tidy(struct format_job_tree *jobs, int force)
 {
        struct format_job       *fj, *fj1;
        time_t                   now;
-       struct timeval           tv = { .tv_sec = 60 };
 
        now = time(NULL);
-       RB_FOREACH_SAFE(fj, format_job_tree, &format_jobs, fj1) {
-               if (fj->last > now || now - fj->last < 3600)
+       RB_FOREACH_SAFE(fj, format_job_tree, jobs, fj1) {
+               if (!force && (fj->last > now || now - fj->last < 3600))
                        continue;
-               RB_REMOVE(format_job_tree, &format_jobs, fj);
+               RB_REMOVE(format_job_tree, jobs, fj);
 
                log_debug("%s: %s", __func__, fj->cmd);
 
@@ -337,6 +348,29 @@ format_job_timer(__unused int fd, __unused short events, __unused void *arg)
 
                free(fj);
        }
+}
+
+/* Remove old jobs for client. */
+void
+format_lost_client(struct client *c)
+{
+       if (c->jobs != NULL)
+               format_job_tidy(c->jobs, 1);
+       free(c->jobs);
+}
+
+/* Remove old jobs periodically. */
+static void
+format_job_timer(__unused int fd, __unused short events, __unused void *arg)
+{
+       struct client   *c;
+       struct timeval   tv = { .tv_sec = 60 };
+
+       format_job_tidy(&format_jobs, 0);
+       TAILQ_FOREACH(c, &clients, entry) {
+               if (c->jobs != NULL)
+                       format_job_tidy(c->jobs, 0);
+       }
 
        evtimer_del(&format_job_event);
        evtimer_add(&format_job_event, &tv);
@@ -533,7 +567,7 @@ format_merge(struct format_tree *ft, struct format_tree *from)
 
 /* Create a new tree. */
 struct format_tree *
-format_create(struct cmdq_item *item, int tag, int flags)
+format_create(struct client *c, struct cmdq_item *item, int tag, int flags)
 {
        struct format_tree      *ft;
 
@@ -545,6 +579,11 @@ format_create(struct cmdq_item *item, int tag, int flags)
        ft = xcalloc(1, sizeof *ft);
        RB_INIT(&ft->tree);
 
+       if (c != NULL) {
+               ft->client = c;
+               ft->client->references++;
+       }
+
        ft->tag = tag;
        ft->flags = flags;
 
@@ -577,6 +616,8 @@ format_free(struct format_tree *ft)
                free(fe);
        }
 
+       if (ft->client != NULL)
+               server_client_unref(ft->client);
        free(ft);
 }
 
@@ -1099,7 +1140,10 @@ format_single(struct cmdq_item *item, const char *fmt, struct client *c,
        struct format_tree      *ft;
        char                    *expanded;
 
-       ft = format_create(item, FORMAT_NONE, 0);
+       if (item != NULL)
+               ft = format_create(item->client, item, FORMAT_NONE, 0);
+       else
+               ft = format_create(NULL, item, FORMAT_NONE, 0);
        format_defaults(ft, c, s, wl, wp);
 
        expanded = format_expand(ft, fmt);
index 7d446b6..9fa8d0c 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: names.c,v 1.39 2017/02/03 11:57:27 nicm Exp $ */
+/* $OpenBSD: names.c,v 1.40 2017/05/01 12:20:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -124,7 +124,7 @@ format_window_name(struct window *w)
        const char              *fmt;
        char                    *name;
 
-       ft = format_create(NULL, FORMAT_WINDOW|w->id, 0);
+       ft = format_create(NULL, NULL, FORMAT_WINDOW|w->id, 0);
        format_defaults_window(ft, w);
        format_defaults_pane(ft, w->active);
 
index a86e043..6af19b8 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: screen-redraw.c,v 1.45 2017/04/05 10:49:46 nicm Exp $ */
+/* $OpenBSD: screen-redraw.c,v 1.46 2017/05/01 12:20:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -280,7 +280,7 @@ screen_redraw_make_pane_status(struct client *c, struct window *w,
 
        fmt = options_get_string(w->options, "pane-border-format");
 
-       ft = format_create(NULL, FORMAT_PANE|wp->id, 0);
+       ft = format_create(c, NULL, FORMAT_PANE|wp->id, 0);
        format_defaults(ft, c, NULL, NULL, wp);
 
        memcpy(&old, &wp->status_screen, sizeof old);
index d16b15a..ce9956d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: server-client.c,v 1.227 2017/04/22 08:56:24 nicm Exp $ */
+/* $OpenBSD: server-client.c,v 1.228 2017/05/01 12:20:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -283,6 +283,7 @@ server_client_lost(struct client *c)
        free(c->prompt_string);
        free(c->prompt_buffer);
 
+       format_lost_client(c);
        environ_free(c->environ);
 
        proc_remove_peer(c->peer);
@@ -1326,7 +1327,7 @@ server_client_set_title(struct client *c)
 
        template = options_get_string(s->options, "set-titles-string");
 
-       ft = format_create(NULL, FORMAT_NONE, 0);
+       ft = format_create(c, NULL, FORMAT_NONE, 0);
        format_defaults(ft, c, NULL, NULL, NULL);
 
        title = format_expand_time(ft, template, time(NULL));
index d1d4bab..c82f69c 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: status.c,v 1.163 2017/04/22 12:55:06 nicm Exp $ */
+/* $OpenBSD: status.c,v 1.164 2017/05/01 12:20:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -519,9 +519,9 @@ status_replace(struct client *c, struct winlink *wl, const char *fmt, time_t t)
        else
                tag = FORMAT_NONE;
        if (c->flags & CLIENT_STATUSFORCE)
-               ft = format_create(NULL, tag, FORMAT_STATUS|FORMAT_FORCE);
+               ft = format_create(c, NULL, tag, FORMAT_STATUS|FORMAT_FORCE);
        else
-               ft = format_create(NULL, tag, FORMAT_STATUS);
+               ft = format_create(c, NULL, tag, FORMAT_STATUS);
        format_defaults(ft, c, NULL, wl, NULL);
 
        expanded = format_expand_time(ft, fmt, t);
@@ -663,7 +663,7 @@ status_prompt_set(struct client *c, const char *msg, const char *input,
        time_t                   t;
        char                    *tmp;
 
-       ft = format_create(NULL, FORMAT_NONE, 0);
+       ft = format_create(c, NULL, FORMAT_NONE, 0);
        format_defaults(ft, c, NULL, NULL, NULL);
 
        t = time(NULL);
@@ -724,7 +724,7 @@ status_prompt_update(struct client *c, const char *msg, const char *input)
        time_t                   t;
        char                    *tmp;
 
-       ft = format_create(NULL, FORMAT_NONE, 0);
+       ft = format_create(c, NULL, FORMAT_NONE, 0);
        format_defaults(ft, c, NULL, NULL, NULL);
 
        t = time(NULL);
index d5aef57..fa09693 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.755 2017/04/28 19:13:55 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.756 2017/05/01 12:20:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -43,6 +43,7 @@ struct client;
 struct cmdq_item;
 struct cmdq_list;
 struct environ;
+struct format_job_tree;
 struct input_ctx;
 struct mode_key_cmdstr;
 struct mouse_event;
@@ -1290,6 +1291,7 @@ struct client {
        struct timeval   activity_time;
 
        struct environ  *environ;
+       struct format_job_tree  *jobs;
 
        char            *title;
        const char      *cwd;
@@ -1501,7 +1503,8 @@ char              *paste_make_sample(struct paste_buffer *);
 #define FORMAT_PANE 0x80000000U
 #define FORMAT_WINDOW 0x40000000U
 struct format_tree;
-struct format_tree *format_create(struct cmdq_item *, int, int);
+struct format_tree *format_create(struct client *, struct cmdq_item *, int,
+                    int);
 void            format_free(struct format_tree *);
 void printflike(3, 4) format_add(struct format_tree *, const char *,
                     const char *, ...);
@@ -1517,6 +1520,7 @@ void               format_defaults_pane(struct format_tree *,
                     struct window_pane *);
 void            format_defaults_paste_buffer(struct format_tree *,
                     struct paste_buffer *);
+void            format_lost_client(struct client *);
 
 /* hooks.c */
 struct hook;
index f157ccf..80b3de3 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: window-choose.c,v 1.89 2017/04/28 19:13:55 nicm Exp $ */
+/* $OpenBSD: window-choose.c,v 1.90 2017/05/01 12:20:55 nicm Exp $ */
 
 /*
  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -202,7 +202,7 @@ window_choose_data_create(int type, struct client *c, struct session *s)
        wcd = xmalloc(sizeof *wcd);
        wcd->type = type;
 
-       wcd->ft = format_create(NULL, FORMAT_NONE, 0);
+       wcd->ft = format_create(c, NULL, FORMAT_NONE, 0);
        wcd->ft_template = NULL;
 
        wcd->command = NULL;