fzy
terminal fuzzy finder picker
git clone https://9o.is/git/fzy.git
commit 367350794abb3abe239b11031496002eb7b19152 parent 6fba9f0d661e76b24a16b08857a17238884e2320 Author: Jul <jul@9o.is> Date: Tue, 24 Feb 2026 03:14:38 +0800 complete multiselection Diffstat:
| M | src/choices.c | | | 45 | +++++++++++++++++++++++++++++---------------- |
| M | src/choices.h | | | 3 | +++ |
| M | src/tty_interface.c | | | 6 | +++--- |
3 files changed, 35 insertions(+), 19 deletions(-)
diff --git a/src/choices.c b/src/choices.c @@ -46,6 +46,14 @@ static void *safe_realloc(void *buffer, size_t size) { return buffer; } +static void multiselection_init(choices_t *c) { + c->multiselection_size = 0; + c->multiselections = (unsigned char *) malloc(c->size * sizeof(unsigned char)); + for (size_t i = 0; i < c->size; i++) { + c->multiselections[i] = 0; + } +} + void choices_fread(choices_t *c, FILE *file, char input_delimiter) { /* Save current position for parsing later */ size_t buffer_start = c->buffer_size; @@ -85,6 +93,8 @@ void choices_fread(choices_t *c, FILE *file, char input_delimiter) { line = nl; } while (line && line < line_end); + + multiselection_init(c); } static void choices_resize(choices_t *c, size_t new_capacity) { @@ -94,10 +104,8 @@ static void choices_resize(choices_t *c, size_t new_capacity) { static void choices_reset_search(choices_t *c) { free(c->results); - free(c->multiselections); - c->selection = c->available = c->multiselection_size = 0; + c->selection = c->available = 0; c->results = NULL; - c->multiselections = NULL; } void choices_init(choices_t *c, options_t *options) { @@ -235,6 +243,7 @@ static void *choices_search_worker(void *data) { for(size_t i = start; i < end; i++) { if (has_match(job->search, c->strings[i])) { + result->list[result->size].index = i; result->list[result->size].str = c->strings[i]; result->list[result->size].score = match(job->search, c->strings[i]); result->size++; @@ -265,14 +274,6 @@ static void *choices_search_worker(void *data) { return NULL; } -void multiselection_init(choices_t *c) { - c->multiselection_size = 0; - c->multiselections = (unsigned char *) malloc(c->available * sizeof(unsigned char)); - for (size_t i = 0; i < c->available; i++) { - c->multiselections[i] = 0; - } -} - void choices_search(choices_t *c, const char *search) { choices_reset_search(c); @@ -319,7 +320,6 @@ void choices_search(choices_t *c, const char *search) { c->results = workers[0].result.list; c->available = workers[0].result.size; - multiselection_init(c); free(workers); pthread_mutex_destroy(&job->lock); free(job); @@ -333,6 +333,14 @@ const char *choices_get(choices_t *c, size_t n) { } } +const char *choices_getmulti(choices_t *c, size_t n) { + if (n < c->size) { + return c->strings[n]; + } else { + return NULL; + } +} + score_t choices_getscore(choices_t *c, size_t n) { return c->results[n].score; } @@ -349,14 +357,19 @@ void choices_next(choices_t *c) { void choices_multiselect_toggle(choices_t *c) { if (!c->available) return; - unsigned char selected = 1 == c->multiselections[c->selection]; + size_t index = c->results[c->selection].index; - if (selected) { - c->multiselections[c->selection] = 0; + if (c->multiselections[index]) { + c->multiselections[index] = 0; c->multiselection_size--; } else { - c->multiselections[c->selection] = 1; + c->multiselections[index] = 1; c->multiselection_size++; } } +size_t choices_selected(choices_t *c, size_t n) { + if (!c->available) return 0; + size_t index = c->results[n].index; + return c->multiselections[index]; +} diff --git a/src/choices.h b/src/choices.h @@ -13,6 +13,7 @@ extern "C" { struct scored_result { score_t score; const char *str; + size_t index; }; typedef struct { @@ -41,10 +42,12 @@ void choices_add(choices_t *c, const char *choice); size_t choices_available(choices_t *c); void choices_search(choices_t *c, const char *search); const char *choices_get(choices_t *c, size_t n); +const char *choices_getmulti(choices_t *c, size_t n); score_t choices_getscore(choices_t *c, size_t n); void choices_prev(choices_t *c); void choices_next(choices_t *c); void choices_multiselect_toggle(choices_t *c); +size_t choices_selected(choices_t *c, size_t n); #ifdef __cplusplus } diff --git a/src/tty_interface.c b/src/tty_interface.c @@ -123,7 +123,7 @@ static void draw(tty_interface_t *state) { tty_clearline(tty); const char *choice = choices_get(choices, i); if (choice) { - if (options->multi) tty_printf(tty, choices->multiselections[i] == 1 ? "* " : " "); + if (options->multi) tty_printf(tty, choices_selected(choices, i) == 1 ? "* " : " "); draw_match(state, choice, i == choices->selection); } } @@ -164,10 +164,10 @@ static void action_emit(tty_interface_t *state) { if (state->options->multi) { int multiselected = 0; - for (size_t i = 0; i < state->choices->available; i++) { + for (size_t i = 0; i < state->choices->size; i++) { if (state->choices->multiselections[i] != 1) continue; - const char *name = choices_get(state->choices, i); + const char *name = choices_getmulti(state->choices, i); if (!name) continue; if (!multiselected) {