Add a session, pane and user mouse range types for the status line and
authornicm <nicm@openbsd.org>
Thu, 17 Aug 2023 14:10:28 +0000 (14:10 +0000)
committernicm <nicm@openbsd.org>
Thu, 17 Aug 2023 14:10:28 +0000 (14:10 +0000)
add format variables for mouse_status_line and mouse_status_range so
they can be associated with different commands in the key bindings.
GitHub issue 3652.

usr.bin/tmux/cmd.c
usr.bin/tmux/format-draw.c
usr.bin/tmux/format.c
usr.bin/tmux/server-client.c
usr.bin/tmux/style.c
usr.bin/tmux/tmux.1
usr.bin/tmux/tmux.h

index bd6a090..f5c71fb 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd.c,v 1.174 2022/05/30 12:48:57 nicm Exp $ */
+/* $OpenBSD: cmd.c,v 1.175 2023/08/17 14:10:28 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -813,10 +813,14 @@ cmd_mouse_pane(struct mouse_event *m, struct session **sp,
 
        if ((wl = cmd_mouse_window(m, sp)) == NULL)
                return (NULL);
-       if ((wp = window_pane_find_by_id(m->wp)) == NULL)
-               return (NULL);
-       if (!window_has_pane(wl->window, wp))
-               return (NULL);
+       if (m->wp == -1)
+               wp = wl->window->active;
+       else {
+               if ((wp = window_pane_find_by_id(m->wp)) == NULL)
+                       return (NULL);
+               if (!window_has_pane(wl->window, wp))
+                       return (NULL);
+       }
 
        if (wlp != NULL)
                *wlp = wl;
index ba3a011..f05cdb0 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: format-draw.c,v 1.27 2023/08/07 10:04:29 nicm Exp $ */
+/* $OpenBSD: format-draw.c,v 1.28 2023/08/17 14:10:28 nicm Exp $ */
 
 /*
  * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -33,6 +33,7 @@ struct format_range {
 
        enum style_range_type            type;
        u_int                            argument;
+       char                             string[16];
 
        TAILQ_ENTRY(format_range)        entry;
 };
@@ -44,9 +45,18 @@ format_is_type(struct format_range *fr, struct style *sy)
 {
        if (fr->type != sy->range_type)
                return (0);
-       if (fr->type == STYLE_RANGE_WINDOW &&
-           fr->argument != sy->range_argument)
-               return (0);
+       switch (fr->type) {
+       case STYLE_RANGE_NONE:
+       case STYLE_RANGE_LEFT:
+       case STYLE_RANGE_RIGHT:
+               return (1);
+       case STYLE_RANGE_PANE:
+       case STYLE_RANGE_WINDOW:
+       case STYLE_RANGE_SESSION:
+               return (fr->argument == sy->range_argument);
+       case STYLE_RANGE_USER:
+               return (strcmp(fr->string, sy->range_string) == 0);
+       }
        return (1);
 }
 
@@ -942,6 +952,8 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
 
                                fr->type = sy.range_type;
                                fr->argument = sy.range_argument;
+                               strlcpy(fr->string, sy.range_string,
+                                   sizeof fr->string);
                        }
                }
 
@@ -1013,13 +1025,39 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
                sr = xcalloc(1, sizeof *sr);
                sr->type = fr->type;
                sr->argument = fr->argument;
+               strlcpy(sr->string, fr->string, sizeof sr->string);
                sr->start = fr->start;
                sr->end = fr->end;
                TAILQ_INSERT_TAIL(srs, sr, entry);
 
-               log_debug("%s: range %d|%u at %u-%u", __func__, sr->type,
-                   sr->argument, sr->start, sr->end);
-
+               switch (sr->type) {
+               case STYLE_RANGE_NONE:
+                       break;
+               case STYLE_RANGE_LEFT:
+                       log_debug("%s: range left at %u-%u", __func__,
+                           sr->start, sr->end);
+                       break;
+               case STYLE_RANGE_RIGHT:
+                       log_debug("%s: range right at %u-%u", __func__,
+                           sr->start, sr->end);
+                       break;
+               case STYLE_RANGE_PANE:
+                       log_debug("%s: range pane|%%%u at %u-%u", __func__,
+                           sr->argument, sr->start, sr->end);
+                       break;
+               case STYLE_RANGE_WINDOW:
+                       log_debug("%s: range window|%u at %u-%u", __func__,
+                           sr->argument, sr->start, sr->end);
+                       break;
+               case STYLE_RANGE_SESSION:
+                       log_debug("%s: range session|$%u at %u-%u", __func__,
+                           sr->argument, sr->start, sr->end);
+                       break;
+               case STYLE_RANGE_USER:
+                       log_debug("%s: range user|%u at %u-%u", __func__,
+                           sr->argument, sr->start, sr->end);
+                       break;
+               }
                format_free_range(&frs, fr);
        }
 
index ff1293e..430bb35 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: format.c,v 1.316 2023/07/10 09:24:53 nicm Exp $ */
+/* $OpenBSD: format.c,v 1.317 2023/08/17 14:10:28 nicm Exp $ */
 
 /*
  * Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1191,6 +1191,72 @@ format_cb_mouse_line(struct format_tree *ft)
        return (format_grid_line(gd, gd->hsize + y));
 }
 
+/* Callback for mouse_status_line. */
+static void *
+format_cb_mouse_status_line(struct format_tree *ft)
+{
+       char    *value;
+       u_int    y;
+
+       if (!ft->m.valid)
+               return (NULL);
+       if (ft->c == NULL || (~ft->c->tty.flags & TTY_STARTED))
+               return (NULL);
+
+       if (ft->m.statusat == 0 && ft->m.y < ft->m.statuslines) {
+               y = ft->m.y;
+       } else if (ft->m.statusat > 0 && ft->m.y >= (u_int)ft->m.statusat) {
+               y = ft->m.y - ft->m.statusat;
+       } else
+               return (NULL);
+       xasprintf(&value, "%u", y);
+       return (value);
+
+}
+
+/* Callback for mouse_status_range. */
+static void *
+format_cb_mouse_status_range(struct format_tree *ft)
+{
+       struct style_range      *sr;
+       u_int                    x, y;
+
+       if (!ft->m.valid)
+               return (NULL);
+       if (ft->c == NULL || (~ft->c->tty.flags & TTY_STARTED))
+               return (NULL);
+
+       if (ft->m.statusat == 0 && ft->m.y < ft->m.statuslines) {
+               x = ft->m.x;
+               y = ft->m.y;
+       } else if (ft->m.statusat > 0 && ft->m.y >= (u_int)ft->m.statusat) {
+               x = ft->m.x;
+               y = ft->m.y - ft->m.statusat;
+       } else
+               return (NULL);
+
+       sr = status_get_range(ft->c, x, y);
+       if (sr == NULL)
+               return (NULL);
+       switch (sr->type) {
+       case STYLE_RANGE_NONE:
+               return (NULL);
+       case STYLE_RANGE_LEFT:
+               return (xstrdup("left"));
+       case STYLE_RANGE_RIGHT:
+               return (xstrdup("right"));
+       case STYLE_RANGE_PANE:
+               return (xstrdup("pane"));
+       case STYLE_RANGE_WINDOW:
+               return (xstrdup("window"));
+       case STYLE_RANGE_SESSION:
+               return (xstrdup("session"));
+       case STYLE_RANGE_USER:
+               return (xstrdup(sr->string));
+       }
+       return (NULL);
+}
+
 /* Callback for alternate_on. */
 static void *
 format_cb_alternate_on(struct format_tree *ft)
@@ -2848,6 +2914,12 @@ static const struct format_table_entry format_table[] = {
        { "mouse_standard_flag", FORMAT_TABLE_STRING,
          format_cb_mouse_standard_flag
        },
+       { "mouse_status_line", FORMAT_TABLE_STRING,
+         format_cb_mouse_status_line
+       },
+       { "mouse_status_range", FORMAT_TABLE_STRING,
+         format_cb_mouse_status_range
+       },
        { "mouse_utf8_flag", FORMAT_TABLE_STRING,
          format_cb_mouse_utf8_flag
        },
index a28cf5a..c57e57e 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: server-client.c,v 1.400 2023/02/05 21:15:32 nicm Exp $ */
+/* $OpenBSD: server-client.c,v 1.401 2023/08/17 14:10:28 nicm Exp $ */
 
 /*
  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -564,9 +564,9 @@ static key_code
 server_client_check_mouse(struct client *c, struct key_event *event)
 {
        struct mouse_event      *m = &event->m;
-       struct session          *s = c->session;
-       struct winlink          *wl;
-       struct window_pane      *wp;
+       struct session          *s = c->session, *fs;
+       struct winlink          *fwl;
+       struct window_pane      *wp, *fwp;
        u_int                    x, y, b, sx, sy, px, py;
        int                      ignore = 0;
        key_code                 key;
@@ -672,6 +672,7 @@ have_event:
        /* Save the session. */
        m->s = s->id;
        m->w = -1;
+       m->wp = -1;
        m->ignore = ignore;
 
        /* Is this on the status line? */
@@ -688,18 +689,42 @@ have_event:
                        case STYLE_RANGE_NONE:
                                return (KEYC_UNKNOWN);
                        case STYLE_RANGE_LEFT:
+                               log_debug("mouse range: left");
                                where = STATUS_LEFT;
                                break;
                        case STYLE_RANGE_RIGHT:
+                               log_debug("mouse range: right");
                                where = STATUS_RIGHT;
                                break;
+                       case STYLE_RANGE_PANE:
+                               fwp = window_pane_find_by_id(sr->argument);
+                               if (fwp == NULL)
+                                       return (KEYC_UNKNOWN);
+                               m->wp = sr->argument;
+
+                               log_debug("mouse range: pane %%%u", m->wp);
+                               where = STATUS;
+                               break;
                        case STYLE_RANGE_WINDOW:
-                               wl = winlink_find_by_index(&s->windows,
+                               fwl = winlink_find_by_index(&s->windows,
                                    sr->argument);
-                               if (wl == NULL)
+                               if (fwl == NULL)
                                        return (KEYC_UNKNOWN);
-                               m->w = wl->window->id;
+                               m->w = fwl->window->id;
 
+                               log_debug("mouse range: window @%u", m->w);
+                               where = STATUS;
+                               break;
+                       case STYLE_RANGE_SESSION:
+                               fs = session_find_by_id(sr->argument);
+                               if (fs == NULL)
+                                       return (KEYC_UNKNOWN);
+                               m->s = sr->argument;
+
+                               log_debug("mouse range: session $%u", m->s);
+                               where = STATUS;
+                               break;
+                       case STYLE_RANGE_USER:
                                where = STATUS;
                                break;
                        }
index 7fec0b3..cb507c2 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: style.c,v 1.32 2023/06/26 07:17:40 nicm Exp $ */
+/* $OpenBSD: style.c,v 1.33 2023/08/17 14:10:28 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -37,11 +37,18 @@ static struct style style_default = {
        STYLE_ALIGN_DEFAULT,
        STYLE_LIST_OFF,
 
-       STYLE_RANGE_NONE, 0,
+       STYLE_RANGE_NONE, 0, "",
 
        STYLE_DEFAULT_BASE
 };
 
+/* Set range string. */
+static void
+style_set_range_string(struct style *sy, const char *s)
+{
+       strlcpy(sy->range_string, s, sizeof sy->range_string);
+}
+
 /*
  * Parse an embedded style of the form "fg=colour,bg=colour,bright,...".  Note
  * that this adds onto the given style, so it must have been initialized
@@ -104,32 +111,67 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
                } else if (strcasecmp(tmp, "norange") == 0) {
                        sy->range_type = style_default.range_type;
                        sy->range_argument = style_default.range_type;
+                       strlcpy(sy->range_string, style_default.range_string,
+                           sizeof sy->range_string);
                } else if (end > 6 && strncasecmp(tmp, "range=", 6) == 0) {
                        found = strchr(tmp + 6, '|');
                        if (found != NULL) {
                                *found++ = '\0';
                                if (*found == '\0')
                                        goto error;
-                               for (cp = found; *cp != '\0'; cp++) {
-                                       if (!isdigit((u_char)*cp))
-                                               goto error;
-                               }
                        }
                        if (strcasecmp(tmp + 6, "left") == 0) {
                                if (found != NULL)
                                        goto error;
                                sy->range_type = STYLE_RANGE_LEFT;
                                sy->range_argument = 0;
+                               style_set_range_string(sy, "");
                        } else if (strcasecmp(tmp + 6, "right") == 0) {
                                if (found != NULL)
                                        goto error;
                                sy->range_type = STYLE_RANGE_RIGHT;
                                sy->range_argument = 0;
+                               style_set_range_string(sy, "");
+                       } else if (strcasecmp(tmp + 6, "pane") == 0) {
+                               if (found == NULL)
+                                       goto error;
+                               if (*found != '%' || found[1] == '\0')
+                                       goto error;
+                               for (cp = found + 1; *cp != '\0'; cp++) {
+                                       if (!isdigit((u_char)*cp))
+                                               goto error;
+                               }
+                               sy->range_type = STYLE_RANGE_PANE;
+                               sy->range_argument = atoi(found + 1);
+                               style_set_range_string(sy, "");
                        } else if (strcasecmp(tmp + 6, "window") == 0) {
                                if (found == NULL)
                                        goto error;
+                               for (cp = found; *cp != '\0'; cp++) {
+                                       if (!isdigit((u_char)*cp))
+                                               goto error;
+                               }
                                sy->range_type = STYLE_RANGE_WINDOW;
                                sy->range_argument = atoi(found);
+                               style_set_range_string(sy, "");
+                       } else if (strcasecmp(tmp + 6, "session") == 0) {
+                               if (found == NULL)
+                                       goto error;
+                               if (*found != '$' || found[1] == '\0')
+                                       goto error;
+                               for (cp = found + 1; *cp != '\0'; cp++) {
+                                       if (!isdigit((u_char)*cp))
+                                               goto error;
+                               }
+                               sy->range_type = STYLE_RANGE_SESSION;
+                               sy->range_argument = atoi(found + 1);
+                               style_set_range_string(sy, "");
+                       } else if (strcasecmp(tmp + 6, "user") == 0) {
+                               if (found == NULL)
+                                       goto error;
+                               sy->range_type = STYLE_RANGE_USER;
+                               sy->range_argument = 0;
+                               style_set_range_string(sy, found);
                        }
                } else if (strcasecmp(tmp, "noalign") == 0)
                        sy->align = style_default.align;
@@ -222,9 +264,19 @@ style_tostring(struct style *sy)
                        tmp = "left";
                else if (sy->range_type == STYLE_RANGE_RIGHT)
                        tmp = "right";
-               else if (sy->range_type == STYLE_RANGE_WINDOW) {
+               else if (sy->range_type == STYLE_RANGE_PANE) {
+                       snprintf(b, sizeof b, "pane|%%%u", sy->range_argument);
+                       tmp = b;
+               } else if (sy->range_type == STYLE_RANGE_WINDOW) {
                        snprintf(b, sizeof b, "window|%u", sy->range_argument);
                        tmp = b;
+               } else if (sy->range_type == STYLE_RANGE_SESSION) {
+                       snprintf(b, sizeof b, "session|$%u",
+                           sy->range_argument);
+                       tmp = b;
+               } else if (sy->range_type == STYLE_RANGE_USER) {
+                       snprintf(b, sizeof b, "user|%s", sy->range_string);
+                       tmp = b;
                }
                off += xsnprintf(s + off, sizeof s - off, "%srange=%s", comma,
                    tmp);
index 1e43c29..34ee403 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tmux.1,v 1.927 2023/08/15 07:01:47 nicm Exp $
+.\" $OpenBSD: tmux.1,v 1.928 2023/08/17 14:10:28 nicm Exp $
 .\"
 .\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
 .\"
@@ -14,7 +14,7 @@
 .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: August 15 2023 $
+.Dd $Mdocdate: August 17 2023 $
 .Dt TMUX 1
 .Os
 .Sh NAME
@@ -5443,6 +5443,8 @@ The following variables are available, where appropriate:
 .It Li "mouse_line" Ta "" Ta "Line under mouse, if any"
 .It Li "mouse_sgr_flag" Ta "" Ta "Pane mouse SGR flag"
 .It Li "mouse_standard_flag" Ta "" Ta "Pane mouse standard flag"
+.It Li "mouse_status_line" Ta "" Ta "Status line on which mouse event took place"
+.It Li "mouse_status_range" Ta "" Ta "Range type or argument of mouse event on status line"
 .It Li "mouse_utf8_flag" Ta "" Ta "Pane mouse UTF-8 flag"
 .It Li "mouse_word" Ta "" Ta "Word under mouse, if any"
 .It Li "mouse_x" Ta "" Ta "Mouse X position, if any"
@@ -5681,26 +5683,56 @@ Only one default may be pushed (each
 replaces the previous saved default).
 .It Xo Ic range=left ,
 .Ic range=right ,
+.Ic range=session|X ,
 .Ic range=window|X ,
+.Ic range=pane|X ,
+.Ic range=user|X ,
 .Ic norange
 .Xc
-Mark a range in the
+Mark a range for mouse events in the
 .Ic status-format
 option.
+When a mouse event occurs in the
 .Ic range=left
-and
+or
 .Ic range=right
-are the text used for the
+range, the
 .Ql StatusLeft
 and
 .Ql StatusRight
-mouse keys.
+key bindings are triggered.
+.Pp
+.Ic range=session|X ,
 .Ic range=window|X
-is the range for a window passed to the
+and
+.Ic range=pane|X
+are ranges for a session, window or pane.
+These trigger the
 .Ql Status
-mouse key, where
+mouse key with the target session, window or pane given by the
+.Ql X
+argument.
+.Ql X
+is a session ID, window index in the current session or a pane ID.
+For these, the
+.Ic mouse_status_range
+format variable will be set to
+.Ql session ,
+.Ql window
+or
+.Ql pane .
+.Pp
+.Ic range=user|X
+is a user-defined range; it triggers the
+.Ql Status
+mouse key.
+The argument
+.Ql X
+will be available in the
+.Ic mouse_status_range
+format variable.
 .Ql X
-is a window index.
+must be at most 15 bytes in length.
 .El
 .Pp
 Examples are:
index 0ee5813..8a63e8b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.1205 2023/08/15 07:01:47 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.1206 2023/08/17 14:10:28 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -795,11 +795,15 @@ enum style_range_type {
        STYLE_RANGE_NONE,
        STYLE_RANGE_LEFT,
        STYLE_RANGE_RIGHT,
-       STYLE_RANGE_WINDOW
+       STYLE_RANGE_PANE,
+       STYLE_RANGE_WINDOW,
+       STYLE_RANGE_SESSION,
+       STYLE_RANGE_USER
 };
 struct style_range {
        enum style_range_type    type;
        u_int                    argument;
+       char                     string[16];
 
        u_int                    start;
        u_int                    end; /* not included */
@@ -826,6 +830,7 @@ struct style {
 
        enum style_range_type   range_type;
        u_int                   range_argument;
+       char                    range_string[16];
 
        enum style_default_type default_type;
 };