Add simple searching (C-s and n) to the various choose modes: by name
authornicm <nicm@openbsd.org>
Wed, 7 Jun 2017 14:37:30 +0000 (14:37 +0000)
committernicm <nicm@openbsd.org>
Wed, 7 Jun 2017 14:37:30 +0000 (14:37 +0000)
for client and tree, and by name and content for buffer.

usr.bin/tmux/mode-tree.c
usr.bin/tmux/tmux.1
usr.bin/tmux/tmux.h
usr.bin/tmux/window-buffer.c
usr.bin/tmux/window-client.c
usr.bin/tmux/window-tree.c

index dbd4d36..d7e0957 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: mode-tree.c,v 1.2 2017/06/04 15:36:33 nicm Exp $ */
+/* $OpenBSD: mode-tree.c,v 1.3 2017/06/07 14:37:30 nicm Exp $ */
 
 /*
  * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -29,6 +29,9 @@ struct mode_tree_item;
 TAILQ_HEAD(mode_tree_list, mode_tree_item);
 
 struct mode_tree_data {
+       int                       dead;
+       u_int                     references;
+
        struct window_pane       *wp;
        void                     *modedata;
 
@@ -38,6 +41,7 @@ struct mode_tree_data {
 
        void                     (*buildcb)(void *, u_int, uint64_t *);
        struct screen           *(*drawcb)(void *, void *, u_int, u_int);
+       int                      (*searchcb)(void*, void *, const char *);
 
        struct mode_tree_list     children;
        struct mode_tree_list     saved;
@@ -54,6 +58,8 @@ struct mode_tree_data {
        u_int                     current;
 
        struct screen             screen;
+
+       char                     *ss;
 };
 
 struct mode_tree_item {
@@ -171,6 +177,27 @@ mode_tree_clear_tagged(struct mode_tree_list *mtl)
        }
 }
 
+static void
+mode_tree_set_current(struct mode_tree_data *mtd, uint64_t tag)
+{
+       u_int   i;
+
+       for (i = 0; i < mtd->line_size; i++) {
+               if (mtd->line_list[i].item->tag == tag)
+                       break;
+       }
+       if (i != mtd->line_size) {
+               mtd->current = i;
+               if (mtd->current > mtd->height - 1)
+                       mtd->offset = 1 + mtd->current - mtd->height;
+               else
+                       mtd->offset = 0;
+       } else {
+               mtd->current = 0;
+               mtd->offset = 0;
+       }
+}
+
 void
 mode_tree_up(struct mode_tree_data *mtd, int wrap)
 {
@@ -248,11 +275,14 @@ mode_tree_each_tagged(struct mode_tree_data *mtd, void (*cb)(void *, void *,
 struct mode_tree_data *
 mode_tree_start(struct window_pane *wp, void (*buildcb)(void *, u_int,
     uint64_t *), struct screen *(*drawcb)(void *, void *, u_int, u_int),
-    void *modedata, const char **sort_list, u_int sort_size, struct screen **s)
+    int (*searchcb)(void *, void *, const char *), void *modedata,
+    const char **sort_list, u_int sort_size, struct screen **s)
 {
        struct mode_tree_data   *mtd;
 
        mtd = xcalloc(1, sizeof *mtd);
+       mtd->references = 1;
+
        mtd->wp = wp;
        mtd->modedata = modedata;
 
@@ -262,6 +292,7 @@ mode_tree_start(struct window_pane *wp, void (*buildcb)(void *, u_int,
 
        mtd->buildcb = buildcb;
        mtd->drawcb = drawcb;
+       mtd->searchcb = searchcb;
 
        TAILQ_INIT(&mtd->children);
 
@@ -277,7 +308,6 @@ mode_tree_build(struct mode_tree_data *mtd)
 {
        struct screen   *s = &mtd->screen;
        uint64_t         tag;
-       u_int            i;
 
        if (mtd->line_list != NULL)
                tag = mtd->line_list[mtd->current].item->tag;
@@ -295,16 +325,7 @@ mode_tree_build(struct mode_tree_data *mtd)
        mode_tree_clear_lines(mtd);
        mode_tree_build_lines(mtd, &mtd->children, 0);
 
-       for (i = 0; i < mtd->line_size; i++) {
-               if (mtd->line_list[i].item->tag == tag)
-                       break;
-       }
-       if (i != mtd->line_size)
-               mtd->current = i;
-       else {
-               mtd->current = 0;
-               mtd->offset = 0;
-       }
+       mode_tree_set_current(mtd, tag);
 
        mtd->width = screen_size_x(s);
        mtd->height = (screen_size_y(s) / 3) * 2;
@@ -316,13 +337,22 @@ mode_tree_build(struct mode_tree_data *mtd)
                mtd->height = screen_size_y(s);
 }
 
+static void
+mode_tree_remove_ref(struct mode_tree_data *mtd)
+{
+       if (--mtd->references == 0)
+               free(mtd);
+}
+
 void
 mode_tree_free(struct mode_tree_data *mtd)
 {
        mode_tree_free_items(&mtd->children);
        mode_tree_clear_lines(mtd);
        screen_free(&mtd->screen);
-       free(mtd);
+
+       mtd->dead = 1;
+       mode_tree_remove_ref(mtd);
 }
 
 void
@@ -529,8 +559,98 @@ mode_tree_draw(struct mode_tree_data *mtd)
        screen_write_stop(&ctx);
 }
 
+static struct mode_tree_item *
+mode_tree_search_for(struct mode_tree_data *mtd)
+{
+       struct mode_tree_item   *mti, *last, *next;
+
+       if (mtd->ss == NULL)
+               return (NULL);
+
+       mti = last = mtd->line_list[mtd->current].item;
+       for (;;) {
+               if (!TAILQ_EMPTY(&mti->children))
+                       mti = TAILQ_FIRST(&mti->children);
+               else if ((next = TAILQ_NEXT(mti, entry)) != NULL)
+                       mti = next;
+               else {
+                       for (;;) {
+                               mti = mti->parent;
+                               if (mti == NULL)
+                                       break;
+                               if ((next = TAILQ_NEXT(mti, entry)) != NULL) {
+                                       mti = next;
+                                       break;
+                               }
+                       }
+               }
+               if (mti == NULL)
+                       mti = TAILQ_FIRST(&mtd->children);
+               if (mti == last)
+                       break;
+
+               if (mtd->searchcb == NULL) {
+                       if (strstr(mti->name, mtd->ss) != NULL)
+                               return (mti);
+                       continue;
+               }
+               if (mtd->searchcb(mtd->modedata, mti->itemdata, mtd->ss))
+                   return (mti);
+       }
+       return (NULL);
+}
+
+static void
+mode_tree_search_set(struct mode_tree_data *mtd)
+{
+       struct mode_tree_item   *mti, *loop;
+       uint64_t                 tag;
+
+       mti = mode_tree_search_for(mtd);
+       if (mti == NULL)
+               return;
+       tag = mti->tag;
+
+       loop = mti->parent;
+       while (loop != NULL) {
+               loop->expanded = 1;
+               loop = loop->parent;
+       }
+       mode_tree_build(mtd);
+
+       mode_tree_set_current(mtd, tag);
+       mode_tree_draw(mtd);
+}
+
+static int
+mode_tree_search_callback(__unused struct client *c, void *data, const char *s,
+    __unused int done)
+{
+       struct mode_tree_data   *mtd = data;
+
+       if (mtd->dead)
+               return (0);
+
+       free(mtd->ss);
+       if (*s == '\0') {
+               mtd->ss = NULL;
+               return (0);
+       }
+       mtd->ss = xstrdup(s);
+       mode_tree_search_set(mtd);
+
+       return (0);
+}
+
+static void
+mode_tree_search_free(void *data)
+{
+       mode_tree_remove_ref(data);
+}
+
 int
-mode_tree_key(struct mode_tree_data *mtd, key_code *key, struct mouse_event *m)
+mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
+    struct mouse_event *m)
 {
        struct mode_tree_line   *line;
        struct mode_tree_item   *current, *parent;
@@ -672,6 +792,15 @@ mode_tree_key(struct mode_tree_data *mtd, key_code *key, struct mouse_event *m)
                        mode_tree_build(mtd);
                }
                break;
+       case '\023': /* C-s */
+               mtd->references++;
+               status_prompt_set(c, "(search) ", "",
+                   mode_tree_search_callback, mode_tree_search_free, mtd,
+                   PROMPT_NOFORMAT);
+               break;
+       case 'n':
+               mode_tree_search_set(mtd);
+               break;
        }
        return (0);
 }
index 5fc01f3..00f59f2 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tmux.1,v 1.558 2017/06/04 08:25:57 nicm Exp $
+.\" $OpenBSD: tmux.1,v 1.559 2017/06/07 14:37:30 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: June 4 2017 $
+.Dd $Mdocdate: June 7 2017 $
 .Dt TMUX 1
 .Os
 .Sh NAME
@@ -1365,6 +1365,8 @@ The following keys may be used in client mode:
 .It Li "Enter" Ta "Choose selected client"
 .It Li "Up" Ta "Select previous client"
 .It Li "Down" Ta "Select next client"
+.It Li "C-s" Ta "Search by name"
+.It Li "n" Ta "Repeat last search"
 .It Li "t" Ta "Toggle if client is tagged"
 .It Li "T" Ta "Tag no clients"
 .It Li "C-t" Ta "Tag all clients"
@@ -1406,6 +1408,8 @@ The following keys may be used in tree mode:
 .It Li "Enter" Ta "Choose selected item"
 .It Li "Up" Ta "Select previous item"
 .It Li "Down" Ta "Select next item"
+.It Li "C-s" Ta "Search by name"
+.It Li "n" Ta "Repeat last search"
 .It Li "t" Ta "Toggle if item is tagged"
 .It Li "T" Ta "Tag no items"
 .It Li "C-t" Ta "Tag all items"
@@ -3958,6 +3962,8 @@ The following keys may be used in buffer mode:
 .It Li "Enter" Ta "Choose selected buffer"
 .It Li "Up" Ta "Select previous buffer"
 .It Li "Down" Ta "Select next buffer"
+.It Li "C-s" Ta "Search by name or content"
+.It Li "n" Ta "Repeat last search"
 .It Li "t" Ta "Toggle if buffer is tagged"
 .It Li "T" Ta "Tag no buffers"
 .It Li "C-t" Ta "Tag all buffers"
index b80ee65..96cbf39 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.781 2017/06/04 09:02:36 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.782 2017/06/07 14:37:30 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -2203,8 +2203,8 @@ void       mode_tree_up(struct mode_tree_data *, int);
 void    mode_tree_down(struct mode_tree_data *, int);
 struct mode_tree_data *mode_tree_start(struct window_pane *,
             void (*)(void *, u_int, uint64_t *), struct screen *(*)(void *,
-            void *, u_int, u_int), void *, const char **, u_int,
-            struct screen **);
+            void *, u_int, u_int), int (*)(void *, void *, const char *),
+            void *, const char **, u_int, struct screen **);
 void    mode_tree_build(struct mode_tree_data *);
 void    mode_tree_free(struct mode_tree_data *);
 void    mode_tree_resize(struct mode_tree_data *, u_int, u_int);
@@ -2213,7 +2213,7 @@ struct mode_tree_item *mode_tree_add(struct mode_tree_data *,
             const char *, int);
 void    mode_tree_remove(struct mode_tree_data *, struct mode_tree_item *);
 void    mode_tree_draw(struct mode_tree_data *);
-int     mode_tree_key(struct mode_tree_data *, key_code *,
+int     mode_tree_key(struct mode_tree_data *, struct client *, key_code *,
             struct mouse_event *);
 void    mode_tree_run_command(struct client *, struct cmd_find_state *,
             const char *, const char *);
index 0782227..9ef3ea8 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: window-buffer.c,v 1.3 2017/05/31 17:56:48 nicm Exp $ */
+/* $OpenBSD: window-buffer.c,v 1.4 2017/06/07 14:37:30 nicm Exp $ */
 
 /*
  * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -227,6 +227,22 @@ window_buffer_draw(__unused void *modedata, void *itemdata, u_int sx, u_int sy)
        return (&s);
 }
 
+static int
+window_buffer_search(__unused void *modedata, void *itemdata, const char *ss)
+{
+       struct window_buffer_itemdata   *item = itemdata;
+       struct paste_buffer             *pb;
+       const char                      *bufdata;
+       size_t                           bufsize;
+
+       if ((pb = paste_get_name(item->name)) == NULL)
+               return (0);
+       if (strstr(item->name, ss) != NULL)
+               return (0);
+       bufdata = paste_buffer_data(pb, &bufsize);
+       return (memmem(bufdata, bufsize, ss, strlen(ss)) != NULL);
+}
+
 static struct screen *
 window_buffer_init(struct window_pane *wp, __unused struct cmd_find_state *fs,
     struct args *args)
@@ -242,8 +258,8 @@ window_buffer_init(struct window_pane *wp, __unused struct cmd_find_state *fs,
                data->command = xstrdup(args->argv[0]);
 
        data->data = mode_tree_start(wp, window_buffer_build,
-           window_buffer_draw, data, window_buffer_sort_list,
-           nitems(window_buffer_sort_list), &s);
+           window_buffer_draw, window_buffer_search, data,
+           window_buffer_sort_list, nitems(window_buffer_sort_list), &s);
 
        mode_tree_build(data->data);
        mode_tree_draw(data->data);
@@ -312,7 +328,7 @@ window_buffer_key(struct window_pane *wp, struct client *c,
         * Enter = paste buffer
         */
 
-       finished = mode_tree_key(data->data, &key, m);
+       finished = mode_tree_key(data->data, c, &key, m);
        switch (key) {
        case 'd':
                item = mode_tree_get_current(data->data);
index 585435b..6cc2b05 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: window-client.c,v 1.2 2017/05/31 15:27:57 nicm Exp $ */
+/* $OpenBSD: window-client.c,v 1.3 2017/06/07 14:37:30 nicm Exp $ */
 
 /*
  * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -224,7 +224,7 @@ window_client_init(struct window_pane *wp, __unused struct cmd_find_state *fs,
                data->command = xstrdup(args->argv[0]);
 
        data->data = mode_tree_start(wp, window_client_build,
-           window_client_draw, data, window_client_sort_list,
+           window_client_draw, NULL, data, window_client_sort_list,
            nitems(window_client_sort_list), &s);
 
        mode_tree_build(data->data);
@@ -301,7 +301,7 @@ window_client_key(struct window_pane *wp, struct client *c,
         * Enter = detach client
         */
 
-       finished = mode_tree_key(data->data, &key, m);
+       finished = mode_tree_key(data->data, c, &key, m);
        switch (key) {
        case 'd':
        case 'x':
index 9f7d930..fea3279 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: window-tree.c,v 1.2 2017/06/06 15:07:35 nicm Exp $ */
+/* $OpenBSD: window-tree.c,v 1.3 2017/06/07 14:37:30 nicm Exp $ */
 
 /*
  * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -440,6 +440,39 @@ window_tree_draw(__unused void *modedata, void *itemdata, u_int sx, u_int sy)
        return (&s);
 }
 
+static int
+window_tree_search(__unused void *modedata, void *itemdata, const char *ss)
+{
+       struct window_tree_itemdata     *item = itemdata;
+       struct session                  *s;
+       struct winlink                  *wl;
+       struct window_pane              *wp;
+       const char                      *cmd;
+
+       window_tree_pull_item(item, &s, &wl, &wp);
+
+       switch (item->type) {
+       case WINDOW_TREE_NONE:
+               return (0);
+       case WINDOW_TREE_SESSION:
+               if (s == NULL)
+                       return (0);
+               return (strstr(s->name, ss) != NULL);
+       case WINDOW_TREE_WINDOW:
+               if (s == NULL || wl == NULL)
+                       return (0);
+               return (strstr(wl->window->name, ss) != NULL);
+       case WINDOW_TREE_PANE:
+               if (s == NULL || wl == NULL || wp == NULL)
+                       break;
+               cmd = get_proc_name(wp->fd, wp->tty);
+               if (cmd == NULL || *cmd == '\0')
+                       return (0);
+               return (strstr(cmd, ss) != NULL);
+       }
+       return (0);
+}
+
 static struct screen *
 window_tree_init(struct window_pane *wp, struct cmd_find_state *fs,
     struct args *args)
@@ -470,8 +503,8 @@ window_tree_init(struct window_pane *wp, struct cmd_find_state *fs,
        else
                data->command = xstrdup(args->argv[0]);
 
-       data->data = mode_tree_start(wp, window_tree_build,
-           window_tree_draw, data, window_tree_sort_list,
+       data->data = mode_tree_start(wp, window_tree_build, window_tree_draw,
+           window_tree_search, data, window_tree_sort_list,
            nitems(window_tree_sort_list), &s);
 
        mode_tree_build(data->data);
@@ -674,7 +707,7 @@ window_tree_key(struct window_pane *wp, struct client *c,
         * f = enter filter
         */
 
-       finished = mode_tree_key(data->data, &key, m);
+       finished = mode_tree_key(data->data, c, &key, m);
        switch (key) {
        case 'f':
                data->references++;