Support case insensitive search in modes in the same way as copy mode

(like emacs, so all-lowercase means case insensitive). GitHub issue
4396.
This commit is contained in:
nicm
2025-10-28 14:21:06 +00:00
parent b4ba6e49af
commit 9bf8ca5856
4 changed files with 108 additions and 42 deletions

View File

@@ -82,6 +82,7 @@ struct mode_tree_data {
char *filter;
int no_matches;
enum mode_tree_search_dir search_dir;
int search_icase;
};
struct mode_tree_item {
@@ -132,6 +133,17 @@ static const struct menu_item mode_tree_menu_items[] = {
{ NULL, KEYC_NONE, NULL }
};
static int
mode_tree_is_lowercase(const char *ptr)
{
while (*ptr != '\0') {
if (*ptr != tolower((u_char)*ptr))
return (0);
++ptr;
}
return (1);
}
static struct mode_tree_item *
mode_tree_find_item(struct mode_tree_list *mtl, uint64_t tag)
{
@@ -882,6 +894,7 @@ static struct mode_tree_item *
mode_tree_search_backward(struct mode_tree_data *mtd)
{
struct mode_tree_item *mti, *last, *prev;
int icase = mtd->search_icase;
if (mtd->search == NULL)
return (NULL);
@@ -890,8 +903,10 @@ mode_tree_search_backward(struct mode_tree_data *mtd)
for (;;) {
if ((prev = TAILQ_PREV(mti, mode_tree_list, entry)) != NULL) {
/* Point to the last child in the previous subtree. */
while (!TAILQ_EMPTY(&prev->children))
prev = TAILQ_LAST(&prev->children, mode_tree_list);
while (!TAILQ_EMPTY(&prev->children)) {
prev = TAILQ_LAST(&prev->children,
mode_tree_list);
}
mti = prev;
} else {
/* If prev is NULL, jump to the parent. */
@@ -901,29 +916,34 @@ mode_tree_search_backward(struct mode_tree_data *mtd)
if (mti == NULL) {
/* Point to the last child in the last root subtree. */
prev = TAILQ_LAST(&mtd->children, mode_tree_list);
while (!TAILQ_EMPTY(&prev->children))
prev = TAILQ_LAST(&prev->children, mode_tree_list);
while (!TAILQ_EMPTY(&prev->children)) {
prev = TAILQ_LAST(&prev->children,
mode_tree_list);
}
mti = prev;
}
if (mti == last)
break;
if (mtd->searchcb == NULL) {
if (strstr(mti->name, mtd->search) != NULL)
if (!icase && strstr(mti->name, mtd->search) != NULL)
return (mti);
if (icase && strcasestr(mti->name, mtd->search) != NULL)
return (mti);
continue;
}
if (mtd->searchcb(mtd->modedata, mti->itemdata, mtd->search))
if (mtd->searchcb(mtd->modedata, mti->itemdata, mtd->search,
icase))
return (mti);
}
return (NULL);
}
static struct mode_tree_item *
mode_tree_search_forward(struct mode_tree_data *mtd)
{
struct mode_tree_item *mti, *last, *next;
int icase = mtd->search_icase;
if (mtd->search == NULL)
return (NULL);
@@ -951,11 +971,14 @@ mode_tree_search_forward(struct mode_tree_data *mtd)
break;
if (mtd->searchcb == NULL) {
if (strstr(mti->name, mtd->search) != NULL)
if (!icase && strstr(mti->name, mtd->search) != NULL)
return (mti);
if (icase && strcasestr(mti->name, mtd->search) != NULL)
return (mti);
continue;
}
if (mtd->searchcb(mtd->modedata, mti->itemdata, mtd->search))
if (mtd->searchcb(mtd->modedata, mti->itemdata, mtd->search,
icase))
return (mti);
}
return (NULL);
@@ -1002,6 +1025,7 @@ mode_tree_search_callback(__unused struct client *c, void *data, const char *s,
return (0);
}
mtd->search = xstrdup(s);
mtd->search_icase = mode_tree_is_lowercase(s);
mode_tree_search_set(mtd);
return (0);
@@ -1309,6 +1333,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
case '/':
case 's'|KEYC_CTRL:
mtd->references++;
mtd->search_dir = MODE_TREE_SEARCH_FORWARD;
status_prompt_set(c, NULL, "(search) ", "",
mode_tree_search_callback, mode_tree_search_free, mtd,
PROMPT_NOFORMAT, PROMPT_TYPE_SEARCH);

2
tmux.h
View File

@@ -3290,7 +3290,7 @@ typedef void (*mode_tree_build_cb)(void *, struct mode_tree_sort_criteria *,
uint64_t *, const char *);
typedef void (*mode_tree_draw_cb)(void *, void *, struct screen_write_ctx *,
u_int, u_int);
typedef int (*mode_tree_search_cb)(void *, void *, const char *);
typedef int (*mode_tree_search_cb)(void *, void *, const char *, int);
typedef void (*mode_tree_menu_cb)(void *, struct client *, key_code);
typedef u_int (*mode_tree_height_cb)(void *, u_int);
typedef key_code (*mode_tree_key_cb)(void *, void *, u_int);

View File

@@ -18,6 +18,7 @@
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -255,7 +256,30 @@ window_buffer_draw(__unused void *modedata, void *itemdata,
}
static int
window_buffer_search(__unused void *modedata, void *itemdata, const char *ss)
window_buffer_find(const void *data, size_t datalen, const void *find,
size_t findlen, int icase)
{
const u_char *udata = data, *ufind = find;
size_t i, j;
if (findlen == 0 || datalen < findlen)
return (0);
for (i = 0; i + findlen <= datalen; i++) {
for (j = 0; j < findlen; j++) {
if (!icase && udata[i + j] != ufind[j])
break;
if (icase && tolower(udata[i + j]) != tolower(ufind[j]))
break;
}
if (j == findlen)
return (1);
}
return (0);
}
static int
window_buffer_search(__unused void *modedata, void *itemdata, const char *ss,
int icase)
{
struct window_buffer_itemdata *item = itemdata;
struct paste_buffer *pb;
@@ -264,10 +288,19 @@ window_buffer_search(__unused void *modedata, void *itemdata, const char *ss)
if ((pb = paste_get_name(item->name)) == NULL)
return (0);
if (icase) {
if (strcasestr(item->name, ss) != NULL)
return (1);
bufdata = paste_buffer_data(pb, &bufsize);
return (window_buffer_find(bufdata, bufsize, ss, strlen(ss),
icase));
} else {
if (strstr(item->name, ss) != NULL)
return (1);
bufdata = paste_buffer_data(pb, &bufsize);
return (memmem(bufdata, bufsize, ss, strlen(ss)) != NULL);
return (window_buffer_find(bufdata, bufsize, ss, strlen(ss),
icase));
}
}
static void

View File

@@ -836,7 +836,8 @@ window_tree_draw(void *modedata, void *itemdata, struct screen_write_ctx *ctx,
}
static int
window_tree_search(__unused void *modedata, void *itemdata, const char *ss)
window_tree_search(__unused void *modedata, void *itemdata, const char *ss,
int icase)
{
struct window_tree_itemdata *item = itemdata;
struct session *s;
@@ -853,10 +854,14 @@ window_tree_search(__unused void *modedata, void *itemdata, const char *ss)
case WINDOW_TREE_SESSION:
if (s == NULL)
return (0);
if (icase)
return (strcasestr(s->name, ss) != NULL);
return (strstr(s->name, ss) != NULL);
case WINDOW_TREE_WINDOW:
if (s == NULL || wl == NULL)
return (0);
if (icase)
return (strcasestr(wl->window->name, ss) != NULL);
return (strstr(wl->window->name, ss) != NULL);
case WINDOW_TREE_PANE:
if (s == NULL || wl == NULL || wp == NULL)
@@ -866,6 +871,9 @@ window_tree_search(__unused void *modedata, void *itemdata, const char *ss)
free(cmd);
return (0);
}
if (icase)
retval = (strcasestr(cmd, ss) != NULL);
else
retval = (strstr(cmd, ss) != NULL);
free(cmd);
return (retval);