From 5ea3d1dab234678ba2bb3076bfa3f0dfab6d8cd6 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Sat, 13 Sep 2014 22:19:52 -0700 Subject: Refactor into choices.c --- Makefile | 2 +- choices.c | 89 ++++++++++++++++++++++++++++++++++++++ choices.h | 22 ++++++++++ fzy.c | 143 ++++++++++++++++++-------------------------------------------- 4 files changed, 152 insertions(+), 104 deletions(-) create mode 100644 choices.c create mode 100644 choices.h diff --git a/Makefile b/Makefile index e2b8160..e997299 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ fzytest: fzytest.o match.o test: fzytest -./fzytest -fzy: fzy.o match.o tty.o +fzy: fzy.o match.o tty.o choices.o $(CC) $(CFLAGS) $(CCFLAGS) -o $@ $^ %.o: %.c fzy.h diff --git a/choices.c b/choices.c new file mode 100644 index 0000000..bd3f016 --- /dev/null +++ b/choices.c @@ -0,0 +1,89 @@ +#define _GNU_SOURCE +#include + +#include "choices.h" +#include "fzy.h" + +#define INITIAL_CAPACITY 1 + +static int cmpchoice(size_t *idx1, size_t *idx2, double *choices_score) { + double score1 = choices_score[*idx1]; + double score2 = choices_score[*idx2]; + + if(score1 == score2) + return 0; + else if(score1 < score2) + return 1; + else + return -1; +} + +static void choices_resize(choices_t *c, int new_capacity){ + c->strings = realloc(c->strings, new_capacity * sizeof(const char *)); + c->scores = realloc(c->scores, new_capacity * sizeof(double)); + c->sorted = realloc(c->sorted, new_capacity * sizeof(size_t)); + + for(int i = c->capacity; i < new_capacity; i++){ + c->strings[i] = NULL; + } + c->capacity = new_capacity; +} + +void choices_init(choices_t *c){ + c->strings = NULL; + c->scores = NULL; + c->sorted = NULL; + c->capacity = c->size = 0; + c->selection = c->available = 0; + choices_resize(c, INITIAL_CAPACITY); +} +void choices_free(choices_t *c){ + free(c->strings); + free(c->scores); + free(c->sorted); +}; + +void choices_add(choices_t *c, const char *choice){ + if(c->size == c->capacity){ + choices_resize(c, c->capacity * 2); + } + c->strings[c->size++] = choice; +} + +size_t choices_available(choices_t *c){ + return c->available; +} + +void choices_search(choices_t *c, const char *search){ + c->selection = 0; + c->available = 0; + + for(size_t i = 0; i < c->size; i++){ + if(has_match(search, c->strings[i])){ + c->scores[i] = match(search, c->strings[i]); + c->sorted[c->available++] = i; + } + } + + qsort_r(c->sorted, c->available, sizeof(size_t), (int (*)(const void *, const void *, void *))cmpchoice, c->scores); +} + +const char *choices_get(choices_t *c, size_t n){ + if(n < c->available){ + return c->strings[c->sorted[n]]; + }else{ + return NULL; + } +} +double choices_getscore(choices_t *c, size_t n){ + return c->scores[c->sorted[n]];; +} + +void choices_prev(choices_t *c){ + c->selection = (c->selection + c->available - 1) % c->available; +} + +void choices_next(choices_t *c){ + c->selection = (c->selection + 1) % c->available; +} + diff --git a/choices.h b/choices.h new file mode 100644 index 0000000..d11fbac --- /dev/null +++ b/choices.h @@ -0,0 +1,22 @@ +typedef struct { + size_t capacity; + size_t size; + + const char **strings; + double *scores; + + size_t *sorted; + size_t available; + size_t selection; +} choices_t; + +void choices_init(choices_t *c); +void choices_free(choices_t *c); +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); +double choices_getscore(choices_t *c, size_t n); +void choices_prev(choices_t *c); +void choices_next(choices_t *c); + diff --git a/fzy.c b/fzy.c index f1b7302..b1abd80 100644 --- a/fzy.c +++ b/fzy.c @@ -7,41 +7,14 @@ #include "fzy.h" #include "tty.h" +#include "choices.h" int flag_show_scores = 0; size_t num_lines = 10; size_t scrolloff = 1; - -#define INITIAL_CAPACITY 1 -int choices_capacity = 0; -int choices_n = 0; -const char **choices = NULL; -double *choices_score = NULL; -size_t *choices_sorted = NULL; -size_t current_selection = 0; - -void resize_choices(int new_capacity){ - choices = realloc(choices, new_capacity * sizeof(const char *)); - choices_score = realloc(choices_score, new_capacity * sizeof(double)); - choices_sorted = realloc(choices_sorted, new_capacity * sizeof(size_t)); - - int i = choices_capacity; - for(; i < new_capacity; i++){ - choices[i] = NULL; - } - choices_capacity = new_capacity; -} - -void add_choice(const char *choice){ - if(choices_n == choices_capacity){ - resize_choices(choices_capacity * 2); - } - choices[choices_n++] = choice; -} - -void read_choices(){ +void read_choices(choices_t *c){ char *line = NULL; size_t len = 0; ssize_t read; @@ -51,44 +24,13 @@ void read_choices(){ if((nl = strchr(line, '\n'))) *nl = '\0'; - add_choice(line); + choices_add(c, line); line = NULL; } free(line); } -size_t choices_available = 0; - -static int cmpchoice(const void *p1, const void *p2) { - size_t idx1 = *(size_t *)p1; - size_t idx2 = *(size_t *)p2; - - double score1 = choices_score[idx1]; - double score2 = choices_score[idx2]; - - if(score1 == score2) - return 0; - else if(score1 < score2) - return 1; - else - return -1; -} - -void run_search(char *needle){ - current_selection = 0; - choices_available = 0; - int i; - for(i = 0; i < choices_n; i++){ - if(has_match(needle, choices[i])){ - choices_score[i] = match(needle, choices[i]); - choices_sorted[choices_available++] = i; - } - } - - qsort(choices_sorted, choices_available, sizeof(size_t), cmpchoice); -} - #define SEARCH_SIZE_MAX 4096 int search_size; char search[SEARCH_SIZE_MAX + 1] = {0}; @@ -131,12 +73,13 @@ void draw_match(tty_t *tty, const char *choice, int selected){ tty_setnormal(tty); } -void draw(tty_t *tty){ +void draw(tty_t *tty, choices_t *choices){ size_t start = 0; + size_t current_selection = choices->selection; if(current_selection + scrolloff >= num_lines){ start = current_selection + scrolloff - num_lines + 1; - if(start + num_lines >= choices_available){ - start = choices_available - num_lines; + if(start + num_lines >= choices_available(choices)){ + start = choices_available(choices) - num_lines; } } const char *prompt = "> "; @@ -144,9 +87,9 @@ void draw(tty_t *tty){ tty_printf(tty, "%s%s", prompt, search); for(size_t i = start; i < start + num_lines; i++){ tty_newline(tty); - if(i < choices_available){ - size_t choice_idx = choices_sorted[i]; - draw_match(tty, choices[choice_idx], i == current_selection); + const char *choice = choices_get(choices, i); + if(choice){ + draw_match(tty, choice, i == choices->selection); } } tty_clearline(tty); @@ -155,13 +98,11 @@ void draw(tty_t *tty){ tty_flush(tty); } -void emit(tty_t *tty){ - /* ttyout should be flushed before outputting on stdout */ - fclose(tty->fout); - - if(choices_available){ +void emit(choices_t *choices){ + const char *selection = choices_get(choices, choices->selection); + if(selection){ /* output the selected result */ - printf("%s\n", choices[choices_sorted[current_selection]]); + printf("%s\n", selection); }else{ /* No match, output the query instead */ printf("%s\n", search); @@ -170,58 +111,54 @@ void emit(tty_t *tty){ exit(EXIT_SUCCESS); } -void action_prev(){ - current_selection = (current_selection + choices_available - 1) % choices_available; -} - -void action_next(){ - current_selection = (current_selection + 1) % choices_available; -} - -void run(tty_t *tty){ - run_search(search); +void run(tty_t *tty, choices_t *choices){ + choices_search(choices, search); char ch; do { - draw(tty); + draw(tty, choices); ch = tty_getchar(tty); if(isprint(ch)){ if(search_size < SEARCH_SIZE_MAX){ search[search_size++] = ch; search[search_size] = '\0'; - run_search(search); + choices_search(choices, search); } }else if(ch == 127 || ch == 8){ /* DEL || backspace */ if(search_size) search[--search_size] = '\0'; - run_search(search); + choices_search(choices, search); }else if(ch == 21){ /* C-U */ search_size = 0; search[0] = '\0'; - run_search(search); + choices_search(choices, search); }else if(ch == 23){ /* C-W */ if(search_size) search[--search_size] = '\0'; while(search_size && !isspace(search[--search_size])) search[search_size] = '\0'; - run_search(search); + choices_search(choices, search); }else if(ch == 14){ /* C-N */ - action_next(); + choices_next(choices); }else if(ch == 16){ /* C-P */ - action_prev(); + choices_prev(choices); }else if(ch == 9){ /* TAB */ - strncpy(search, choices[choices_sorted[current_selection]], SEARCH_SIZE_MAX); + strncpy(search, choices_get(choices, choices->selection), SEARCH_SIZE_MAX); search_size = strlen(search); }else if(ch == 10){ /* Enter */ clear(tty); - emit(tty); + + /* ttyout should be flushed before outputting on stdout */ + fclose(tty->fout); + + emit(choices); }else if(ch == 27){ /* ESC */ ch = tty_getchar(tty); if(ch == '[' || ch == 'O'){ ch = tty_getchar(tty); if(ch == 'A'){ /* UP ARROW */ - action_prev(); + choices_prev(choices); }else if(ch == 'B'){ /* DOWN ARROW */ - action_next(); + choices_next(choices); } } } @@ -297,8 +234,9 @@ int main(int argc, char *argv[]){ exit(EXIT_FAILURE); } - resize_choices(INITIAL_CAPACITY); - read_choices(); + choices_t choices; + choices_init(&choices); + read_choices(&choices); if(benchmark){ if(!initial_query){ @@ -306,21 +244,20 @@ int main(int argc, char *argv[]){ exit(EXIT_FAILURE); } for(int i = 0; i < 100; i++) - run_search(initial_query); + choices_search(&choices, initial_query); }else if(initial_query){ - run_search(initial_query); - for(size_t i = 0; i < choices_available; i++){ - size_t choice_idx = choices_sorted[i]; + choices_search(&choices, initial_query); + for(size_t i = 0; i < choices_available(&choices); i++){ if(flag_show_scores) - printf("%f\t", choices_score[choice_idx]); - printf("%s\n", choices[choice_idx]); + printf("%f\t", choices_getscore(&choices, i)); + printf("%s\n", choices_get(&choices, i)); } }else{ /* interactive */ tty_t tty; tty_init(&tty, tty_filename); - run(&tty); + run(&tty, &choices); } return 0; -- cgit v1.2.3