summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--choices.c89
-rw-r--r--choices.h22
-rw-r--r--fzy.c143
4 files changed, 152 insertions, 104 deletions
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 <stdlib.h>
+
+#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;