Browse code

Refactor into choices.c

John Hawthorn authored on 14/09/2014 05:19:52
Showing 4 changed files

... ...
@@ -16,7 +16,7 @@ fzytest: fzytest.o match.o
16 16
 test: fzytest
17 17
 	-./fzytest
18 18
 
19
-fzy: fzy.o match.o tty.o
19
+fzy: fzy.o match.o tty.o choices.o
20 20
 	$(CC) $(CFLAGS) $(CCFLAGS) -o $@ $^
21 21
 
22 22
 %.o: %.c fzy.h
23 23
new file mode 100644
... ...
@@ -0,0 +1,89 @@
1
+#define _GNU_SOURCE
2
+#include <stdlib.h>
3
+
4
+#include "choices.h"
5
+#include "fzy.h"
6
+
7
+#define INITIAL_CAPACITY 1
8
+
9
+static int cmpchoice(size_t *idx1, size_t *idx2, double *choices_score) {
10
+	double score1 = choices_score[*idx1];
11
+	double score2 = choices_score[*idx2];
12
+
13
+	if(score1 == score2)
14
+		return 0;
15
+	else if(score1 < score2)
16
+		return 1;
17
+	else
18
+		return -1;
19
+}
20
+
21
+static void choices_resize(choices_t *c, int new_capacity){
22
+	c->strings = realloc(c->strings, new_capacity * sizeof(const char *));
23
+	c->scores  = realloc(c->scores,  new_capacity * sizeof(double));
24
+	c->sorted  = realloc(c->sorted,  new_capacity * sizeof(size_t));
25
+
26
+	for(int i = c->capacity; i < new_capacity; i++){
27
+		c->strings[i] = NULL;
28
+	}
29
+	c->capacity = new_capacity;
30
+}
31
+
32
+void choices_init(choices_t *c){
33
+	c->strings = NULL;
34
+	c->scores  = NULL;
35
+	c->sorted  = NULL;
36
+	c->capacity = c->size = 0;
37
+	c->selection = c->available = 0;
38
+	choices_resize(c, INITIAL_CAPACITY);
39
+}
40
+void choices_free(choices_t *c){
41
+	free(c->strings);
42
+	free(c->scores);
43
+	free(c->sorted);
44
+};
45
+
46
+void choices_add(choices_t *c, const char *choice){
47
+	if(c->size == c->capacity){
48
+		choices_resize(c, c->capacity * 2);
49
+	}
50
+	c->strings[c->size++] = choice;
51
+}
52
+
53
+size_t choices_available(choices_t *c){
54
+	return c->available;
55
+}
56
+
57
+void choices_search(choices_t *c, const char *search){
58
+	c->selection = 0;
59
+	c->available = 0;
60
+
61
+	for(size_t i = 0; i < c->size; i++){
62
+		if(has_match(search, c->strings[i])){
63
+			c->scores[i] = match(search, c->strings[i]);
64
+			c->sorted[c->available++] = i;
65
+		}
66
+	}
67
+
68
+	qsort_r(c->sorted, c->available, sizeof(size_t), (int (*)(const void *, const void *, void *))cmpchoice, c->scores);
69
+}
70
+
71
+const char *choices_get(choices_t *c, size_t n){
72
+	if(n < c->available){
73
+		return c->strings[c->sorted[n]];
74
+	}else{
75
+		return NULL;
76
+	}
77
+}
78
+double choices_getscore(choices_t *c, size_t n){
79
+	return c->scores[c->sorted[n]];;
80
+}
81
+
82
+void choices_prev(choices_t *c){
83
+	c->selection = (c->selection + c->available - 1) % c->available;
84
+}
85
+
86
+void choices_next(choices_t *c){
87
+	c->selection = (c->selection + 1) % c->available;
88
+}
89
+
0 90
new file mode 100644
... ...
@@ -0,0 +1,22 @@
1
+typedef struct {
2
+	size_t capacity;
3
+	size_t size;
4
+
5
+	const char **strings;
6
+	double *scores;
7
+
8
+	size_t *sorted;
9
+	size_t available;
10
+	size_t selection;
11
+} choices_t;
12
+
13
+void choices_init(choices_t *c);
14
+void choices_free(choices_t *c);
15
+void choices_add(choices_t *c, const char *choice);
16
+size_t choices_available(choices_t *c);
17
+void choices_search(choices_t *c, const char *search);
18
+const char *choices_get(choices_t *c, size_t n);
19
+double choices_getscore(choices_t *c, size_t n);
20
+void choices_prev(choices_t *c);
21
+void choices_next(choices_t *c);
22
+
... ...
@@ -7,41 +7,14 @@
7 7
 
8 8
 #include "fzy.h"
9 9
 #include "tty.h"
10
+#include "choices.h"
10 11
 
11 12
 int flag_show_scores = 0;
12 13
 
13 14
 size_t num_lines = 10;
14 15
 size_t scrolloff = 1;
15 16
 
16
-
17
-#define INITIAL_CAPACITY 1
18
-int choices_capacity = 0;
19
-int choices_n = 0;
20
-const char **choices = NULL;
21
-double *choices_score = NULL;
22
-size_t *choices_sorted = NULL;
23
-size_t current_selection = 0;
24
-
25
-void resize_choices(int new_capacity){
26
-	choices = realloc(choices, new_capacity * sizeof(const char *));
27
-	choices_score = realloc(choices_score, new_capacity * sizeof(double));
28
-	choices_sorted = realloc(choices_sorted, new_capacity * sizeof(size_t));
29
-
30
-	int i = choices_capacity;
31
-	for(; i < new_capacity; i++){
32
-		choices[i] = NULL;
33
-	}
34
-	choices_capacity = new_capacity;
35
-}
36
-
37
-void add_choice(const char *choice){
38
-	if(choices_n == choices_capacity){
39
-		resize_choices(choices_capacity * 2);
40
-	}
41
-	choices[choices_n++] = choice;
42
-}
43
-
44
-void read_choices(){
17
+void read_choices(choices_t *c){
45 18
 	char *line = NULL;
46 19
 	size_t len = 0;
47 20
 	ssize_t read;
... ...
@@ -51,44 +24,13 @@ void read_choices(){
51 24
 		if((nl = strchr(line, '\n')))
52 25
 			*nl = '\0';
53 26
 
54
-		add_choice(line);
27
+		choices_add(c, line);
55 28
 
56 29
 		line = NULL;
57 30
 	}
58 31
 	free(line);
59 32
 }
60 33
 
61
-size_t choices_available = 0;
62
-
63
-static int cmpchoice(const void *p1, const void *p2) {
64
-	size_t idx1 = *(size_t *)p1;
65
-	size_t idx2 = *(size_t *)p2;
66
-
67
-	double score1 = choices_score[idx1];
68
-	double score2 = choices_score[idx2];
69
-
70
-	if(score1 == score2)
71
-		return 0;
72
-	else if(score1 < score2)
73
-		return 1;
74
-	else
75
-		return -1;
76
-}
77
-
78
-void run_search(char *needle){
79
-	current_selection = 0;
80
-	choices_available = 0;
81
-	int i;
82
-	for(i = 0; i < choices_n; i++){
83
-		if(has_match(needle, choices[i])){
84
-			choices_score[i] = match(needle, choices[i]);
85
-			choices_sorted[choices_available++] = i;
86
-		}
87
-	}
88
-
89
-	qsort(choices_sorted, choices_available, sizeof(size_t), cmpchoice);
90
-}
91
-
92 34
 #define SEARCH_SIZE_MAX 4096
93 35
 int search_size;
94 36
 char search[SEARCH_SIZE_MAX + 1] = {0};
... ...
@@ -131,12 +73,13 @@ void draw_match(tty_t *tty, const char *choice, int selected){
131 73
 	tty_setnormal(tty);
132 74
 }
133 75
 
134
-void draw(tty_t *tty){
76
+void draw(tty_t *tty, choices_t *choices){
135 77
 	size_t start = 0;
78
+	size_t current_selection = choices->selection;
136 79
 	if(current_selection + scrolloff >= num_lines){
137 80
 		start = current_selection + scrolloff - num_lines + 1;
138
-		if(start + num_lines >= choices_available){
139
-			start = choices_available - num_lines;
81
+		if(start + num_lines >= choices_available(choices)){
82
+			start = choices_available(choices) - num_lines;
140 83
 		}
141 84
 	}
142 85
 	const char *prompt = "> ";
... ...
@@ -144,9 +87,9 @@ void draw(tty_t *tty){
144 87
 	tty_printf(tty, "%s%s", prompt, search);
145 88
 	for(size_t i = start; i < start + num_lines; i++){
146 89
 		tty_newline(tty);
147
-		if(i < choices_available){
148
-			size_t choice_idx = choices_sorted[i];
149
-			draw_match(tty, choices[choice_idx], i == current_selection);
90
+		const char *choice = choices_get(choices, i);
91
+		if(choice){
92
+			draw_match(tty, choice, i == choices->selection);
150 93
 		}
151 94
 	}
152 95
 	tty_clearline(tty);
... ...
@@ -155,13 +98,11 @@ void draw(tty_t *tty){
155 98
 	tty_flush(tty);
156 99
 }
157 100
 
158
-void emit(tty_t *tty){
159
-	/* ttyout should be flushed before outputting on stdout */
160
-	fclose(tty->fout);
161
-
162
-	if(choices_available){
101
+void emit(choices_t *choices){
102
+	const char *selection = choices_get(choices, choices->selection);
103
+	if(selection){
163 104
 		/* output the selected result */
164
-		printf("%s\n", choices[choices_sorted[current_selection]]);
105
+		printf("%s\n", selection);
165 106
 	}else{
166 107
 		/* No match, output the query instead */
167 108
 		printf("%s\n", search);
... ...
@@ -170,58 +111,54 @@ void emit(tty_t *tty){
170 111
 	exit(EXIT_SUCCESS);
171 112
 }
172 113
 
173
-void action_prev(){
174
-	current_selection = (current_selection + choices_available - 1) % choices_available;
175
-}
176
-
177
-void action_next(){
178
-	current_selection = (current_selection + 1) % choices_available;
179
-}
180
-
181
-void run(tty_t *tty){
182
-	run_search(search);
114
+void run(tty_t *tty, choices_t *choices){
115
+	choices_search(choices, search);
183 116
 	char ch;
184 117
 	do {
185
-		draw(tty);
118
+		draw(tty, choices);
186 119
 		ch = tty_getchar(tty);
187 120
 		if(isprint(ch)){
188 121
 			if(search_size < SEARCH_SIZE_MAX){
189 122
 				search[search_size++] = ch;
190 123
 				search[search_size] = '\0';
191
-				run_search(search);
124
+				choices_search(choices, search);
192 125
 			}
193 126
 		}else if(ch == 127 || ch == 8){ /* DEL || backspace */
194 127
 			if(search_size)
195 128
 				search[--search_size] = '\0';
196
-			run_search(search);
129
+			choices_search(choices, search);
197 130
 		}else if(ch == 21){ /* C-U */
198 131
 			search_size = 0;
199 132
 			search[0] = '\0';
200
-			run_search(search);
133
+			choices_search(choices, search);
201 134
 		}else if(ch == 23){ /* C-W */
202 135
 			if(search_size)
203 136
 				search[--search_size] = '\0';
204 137
 			while(search_size && !isspace(search[--search_size]))
205 138
 				search[search_size] = '\0';
206
-			run_search(search);
139
+			choices_search(choices, search);
207 140
 		}else if(ch == 14){ /* C-N */
208
-			action_next();
141
+			choices_next(choices);
209 142
 		}else if(ch == 16){ /* C-P */
210
-			action_prev();
143
+			choices_prev(choices);
211 144
 		}else if(ch == 9){ /* TAB */
212
-			strncpy(search, choices[choices_sorted[current_selection]], SEARCH_SIZE_MAX);
145
+			strncpy(search, choices_get(choices, choices->selection), SEARCH_SIZE_MAX);
213 146
 			search_size = strlen(search);
214 147
 		}else if(ch == 10){ /* Enter */
215 148
 			clear(tty);
216
-			emit(tty);
149
+
150
+			/* ttyout should be flushed before outputting on stdout */
151
+			fclose(tty->fout);
152
+
153
+			emit(choices);
217 154
 		}else if(ch == 27){ /* ESC */
218 155
 			ch = tty_getchar(tty);
219 156
 			if(ch == '[' || ch == 'O'){
220 157
 				ch = tty_getchar(tty);
221 158
 				if(ch == 'A'){ /* UP ARROW */
222
-					action_prev();
159
+					choices_prev(choices);
223 160
 				}else if(ch == 'B'){ /* DOWN ARROW */
224
-					action_next();
161
+					choices_next(choices);
225 162
 				}
226 163
 			}
227 164
 		}
... ...
@@ -297,8 +234,9 @@ int main(int argc, char *argv[]){
297 234
 		exit(EXIT_FAILURE);
298 235
 	}
299 236
 
300
-	resize_choices(INITIAL_CAPACITY);
301
-	read_choices();
237
+	choices_t choices;
238
+	choices_init(&choices);
239
+	read_choices(&choices);
302 240
 
303 241
 	if(benchmark){
304 242
 		if(!initial_query){
... ...
@@ -306,21 +244,20 @@ int main(int argc, char *argv[]){
306 244
 			exit(EXIT_FAILURE);
307 245
 		}
308 246
 		for(int i = 0; i < 100; i++)
309
-			run_search(initial_query);
247
+			choices_search(&choices, initial_query);
310 248
 	}else if(initial_query){
311
-		run_search(initial_query);
312
-		for(size_t i = 0; i < choices_available; i++){
313
-			size_t choice_idx = choices_sorted[i];
249
+		choices_search(&choices, initial_query);
250
+		for(size_t i = 0; i < choices_available(&choices); i++){
314 251
 			if(flag_show_scores)
315
-				printf("%f\t", choices_score[choice_idx]);
316
-			printf("%s\n", choices[choice_idx]);
252
+				printf("%f\t", choices_getscore(&choices, i));
253
+			printf("%s\n", choices_get(&choices, i));
317 254
 		}
318 255
 	}else{
319 256
 		/* interactive */
320 257
 		tty_t tty;
321 258
 		tty_init(&tty, tty_filename);
322 259
 
323
-		run(&tty);
260
+		run(&tty, &choices);
324 261
 	}
325 262
 
326 263
 	return 0;