Browse code

Move sources into src directory

John Hawthorn authored on 21/05/2016 21:56:03
Showing 1 changed files
1 1
deleted file mode 100644
... ...
@@ -1,290 +0,0 @@
1
-#include <stdio.h>
2
-#include <string.h>
3
-#include <stdlib.h>
4
-#include <ctype.h>
5
-#include <getopt.h>
6
-#include <limits.h>
7
-
8
-#include "match.h"
9
-#include "tty.h"
10
-#include "choices.h"
11
-
12
-#include "config.h"
13
-
14
-static int flag_show_scores = 0;
15
-
16
-static size_t num_lines = 10;
17
-static size_t scrolloff = 1;
18
-
19
-static const char *prompt = "> ";
20
-
21
-#define SEARCH_SIZE_MAX 4096
22
-static char search[SEARCH_SIZE_MAX + 1] = {0};
23
-
24
-static void clear(tty_t *tty) {
25
-	tty_setcol(tty, 0);
26
-	size_t line = 0;
27
-	while (line++ < num_lines) {
28
-		tty_newline(tty);
29
-	}
30
-	tty_clearline(tty);
31
-	tty_moveup(tty, line - 1);
32
-	tty_flush(tty);
33
-}
34
-
35
-static void draw_match(tty_t *tty, const char *choice, int selected) {
36
-	int n = strlen(search);
37
-	size_t positions[n + 1];
38
-	for (int i = 0; i < n + 1; i++)
39
-		positions[i] = -1;
40
-
41
-	double score = match_positions(search, choice, &positions[0]);
42
-
43
-	size_t maxwidth = tty_getwidth(tty);
44
-
45
-	if (flag_show_scores)
46
-		tty_printf(tty, "(%5.2f) ", score);
47
-
48
-	if (selected)
49
-		tty_setinvert(tty);
50
-
51
-	for (size_t i = 0, p = 0; choice[i] != '\0'; i++) {
52
-		if (i + 1 < maxwidth) {
53
-			if (positions[p] == i) {
54
-				tty_setfg(tty, TTY_COLOR_HIGHLIGHT);
55
-				p++;
56
-			} else {
57
-				tty_setfg(tty, TTY_COLOR_NORMAL);
58
-			}
59
-			tty_printf(tty, "%c", choice[i]);
60
-		} else {
61
-			tty_printf(tty, "$");
62
-			break;
63
-		}
64
-	}
65
-	tty_setnormal(tty);
66
-}
67
-
68
-static void draw(tty_t *tty, choices_t *choices) {
69
-	size_t start = 0;
70
-	size_t current_selection = choices->selection;
71
-	if (current_selection + scrolloff >= num_lines) {
72
-		start = current_selection + scrolloff - num_lines + 1;
73
-		if (start + num_lines >= choices_available(choices)) {
74
-			start = choices_available(choices) - num_lines;
75
-		}
76
-	}
77
-	tty_setcol(tty, 0);
78
-	tty_printf(tty, "%s%s", prompt, search);
79
-	tty_clearline(tty);
80
-	for (size_t i = start; i < start + num_lines; i++) {
81
-		tty_printf(tty, "\n");
82
-		tty_clearline(tty);
83
-		const char *choice = choices_get(choices, i);
84
-		if (choice) {
85
-			draw_match(tty, choice, i == choices->selection);
86
-		}
87
-	}
88
-	tty_moveup(tty, num_lines);
89
-	tty_setcol(tty, strlen(prompt) + strlen(search));
90
-	tty_flush(tty);
91
-}
92
-
93
-static void emit(choices_t *choices) {
94
-	const char *selection = choices_get(choices, choices->selection);
95
-	if (selection) {
96
-		/* output the selected result */
97
-		printf("%s\n", selection);
98
-	} else {
99
-		/* No match, output the query instead */
100
-		printf("%s\n", search);
101
-	}
102
-}
103
-
104
-#define KEY_CTRL(key) ((key) - ('@'))
105
-#define KEY_DEL 127
106
-#define KEY_ESC 27
107
-
108
-static void run(tty_t *tty, choices_t *choices) {
109
-	choices_search(choices, search);
110
-	char ch;
111
-	do {
112
-		draw(tty, choices);
113
-		ch = tty_getchar(tty);
114
-		size_t search_size = strlen(search);
115
-		if (isprint(ch)) {
116
-			if (search_size < SEARCH_SIZE_MAX) {
117
-				search[search_size++] = ch;
118
-				search[search_size] = '\0';
119
-				choices_search(choices, search);
120
-			}
121
-		} else if (ch == KEY_DEL || ch == KEY_CTRL('H')) { /* DEL || Backspace (C-H) */
122
-			if (search_size)
123
-				search[--search_size] = '\0';
124
-			choices_search(choices, search);
125
-		} else if (ch == KEY_CTRL('U')) { /* C-U */
126
-			search_size = 0;
127
-			search[0] = '\0';
128
-			choices_search(choices, search);
129
-		} else if (ch == KEY_CTRL('W')) { /* C-W */
130
-			if (search_size)
131
-				search[--search_size] = '\0';
132
-			while (search_size && !isspace(search[--search_size]))
133
-				search[search_size] = '\0';
134
-			choices_search(choices, search);
135
-		} else if (ch == KEY_CTRL('N')) { /* C-N */
136
-			choices_next(choices);
137
-		} else if (ch == KEY_CTRL('P')) { /* C-P */
138
-			choices_prev(choices);
139
-		} else if (ch == KEY_CTRL('I')) { /* TAB (C-I) */
140
-			strncpy(search, choices_get(choices, choices->selection), SEARCH_SIZE_MAX);
141
-			choices_search(choices, search);
142
-		} else if (ch == KEY_CTRL('C') || ch == KEY_CTRL('D')) { /* ^C || ^D */
143
-			clear(tty);
144
-			tty_close(tty);
145
-			exit(EXIT_FAILURE);
146
-		} else if (ch == KEY_CTRL('M')) { /* CR */
147
-			clear(tty);
148
-
149
-			/* ttyout should be flushed before outputting on stdout */
150
-			tty_close(tty);
151
-
152
-			emit(choices);
153
-
154
-			/* Return to eventually exit successfully */
155
-			return;
156
-		} else if (ch == KEY_ESC) { /* ESC */
157
-			ch = tty_getchar(tty);
158
-			if (ch == '[' || ch == 'O') {
159
-				ch = tty_getchar(tty);
160
-				if (ch == 'A') { /* UP ARROW */
161
-					choices_prev(choices);
162
-				} else if (ch == 'B') { /* DOWN ARROW */
163
-					choices_next(choices);
164
-				}
165
-			}
166
-		}
167
-	} while (1);
168
-}
169
-
170
-static const char *usage_str =
171
-    ""
172
-    "Usage: fzy [OPTION]...\n"
173
-    " -l, --lines=LINES        Specify how many lines of results to show (default 10)\n"
174
-    " -p, --prompt=PROMPT      Input prompt (default '> ')\n"
175
-    " -q, --query=QUERY        Use QUERY as the initial search string\n"
176
-    " -e, --show-matches=QUERY Output the sorted matches of QUERY\n"
177
-    " -t, --tty=TTY            Specify file to use as TTY device (default /dev/tty)\n"
178
-    " -s, --show-scores        Show the scores of each match\n"
179
-    " -h, --help     Display this help and exit\n"
180
-    " -v, --version  Output version information and exit\n";
181
-
182
-static void usage(const char *argv0) {
183
-	fprintf(stderr, usage_str, argv0);
184
-}
185
-
186
-static struct option longopts[] = {{"show-matches", required_argument, NULL, 'e'},
187
-				   {"query", required_argument, NULL, 'q'},
188
-				   {"lines", required_argument, NULL, 'l'},
189
-				   {"tty", required_argument, NULL, 't'},
190
-				   {"prompt", required_argument, NULL, 'p'},
191
-				   {"show-scores", no_argument, NULL, 's'},
192
-				   {"version", no_argument, NULL, 'v'},
193
-				   {"benchmark", optional_argument, NULL, 'b'},
194
-				   {"help", no_argument, NULL, 'h'},
195
-				   {NULL, 0, NULL, 0}};
196
-
197
-int main(int argc, char *argv[]) {
198
-	int benchmark = 0;
199
-	const char *filter = NULL;
200
-	const char *tty_filename = "/dev/tty";
201
-	char c;
202
-	while ((c = getopt_long(argc, argv, "vhse:q:l:t:p:", longopts, NULL)) != -1) {
203
-		switch (c) {
204
-			case 'v':
205
-				printf("%s " VERSION " (c) 2014 John Hawthorn\n", argv[0]);
206
-				exit(EXIT_SUCCESS);
207
-			case 's':
208
-				flag_show_scores = 1;
209
-				break;
210
-			case 'q':
211
-				strncpy(search, optarg, SEARCH_SIZE_MAX);
212
-				break;
213
-			case 'e':
214
-				filter = optarg;
215
-				break;
216
-			case 'b':
217
-				if (optarg) {
218
-					if (sscanf(optarg, "%d", &benchmark) != 1) {
219
-						usage(argv[0]);
220
-						exit(EXIT_FAILURE);
221
-					}
222
-				} else {
223
-					benchmark = 100;
224
-				}
225
-				break;
226
-			case 't':
227
-				tty_filename = optarg;
228
-				break;
229
-			case 'p':
230
-				prompt = optarg;
231
-				break;
232
-			case 'l': {
233
-				int l;
234
-				if (!strcmp(optarg, "max")) {
235
-					l = INT_MAX;
236
-				} else if (sscanf(optarg, "%d", &l) != 1 || l < 3) {
237
-					fprintf(stderr, "Invalid format for --lines: %s\n", optarg);
238
-					fprintf(stderr, "Must be integer in range 3..\n");
239
-					usage(argv[0]);
240
-					exit(EXIT_FAILURE);
241
-				}
242
-				num_lines = l;
243
-			} break;
244
-			case 'h':
245
-			default:
246
-				usage(argv[0]);
247
-				exit(EXIT_SUCCESS);
248
-		}
249
-	}
250
-	if (optind != argc) {
251
-		usage(argv[0]);
252
-		exit(EXIT_FAILURE);
253
-	}
254
-
255
-	choices_t choices;
256
-	choices_init(&choices);
257
-	choices_fread(&choices, stdin);
258
-
259
-	if (benchmark) {
260
-		if (!filter) {
261
-			fprintf(stderr, "Must specify -e/--show-matches with --benchmark\n");
262
-			exit(EXIT_FAILURE);
263
-		}
264
-		for (int i = 0; i < benchmark; i++)
265
-			choices_search(&choices, filter);
266
-	} else if (filter) {
267
-		choices_search(&choices, filter);
268
-		for (size_t i = 0; i < choices_available(&choices); i++) {
269
-			if (flag_show_scores)
270
-				printf("%f\t", choices_getscore(&choices, i));
271
-			printf("%s\n", choices_get(&choices, i));
272
-		}
273
-	} else {
274
-		/* interactive */
275
-		tty_t tty;
276
-		tty_init(&tty, tty_filename);
277
-
278
-		if (num_lines > choices.size)
279
-			num_lines = choices.size;
280
-
281
-		if (num_lines + 1 > tty_getheight(&tty))
282
-			num_lines = tty_getheight(&tty) - 1;
283
-
284
-		run(&tty, &choices);
285
-	}
286
-
287
-	choices_destroy(&choices);
288
-
289
-	return 0;
290
-}
Browse code

Group together num_lines logic

John Hawthorn authored on 17/05/2016 03:08:57
Showing 1 changed files
... ...
@@ -256,9 +256,6 @@ int main(int argc, char *argv[]) {
256 256
 	choices_init(&choices);
257 257
 	choices_fread(&choices, stdin);
258 258
 
259
-	if (num_lines > choices.size)
260
-		num_lines = choices.size;
261
-
262 259
 	if (benchmark) {
263 260
 		if (!filter) {
264 261
 			fprintf(stderr, "Must specify -e/--show-matches with --benchmark\n");
... ...
@@ -278,6 +275,9 @@ int main(int argc, char *argv[]) {
278 275
 		tty_t tty;
279 276
 		tty_init(&tty, tty_filename);
280 277
 
278
+		if (num_lines > choices.size)
279
+			num_lines = choices.size;
280
+
281 281
 		if (num_lines + 1 > tty_getheight(&tty))
282 282
 			num_lines = tty_getheight(&tty) - 1;
283 283
 
Browse code

Add -q/--query for specifying initial query

This matches fzf's -q and selecta's -s

John Hawthorn authored on 17/05/2016 02:33:44
Showing 1 changed files
... ...
@@ -19,7 +19,6 @@ static size_t scrolloff = 1;
19 19
 static const char *prompt = "> ";
20 20
 
21 21
 #define SEARCH_SIZE_MAX 4096
22
-static size_t search_size;
23 22
 static char search[SEARCH_SIZE_MAX + 1] = {0};
24 23
 
25 24
 static void clear(tty_t *tty) {
... ...
@@ -112,6 +111,7 @@ static void run(tty_t *tty, choices_t *choices) {
112 111
 	do {
113 112
 		draw(tty, choices);
114 113
 		ch = tty_getchar(tty);
114
+		size_t search_size = strlen(search);
115 115
 		if (isprint(ch)) {
116 116
 			if (search_size < SEARCH_SIZE_MAX) {
117 117
 				search[search_size++] = ch;
... ...
@@ -138,7 +138,6 @@ static void run(tty_t *tty, choices_t *choices) {
138 138
 			choices_prev(choices);
139 139
 		} else if (ch == KEY_CTRL('I')) { /* TAB (C-I) */
140 140
 			strncpy(search, choices_get(choices, choices->selection), SEARCH_SIZE_MAX);
141
-			search_size = strlen(search);
142 141
 			choices_search(choices, search);
143 142
 		} else if (ch == KEY_CTRL('C') || ch == KEY_CTRL('D')) { /* ^C || ^D */
144 143
 			clear(tty);
... ...
@@ -173,6 +172,7 @@ static const char *usage_str =
173 172
     "Usage: fzy [OPTION]...\n"
174 173
     " -l, --lines=LINES        Specify how many lines of results to show (default 10)\n"
175 174
     " -p, --prompt=PROMPT      Input prompt (default '> ')\n"
175
+    " -q, --query=QUERY        Use QUERY as the initial search string\n"
176 176
     " -e, --show-matches=QUERY Output the sorted matches of QUERY\n"
177 177
     " -t, --tty=TTY            Specify file to use as TTY device (default /dev/tty)\n"
178 178
     " -s, --show-scores        Show the scores of each match\n"
... ...
@@ -184,6 +184,7 @@ static void usage(const char *argv0) {
184 184
 }
185 185
 
186 186
 static struct option longopts[] = {{"show-matches", required_argument, NULL, 'e'},
187
+				   {"query", required_argument, NULL, 'q'},
187 188
 				   {"lines", required_argument, NULL, 'l'},
188 189
 				   {"tty", required_argument, NULL, 't'},
189 190
 				   {"prompt", required_argument, NULL, 'p'},
... ...
@@ -198,7 +199,7 @@ int main(int argc, char *argv[]) {
198 199
 	const char *filter = NULL;
199 200
 	const char *tty_filename = "/dev/tty";
200 201
 	char c;
201
-	while ((c = getopt_long(argc, argv, "vhse:l:t:p:", longopts, NULL)) != -1) {
202
+	while ((c = getopt_long(argc, argv, "vhse:q:l:t:p:", longopts, NULL)) != -1) {
202 203
 		switch (c) {
203 204
 			case 'v':
204 205
 				printf("%s " VERSION " (c) 2014 John Hawthorn\n", argv[0]);
... ...
@@ -206,6 +207,9 @@ int main(int argc, char *argv[]) {
206 207
 			case 's':
207 208
 				flag_show_scores = 1;
208 209
 				break;
210
+			case 'q':
211
+				strncpy(search, optarg, SEARCH_SIZE_MAX);
212
+				break;
209 213
 			case 'e':
210 214
 				filter = optarg;
211 215
 				break;
Browse code

Rename initial_query to filter

More acurately represents what it really does.

John Hawthorn authored on 17/05/2016 02:37:35
Showing 1 changed files
... ...
@@ -195,7 +195,7 @@ static struct option longopts[] = {{"show-matches", required_argument, NULL, 'e'
195 195
 
196 196
 int main(int argc, char *argv[]) {
197 197
 	int benchmark = 0;
198
-	const char *initial_query = NULL;
198
+	const char *filter = NULL;
199 199
 	const char *tty_filename = "/dev/tty";
200 200
 	char c;
201 201
 	while ((c = getopt_long(argc, argv, "vhse:l:t:p:", longopts, NULL)) != -1) {
... ...
@@ -207,7 +207,7 @@ int main(int argc, char *argv[]) {
207 207
 				flag_show_scores = 1;
208 208
 				break;
209 209
 			case 'e':
210
-				initial_query = optarg;
210
+				filter = optarg;
211 211
 				break;
212 212
 			case 'b':
213 213
 				if (optarg) {
... ...
@@ -256,14 +256,14 @@ int main(int argc, char *argv[]) {
256 256
 		num_lines = choices.size;
257 257
 
258 258
 	if (benchmark) {
259
-		if (!initial_query) {
259
+		if (!filter) {
260 260
 			fprintf(stderr, "Must specify -e/--show-matches with --benchmark\n");
261 261
 			exit(EXIT_FAILURE);
262 262
 		}
263 263
 		for (int i = 0; i < benchmark; i++)
264
-			choices_search(&choices, initial_query);
265
-	} else if (initial_query) {
266
-		choices_search(&choices, initial_query);
264
+			choices_search(&choices, filter);
265
+	} else if (filter) {
266
+		choices_search(&choices, filter);
267 267
 		for (size_t i = 0; i < choices_available(&choices); i++) {
268 268
 			if (flag_show_scores)
269 269
 				printf("%f\t", choices_getscore(&choices, i));
Browse code

Ensure last line is cleared on exit.

Previously we were failing to clear the very last line when exiting.

Thanks to Zaplanincan for reporting the issue.

John Hawthorn authored on 17/05/2016 02:05:58
Showing 1 changed files
... ...
@@ -28,6 +28,7 @@ static void clear(tty_t *tty) {
28 28
 	while (line++ < num_lines) {
29 29
 		tty_newline(tty);
30 30
 	}
31
+	tty_clearline(tty);
31 32
 	tty_moveup(tty, line - 1);
32 33
 	tty_flush(tty);
33 34
 }
Browse code

Make run returns on success, then exit from main

No real advantage, but I get to feel warm and fuzzy about

HEAP SUMMARY:
in use at exit: 0 bytes in 0 blocks
total heap usage: 8 allocs, 8 frees, 15,425 bytes allocated

John Hawthorn authored on 03/05/2016 04:48:09
Showing 1 changed files
... ...
@@ -99,8 +99,6 @@ static void emit(choices_t *choices) {
99 99
 		/* No match, output the query instead */
100 100
 		printf("%s\n", search);
101 101
 	}
102
-
103
-	exit(EXIT_SUCCESS);
104 102
 }
105 103
 
106 104
 #define KEY_CTRL(key) ((key) - ('@'))
... ...
@@ -152,6 +150,9 @@ static void run(tty_t *tty, choices_t *choices) {
152 150
 			tty_close(tty);
153 151
 
154 152
 			emit(choices);
153
+
154
+			/* Return to eventually exit successfully */
155
+			return;
155 156
 		} else if (ch == KEY_ESC) { /* ESC */
156 157
 			ch = tty_getchar(tty);
157 158
 			if (ch == '[' || ch == 'O') {
Browse code

Destroy choices on exit

John Hawthorn authored on 03/05/2016 04:46:35
Showing 1 changed files
... ...
@@ -278,5 +278,7 @@ int main(int argc, char *argv[]) {
278 278
 		run(&tty, &choices);
279 279
 	}
280 280
 
281
+	choices_destroy(&choices);
282
+
281 283
 	return 0;
282 284
 }
Browse code

Move input reading to choices.c

Also refactored and added comments.

John Hawthorn authored on 23/04/2016 18:25:47
Showing 1 changed files
... ...
@@ -18,37 +18,6 @@ static size_t scrolloff = 1;
18 18
 
19 19
 static const char *prompt = "> ";
20 20
 
21
-static void read_choices(choices_t *c) {
22
-	size_t bufsize = 65536;
23
-	size_t pos = 0;
24
-	size_t sizeread;
25
-
26
-	/* Read entire file into contiguous memory buffer */
27
-	char *buf = malloc(bufsize);
28
-	while ((sizeread = fread(buf + pos, 1, bufsize - pos, stdin))) {
29
-		pos += sizeread;
30
-		bufsize *= 2;
31
-		buf = realloc(buf, bufsize);
32
-	}
33
-	buf = realloc(buf, pos + 1);
34
-
35
-	buf[pos] = 0;
36
-
37
-	/* Tokenize input and add to choices */
38
-	char *line = buf;
39
-	do {
40
-		char *nl = strchr(line, '\n');
41
-		if (nl)
42
-			*nl++ = '\0';
43
-
44
-		/* Skip empty lines */
45
-		if (*line)
46
-			choices_add(c, line);
47
-
48
-		line = nl;
49
-	} while (line);
50
-}
51
-
52 21
 #define SEARCH_SIZE_MAX 4096
53 22
 static size_t search_size;
54 23
 static char search[SEARCH_SIZE_MAX + 1] = {0};
... ...
@@ -279,7 +248,7 @@ int main(int argc, char *argv[]) {
279 248
 
280 249
 	choices_t choices;
281 250
 	choices_init(&choices);
282
-	read_choices(&choices);
251
+	choices_fread(&choices, stdin);
283 252
 
284 253
 	if (num_lines > choices.size)
285 254
 		num_lines = choices.size;
Browse code

Read entire input into contiguous memory

This should be slightly faster at loading the input into memory, since
fewer mallocs will be required vs running one malloc per-line of input.

Realloc on modern systems is fast. It can use mremap internally to remap
virtual memory pages and avoid copying. This can be seen in strace. Neat!

I thought that this might be friendlier to caching, but there was no
noticeable differnce when scanning through the strings for matches. It's
probable that the previous strdups placed them more-or-less contiguously
and the extra padding for malloc bookkeeping didn't make a significant
differnce. This also suggests that alignment of the candidate strings
wasn't important.

John Hawthorn authored on 21/04/2016 18:12:15
Showing 1 changed files
... ...
@@ -19,19 +19,34 @@ static size_t scrolloff = 1;
19 19
 static const char *prompt = "> ";
20 20
 
21 21
 static void read_choices(choices_t *c) {
22
-	const char *line;
23
-	char buf[4096];
24
-	while (fgets(buf, sizeof buf, stdin)) {
25
-		char *nl;
26
-		if ((nl = strchr(buf, '\n')))
27
-			*nl = '\0';
28
-
29
-		if (!(line = strdup(buf))) {
30
-			fprintf(stderr, "Cannot allocate memory");
31
-			abort();
32
-		}
33
-		choices_add(c, line);
22
+	size_t bufsize = 65536;
23
+	size_t pos = 0;
24
+	size_t sizeread;
25
+
26
+	/* Read entire file into contiguous memory buffer */
27
+	char *buf = malloc(bufsize);
28
+	while ((sizeread = fread(buf + pos, 1, bufsize - pos, stdin))) {
29
+		pos += sizeread;
30
+		bufsize *= 2;
31
+		buf = realloc(buf, bufsize);
34 32
 	}
33
+	buf = realloc(buf, pos + 1);
34
+
35
+	buf[pos] = 0;
36
+
37
+	/* Tokenize input and add to choices */
38
+	char *line = buf;
39
+	do {
40
+		char *nl = strchr(line, '\n');
41
+		if (nl)
42
+			*nl++ = '\0';
43
+
44
+		/* Skip empty lines */
45
+		if (*line)
46
+			choices_add(c, line);
47
+
48
+		line = nl;
49
+	} while (line);
35 50
 }
36 51
 
37 52
 #define SEARCH_SIZE_MAX 4096
Browse code

Use macros to represent control keys

Prefers "magic letters" to magic numbers. It's easier to think of all
control codes as their shifted versions of letters A-Z in the ascii
table.

John Hawthorn authored on 10/04/2016 05:10:09
Showing 1 changed files
... ...
@@ -119,6 +119,10 @@ static void emit(choices_t *choices) {
119 119
 	exit(EXIT_SUCCESS);
120 120
 }
121 121
 
122
+#define KEY_CTRL(key) ((key) - ('@'))
123
+#define KEY_DEL 127
124
+#define KEY_ESC 27
125
+
122 126
 static void run(tty_t *tty, choices_t *choices) {
123 127
 	choices_search(choices, search);
124 128
 	char ch;
... ...
@@ -131,40 +135,40 @@ static void run(tty_t *tty, choices_t *choices) {
131 135
 				search[search_size] = '\0';
132 136
 				choices_search(choices, search);
133 137
 			}
134
-		} else if (ch == 127 || ch == 8) { /* DEL || backspace */
138
+		} else if (ch == KEY_DEL || ch == KEY_CTRL('H')) { /* DEL || Backspace (C-H) */
135 139
 			if (search_size)
136 140
 				search[--search_size] = '\0';
137 141
 			choices_search(choices, search);
138
-		} else if (ch == 21) { /* C-U */
142
+		} else if (ch == KEY_CTRL('U')) { /* C-U */
139 143
 			search_size = 0;
140 144
 			search[0] = '\0';
141 145
 			choices_search(choices, search);
142
-		} else if (ch == 23) { /* C-W */
146
+		} else if (ch == KEY_CTRL('W')) { /* C-W */
143 147
 			if (search_size)
144 148
 				search[--search_size] = '\0';
145 149
 			while (search_size && !isspace(search[--search_size]))
146 150
 				search[search_size] = '\0';
147 151
 			choices_search(choices, search);
148
-		} else if (ch == 14) { /* C-N */
152
+		} else if (ch == KEY_CTRL('N')) { /* C-N */
149 153
 			choices_next(choices);
150
-		} else if (ch == 16) { /* C-P */
154
+		} else if (ch == KEY_CTRL('P')) { /* C-P */
151 155
 			choices_prev(choices);
152
-		} else if (ch == 9) { /* TAB */
156
+		} else if (ch == KEY_CTRL('I')) { /* TAB (C-I) */
153 157
 			strncpy(search, choices_get(choices, choices->selection), SEARCH_SIZE_MAX);
154 158
 			search_size = strlen(search);
155 159
 			choices_search(choices, search);
156
-		} else if (ch == 3 || ch == 4) { /* ^C || ^D */
160
+		} else if (ch == KEY_CTRL('C') || ch == KEY_CTRL('D')) { /* ^C || ^D */
157 161
 			clear(tty);
158 162
 			tty_close(tty);
159 163
 			exit(EXIT_FAILURE);
160
-		} else if (ch == 13) { /* CR */
164
+		} else if (ch == KEY_CTRL('M')) { /* CR */
161 165
 			clear(tty);
162 166
 
163 167
 			/* ttyout should be flushed before outputting on stdout */
164 168
 			tty_close(tty);
165 169
 
166 170
 			emit(choices);
167
-		} else if (ch == 27) { /* ESC */
171
+		} else if (ch == KEY_ESC) { /* ESC */
168 172
 			ch = tty_getchar(tty);
169 173
 			if (ch == '[' || ch == 'O') {
170 174
 				ch = tty_getchar(tty);
Browse code

Unset ICRNL on tty

I get a few reports of enter not working with fzy occasionally. This
usually occurrs after running a badly behaved program which doesn't
clean up the tty properly (looking at you, pry) after cleaning the
ICRNL flag.

This commit now always unsets ICRNL. This also could have been fixed by
ensuring ICRNL was set, but I believe this will give more control over
keybindings.

John Hawthorn authored on 05/04/2016 22:30:19
Showing 1 changed files
... ...
@@ -157,7 +157,7 @@ static void run(tty_t *tty, choices_t *choices) {
157 157
 			clear(tty);
158 158
 			tty_close(tty);
159 159
 			exit(EXIT_FAILURE);
160
-		} else if (ch == 10) { /* Enter */
160
+		} else if (ch == 13) { /* CR */
161 161
 			clear(tty);
162 162
 
163 163
 			/* ttyout should be flushed before outputting on stdout */
Browse code

Fix indentation

John Hawthorn authored on 10/01/2016 03:49:51
Showing 1 changed files
... ...
@@ -221,12 +221,12 @@ int main(int argc, char *argv[]) {
221 221
 				break;
222 222
 			case 'b':
223 223
 				if (optarg) {
224
-				    if (sscanf(optarg, "%d", &benchmark) != 1) {
225
-					usage(argv[0]);
226
-					exit(EXIT_FAILURE);
227
-				    }
224
+					if (sscanf(optarg, "%d", &benchmark) != 1) {
225
+						usage(argv[0]);
226
+						exit(EXIT_FAILURE);
227
+					}
228 228
 				} else {
229
-				    benchmark = 100;
229
+					benchmark = 100;
230 230
 				}
231 231
 				break;
232 232
 			case 't':
Browse code

Allow specifying count for benchmark

This is helpful because some searches are an order of magnitude easier
than others.

John Hawthorn authored on 08/12/2015 01:11:42
Showing 1 changed files
... ...
@@ -199,7 +199,7 @@ static struct option longopts[] = {{"show-matches", required_argument, NULL, 'e'
199 199
 				   {"prompt", required_argument, NULL, 'p'},
200 200
 				   {"show-scores", no_argument, NULL, 's'},
201 201
 				   {"version", no_argument, NULL, 'v'},
202
-				   {"benchmark", no_argument, NULL, 'b'},
202
+				   {"benchmark", optional_argument, NULL, 'b'},
203 203
 				   {"help", no_argument, NULL, 'h'},
204 204
 				   {NULL, 0, NULL, 0}};
205 205
 
... ...
@@ -220,7 +220,14 @@ int main(int argc, char *argv[]) {
220 220
 				initial_query = optarg;
221 221
 				break;
222 222
 			case 'b':
223
-				benchmark = 1;
223
+				if (optarg) {
224
+				    if (sscanf(optarg, "%d", &benchmark) != 1) {
225
+					usage(argv[0]);
226
+					exit(EXIT_FAILURE);
227
+				    }
228
+				} else {
229
+				    benchmark = 100;
230
+				}
224 231
 				break;
225 232
 			case 't':
226 233
 				tty_filename = optarg;
... ...
@@ -263,7 +270,7 @@ int main(int argc, char *argv[]) {
263 270
 			fprintf(stderr, "Must specify -e/--show-matches with --benchmark\n");
264 271
 			exit(EXIT_FAILURE);
265 272
 		}
266
-		for (int i = 0; i < 100; i++)
273
+		for (int i = 0; i < benchmark; i++)
267 274
 			choices_search(&choices, initial_query);
268 275
 	} else if (initial_query) {
269 276
 		choices_search(&choices, initial_query);
Browse code

Use static where appropriate in fzy.c

John Hawthorn authored on 07/11/2015 10:00:43
Showing 1 changed files
... ...
@@ -11,14 +11,14 @@
11 11
 
12 12
 #include "config.h"
13 13
 
14
-int flag_show_scores = 0;
14
+static int flag_show_scores = 0;
15 15
 
16
-size_t num_lines = 10;
17
-size_t scrolloff = 1;
16
+static size_t num_lines = 10;
17
+static size_t scrolloff = 1;
18 18
 
19
-const char *prompt = "> ";
19
+static const char *prompt = "> ";
20 20
 
21
-void read_choices(choices_t *c) {
21
+static void read_choices(choices_t *c) {
22 22
 	const char *line;
23 23
 	char buf[4096];
24 24
 	while (fgets(buf, sizeof buf, stdin)) {
... ...
@@ -35,10 +35,10 @@ void read_choices(choices_t *c) {
35 35
 }
36 36
 
37 37
 #define SEARCH_SIZE_MAX 4096
38
-size_t search_size;
39
-char search[SEARCH_SIZE_MAX + 1] = {0};
38
+static size_t search_size;
39
+static char search[SEARCH_SIZE_MAX + 1] = {0};
40 40
 
41
-void clear(tty_t *tty) {
41
+static void clear(tty_t *tty) {
42 42
 	tty_setcol(tty, 0);
43 43
 	size_t line = 0;
44 44
 	while (line++ < num_lines) {
... ...
@@ -48,7 +48,7 @@ void clear(tty_t *tty) {
48 48
 	tty_flush(tty);
49 49
 }
50 50
 
51
-void draw_match(tty_t *tty, const char *choice, int selected) {
51
+static void draw_match(tty_t *tty, const char *choice, int selected) {
52 52
 	int n = strlen(search);
53 53
 	size_t positions[n + 1];
54 54
 	for (int i = 0; i < n + 1; i++)
... ...
@@ -81,7 +81,7 @@ void draw_match(tty_t *tty, const char *choice, int selected) {
81 81
 	tty_setnormal(tty);
82 82
 }
83 83
 
84
-void draw(tty_t *tty, choices_t *choices) {
84
+static void draw(tty_t *tty, choices_t *choices) {
85 85
 	size_t start = 0;
86 86
 	size_t current_selection = choices->selection;
87 87
 	if (current_selection + scrolloff >= num_lines) {
... ...
@@ -106,7 +106,7 @@ void draw(tty_t *tty, choices_t *choices) {
106 106
 	tty_flush(tty);
107 107
 }
108 108
 
109
-void emit(choices_t *choices) {
109
+static void emit(choices_t *choices) {
110 110
 	const char *selection = choices_get(choices, choices->selection);
111 111
 	if (selection) {
112 112
 		/* output the selected result */
... ...
@@ -119,7 +119,7 @@ void emit(choices_t *choices) {
119 119
 	exit(EXIT_SUCCESS);
120 120
 }
121 121
 
122
-void run(tty_t *tty, choices_t *choices) {
122
+static void run(tty_t *tty, choices_t *choices) {
123 123
 	choices_search(choices, search);
124 124
 	char ch;
125 125
 	do {
... ...
@@ -189,7 +189,7 @@ static const char *usage_str =
189 189
     " -h, --help     Display this help and exit\n"
190 190
     " -v, --version  Output version information and exit\n";
191 191
 
192
-void usage(const char *argv0) {
192
+static void usage(const char *argv0) {
193 193
 	fprintf(stderr, usage_str, argv0);
194 194
 }
195 195
 
Browse code

Use size_t where appropriate

John Hawthorn authored on 07/11/2015 09:58:09
Showing 1 changed files
... ...
@@ -35,7 +35,7 @@ void read_choices(choices_t *c) {
35 35
 }
36 36
 
37 37
 #define SEARCH_SIZE_MAX 4096
38
-int search_size;
38
+size_t search_size;
39 39
 char search[SEARCH_SIZE_MAX + 1] = {0};
40 40
 
41 41
 void clear(tty_t *tty) {
Browse code

Apply clang-format to all files

Apologies that this uses my preferred formatting style: mostly the same
as Linux, but without a break between function and brace. Adds spaces in
a few places they weren't before.

John Hawthorn authored on 07/11/2015 05:45:02
Showing 1 changed files
... ...
@@ -18,15 +18,15 @@ size_t scrolloff = 1;
18 18
 
19 19
 const char *prompt = "> ";
20 20
 
21
-void read_choices(choices_t *c){
21
+void read_choices(choices_t *c) {
22 22
 	const char *line;
23 23
 	char buf[4096];
24
-	while(fgets(buf, sizeof buf, stdin)){
24
+	while (fgets(buf, sizeof buf, stdin)) {
25 25
 		char *nl;
26
-		if((nl = strchr(buf, '\n')))
26
+		if ((nl = strchr(buf, '\n')))
27 27
 			*nl = '\0';
28 28
 
29
-		if(!(line = strdup(buf))){
29
+		if (!(line = strdup(buf))) {
30 30
 			fprintf(stderr, "Cannot allocate memory");
31 31
 			abort();
32 32
 		}
... ...
@@ -38,42 +38,42 @@ void read_choices(choices_t *c){
38 38
 int search_size;
39 39
 char search[SEARCH_SIZE_MAX + 1] = {0};
40 40
 
41
-void clear(tty_t *tty){
41
+void clear(tty_t *tty) {
42 42
 	tty_setcol(tty, 0);
43 43
 	size_t line = 0;
44
-	while(line++ < num_lines){
44
+	while (line++ < num_lines) {
45 45
 		tty_newline(tty);
46 46
 	}
47
-	tty_moveup(tty, line-1);
47
+	tty_moveup(tty, line - 1);
48 48
 	tty_flush(tty);
49 49
 }
50 50
 
51
-void draw_match(tty_t *tty, const char *choice, int selected){
51
+void draw_match(tty_t *tty, const char *choice, int selected) {
52 52
 	int n = strlen(search);
53 53
 	size_t positions[n + 1];
54
-	for(int i = 0; i < n + 1; i++)
54
+	for (int i = 0; i < n + 1; i++)
55 55
 		positions[i] = -1;
56 56
 
57 57
 	double score = match_positions(search, choice, &positions[0]);
58 58
 
59 59
 	size_t maxwidth = tty_getwidth(tty);
60 60
 
61
-	if(flag_show_scores)
61
+	if (flag_show_scores)
62 62
 		tty_printf(tty, "(%5.2f) ", score);
63 63
 
64
-	if(selected)
64
+	if (selected)
65 65
 		tty_setinvert(tty);
66 66
 
67
-	for(size_t i = 0, p = 0; choice[i] != '\0'; i++){
68
-		if(i+1 < maxwidth){
69
-			if(positions[p] == i){
67
+	for (size_t i = 0, p = 0; choice[i] != '\0'; i++) {
68
+		if (i + 1 < maxwidth) {
69
+			if (positions[p] == i) {
70 70
 				tty_setfg(tty, TTY_COLOR_HIGHLIGHT);
71 71
 				p++;
72
-			}else{
72
+			} else {
73 73
 				tty_setfg(tty, TTY_COLOR_NORMAL);
74 74
 			}
75 75
 			tty_printf(tty, "%c", choice[i]);
76
-		}else{
76
+		} else {
77 77
 			tty_printf(tty, "$");
78 78
 			break;
79 79
 		}
... ...
@@ -81,23 +81,23 @@ void draw_match(tty_t *tty, const char *choice, int selected){
81 81
 	tty_setnormal(tty);
82 82
 }
83 83
 
84
-void draw(tty_t *tty, choices_t *choices){
84
+void draw(tty_t *tty, choices_t *choices) {
85 85
 	size_t start = 0;
86 86
 	size_t current_selection = choices->selection;
87
-	if(current_selection + scrolloff >= num_lines){
87
+	if (current_selection + scrolloff >= num_lines) {
88 88
 		start = current_selection + scrolloff - num_lines + 1;
89
-		if(start + num_lines >= choices_available(choices)){
89
+		if (start + num_lines >= choices_available(choices)) {
90 90
 			start = choices_available(choices) - num_lines;
91 91
 		}
92 92
 	}
93 93
 	tty_setcol(tty, 0);
94 94
 	tty_printf(tty, "%s%s", prompt, search);
95 95
 	tty_clearline(tty);
96
-	for(size_t i = start; i < start + num_lines; i++){
96
+	for (size_t i = start; i < start + num_lines; i++) {
97 97
 		tty_printf(tty, "\n");
98 98
 		tty_clearline(tty);
99 99
 		const char *choice = choices_get(choices, i);
100
-		if(choice){
100
+		if (choice) {
101 101
 			draw_match(tty, choice, i == choices->selection);
102 102
 		}
103 103
 	}
... ...
@@ -106,12 +106,12 @@ void draw(tty_t *tty, choices_t *choices){
106 106
 	tty_flush(tty);
107 107
 }
108 108
 
109
-void emit(choices_t *choices){
109
+void emit(choices_t *choices) {
110 110
 	const char *selection = choices_get(choices, choices->selection);
111
-	if(selection){
111
+	if (selection) {
112 112
 		/* output the selected result */
113 113
 		printf("%s\n", selection);
114
-	}else{
114
+	} else {
115 115
 		/* No match, output the query instead */
116 116
 		printf("%s\n", search);
117 117
 	}
... ...
@@ -119,98 +119,97 @@ void emit(choices_t *choices){
119 119
 	exit(EXIT_SUCCESS);
120 120
 }
121 121
 
122
-void run(tty_t *tty, choices_t *choices){
122
+void run(tty_t *tty, choices_t *choices) {
123 123
 	choices_search(choices, search);
124 124
 	char ch;
125 125
 	do {
126 126
 		draw(tty, choices);
127 127
 		ch = tty_getchar(tty);
128
-		if(isprint(ch)){
129
-			if(search_size < SEARCH_SIZE_MAX){
128
+		if (isprint(ch)) {
129
+			if (search_size < SEARCH_SIZE_MAX) {
130 130
 				search[search_size++] = ch;
131 131
 				search[search_size] = '\0';
132 132
 				choices_search(choices, search);
133 133
 			}
134
-		}else if(ch == 127 || ch == 8){ /* DEL || backspace */
135
-			if(search_size)
134
+		} else if (ch == 127 || ch == 8) { /* DEL || backspace */
135
+			if (search_size)
136 136
 				search[--search_size] = '\0';
137 137
 			choices_search(choices, search);
138
-		}else if(ch == 21){ /* C-U */
138
+		} else if (ch == 21) { /* C-U */
139 139
 			search_size = 0;
140 140
 			search[0] = '\0';
141 141
 			choices_search(choices, search);
142
-		}else if(ch == 23){ /* C-W */
143
-			if(search_size)
142
+		} else if (ch == 23) { /* C-W */
143
+			if (search_size)
144 144
 				search[--search_size] = '\0';
145
-			while(search_size && !isspace(search[--search_size]))
145
+			while (search_size && !isspace(search[--search_size]))
146 146
 				search[search_size] = '\0';
147 147
 			choices_search(choices, search);
148
-		}else if(ch == 14){ /* C-N */
148
+		} else if (ch == 14) { /* C-N */
149 149
 			choices_next(choices);
150
-		}else if(ch == 16){ /* C-P */
150
+		} else if (ch == 16) { /* C-P */
151 151
 			choices_prev(choices);
152
-		}else if(ch == 9){ /* TAB */
152
+		} else if (ch == 9) { /* TAB */
153 153
 			strncpy(search, choices_get(choices, choices->selection), SEARCH_SIZE_MAX);
154 154
 			search_size = strlen(search);
155 155
 			choices_search(choices, search);
156
-		}else if(ch == 3 || ch == 4){ /* ^C || ^D */
156
+		} else if (ch == 3 || ch == 4) { /* ^C || ^D */
157 157
 			clear(tty);
158 158
 			tty_close(tty);
159 159
 			exit(EXIT_FAILURE);
160
-		}else if(ch == 10){ /* Enter */
160
+		} else if (ch == 10) { /* Enter */
161 161
 			clear(tty);
162 162
 
163 163
 			/* ttyout should be flushed before outputting on stdout */
164 164
 			tty_close(tty);
165 165
 
166 166
 			emit(choices);
167
-		}else if(ch == 27){ /* ESC */
167
+		} else if (ch == 27) { /* ESC */
168 168
 			ch = tty_getchar(tty);
169
-			if(ch == '[' || ch == 'O'){
169
+			if (ch == '[' || ch == 'O') {
170 170
 				ch = tty_getchar(tty);
171
-				if(ch == 'A'){ /* UP ARROW */
171
+				if (ch == 'A') { /* UP ARROW */
172 172
 					choices_prev(choices);
173
-				}else if(ch == 'B'){ /* DOWN ARROW */
173
+				} else if (ch == 'B') { /* DOWN ARROW */
174 174
 					choices_next(choices);
175 175
 				}
176 176
 			}
177 177
 		}
178
-	}while(1);
178
+	} while (1);
179 179
 }
180 180
 
181
-static const char *usage_str = ""
182
-"Usage: fzy [OPTION]...\n"
183
-" -l, --lines=LINES        Specify how many lines of results to show (default 10)\n"
184
-" -p, --prompt=PROMPT      Input prompt (default '> ')\n"
185
-" -e, --show-matches=QUERY Output the sorted matches of QUERY\n"
186
-" -t, --tty=TTY            Specify file to use as TTY device (default /dev/tty)\n"
187
-" -s, --show-scores        Show the scores of each match\n"
188
-" -h, --help     Display this help and exit\n"
189
-" -v, --version  Output version information and exit\n";
181
+static const char *usage_str =
182
+    ""
183
+    "Usage: fzy [OPTION]...\n"
184
+    " -l, --lines=LINES        Specify how many lines of results to show (default 10)\n"
185
+    " -p, --prompt=PROMPT      Input prompt (default '> ')\n"
186
+    " -e, --show-matches=QUERY Output the sorted matches of QUERY\n"
187
+    " -t, --tty=TTY            Specify file to use as TTY device (default /dev/tty)\n"
188
+    " -s, --show-scores        Show the scores of each match\n"
189
+    " -h, --help     Display this help and exit\n"
190
+    " -v, --version  Output version information and exit\n";
190 191
 
191
-void usage(const char *argv0){
192
+void usage(const char *argv0) {
192 193
 	fprintf(stderr, usage_str, argv0);
193 194
 }
194 195
 
195
-static struct option longopts[] = {
196
-	{ "show-matches", required_argument, NULL, 'e' },
197
-	{ "lines", required_argument, NULL, 'l' },
198
-	{ "tty", required_argument, NULL, 't' },
199
-	{ "prompt", required_argument, NULL, 'p' },
200
-	{ "show-scores", no_argument, NULL, 's' },
201
-	{ "version", no_argument, NULL, 'v' },
202
-	{ "benchmark", no_argument, NULL, 'b' },
203
-	{ "help",    no_argument, NULL, 'h' },
204
-	{ NULL,      0,           NULL, 0 }
205
-};
196
+static struct option longopts[] = {{"show-matches", required_argument, NULL, 'e'},
197
+				   {"lines", required_argument, NULL, 'l'},
198
+				   {"tty", required_argument, NULL, 't'},
199
+				   {"prompt", required_argument, NULL, 'p'},
200
+				   {"show-scores", no_argument, NULL, 's'},
201
+				   {"version", no_argument, NULL, 'v'},
202
+				   {"benchmark", no_argument, NULL, 'b'},
203
+				   {"help", no_argument, NULL, 'h'},
204
+				   {NULL, 0, NULL, 0}};
206 205
 
207
-int main(int argc, char *argv[]){
206
+int main(int argc, char *argv[]) {
208 207
 	int benchmark = 0;
209 208
 	const char *initial_query = NULL;
210 209
 	const char *tty_filename = "/dev/tty";
211 210
 	char c;
212
-	while((c = getopt_long(argc, argv, "vhse:l:t:p:", longopts, NULL)) != -1){
213
-		switch(c){
211
+	while ((c = getopt_long(argc, argv, "vhse:l:t:p:", longopts, NULL)) != -1) {
212
+		switch (c) {
214 213
 			case 'v':
215 214
 				printf("%s " VERSION " (c) 2014 John Hawthorn\n", argv[0]);
216 215
 				exit(EXIT_SUCCESS);
... ...
@@ -229,27 +228,25 @@ int main(int argc, char *argv[]){
229 228
 			case 'p':
230 229
 				prompt = optarg;
231 230
 				break;
232
-			case 'l':
233
-				{
234
-					int l;
235
-					if(!strcmp(optarg, "max")){
236
-						l = INT_MAX;
237
-					}else if(sscanf(optarg, "%d", &l) != 1 || l < 3){
238
-						fprintf(stderr, "Invalid format for --lines: %s\n", optarg);
239
-						fprintf(stderr, "Must be integer in range 3..\n");
240
-						usage(argv[0]);
241
-						exit(EXIT_FAILURE);
242
-					}
243
-					num_lines = l;
231
+			case 'l': {
232
+				int l;
233
+				if (!strcmp(optarg, "max")) {
234
+					l = INT_MAX;
235
+				} else if (sscanf(optarg, "%d", &l) != 1 || l < 3) {
236
+					fprintf(stderr, "Invalid format for --lines: %s\n", optarg);
237
+					fprintf(stderr, "Must be integer in range 3..\n");
238
+					usage(argv[0]);
239
+					exit(EXIT_FAILURE);
244 240
 				}
245
-				break;
241
+				num_lines = l;
242
+			} break;
246 243
 			case 'h':
247 244
 			default:
248 245
 				usage(argv[0]);
249 246
 				exit(EXIT_SUCCESS);
250 247
 		}
251 248
 	}
252
-	if(optind != argc){
249
+	if (optind != argc) {
253 250
 		usage(argv[0]);
254 251
 		exit(EXIT_FAILURE);
255 252
 	}
... ...
@@ -258,29 +255,29 @@ int main(int argc, char *argv[]){
258 255
 	choices_init(&choices);
259 256
 	read_choices(&choices);
260 257
 
261
-	if(num_lines > choices.size)
258
+	if (num_lines > choices.size)
262 259
 		num_lines = choices.size;
263 260
 
264
-	if(benchmark){
265
-		if(!initial_query){
261
+	if (benchmark) {
262
+		if (!initial_query) {
266 263
 			fprintf(stderr, "Must specify -e/--show-matches with --benchmark\n");
267 264
 			exit(EXIT_FAILURE);
268 265
 		}
269
-		for(int i = 0; i < 100; i++)
266
+		for (int i = 0; i < 100; i++)
270 267
 			choices_search(&choices, initial_query);
271
-	}else if(initial_query){
268
+	} else if (initial_query) {
272 269
 		choices_search(&choices, initial_query);
273
-		for(size_t i = 0; i < choices_available(&choices); i++){
274
-			if(flag_show_scores)
270
+		for (size_t i = 0; i < choices_available(&choices); i++) {
271
+			if (flag_show_scores)
275 272
 				printf("%f\t", choices_getscore(&choices, i));
276 273
 			printf("%s\n", choices_get(&choices, i));
277 274
 		}
278
-	}else{
275
+	} else {
279 276
 		/* interactive */
280 277
 		tty_t tty;
281 278
 		tty_init(&tty, tty_filename);
282 279
 
283
-		if(num_lines + 1 > tty_getheight(&tty))
280
+		if (num_lines + 1 > tty_getheight(&tty))
284 281
 			num_lines = tty_getheight(&tty) - 1;
285 282
 
286 283
 		run(&tty, &choices);
Browse code

Disable signals from ^C (and friends)

Allows us to interpret ^C through ^Z as control codes and handle them
properly.

Also fixes resetting termios after ^C

John Hawthorn authored on 19/10/2014 23:42:38
Showing 1 changed files
... ...
@@ -153,6 +153,10 @@ void run(tty_t *tty, choices_t *choices){
153 153
 			strncpy(search, choices_get(choices, choices->selection), SEARCH_SIZE_MAX);
154 154
 			search_size = strlen(search);
155 155
 			choices_search(choices, search);
156
+		}else if(ch == 3 || ch == 4){ /* ^C || ^D */
157
+			clear(tty);
158
+			tty_close(tty);
159
+			exit(EXIT_FAILURE);
156 160
 		}else if(ch == 10){ /* Enter */
157 161
 			clear(tty);
158 162
 
Browse code

termios should be reset on successful exit.

Still needs to be fixed on an exit due to ^C

Thanks @rtandy

John Hawthorn authored on 19/10/2014 23:19:24
Showing 1 changed files
... ...
@@ -157,7 +157,7 @@ void run(tty_t *tty, choices_t *choices){
157 157
 			clear(tty);
158 158
 
159 159
 			/* ttyout should be flushed before outputting on stdout */
160
-			fclose(tty->fout);
160
+			tty_close(tty);
161 161
 
162 162
 			emit(choices);
163 163
 		}else if(ch == 27){ /* ESC */
Browse code

Remove getline in favour of fgets/strdup

getline is a little greedy with memory usage, using a little extra for
every line read. strdup should always use the minimum amount.

John Hawthorn authored on 21/09/2014 22:23:23
Showing 1 changed files
... ...
@@ -19,20 +19,19 @@ size_t scrolloff = 1;
19 19
 const char *prompt = "> ";
20 20
 
21 21
 void read_choices(choices_t *c){
22
-	char *line = NULL;
23
-	size_t len = 0;
24
-	ssize_t read;
25
-
26
-	while ((read = getline(&line, &len, stdin)) != -1) {
22
+	const char *line;
23
+	char buf[4096];
24
+	while(fgets(buf, sizeof buf, stdin)){
27 25
 		char *nl;
28
-		if((nl = strchr(line, '\n')))
26
+		if((nl = strchr(buf, '\n')))
29 27
 			*nl = '\0';
30 28
 
29
+		if(!(line = strdup(buf))){
30
+			fprintf(stderr, "Cannot allocate memory");
31
+			abort();
32
+		}
31 33
 		choices_add(c, line);
32
-
33
-		line = NULL;
34 34
 	}
35
-	free(line);
36 35
 }
37 36
 
38 37
 #define SEARCH_SIZE_MAX 4096
Browse code

Specify const char *

John Hawthorn authored on 21/09/2014 21:04:56
Showing 1 changed files
... ...
@@ -203,8 +203,8 @@ static struct option longopts[] = {
203 203
 
204 204
 int main(int argc, char *argv[]){
205 205
 	int benchmark = 0;
206
-	char *initial_query = NULL;
207
-	char *tty_filename = "/dev/tty";
206
+	const char *initial_query = NULL;
207
+	const char *tty_filename = "/dev/tty";
208 208
 	char c;
209 209
 	while((c = getopt_long(argc, argv, "vhse:l:t:p:", longopts, NULL)) != -1){
210 210
 		switch(c){
Browse code

Allow custom prompt

John Hawthorn authored on 21/09/2014 21:04:00
Showing 1 changed files
... ...
@@ -16,6 +16,8 @@ int flag_show_scores = 0;
16 16
 size_t num_lines = 10;
17 17
 size_t scrolloff = 1;
18 18
 
19
+const char *prompt = "> ";
20
+
19 21
 void read_choices(choices_t *c){
20 22
 	char *line = NULL;
21 23
 	size_t len = 0;
... ...
@@ -89,7 +91,6 @@ void draw(tty_t *tty, choices_t *choices){
89 91
 			start = choices_available(choices) - num_lines;
90 92
 		}
91 93
 	}
92
-	const char *prompt = "> ";
93 94
 	tty_setcol(tty, 0);
94 95
 	tty_printf(tty, "%s%s", prompt, search);
95 96
 	tty_clearline(tty);
... ...
@@ -177,11 +178,12 @@ void run(tty_t *tty, choices_t *choices){
177 178
 static const char *usage_str = ""
178 179
 "Usage: fzy [OPTION]...\n"
179 180
 " -l, --lines=LINES        Specify how many lines of results to show (default 10)\n"
180
-" -e, --show-matches=QUERY output the sorted matches of QUERY\n"
181
+" -p, --prompt=PROMPT      Input prompt (default '> ')\n"
182
+" -e, --show-matches=QUERY Output the sorted matches of QUERY\n"
181 183
 " -t, --tty=TTY            Specify file to use as TTY device (default /dev/tty)\n"
182
-" -s, --show-scores        show the scores of each match\n"
183
-" -h, --help     display this help and exit\n"
184
-" -v, --version  output version information and exit\n";
184
+" -s, --show-scores        Show the scores of each match\n"
185
+" -h, --help     Display this help and exit\n"
186
+" -v, --version  Output version information and exit\n";
185 187
 
186 188
 void usage(const char *argv0){
187 189
 	fprintf(stderr, usage_str, argv0);
... ...
@@ -191,6 +193,7 @@ static struct option longopts[] = {
191 193
 	{ "show-matches", required_argument, NULL, 'e' },
192 194
 	{ "lines", required_argument, NULL, 'l' },
193 195
 	{ "tty", required_argument, NULL, 't' },
196
+	{ "prompt", required_argument, NULL, 'p' },
194 197
 	{ "show-scores", no_argument, NULL, 's' },
195 198
 	{ "version", no_argument, NULL, 'v' },
196 199
 	{ "benchmark", no_argument, NULL, 'b' },
... ...
@@ -203,7 +206,7 @@ int main(int argc, char *argv[]){
203 206
 	char *initial_query = NULL;
204 207
 	char *tty_filename = "/dev/tty";
205 208
 	char c;
206
-	while((c = getopt_long(argc, argv, "vhse:l:t:", longopts, NULL)) != -1){
209
+	while((c = getopt_long(argc, argv, "vhse:l:t:p:", longopts, NULL)) != -1){
207 210
 		switch(c){
208 211
 			case 'v':
209 212
 				printf("%s " VERSION " (c) 2014 John Hawthorn\n", argv[0]);
... ...
@@ -220,6 +223,9 @@ int main(int argc, char *argv[]){
220 223
 			case 't':
221 224
 				tty_filename = optarg;
222 225
 				break;
226
+			case 'p':
227
+				prompt = optarg;
228
+				break;
223 229
 			case 'l':
224 230
 				{
225 231
 					int l;
Browse code

Re-run search on TAB

John Hawthorn authored on 18/09/2014 03:42:18
Showing 1 changed files
... ...
@@ -152,6 +152,7 @@ void run(tty_t *tty, choices_t *choices){
152 152
 		}else if(ch == 9){ /* TAB */
153 153
 			strncpy(search, choices_get(choices, choices->selection), SEARCH_SIZE_MAX);
154 154
 			search_size = strlen(search);
155
+			choices_search(choices, search);
155 156
 		}else if(ch == 10){ /* Enter */
156 157
 			clear(tty);
157 158
 
Browse code

Move _GNU_SOURCE definition to makefile

John Hawthorn authored on 18/09/2014 03:23:20
Showing 1 changed files
... ...
@@ -1,4 +1,3 @@
1
-#define _GNU_SOURCE
2 1
 #include <stdio.h>
3 2
 #include <string.h>
4 3
 #include <stdlib.h>
Browse code

Allow specifying max for limit

John Hawthorn authored on 17/09/2014 02:20:39
Showing 1 changed files
... ...
@@ -4,6 +4,7 @@
4 4
 #include <stdlib.h>
5 5
 #include <ctype.h>
6 6
 #include <getopt.h>
7
+#include <limits.h>
7 8
 
8 9
 #include "match.h"
9 10
 #include "tty.h"
... ...
@@ -222,7 +223,9 @@ int main(int argc, char *argv[]){
222 223
 			case 'l':
223 224
 				{
224 225
 					int l;
225
-					if(sscanf(optarg, "%d", &l) != 1 || l < 3){
226
+					if(!strcmp(optarg, "max")){
227
+						l = INT_MAX;
228
+					}else if(sscanf(optarg, "%d", &l) != 1 || l < 3){
226 229
 						fprintf(stderr, "Invalid format for --lines: %s\n", optarg);
227 230
 						fprintf(stderr, "Must be integer in range 3..\n");
228 231
 						usage(argv[0]);
Browse code

Cap max lines at terminal height

John Hawthorn authored on 17/09/2014 02:13:41
Showing 1 changed files
... ...
@@ -246,6 +246,9 @@ int main(int argc, char *argv[]){
246 246
 	choices_init(&choices);
247 247
 	read_choices(&choices);
248 248
 
249
+	if(num_lines > choices.size)
250
+		num_lines = choices.size;
251
+
249 252
 	if(benchmark){
250 253
 		if(!initial_query){
251 254
 			fprintf(stderr, "Must specify -e/--show-matches with --benchmark\n");
... ...
@@ -265,6 +268,9 @@ int main(int argc, char *argv[]){
265 268
 		tty_t tty;
266 269
 		tty_init(&tty, tty_filename);
267 270
 
271
+		if(num_lines + 1 > tty_getheight(&tty))
272
+			num_lines = tty_getheight(&tty) - 1;
273
+
268 274
 		run(&tty, &choices);
269 275
 	}
270 276
 
Browse code

Add config.h

John Hawthorn authored on 17/09/2014 01:41:49
Showing 1 changed files
... ...
@@ -9,6 +9,8 @@
9 9
 #include "tty.h"
10 10
 #include "choices.h"
11 11
 
12
+#include "config.h"
13
+
12 14
 int flag_show_scores = 0;
13 15
 
14 16
 size_t num_lines = 10;
... ...
@@ -45,8 +47,6 @@ void clear(tty_t *tty){
45 47
 	tty_flush(tty);
46 48
 }
47 49
 
48
-#define TTY_COLOR_HIGHLIGHT TTY_COLOR_YELLOW
49
-
50 50
 void draw_match(tty_t *tty, const char *choice, int selected){
51 51
 	int n = strlen(search);
52 52
 	size_t positions[n + 1];
Browse code

Truncate matches at terminal width

John Hawthorn authored on 15/09/2014 07:07:18
Showing 1 changed files
... ...
@@ -55,6 +55,8 @@ void draw_match(tty_t *tty, const char *choice, int selected){
55 55
 
56 56
 	double score = match_positions(search, choice, &positions[0]);
57 57
 
58
+	size_t maxwidth = tty_getwidth(tty);
59
+
58 60
 	if(flag_show_scores)
59 61
 		tty_printf(tty, "(%5.2f) ", score);
60 62
 
... ...
@@ -62,13 +64,18 @@ void draw_match(tty_t *tty, const char *choice, int selected){
62 64
 		tty_setinvert(tty);
63 65
 
64 66
 	for(size_t i = 0, p = 0; choice[i] != '\0'; i++){
65
-		if(positions[p] == i){
66
-			tty_setfg(tty, TTY_COLOR_HIGHLIGHT);
67
-			p++;
67
+		if(i+1 < maxwidth){
68
+			if(positions[p] == i){
69
+				tty_setfg(tty, TTY_COLOR_HIGHLIGHT);
70
+				p++;
71
+			}else{
72
+				tty_setfg(tty, TTY_COLOR_NORMAL);
73
+			}
74
+			tty_printf(tty, "%c", choice[i]);
68 75
 		}else{
69
-			tty_setfg(tty, TTY_COLOR_NORMAL);
76
+			tty_printf(tty, "$");
77
+			break;
70 78
 		}
71
-		tty_printf(tty, "%c", choice[i]);
72 79
 	}
73 80
 	tty_setnormal(tty);
74 81
 }
... ...
@@ -85,14 +92,15 @@ void draw(tty_t *tty, choices_t *choices){
85 92
 	const char *prompt = "> ";
86 93
 	tty_setcol(tty, 0);
87 94
 	tty_printf(tty, "%s%s", prompt, search);
95
+	tty_clearline(tty);
88 96
 	for(size_t i = start; i < start + num_lines; i++){
89
-		tty_newline(tty);
97
+		tty_printf(tty, "\n");
98
+		tty_clearline(tty);
90 99
 		const char *choice = choices_get(choices, i);
91 100
 		if(choice){
92 101
 			draw_match(tty, choice, i == choices->selection);
93 102
 		}
94 103
 	}
95
-	tty_clearline(tty);
96 104
 	tty_moveup(tty, num_lines);
97 105
 	tty_setcol(tty, strlen(prompt) + strlen(search));
98 106
 	tty_flush(tty);
Browse code

Cleanup headers

John Hawthorn authored on 15/09/2014 02:42:43
Showing 1 changed files
... ...
@@ -5,7 +5,7 @@
5 5
 #include <ctype.h>
6 6
 #include <getopt.h>
7 7
 
8
-#include "fzy.h"
8
+#include "match.h"
9 9
 #include "tty.h"
10 10
 #include "choices.h"
11 11
 
Browse code

Refactor into choices.c

John Hawthorn authored on 14/09/2014 05:19:52
Showing 1 changed files
... ...
@@ -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;
Browse code

Move score printing into draw_match

John Hawthorn authored on 14/09/2014 04:27:05
Showing 1 changed files
... ...
@@ -111,7 +111,10 @@ void draw_match(tty_t *tty, const char *choice, int selected){
111 111
 	for(int i = 0; i < n + 1; i++)
112 112
 		positions[i] = -1;
113 113
 
114
-	match_positions(search, choice, &positions[0]);
114
+	double score = match_positions(search, choice, &positions[0]);
115
+
116
+	if(flag_show_scores)
117
+		tty_printf(tty, "(%5.2f) ", score);
115 118
 
116 119
 	if(selected)
117 120
 		tty_setinvert(tty);
... ...
@@ -143,8 +146,6 @@ void draw(tty_t *tty){
143 146
 		tty_newline(tty);
144 147
 		if(i < choices_available){
145 148
 			size_t choice_idx = choices_sorted[i];
146
-			if(flag_show_scores)
147
-				tty_printf(tty, "(%5.2f) ", choices_score[choice_idx]);
148 149
 			draw_match(tty, choices[choice_idx], i == current_selection);
149 150
 		}
150 151
 	}
Browse code

Add TAB

John Hawthorn authored on 14/09/2014 03:56:40
Showing 1 changed files
... ...
@@ -207,6 +207,9 @@ void run(tty_t *tty){
207 207
 			action_next();
208 208
 		}else if(ch == 16){ /* C-P */
209 209
 			action_prev();
210
+		}else if(ch == 9){ /* TAB */
211
+			strncpy(search, choices[choices_sorted[current_selection]], SEARCH_SIZE_MAX);
212
+			search_size = strlen(search);
210 213
 		}else if(ch == 10){ /* Enter */
211 214
 			clear(tty);
212 215
 			emit(tty);
Browse code

Add -t,--tty

John Hawthorn authored on 14/09/2014 03:55:33
Showing 1 changed files
... ...
@@ -225,9 +225,10 @@ void run(tty_t *tty){
225 225
 }
226 226
 
227 227
 static const char *usage_str = ""
228
-"USAGE: fzy [OPTION]...\n"
229
-" -l, --lines=LINES        Specify how many lines of results to show\n"
228
+"Usage: fzy [OPTION]...\n"
229
+" -l, --lines=LINES        Specify how many lines of results to show (default 10)\n"
230 230
 " -e, --show-matches=QUERY output the sorted matches of QUERY\n"
231
+" -t, --tty=TTY            Specify file to use as TTY device (default /dev/tty)\n"
231 232
 " -s, --show-scores        show the scores of each match\n"
232 233
 " -h, --help     display this help and exit\n"
233 234
 " -v, --version  output version information and exit\n";
... ...
@@ -239,6 +240,7 @@ void usage(const char *argv0){
239 240
 static struct option longopts[] = {
240 241
 	{ "show-matches", required_argument, NULL, 'e' },
241 242
 	{ "lines", required_argument, NULL, 'l' },
243
+	{ "tty", required_argument, NULL, 't' },
242 244
 	{ "show-scores", no_argument, NULL, 's' },
243 245
 	{ "version", no_argument, NULL, 'v' },
244 246
 	{ "benchmark", no_argument, NULL, 'b' },
... ...
@@ -249,8 +251,9 @@ static struct option longopts[] = {
249 251
 int main(int argc, char *argv[]){
250 252
 	int benchmark = 0;
251 253
 	char *initial_query = NULL;
254
+	char *tty_filename = "/dev/tty";
252 255
 	char c;
253
-	while((c = getopt_long(argc, argv, "vhse:l:", longopts, NULL)) != -1){
256
+	while((c = getopt_long(argc, argv, "vhse:l:t:", longopts, NULL)) != -1){
254 257
 		switch(c){
255 258
 			case 'v':
256 259
 				printf("%s " VERSION " (c) 2014 John Hawthorn\n", argv[0]);
... ...
@@ -264,6 +267,9 @@ int main(int argc, char *argv[]){
264 267
 			case 'b':
265 268
 				benchmark = 1;
266 269
 				break;
270
+			case 't':
271
+				tty_filename = optarg;
272
+				break;
267 273
 			case 'l':
268 274
 				{
269 275
 					int l;
... ...
@@ -308,7 +314,7 @@ int main(int argc, char *argv[]){
308 314
 	}else{
309 315
 		/* interactive */
310 316
 		tty_t tty;
311
-		tty_init(&tty);
317
+		tty_init(&tty, tty_filename);
312 318
 
313 319
 		run(&tty);
314 320
 	}
Browse code

Fix help for --lines

John Hawthorn authored on 11/09/2014 21:14:40
Showing 1 changed files
... ...
@@ -226,7 +226,7 @@ void run(tty_t *tty){
226 226
 
227 227
 static const char *usage_str = ""
228 228
 "USAGE: fzy [OPTION]...\n"
229
-" -l, --lines              Specify how many lines of results to show\n"
229
+" -l, --lines=LINES        Specify how many lines of results to show\n"
230 230
 " -e, --show-matches=QUERY output the sorted matches of QUERY\n"
231 231
 " -s, --show-scores        show the scores of each match\n"
232 232
 " -h, --help     display this help and exit\n"
Browse code

add --benchmark

John Hawthorn authored on 07/09/2014 00:59:26
Showing 1 changed files
... ...
@@ -241,11 +241,13 @@ static struct option longopts[] = {
241 241
 	{ "lines", required_argument, NULL, 'l' },
242 242
 	{ "show-scores", no_argument, NULL, 's' },
243 243
 	{ "version", no_argument, NULL, 'v' },
244
+	{ "benchmark", no_argument, NULL, 'b' },
244 245
 	{ "help",    no_argument, NULL, 'h' },
245 246
 	{ NULL,      0,           NULL, 0 }
246 247
 };
247 248
 
248 249
 int main(int argc, char *argv[]){
250
+	int benchmark = 0;
249 251
 	char *initial_query = NULL;
250 252
 	char c;
251 253
 	while((c = getopt_long(argc, argv, "vhse:l:", longopts, NULL)) != -1){
... ...
@@ -259,6 +261,9 @@ int main(int argc, char *argv[]){
259 261
 			case 'e':
260 262
 				initial_query = optarg;
261 263
 				break;
264
+			case 'b':
265
+				benchmark = 1;
266
+				break;
262 267
 			case 'l':
263 268
 				{
264 269
 					int l;
... ...
@@ -285,7 +290,14 @@ int main(int argc, char *argv[]){
285 290
 	resize_choices(INITIAL_CAPACITY);
286 291
 	read_choices();
287 292
 
288
-	if(initial_query){
293
+	if(benchmark){
294
+		if(!initial_query){
295
+			fprintf(stderr, "Must specify -e/--show-matches with --benchmark\n");
296
+			exit(EXIT_FAILURE);
297
+		}
298
+		for(int i = 0; i < 100; i++)
299
+			run_search(initial_query);
300
+	}else if(initial_query){
289 301
 		run_search(initial_query);
290 302
 		for(size_t i = 0; i < choices_available; i++){
291 303
 			size_t choice_idx = choices_sorted[i];
Browse code

Allow specifying number of lines to show

John Hawthorn authored on 31/08/2014 03:05:29
Showing 1 changed files
... ...
@@ -10,6 +10,10 @@
10 10
 
11 11
 int flag_show_scores = 0;
12 12
 
13
+size_t num_lines = 10;
14
+size_t scrolloff = 1;
15
+
16
+
13 17
 #define INITIAL_CAPACITY 1
14 18
 int choices_capacity = 0;
15 19
 int choices_n = 0;
... ...
@@ -85,17 +89,14 @@ void run_search(char *needle){
85 89
 	qsort(choices_sorted, choices_available, sizeof(size_t), cmpchoice);
86 90
 }
87 91
 
88
-#define NUMLINES 10
89
-#define SCROLLOFF 1
90
-
91 92
 #define SEARCH_SIZE_MAX 4096
92 93
 int search_size;
93 94
 char search[SEARCH_SIZE_MAX + 1] = {0};
94 95
 
95 96
 void clear(tty_t *tty){
96 97
 	tty_setcol(tty, 0);
97
-	int line = 0;
98
-	while(line++ < NUMLINES){
98
+	size_t line = 0;
99
+	while(line++ < num_lines){
99 100
 		tty_newline(tty);
100 101
 	}
101 102
 	tty_moveup(tty, line-1);
... ...
@@ -129,16 +130,16 @@ void draw_match(tty_t *tty, const char *choice, int selected){
129 130
 
130 131
 void draw(tty_t *tty){
131 132
 	size_t start = 0;
132
-	if(current_selection + SCROLLOFF >= NUMLINES){
133
-		start = current_selection + SCROLLOFF - NUMLINES + 1;
134
-		if(start + NUMLINES >= choices_available){
135
-			start = choices_available - NUMLINES;
133
+	if(current_selection + scrolloff >= num_lines){
134
+		start = current_selection + scrolloff - num_lines + 1;
135
+		if(start + num_lines >= choices_available){
136
+			start = choices_available - num_lines;
136 137
 		}
137 138
 	}
138 139
 	const char *prompt = "> ";
139 140
 	tty_setcol(tty, 0);
140 141
 	tty_printf(tty, "%s%s", prompt, search);
141
-	for(size_t i = start; i < start + NUMLINES; i++){
142
+	for(size_t i = start; i < start + num_lines; i++){
142 143
 		tty_newline(tty);
143 144
 		if(i < choices_available){
144 145
 			size_t choice_idx = choices_sorted[i];
... ...
@@ -148,7 +149,7 @@ void draw(tty_t *tty){
148 149
 		}
149 150
 	}
150 151
 	tty_clearline(tty);
151
-	tty_moveup(tty, NUMLINES);
152
+	tty_moveup(tty, num_lines);
152 153
 	tty_setcol(tty, strlen(prompt) + strlen(search));
153 154
 	tty_flush(tty);
154 155
 }
... ...
@@ -225,6 +226,7 @@ void run(tty_t *tty){
225 226
 
226 227
 static const char *usage_str = ""
227 228
 "USAGE: fzy [OPTION]...\n"
229
+" -l, --lines              Specify how many lines of results to show\n"
228 230
 " -e, --show-matches=QUERY output the sorted matches of QUERY\n"
229 231
 " -s, --show-scores        show the scores of each match\n"
230 232
 " -h, --help     display this help and exit\n"
... ...
@@ -232,11 +234,11 @@ static const char *usage_str = ""
232 234
 
233 235
 void usage(const char *argv0){
234 236
 	fprintf(stderr, usage_str, argv0);
235
-	exit(EXIT_FAILURE);
236 237
 }
237 238
 
238 239
 static struct option longopts[] = {
239 240
 	{ "show-matches", required_argument, NULL, 'e' },
241
+	{ "lines", required_argument, NULL, 'l' },
240 242
 	{ "show-scores", no_argument, NULL, 's' },
241 243
 	{ "version", no_argument, NULL, 'v' },
242 244
 	{ "help",    no_argument, NULL, 'h' },
... ...
@@ -246,7 +248,7 @@ static struct option longopts[] = {
246 248
 int main(int argc, char *argv[]){
247 249
 	char *initial_query = NULL;
248 250
 	char c;
249
-	while((c = getopt_long(argc, argv, "vhse:", longopts, NULL)) != -1){
251
+	while((c = getopt_long(argc, argv, "vhse:l:", longopts, NULL)) != -1){
250 252
 		switch(c){
251 253
 			case 'v':
252 254
 				printf("%s " VERSION " (c) 2014 John Hawthorn\n", argv[0]);
... ...
@@ -257,14 +259,27 @@ int main(int argc, char *argv[]){
257 259
 			case 'e':
258 260
 				initial_query = optarg;
259 261
 				break;
262
+			case 'l':
263
+				{
264
+					int l;
265
+					if(sscanf(optarg, "%d", &l) != 1 || l < 3){
266
+						fprintf(stderr, "Invalid format for --lines: %s\n", optarg);
267
+						fprintf(stderr, "Must be integer in range 3..\n");
268
+						usage(argv[0]);
269
+						exit(EXIT_FAILURE);
270
+					}
271
+					num_lines = l;
272
+				}
273
+				break;
260 274
 			case 'h':
261 275
 			default:
262 276
 				usage(argv[0]);
263
-				exit(EXIT_FAILURE);
277
+				exit(EXIT_SUCCESS);
264 278
 		}
265 279
 	}
266 280
 	if(optind != argc){
267 281
 		usage(argv[0]);
282
+		exit(EXIT_FAILURE);
268 283
 	}
269 284
 
270 285
 	resize_choices(INITIAL_CAPACITY);
Browse code

Use last line of terminal

John Hawthorn authored on 31/08/2014 02:11:18
Showing 1 changed files
... ...
@@ -95,7 +95,7 @@ char search[SEARCH_SIZE_MAX + 1] = {0};
95 95
 void clear(tty_t *tty){
96 96
 	tty_setcol(tty, 0);
97 97
 	int line = 0;
98
-	while(line++ < NUMLINES + 1){
98
+	while(line++ < NUMLINES){
99 99
 		tty_newline(tty);
100 100
 	}
101 101
 	tty_moveup(tty, line-1);
... ...
@@ -132,24 +132,23 @@ void draw(tty_t *tty){
132 132
 	if(current_selection + SCROLLOFF >= NUMLINES){
133 133
 		start = current_selection + SCROLLOFF - NUMLINES + 1;
134 134
 		if(start + NUMLINES >= choices_available){
135
-			start = choices_available - NUMLINES + 1;
135
+			start = choices_available - NUMLINES;
136 136
 		}
137 137
 	}
138 138
 	const char *prompt = "> ";
139 139
 	tty_setcol(tty, 0);
140 140
 	tty_printf(tty, "%s%s", prompt, search);
141
-	tty_newline(tty);
142 141
 	for(size_t i = start; i < start + NUMLINES; i++){
142
+		tty_newline(tty);
143 143
 		if(i < choices_available){
144 144
 			size_t choice_idx = choices_sorted[i];
145 145
 			if(flag_show_scores)
146 146
 				tty_printf(tty, "(%5.2f) ", choices_score[choice_idx]);
147 147
 			draw_match(tty, choices[choice_idx], i == current_selection);
148
-		}else{
149
-			tty_newline(tty);
150 148
 		}
151 149
 	}
152
-	tty_moveup(tty, NUMLINES + 1);
150
+	tty_clearline(tty);
151
+	tty_moveup(tty, NUMLINES);
153 152
 	tty_setcol(tty, strlen(prompt) + strlen(search));
154 153
 	tty_flush(tty);
155 154
 }
Browse code

Add scrolloff

John Hawthorn authored on 21/08/2014 02:58:09
Showing 1 changed files
... ...
@@ -86,6 +86,7 @@ void run_search(char *needle){
86 86
 }
87 87
 
88 88
 #define NUMLINES 10
89
+#define SCROLLOFF 1
89 90
 
90 91
 #define SEARCH_SIZE_MAX 4096
91 92
 int search_size;
... ...
@@ -123,14 +124,16 @@ void draw_match(tty_t *tty, const char *choice, int selected){
123 124
 		}
124 125
 		tty_printf(tty, "%c", choice[i]);
125 126
 	}
126
-	tty_newline(tty);
127 127
 	tty_setnormal(tty);
128 128
 }
129 129
 
130 130
 void draw(tty_t *tty){
131 131
 	size_t start = 0;
132
-	if(current_selection >= NUMLINES){
133
-		start = current_selection - NUMLINES + 1;
132
+	if(current_selection + SCROLLOFF >= NUMLINES){
133
+		start = current_selection + SCROLLOFF - NUMLINES + 1;
134
+		if(start + NUMLINES >= choices_available){
135
+			start = choices_available - NUMLINES + 1;
136
+		}
134 137
 	}
135 138
 	const char *prompt = "> ";
136 139
 	tty_setcol(tty, 0);
Browse code

Skip unnecessary initial clear.

John Hawthorn authored on 21/08/2014 02:07:38
Showing 1 changed files
... ...
@@ -281,7 +281,6 @@ int main(int argc, char *argv[]){
281 281
 		tty_t tty;
282 282
 		tty_init(&tty);
283 283
 
284
-		clear(&tty);
285 284
 		run(&tty);
286 285
 	}
287 286
 
Browse code

Fix -eQUERY invocation

John Hawthorn authored on 20/08/2014 04:43:14
Showing 1 changed files
... ...
@@ -244,7 +244,7 @@ static struct option longopts[] = {
244 244
 int main(int argc, char *argv[]){
245 245
 	char *initial_query = NULL;
246 246
 	char c;
247
-	while((c = getopt_long(argc, argv, "vhs", longopts, NULL)) != -1){
247
+	while((c = getopt_long(argc, argv, "vhse:", longopts, NULL)) != -1){
248 248
 		switch(c){
249 249
 			case 'v':
250 250
 				printf("%s " VERSION " (c) 2014 John Hawthorn\n", argv[0]);
Browse code

Add non-interactive invocation

John Hawthorn authored on 20/08/2014 02:57:44
Showing 1 changed files
... ...
@@ -223,6 +223,7 @@ void run(tty_t *tty){
223 223
 
224 224
 static const char *usage_str = ""
225 225
 "USAGE: fzy [OPTION]...\n"
226
+" -e, --show-matches=QUERY output the sorted matches of QUERY\n"
226 227
 " -s, --show-scores        show the scores of each match\n"
227 228
 " -h, --help     display this help and exit\n"
228 229
 " -v, --version  output version information and exit\n";
... ...
@@ -233,14 +234,15 @@ void usage(const char *argv0){
233 234
 }
234 235
 
235 236
 static struct option longopts[] = {
237
+	{ "show-matches", required_argument, NULL, 'e' },
236 238
 	{ "show-scores", no_argument, NULL, 's' },
237 239
 	{ "version", no_argument, NULL, 'v' },
238 240
 	{ "help",    no_argument, NULL, 'h' },
239 241
 	{ NULL,      0,           NULL, 0 }
240 242
 };
241 243
 
242
-
243 244
 int main(int argc, char *argv[]){
245
+	char *initial_query = NULL;
244 246
 	char c;
245 247
 	while((c = getopt_long(argc, argv, "vhs", longopts, NULL)) != -1){
246 248
 		switch(c){
... ...
@@ -250,6 +252,9 @@ int main(int argc, char *argv[]){
250 252
 			case 's':
251 253
 				flag_show_scores = 1;
252 254
 				break;
255
+			case 'e':
256
+				initial_query = optarg;
257
+				break;
253 258
 			case 'h':
254 259
 			default:
255 260
 				usage(argv[0]);
... ...
@@ -260,14 +265,25 @@ int main(int argc, char *argv[]){
260 265
 		usage(argv[0]);
261 266
 	}
262 267
 
263
-	tty_t tty;
264
-	tty_init(&tty);
265
-
266 268
 	resize_choices(INITIAL_CAPACITY);
267 269
 	read_choices();
268 270
 
269
-	clear(&tty);
270
-	run(&tty);
271
+	if(initial_query){
272
+		run_search(initial_query);
273
+		for(size_t i = 0; i < choices_available; i++){
274
+			size_t choice_idx = choices_sorted[i];
275
+			if(flag_show_scores)
276
+				printf("%f\t", choices_score[choice_idx]);
277
+			printf("%s\n", choices[choice_idx]);
278
+		}
279
+	}else{
280
+		/* interactive */
281
+		tty_t tty;
282
+		tty_init(&tty);
283
+
284
+		clear(&tty);
285
+		run(&tty);
286
+	}
271 287
 
272 288
 	return 0;
273 289
 }
Browse code

Flag to show scores of matches

John Hawthorn authored on 20/08/2014 02:35:45
Showing 1 changed files
... ...
@@ -8,6 +8,8 @@
8 8
 #include "fzy.h"
9 9
 #include "tty.h"
10 10
 
11
+int flag_show_scores = 0;
12
+
11 13
 #define INITIAL_CAPACITY 1
12 14
 int choices_capacity = 0;
13 15
 int choices_n = 0;
... ...
@@ -136,7 +138,10 @@ void draw(tty_t *tty){
136 138
 	tty_newline(tty);
137 139
 	for(size_t i = start; i < start + NUMLINES; i++){
138 140
 		if(i < choices_available){
139
-			draw_match(tty, choices[choices_sorted[i]], i == current_selection);
141
+			size_t choice_idx = choices_sorted[i];
142
+			if(flag_show_scores)
143
+				tty_printf(tty, "(%5.2f) ", choices_score[choice_idx]);
144
+			draw_match(tty, choices[choice_idx], i == current_selection);
140 145
 		}else{
141 146
 			tty_newline(tty);
142 147
 		}
... ...
@@ -218,6 +223,7 @@ void run(tty_t *tty){
218 223
 
219 224
 static const char *usage_str = ""
220 225
 "USAGE: fzy [OPTION]...\n"
226
+" -s, --show-scores        show the scores of each match\n"
221 227
 " -h, --help     display this help and exit\n"
222 228
 " -v, --version  output version information and exit\n";
223 229
 
... ...
@@ -227,6 +233,7 @@ void usage(const char *argv0){
227 233
 }
228 234
 
229 235
 static struct option longopts[] = {
236
+	{ "show-scores", no_argument, NULL, 's' },
230 237
 	{ "version", no_argument, NULL, 'v' },
231 238
 	{ "help",    no_argument, NULL, 'h' },
232 239
 	{ NULL,      0,           NULL, 0 }
... ...
@@ -235,11 +242,14 @@ static struct option longopts[] = {
235 242
 
236 243
 int main(int argc, char *argv[]){
237 244
 	char c;
238
-	while((c = getopt_long(argc, argv, "vh", longopts, NULL)) != -1){
245
+	while((c = getopt_long(argc, argv, "vhs", longopts, NULL)) != -1){
239 246
 		switch(c){
240 247
 			case 'v':
241 248
 				printf("%s " VERSION " (c) 2014 John Hawthorn\n", argv[0]);
242 249
 				exit(EXIT_SUCCESS);
250
+			case 's':
251
+				flag_show_scores = 1;
252
+				break;
243 253
 			case 'h':
244 254
 			default:
245 255
 				usage(argv[0]);
Browse code

Use optparse, support --help, --version

John Hawthorn authored on 20/08/2014 02:16:24
Showing 1 changed files
... ...
@@ -3,6 +3,7 @@
3 3
 #include <string.h>
4 4
 #include <stdlib.h>
5 5
 #include <ctype.h>
6
+#include <getopt.h>
6 7
 
7 8
 #include "fzy.h"
8 9
 #include "tty.h"
... ...
@@ -215,18 +216,40 @@ void run(tty_t *tty){
215 216
 	}while(1);
216 217
 }
217 218
 
219
+static const char *usage_str = ""
220
+"USAGE: fzy [OPTION]...\n"
221
+" -h, --help     display this help and exit\n"
222
+" -v, --version  output version information and exit\n";
223
+
218 224
 void usage(const char *argv0){
219
-	fprintf(stderr, "USAGE: %s\n", argv0);
225
+	fprintf(stderr, usage_str, argv0);
220 226
 	exit(EXIT_FAILURE);
221 227
 }
222 228
 
229
+static struct option longopts[] = {
230
+	{ "version", no_argument, NULL, 'v' },
231
+	{ "help",    no_argument, NULL, 'h' },
232
+	{ NULL,      0,           NULL, 0 }
233
+};
234
+
235
+
223 236
 int main(int argc, char *argv[]){
224
-	if(argc == 2 && !strcmp(argv[1], "-v")){
225
-		printf("%s " VERSION  " (c) 2014 John Hawthorn\n", argv[0]);
226
-		exit(EXIT_SUCCESS);
227
-	}else if(argc != 1){
237
+	char c;
238
+	while((c = getopt_long(argc, argv, "vh", longopts, NULL)) != -1){
239
+		switch(c){
240
+			case 'v':
241
+				printf("%s " VERSION " (c) 2014 John Hawthorn\n", argv[0]);
242
+				exit(EXIT_SUCCESS);
243
+			case 'h':
244
+			default:
245
+				usage(argv[0]);
246
+				exit(EXIT_FAILURE);
247
+		}
248
+	}
249
+	if(optind != argc){
228 250
 		usage(argv[0]);
229 251
 	}
252
+
230 253
 	tty_t tty;
231 254
 	tty_init(&tty);
232 255
 
Browse code

Up/Down might also be ^[OA or ^[OB

John Hawthorn authored on 18/08/2014 20:34:39
Showing 1 changed files
... ...
@@ -203,7 +203,7 @@ void run(tty_t *tty){
203 203
 			emit(tty);
204 204
 		}else if(ch == 27){ /* ESC */
205 205
 			ch = tty_getchar(tty);
206
-			if(ch == '['){
206
+			if(ch == '[' || ch == 'O'){
207 207
 				ch = tty_getchar(tty);
208 208
 				if(ch == 'A'){ /* UP ARROW */
209 209
 					action_prev();
Browse code

Flush at end of clear

John Hawthorn authored on 17/08/2014 03:45:00
Showing 1 changed files
... ...
@@ -95,7 +95,7 @@ void clear(tty_t *tty){
95 95
 		tty_newline(tty);
96 96
 	}
97 97
 	tty_moveup(tty, line-1);
98
-	tty_setcol(tty, 0);
98
+	tty_flush(tty);
99 99
 }
100 100
 
101 101
 #define TTY_COLOR_HIGHLIGHT TTY_COLOR_YELLOW
Browse code

Simplify draw

John Hawthorn authored on 17/08/2014 03:43:34
Showing 1 changed files
... ...
@@ -125,24 +125,22 @@ void draw_match(tty_t *tty, const char *choice, int selected){
125 125
 }
126 126
 
127 127
 void draw(tty_t *tty){
128
-	int start = 0;
128
+	size_t start = 0;
129 129
 	if(current_selection >= NUMLINES){
130 130
 		start = current_selection - NUMLINES + 1;
131 131
 	}
132
-	int line = 0;
133 132
 	const char *prompt = "> ";
134 133
 	tty_setcol(tty, 0);
135 134
 	tty_printf(tty, "%s%s", prompt, search);
136 135
 	tty_newline(tty);
137
-	for(size_t i = start; line < NUMLINES; i++){
136
+	for(size_t i = start; i < start + NUMLINES; i++){
138 137
 		if(i < choices_available){
139 138
 			draw_match(tty, choices[choices_sorted[i]], i == current_selection);
140 139
 		}else{
141 140
 			tty_newline(tty);
142 141
 		}
143
-		line++;
144 142
 	}
145
-	tty_moveup(tty, line + 1);
143
+	tty_moveup(tty, NUMLINES + 1);
146 144
 	tty_setcol(tty, strlen(prompt) + strlen(search));
147 145
 	tty_flush(tty);
148 146
 }
Browse code

Avoid full clear before redraw

Instead of clearing the existing text before redrawing, clear as we draw
using tty_newline (CSI-K). This looks smoother when scrolling under
xterm and probably other terminals.

John Hawthorn authored on 17/08/2014 03:39:06
Showing 1 changed files
... ...
@@ -120,7 +120,7 @@ void draw_match(tty_t *tty, const char *choice, int selected){
120 120
 		}
121 121
 		tty_printf(tty, "%c", choice[i]);
122 122
 	}
123
-	tty_printf(tty, "\n");
123
+	tty_newline(tty);
124 124
 	tty_setnormal(tty);
125 125
 }
126 126
 
... ...
@@ -131,10 +131,15 @@ void draw(tty_t *tty){
131 131
 	}
132 132
 	int line = 0;
133 133
 	const char *prompt = "> ";
134
-	clear(tty);
135
-	tty_printf(tty, "%s%s\n", prompt, search);
136
-	for(size_t i = start; line < NUMLINES && i < choices_available; i++){
137
-		draw_match(tty, choices[choices_sorted[i]], i == current_selection);
134
+	tty_setcol(tty, 0);
135
+	tty_printf(tty, "%s%s", prompt, search);
136
+	tty_newline(tty);
137
+	for(size_t i = start; line < NUMLINES; i++){
138
+		if(i < choices_available){
139
+			draw_match(tty, choices[choices_sorted[i]], i == current_selection);
140
+		}else{
141
+			tty_newline(tty);
142
+		}
138 143
 		line++;
139 144
 	}
140 145
 	tty_moveup(tty, line + 1);
Browse code

Make tty_setcol 0-indexed

John Hawthorn authored on 17/08/2014 03:37:12
Showing 1 changed files
... ...
@@ -138,7 +138,7 @@ void draw(tty_t *tty){
138 138
 		line++;
139 139
 	}
140 140
 	tty_moveup(tty, line + 1);
141
-	tty_setcol(tty, strlen(prompt) + strlen(search) + 1);
141
+	tty_setcol(tty, strlen(prompt) + strlen(search));
142 142
 	tty_flush(tty);
143 143
 }
144 144
 
Browse code

tty_flush

John Hawthorn authored on 17/08/2014 03:34:16
Showing 1 changed files
... ...
@@ -139,7 +139,7 @@ void draw(tty_t *tty){
139 139
 	}
140 140
 	tty_moveup(tty, line + 1);
141 141
 	tty_setcol(tty, strlen(prompt) + strlen(search) + 1);
142
-	fflush(tty->fout);
142
+	tty_flush(tty);
143 143
 }
144 144
 
145 145
 void emit(tty_t *tty){
Browse code

Refactor into tty_moveup

John Hawthorn authored on 17/08/2014 03:33:24
Showing 1 changed files
... ...
@@ -94,7 +94,7 @@ void clear(tty_t *tty){
94 94
 	while(line++ < NUMLINES + 1){
95 95
 		tty_newline(tty);
96 96
 	}
97
-	fprintf(tty->fout, "%c%c%iA", 0x1b, '[', line-1);
97
+	tty_moveup(tty, line-1);
98 98
 	tty_setcol(tty, 0);
99 99
 }
100 100
 
... ...
@@ -137,7 +137,7 @@ void draw(tty_t *tty){
137 137
 		draw_match(tty, choices[choices_sorted[i]], i == current_selection);
138 138
 		line++;
139 139
 	}
140
-	fprintf(tty->fout, "%c%c%iA", 0x1b, '[', line + 1);
140
+	tty_moveup(tty, line + 1);
141 141
 	tty_setcol(tty, strlen(prompt) + strlen(search) + 1);
142 142
 	fflush(tty->fout);
143 143
 }
Browse code

Refactor into tty_newline and tty_setcol

John Hawthorn authored on 17/08/2014 03:31:11
Showing 1 changed files
... ...
@@ -89,13 +89,13 @@ int search_size;
89 89
 char search[SEARCH_SIZE_MAX + 1] = {0};
90 90
 
91 91
 void clear(tty_t *tty){
92
-	fprintf(tty->fout, "%c%c0G", 0x1b, '[');
92
+	tty_setcol(tty, 0);
93 93
 	int line = 0;
94 94
 	while(line++ < NUMLINES + 1){
95
-		fprintf(tty->fout, "%c%cK\n", 0x1b, '[');
95
+		tty_newline(tty);
96 96
 	}
97 97
 	fprintf(tty->fout, "%c%c%iA", 0x1b, '[', line-1);
98
-	fprintf(tty->fout, "%c%c0G", 0x1b, '[');
98
+	tty_setcol(tty, 0);
99 99
 }
100 100
 
101 101
 #define TTY_COLOR_HIGHLIGHT TTY_COLOR_YELLOW
... ...
@@ -138,7 +138,7 @@ void draw(tty_t *tty){
138 138
 		line++;
139 139
 	}
140 140
 	fprintf(tty->fout, "%c%c%iA", 0x1b, '[', line + 1);
141
-	fprintf(tty->fout, "%c%c%ziG", 0x1b, '[', strlen(prompt) + strlen(search) + 1);
141
+	tty_setcol(tty, strlen(prompt) + strlen(search) + 1);
142 142
 	fflush(tty->fout);
143 143
 }
144 144
 
Browse code

Refactor into tty_printf

John Hawthorn authored on 17/08/2014 03:20:09
Showing 1 changed files
... ...
@@ -118,9 +118,9 @@ void draw_match(tty_t *tty, const char *choice, int selected){
118 118
 		}else{
119 119
 			tty_setfg(tty, TTY_COLOR_NORMAL);
120 120
 		}
121
-		fprintf(tty->fout, "%c", choice[i]);
121
+		tty_printf(tty, "%c", choice[i]);
122 122
 	}
123
-	fprintf(tty->fout, "\n");
123
+	tty_printf(tty, "\n");
124 124
 	tty_setnormal(tty);
125 125
 }
126 126
 
... ...
@@ -132,7 +132,7 @@ void draw(tty_t *tty){
132 132
 	int line = 0;
133 133
 	const char *prompt = "> ";
134 134
 	clear(tty);
135
-	fprintf(tty->fout, "%s%s\n", prompt, search);
135
+	tty_printf(tty, "%s%s\n", prompt, search);
136 136
 	for(size_t i = start; line < NUMLINES && i < choices_available; i++){
137 137
 		draw_match(tty, choices[choices_sorted[i]], i == current_selection);
138 138
 		line++;
Browse code

Support UP/DOWN arrow

John Hawthorn authored on 17/08/2014 03:08:51
Showing 1 changed files
... ...
@@ -198,6 +198,16 @@ void run(tty_t *tty){
198 198
 		}else if(ch == 10){ /* Enter */
199 199
 			clear(tty);
200 200
 			emit(tty);
201
+		}else if(ch == 27){ /* ESC */
202
+			ch = tty_getchar(tty);
203
+			if(ch == '['){
204
+				ch = tty_getchar(tty);
205
+				if(ch == 'A'){ /* UP ARROW */
206
+					action_prev();
207
+				}else if(ch == 'B'){ /* DOWN ARROW */
208
+					action_next();
209
+				}
210
+			}
201 211
 		}
202 212
 	}while(1);
203 213
 }
Browse code

Allow selecting past the 10th choice

John Hawthorn authored on 04/08/2014 21:38:43
Showing 1 changed files
... ...
@@ -125,11 +125,15 @@ void draw_match(tty_t *tty, const char *choice, int selected){
125 125
 }
126 126
 
127 127
 void draw(tty_t *tty){
128
+	int start = 0;
129
+	if(current_selection >= NUMLINES){
130
+		start = current_selection - NUMLINES + 1;
131
+	}
128 132
 	int line = 0;
129 133
 	const char *prompt = "> ";
130 134
 	clear(tty);
131 135
 	fprintf(tty->fout, "%s%s\n", prompt, search);
132
-	for(size_t i = 0; line < NUMLINES && i < choices_available; i++){
136
+	for(size_t i = start; line < NUMLINES && i < choices_available; i++){
133 137
 		draw_match(tty, choices[choices_sorted[i]], i == current_selection);
134 138
 		line++;
135 139
 	}
... ...
@@ -154,11 +158,11 @@ void emit(tty_t *tty){
154 158
 }
155 159
 
156 160
 void action_prev(){
157
-	current_selection = (current_selection + NUMLINES - 1) % NUMLINES;
161
+	current_selection = (current_selection + choices_available - 1) % choices_available;
158 162
 }
159 163
 
160 164
 void action_next(){
161
-	current_selection = (current_selection + 1) % NUMLINES;
165
+	current_selection = (current_selection + 1) % choices_available;
162 166
 }
163 167
 
164 168
 void run(tty_t *tty){
Browse code

action_next and action_prev

John Hawthorn authored on 04/08/2014 21:08:37
Showing 1 changed files
... ...
@@ -153,6 +153,14 @@ void emit(tty_t *tty){
153 153
 	exit(EXIT_SUCCESS);
154 154
 }
155 155
 
156
+void action_prev(){
157
+	current_selection = (current_selection + NUMLINES - 1) % NUMLINES;
158
+}
159
+
160
+void action_next(){
161
+	current_selection = (current_selection + 1) % NUMLINES;
162
+}
163
+
156 164
 void run(tty_t *tty){
157 165
 	run_search(search);
158 166
 	char ch;
... ...
@@ -180,9 +188,9 @@ void run(tty_t *tty){
180 188
 				search[search_size] = '\0';
181 189
 			run_search(search);
182 190
 		}else if(ch == 14){ /* C-N */
183
-			current_selection = (current_selection + 1) % NUMLINES;
191
+			action_next();
184 192
 		}else if(ch == 16){ /* C-P */
185
-			current_selection = (current_selection + NUMLINES - 1) % NUMLINES;
193
+			action_prev();
186 194
 		}else if(ch == 10){ /* Enter */
187 195
 			clear(tty);
188 196
 			emit(tty);
Browse code

Define ANSI color values

John Hawthorn authored on 04/08/2014 08:01:43
Showing 1 changed files
... ...
@@ -98,6 +98,8 @@ void clear(tty_t *tty){
98 98
 	fprintf(tty->fout, "%c%c0G", 0x1b, '[');
99 99
 }
100 100
 
101
+#define TTY_COLOR_HIGHLIGHT TTY_COLOR_YELLOW
102
+
101 103
 void draw_match(tty_t *tty, const char *choice, int selected){
102 104
 	int n = strlen(search);
103 105
 	size_t positions[n + 1];
... ...
@@ -111,10 +113,10 @@ void draw_match(tty_t *tty, const char *choice, int selected){
111 113
 
112 114
 	for(size_t i = 0, p = 0; choice[i] != '\0'; i++){
113 115
 		if(positions[p] == i){
114
-			tty_setfg(tty, 3);
116
+			tty_setfg(tty, TTY_COLOR_HIGHLIGHT);
115 117
 			p++;
116 118
 		}else{
117
-			tty_setfg(tty, 9);
119
+			tty_setfg(tty, TTY_COLOR_NORMAL);
118 120
 		}
119 121
 		fprintf(tty->fout, "%c", choice[i]);
120 122
 	}
Browse code

Extract ANSI CSI SGR calls into tty.c

John Hawthorn authored on 04/08/2014 07:08:10
Showing 1 changed files
... ...
@@ -106,17 +106,20 @@ void draw_match(tty_t *tty, const char *choice, int selected){
106 106
 
107 107
 	match_positions(search, choice, &positions[0]);
108 108
 
109
+	if(selected)
110
+		tty_setinvert(tty);
111
+
109 112
 	for(size_t i = 0, p = 0; choice[i] != '\0'; i++){
110 113
 		if(positions[p] == i){
111
-			fprintf(tty->fout, "%c%c33m", 0x1b, '[');
114
+			tty_setfg(tty, 3);
112 115
 			p++;
113 116
 		}else{
114
-			fprintf(tty->fout, "%c%c39;49m", 0x1b, '[');
117
+			tty_setfg(tty, 9);
115 118
 		}
116 119
 		fprintf(tty->fout, "%c", choice[i]);
117 120
 	}
118 121
 	fprintf(tty->fout, "\n");
119
-	fprintf(tty->fout, "%c%c0m", 0x1b, '[');
122
+	tty_setnormal(tty);
120 123
 }
121 124
 
122 125
 void draw(tty_t *tty){
... ...
@@ -125,8 +128,6 @@ void draw(tty_t *tty){
125 128
 	clear(tty);
126 129
 	fprintf(tty->fout, "%s%s\n", prompt, search);
127 130
 	for(size_t i = 0; line < NUMLINES && i < choices_available; i++){
128
-		if(i == current_selection)
129
-			fprintf(tty->fout, "%c%c7m", 0x1b, '[');
130 131
 		draw_match(tty, choices[choices_sorted[i]], i == current_selection);
131 132
 		line++;
132 133
 	}
Browse code

Fix possible overflow on long search string

John Hawthorn authored on 04/08/2014 05:05:37
Showing 1 changed files
... ...
@@ -84,8 +84,9 @@ void run_search(char *needle){
84 84
 
85 85
 #define NUMLINES 10
86 86
 
87
+#define SEARCH_SIZE_MAX 4096
87 88
 int search_size;
88
-char search[4096] = {0};
89
+char search[SEARCH_SIZE_MAX + 1] = {0};
89 90
 
90 91
 void clear(tty_t *tty){
91 92
 	fprintf(tty->fout, "%c%c0G", 0x1b, '[');
... ...
@@ -156,10 +157,11 @@ void run(tty_t *tty){
156 157
 		draw(tty);
157 158
 		ch = tty_getchar(tty);
158 159
 		if(isprint(ch)){
159
-			/* FIXME: overflow */
160
-			search[search_size++] = ch;
161
-			search[search_size] = '\0';
162
-			run_search(search);
160
+			if(search_size < SEARCH_SIZE_MAX){
161
+				search[search_size++] = ch;
162
+				search[search_size] = '\0';
163
+				run_search(search);
164
+			}
163 165
 		}else if(ch == 127 || ch == 8){ /* DEL || backspace */
164 166
 			if(search_size)
165 167
 				search[--search_size] = '\0';
Browse code

Define number of lines as a macro

John Hawthorn authored on 04/08/2014 05:03:07
Showing 1 changed files
... ...
@@ -82,13 +82,15 @@ void run_search(char *needle){
82 82
 	qsort(choices_sorted, choices_available, sizeof(size_t), cmpchoice);
83 83
 }
84 84
 
85
+#define NUMLINES 10
86
+
85 87
 int search_size;
86 88
 char search[4096] = {0};
87 89
 
88 90
 void clear(tty_t *tty){
89 91
 	fprintf(tty->fout, "%c%c0G", 0x1b, '[');
90 92
 	int line = 0;
91
-	while(line++ < 10 + 1){
93
+	while(line++ < NUMLINES + 1){
92 94
 		fprintf(tty->fout, "%c%cK\n", 0x1b, '[');
93 95
 	}
94 96
 	fprintf(tty->fout, "%c%c%iA", 0x1b, '[', line-1);
... ...
@@ -121,7 +123,7 @@ void draw(tty_t *tty){
121 123
 	const char *prompt = "> ";
122 124
 	clear(tty);
123 125
 	fprintf(tty->fout, "%s%s\n", prompt, search);
124
-	for(size_t i = 0; line < 10 && i < choices_available; i++){
126
+	for(size_t i = 0; line < NUMLINES && i < choices_available; i++){
125 127
 		if(i == current_selection)
126 128
 			fprintf(tty->fout, "%c%c7m", 0x1b, '[');
127 129
 		draw_match(tty, choices[choices_sorted[i]], i == current_selection);
... ...
@@ -173,9 +175,9 @@ void run(tty_t *tty){
173 175
 				search[search_size] = '\0';
174 176
 			run_search(search);
175 177
 		}else if(ch == 14){ /* C-N */
176
-			current_selection = (current_selection + 1) % 10;
178
+			current_selection = (current_selection + 1) % NUMLINES;
177 179
 		}else if(ch == 16){ /* C-P */
178
-			current_selection = (current_selection + 9) % 10;
180
+			current_selection = (current_selection + NUMLINES - 1) % NUMLINES;
179 181
 		}else if(ch == 10){ /* Enter */
180 182
 			clear(tty);
181 183
 			emit(tty);
Browse code

Split tty functions into tty.c

John Hawthorn authored on 04/08/2014 04:56:17
Showing 1 changed files
... ...
@@ -2,13 +2,10 @@
2 2
 #include <stdio.h>
3 3
 #include <string.h>
4 4
 #include <stdlib.h>
5
-#include <termios.h>
6
-#include <unistd.h>
7
-#include <sys/stat.h>
8
-#include <fcntl.h>
9 5
 #include <ctype.h>
10 6
 
11 7
 #include "fzy.h"
8
+#include "tty.h"
12 9
 
13 10
 #define INITIAL_CAPACITY 1
14 11
 int choices_capacity = 0;
... ...
@@ -83,58 +80,22 @@ void run_search(char *needle){
83 80
 	}
84 81
 
85 82
 	qsort(choices_sorted, choices_available, sizeof(size_t), cmpchoice);
86
-
87
-}
88
-
89
-int ttyin;
90
-FILE *ttyout;
91
-struct termios original_termios;
92
-
93
-void reset_tty(){
94
-	tcsetattr(ttyin, TCSANOW, &original_termios);
95
-}
96
-
97
-void init_tty(){
98
-	ttyin = open("/dev/tty", O_RDONLY);
99
-	ttyout = fopen("/dev/tty", "w");
100
-
101
-	tcgetattr(ttyin, &original_termios);
102
-
103
-	struct termios new_termios = original_termios;
104
-
105
-	new_termios.c_lflag &= ~(ICANON | ECHO);
106
-
107
-	tcsetattr(ttyin, TCSANOW, &new_termios);
108
-}
109
-
110
-char ttygetchar(){
111
-	char ch;
112
-	int size = read(ttyin, &ch, 1);
113
-	if(size < 0){
114
-		perror("error reading from tty");
115
-		exit(EXIT_FAILURE);
116
-	}else if(size == 0){
117
-		/* EOF */
118
-		exit(EXIT_FAILURE);
119
-	}else{
120
-		return ch;
121
-	}
122 83
 }
123 84
 
124 85
 int search_size;
125 86
 char search[4096] = {0};
126 87
 
127
-void clear(){
128
-	fprintf(ttyout, "%c%c0G", 0x1b, '[');
88
+void clear(tty_t *tty){
89
+	fprintf(tty->fout, "%c%c0G", 0x1b, '[');
129 90
 	int line = 0;
130 91
 	while(line++ < 10 + 1){
131
-		fprintf(ttyout, "%c%cK\n", 0x1b, '[');
92
+		fprintf(tty->fout, "%c%cK\n", 0x1b, '[');
132 93
 	}
133
-	fprintf(ttyout, "%c%c%iA", 0x1b, '[', line-1);
134
-	fprintf(ttyout, "%c%c0G", 0x1b, '[');
94
+	fprintf(tty->fout, "%c%c%iA", 0x1b, '[', line-1);
95
+	fprintf(tty->fout, "%c%c0G", 0x1b, '[');
135 96
 }
136 97
 
137
-void draw_match(const char *choice, int selected){
98
+void draw_match(tty_t *tty, const char *choice, int selected){
138 99
 	int n = strlen(search);
139 100
 	size_t positions[n + 1];
140 101
 	for(int i = 0; i < n + 1; i++)
... ...
@@ -144,36 +105,36 @@ void draw_match(const char *choice, int selected){
144 105
 
145 106
 	for(size_t i = 0, p = 0; choice[i] != '\0'; i++){
146 107
 		if(positions[p] == i){
147
-			fprintf(ttyout, "%c%c33m", 0x1b, '[');
108
+			fprintf(tty->fout, "%c%c33m", 0x1b, '[');
148 109
 			p++;
149 110
 		}else{
150
-			fprintf(ttyout, "%c%c39;49m", 0x1b, '[');
111
+			fprintf(tty->fout, "%c%c39;49m", 0x1b, '[');
151 112
 		}
152
-		fprintf(ttyout, "%c", choice[i]);
113
+		fprintf(tty->fout, "%c", choice[i]);
153 114
 	}
154
-	fprintf(ttyout, "\n");
155
-	fprintf(ttyout, "%c%c0m", 0x1b, '[');
115
+	fprintf(tty->fout, "\n");
116
+	fprintf(tty->fout, "%c%c0m", 0x1b, '[');
156 117
 }
157 118
 
158
-void draw(){
119
+void draw(tty_t *tty){
159 120
 	int line = 0;
160 121
 	const char *prompt = "> ";
161
-	clear();
162
-	fprintf(ttyout, "%s%s\n", prompt, search);
122
+	clear(tty);
123
+	fprintf(tty->fout, "%s%s\n", prompt, search);
163 124
 	for(size_t i = 0; line < 10 && i < choices_available; i++){
164 125
 		if(i == current_selection)
165
-			fprintf(ttyout, "%c%c7m", 0x1b, '[');
166
-		draw_match(choices[choices_sorted[i]], i == current_selection);
126
+			fprintf(tty->fout, "%c%c7m", 0x1b, '[');
127
+		draw_match(tty, choices[choices_sorted[i]], i == current_selection);
167 128
 		line++;
168 129
 	}
169
-	fprintf(ttyout, "%c%c%iA", 0x1b, '[', line + 1);
170
-	fprintf(ttyout, "%c%c%ziG", 0x1b, '[', strlen(prompt) + strlen(search) + 1);
171
-	fflush(ttyout);
130
+	fprintf(tty->fout, "%c%c%iA", 0x1b, '[', line + 1);
131
+	fprintf(tty->fout, "%c%c%ziG", 0x1b, '[', strlen(prompt) + strlen(search) + 1);
132
+	fflush(tty->fout);
172 133
 }
173 134
 
174
-void emit(){
135
+void emit(tty_t *tty){
175 136
 	/* ttyout should be flushed before outputting on stdout */
176
-	fclose(ttyout);
137
+	fclose(tty->fout);
177 138
 
178 139
 	if(choices_available){
179 140
 		/* output the selected result */
... ...
@@ -186,12 +147,12 @@ void emit(){
186 147
 	exit(EXIT_SUCCESS);
187 148
 }
188 149
 
189
-void run(){
150
+void run(tty_t *tty){
190 151
 	run_search(search);
191 152
 	char ch;
192 153
 	do {
193
-		draw();
194
-		ch = ttygetchar();
154
+		draw(tty);
155
+		ch = tty_getchar(tty);
195 156
 		if(isprint(ch)){
196 157
 			/* FIXME: overflow */
197 158
 			search[search_size++] = ch;
... ...
@@ -213,13 +174,11 @@ void run(){
213 174
 			run_search(search);
214 175
 		}else if(ch == 14){ /* C-N */
215 176
 			current_selection = (current_selection + 1) % 10;
216
-			draw();
217 177
 		}else if(ch == 16){ /* C-P */
218 178
 			current_selection = (current_selection + 9) % 10;
219
-			draw();
220 179
 		}else if(ch == 10){ /* Enter */
221
-			clear();
222
-			emit();
180
+			clear(tty);
181
+			emit(tty);
223 182
 		}
224 183
 	}while(1);
225 184
 }
... ...
@@ -236,14 +195,14 @@ int main(int argc, char *argv[]){
236 195
 	}else if(argc != 1){
237 196
 		usage(argv[0]);
238 197
 	}
239
-	atexit(reset_tty);
240
-	init_tty(reset_tty);
198
+	tty_t tty;
199
+	tty_init(&tty);
241 200
 
242 201
 	resize_choices(INITIAL_CAPACITY);
243 202
 	read_choices();
244 203
 
245
-	clear();
246
-	run();
204
+	clear(&tty);
205
+	run(&tty);
247 206
 
248 207
 	return 0;
249 208
 }
Browse code

don't print tabs

Dylan Kendal authored on 28/07/2014 03:37:02
Showing 1 changed files
... ...
@@ -220,8 +220,6 @@ void run(){
220 220
 		}else if(ch == 10){ /* Enter */
221 221
 			clear();
222 222
 			emit();
223
-		}else{
224
-			printf("'%c' (%i)\n", ch, ch);
225 223
 		}
226 224
 	}while(1);
227 225
 }
Browse code

Don't break ties

John Hawthorn authored on 27/07/2014 06:42:02
Showing 1 changed files
... ...
@@ -64,8 +64,7 @@ static int cmpchoice(const void *p1, const void *p2) {
64 64
 	double score2 = choices_score[idx2];
65 65
 
66 66
 	if(score1 == score2)
67
-		/* break ties by length of result */
68
-		return strlen(choices[idx1]) - strlen(choices[idx2]);
67
+		return 0;
69 68
 	else if(score1 < score2)
70 69
 		return 1;
71 70
 	else
Browse code

Revert "No need anymore for strlen to break ties"

This reverts commit e77435e4c26cc5d2c879452d9310890763df0b96.

John Hawthorn authored on 27/07/2014 06:41:20
Showing 1 changed files
... ...
@@ -63,7 +63,13 @@ static int cmpchoice(const void *p1, const void *p2) {
63 63
 	double score1 = choices_score[idx1];
64 64
 	double score2 = choices_score[idx2];
65 65
 
66
-	return score1 - score2;
66
+	if(score1 == score2)
67
+		/* break ties by length of result */
68
+		return strlen(choices[idx1]) - strlen(choices[idx2]);
69
+	else if(score1 < score2)
70
+		return 1;
71
+	else
72
+		return -1;
67 73
 }
68 74
 
69 75
 void run_search(char *needle){
Browse code

^u was not resetting search

John Hawthorn authored on 27/07/2014 06:36:11
Showing 1 changed files
... ...
@@ -199,6 +199,7 @@ void run(){
199 199
 		}else if(ch == 21){ /* C-U */
200 200
 			search_size = 0;
201 201
 			search[0] = '\0';
202
+			run_search(search);
202 203
 		}else if(ch == 23){ /* C-W */
203 204
 			if(search_size)
204 205
 				search[--search_size] = '\0';
Browse code

No need anymore for strlen to break ties

John Hawthorn authored on 27/07/2014 06:05:46
Showing 1 changed files
... ...
@@ -63,13 +63,7 @@ static int cmpchoice(const void *p1, const void *p2) {
63 63
 	double score1 = choices_score[idx1];
64 64
 	double score2 = choices_score[idx2];
65 65
 
66
-	if(score1 == score2)
67
-		/* break ties by length of result */
68
-		return strlen(choices[idx1]) - strlen(choices[idx2]);
69
-	else if(score1 < score2)
70
-		return 1;
71
-	else
72
-		return -1;
66
+	return score1 - score2;
73 67
 }
74 68
 
75 69
 void run_search(char *needle){
Browse code

Add version string

John Hawthorn authored on 27/07/2014 04:51:27
Showing 1 changed files
... ...
@@ -232,7 +232,10 @@ void usage(const char *argv0){
232 232
 }
233 233
 
234 234
 int main(int argc, char *argv[]){
235
-	if(argc != 1){
235
+	if(argc == 2 && !strcmp(argv[1], "-v")){
236
+		printf("%s " VERSION  " (c) 2014 John Hawthorn\n", argv[0]);
237
+		exit(EXIT_SUCCESS);
238
+	}else if(argc != 1){
236 239
 		usage(argv[0]);
237 240
 	}
238 241
 	atexit(reset_tty);
Browse code

Don't require scores to be positive

Previously a successful match was determined by the score being
positive. Now we will use has_match instead.

John Hawthorn authored on 26/07/2014 09:44:12
Showing 1 changed files
... ...
@@ -77,8 +77,8 @@ void run_search(char *needle){
77 77
 	choices_available = 0;
78 78
 	int i;
79 79
 	for(i = 0; i < choices_n; i++){
80
-		choices_score[i] = match(needle, choices[i]);
81
-		if(choices_score[i] >= 0.0){
80
+		if(has_match(needle, choices[i])){
81
+			choices_score[i] = match(needle, choices[i]);
82 82
 			choices_sorted[choices_available++] = i;
83 83
 		}
84 84
 	}
Browse code

Move declarations into fzy.h

John Hawthorn authored on 26/07/2014 09:37:24
Showing 1 changed files
... ...
@@ -8,9 +8,7 @@
8 8
 #include <fcntl.h>
9 9
 #include <ctype.h>
10 10
 
11
-/* from match.c */
12
-double match(const char *needle, const char *haystack);
13
-double match_positions(const char *needle, const char *haystack, size_t *positions);
11
+#include "fzy.h"
14 12
 
15 13
 #define INITIAL_CAPACITY 1
16 14
 int choices_capacity = 0;
Browse code

Highlight matched characters

John Hawthorn authored on 26/07/2014 09:27:31
Showing 1 changed files
... ...
@@ -10,6 +10,7 @@
10 10
 
11 11
 /* from match.c */
12 12
 double match(const char *needle, const char *haystack);
13
+double match_positions(const char *needle, const char *haystack, size_t *positions);
13 14
 
14 15
 #define INITIAL_CAPACITY 1
15 16
 int choices_capacity = 0;
... ...
@@ -136,6 +137,27 @@ void clear(){
136 137
 	fprintf(ttyout, "%c%c0G", 0x1b, '[');
137 138
 }
138 139
 
140
+void draw_match(const char *choice, int selected){
141
+	int n = strlen(search);
142
+	size_t positions[n + 1];
143
+	for(int i = 0; i < n + 1; i++)
144
+		positions[i] = -1;
145
+
146
+	match_positions(search, choice, &positions[0]);
147
+
148
+	for(size_t i = 0, p = 0; choice[i] != '\0'; i++){
149
+		if(positions[p] == i){
150
+			fprintf(ttyout, "%c%c33m", 0x1b, '[');
151
+			p++;
152
+		}else{
153
+			fprintf(ttyout, "%c%c39;49m", 0x1b, '[');
154
+		}
155
+		fprintf(ttyout, "%c", choice[i]);
156
+	}
157
+	fprintf(ttyout, "\n");
158
+	fprintf(ttyout, "%c%c0m", 0x1b, '[');
159
+}
160
+
139 161
 void draw(){
140 162
 	int line = 0;
141 163
 	const char *prompt = "> ";
... ...
@@ -144,9 +166,7 @@ void draw(){
144 166
 	for(size_t i = 0; line < 10 && i < choices_available; i++){
145 167
 		if(i == current_selection)
146 168
 			fprintf(ttyout, "%c%c7m", 0x1b, '[');
147
-		else
148
-			fprintf(ttyout, "%c%c0m", 0x1b, '[');
149
-		fprintf(ttyout, "%s\n", choices[choices_sorted[i]]);
169
+		draw_match(choices[choices_sorted[i]], i == current_selection);
150 170
 		line++;
151 171
 	}
152 172
 	fprintf(ttyout, "%c%c%iA", 0x1b, '[', line + 1);
Browse code

Add ^U and ^H bindings

Change-Id: Ib14ab12e6223267f397b506939f0e6c6f5d3c468

John Hawthorn authored on 25/07/2014 17:53:27
Showing 1 changed files
... ...
@@ -180,10 +180,13 @@ void run(){
180 180
 			search[search_size++] = ch;
181 181
 			search[search_size] = '\0';
182 182
 			run_search(search);
183
-		}else if(ch == 127){ /* DEL */
183
+		}else if(ch == 127 || ch == 8){ /* DEL || backspace */
184 184
 			if(search_size)
185 185
 				search[--search_size] = '\0';
186 186
 			run_search(search);
187
+		}else if(ch == 21){ /* C-U */
188
+			search_size = 0;
189
+			search[0] = '\0';
187 190
 		}else if(ch == 23){ /* C-W */
188 191
 			if(search_size)
189 192
 				search[--search_size] = '\0';
Browse code

Fix warnings

John Hawthorn authored on 13/07/2014 05:16:13
Showing 1 changed files
... ...
@@ -1,3 +1,4 @@
1
+#define _GNU_SOURCE
1 2
 #include <stdio.h>
2 3
 #include <string.h>
3 4
 #include <stdlib.h>
... ...
@@ -16,7 +17,7 @@ int choices_n = 0;
16 17
 const char **choices = NULL;
17 18
 double *choices_score = NULL;
18 19
 size_t *choices_sorted = NULL;
19
-int current_selection = 0;
20
+size_t current_selection = 0;
20 21
 
21 22
 void resize_choices(int new_capacity){
22 23
 	choices = realloc(choices, new_capacity * sizeof(const char *));
... ...
@@ -137,11 +138,10 @@ void clear(){
137 138
 
138 139
 void draw(){
139 140
 	int line = 0;
140
-	int i;
141 141
 	const char *prompt = "> ";
142 142
 	clear();
143 143
 	fprintf(ttyout, "%s%s\n", prompt, search);
144
-	for(i = 0; line < 10 && i < choices_available; i++){
144
+	for(size_t i = 0; line < 10 && i < choices_available; i++){
145 145
 		if(i == current_selection)
146 146
 			fprintf(ttyout, "%c%c7m", 0x1b, '[');
147 147
 		else
... ...
@@ -150,7 +150,7 @@ void draw(){
150 150
 		line++;
151 151
 	}
152 152
 	fprintf(ttyout, "%c%c%iA", 0x1b, '[', line + 1);
153
-	fprintf(ttyout, "%c%c%iG", 0x1b, '[', strlen(prompt) + strlen(search) + 1);
153
+	fprintf(ttyout, "%c%c%ziG", 0x1b, '[', strlen(prompt) + strlen(search) + 1);
154 154
 	fflush(ttyout);
155 155
 }
156 156
 
Browse code

Break match ties by length of result

John Hawthorn authored on 13/07/2014 04:59:22
Showing 1 changed files
... ...
@@ -64,7 +64,8 @@ static int cmpchoice(const void *p1, const void *p2) {
64 64
 	double score2 = choices_score[idx2];
65 65
 
66 66
 	if(score1 == score2)
67
-		return 0;
67
+		/* break ties by length of result */
68
+		return strlen(choices[idx1]) - strlen(choices[idx2]);
68 69
 	else if(score1 < score2)
69 70
 		return 1;
70 71
 	else
Browse code

Selection via C-n and C-p

John Hawthorn authored on 13/07/2014 02:08:01
Showing 1 changed files
... ...
@@ -16,6 +16,7 @@ int choices_n = 0;
16 16
 const char **choices = NULL;
17 17
 double *choices_score = NULL;
18 18
 size_t *choices_sorted = NULL;
19
+int current_selection = 0;
19 20
 
20 21
 void resize_choices(int new_capacity){
21 22
 	choices = realloc(choices, new_capacity * sizeof(const char *));
... ...
@@ -70,8 +71,8 @@ static int cmpchoice(const void *p1, const void *p2) {
70 71
 		return -1;
71 72
 }
72 73
 
73
-
74 74
 void run_search(char *needle){
75
+	current_selection = 0;
75 76
 	choices_available = 0;
76 77
 	int i;
77 78
 	for(i = 0; i < choices_n; i++){
... ...
@@ -139,8 +140,11 @@ void draw(){
139 140
 	const char *prompt = "> ";
140 141
 	clear();
141 142
 	fprintf(ttyout, "%s%s\n", prompt, search);
142
-	run_search(search);
143 143
 	for(i = 0; line < 10 && i < choices_available; i++){
144
+		if(i == current_selection)
145
+			fprintf(ttyout, "%c%c7m", 0x1b, '[');
146
+		else
147
+			fprintf(ttyout, "%c%c0m", 0x1b, '[');
144 148
 		fprintf(ttyout, "%s\n", choices[choices_sorted[i]]);
145 149
 		line++;
146 150
 	}
... ...
@@ -153,10 +157,9 @@ void emit(){
153 157
 	/* ttyout should be flushed before outputting on stdout */
154 158
 	fclose(ttyout);
155 159
 
156
-	run_search(search);
157 160
 	if(choices_available){
158
-		/* output the first result */
159
-		printf("%s\n", choices[choices_sorted[0]]);
161
+		/* output the selected result */
162
+		printf("%s\n", choices[choices_sorted[current_selection]]);
160 163
 	}else{
161 164
 		/* No match, output the query instead */
162 165
 		printf("%s\n", search);
... ...
@@ -166,24 +169,31 @@ void emit(){
166 169
 }
167 170
 
168 171
 void run(){
169
-	draw();
172
+	run_search(search);
170 173
 	char ch;
171 174
 	do {
175
+		draw();
172 176
 		ch = ttygetchar();
173 177
 		if(isprint(ch)){
174 178
 			/* FIXME: overflow */
175 179
 			search[search_size++] = ch;
176 180
 			search[search_size] = '\0';
177
-			draw();
181
+			run_search(search);
178 182
 		}else if(ch == 127){ /* DEL */
179 183
 			if(search_size)
180 184
 				search[--search_size] = '\0';
181
-			draw();
185
+			run_search(search);
182 186
 		}else if(ch == 23){ /* C-W */
183 187
 			if(search_size)
184 188
 				search[--search_size] = '\0';
185 189
 			while(search_size && !isspace(search[--search_size]))
186 190
 				search[search_size] = '\0';
191
+			run_search(search);
192
+		}else if(ch == 14){ /* C-N */
193
+			current_selection = (current_selection + 1) % 10;
194
+			draw();
195
+		}else if(ch == 16){ /* C-P */
196
+			current_selection = (current_selection + 9) % 10;
187 197
 			draw();
188 198
 		}else if(ch == 10){ /* Enter */
189 199
 			clear();
Browse code

Add actual sorting of results

John Hawthorn authored on 13/07/2014 01:49:21
Showing 1 changed files
... ...
@@ -14,9 +14,14 @@ double match(const char *needle, const char *haystack);
14 14
 int choices_capacity = 0;
15 15
 int choices_n = 0;
16 16
 const char **choices = NULL;
17
+double *choices_score = NULL;
18
+size_t *choices_sorted = NULL;
17 19
 
18 20
 void resize_choices(int new_capacity){
19 21
 	choices = realloc(choices, new_capacity * sizeof(const char *));
22
+	choices_score = realloc(choices_score, new_capacity * sizeof(double));
23
+	choices_sorted = realloc(choices_sorted, new_capacity * sizeof(size_t));
24
+
20 25
 	int i = choices_capacity;
21 26
 	for(; i < new_capacity; i++){
22 27
 		choices[i] = NULL;
... ...
@@ -48,14 +53,36 @@ void read_choices(){
48 53
 	free(line);
49 54
 }
50 55
 
56
+size_t choices_available = 0;
57
+
58
+static int cmpchoice(const void *p1, const void *p2) {
59
+	size_t idx1 = *(size_t *)p1;
60
+	size_t idx2 = *(size_t *)p2;
61
+
62
+	double score1 = choices_score[idx1];
63
+	double score2 = choices_score[idx2];
64
+
65
+	if(score1 == score2)
66
+		return 0;
67
+	else if(score1 < score2)
68
+		return 1;
69
+	else
70
+		return -1;
71
+}
72
+
73
+
51 74
 void run_search(char *needle){
75
+	choices_available = 0;
52 76
 	int i;
53 77
 	for(i = 0; i < choices_n; i++){
54
-		double rank = match(needle, choices[i]);
55
-		if(rank > 0){
56
-			printf("%s\n", choices[i]);
78
+		choices_score[i] = match(needle, choices[i]);
79
+		if(choices_score[i] >= 0.0){
80
+			choices_sorted[choices_available++] = i;
57 81
 		}
58 82
 	}
83
+
84
+	qsort(choices_sorted, choices_available, sizeof(size_t), cmpchoice);
85
+
59 86
 }
60 87
 
61 88
 int ttyin;
... ...
@@ -112,12 +139,10 @@ void draw(){
112 139
 	const char *prompt = "> ";
113 140
 	clear();
114 141
 	fprintf(ttyout, "%s%s\n", prompt, search);
115
-	for(i = 0; line < 10 && i < choices_n; i++){
116
-		double rank = match(search, choices[i]);
117
-		if(rank > 0){
118
-			fprintf(ttyout, "%s\n", choices[i]);
119
-			line++;
120
-		}
142
+	run_search(search);
143
+	for(i = 0; line < 10 && i < choices_available; i++){
144
+		fprintf(ttyout, "%s\n", choices[choices_sorted[i]]);
145
+		line++;
121 146
 	}
122 147
 	fprintf(ttyout, "%c%c%iA", 0x1b, '[', line + 1);
123 148
 	fprintf(ttyout, "%c%c%iG", 0x1b, '[', strlen(prompt) + strlen(search) + 1);
... ...
@@ -128,18 +153,15 @@ void emit(){
128 153
 	/* ttyout should be flushed before outputting on stdout */
129 154
 	fclose(ttyout);
130 155
 
131
-	int i;
132
-	for(i = 0; i < choices_n; i++){
133
-		double rank = match(search, choices[i]);
134
-		if(rank > 0){
135
-			/* Output the first match */
136
-			printf("%s\n", choices[i]);
137
-			exit(EXIT_SUCCESS);
138
-		}
156
+	run_search(search);
157
+	if(choices_available){
158
+		/* output the first result */
159
+		printf("%s\n", choices[choices_sorted[0]]);
160
+	}else{
161
+		/* No match, output the query instead */
162
+		printf("%s\n", search);
139 163
 	}
140 164
 
141
-	/* No match, output the query instead */
142
-	printf("%s\n", search);
143 165
 	exit(EXIT_SUCCESS);
144 166
 }
145 167
 
Browse code

Add tests and split matching into match.c

John Hawthorn authored on 12/07/2014 22:07:22
Showing 1 changed files
... ...
@@ -7,15 +7,8 @@
7 7
 #include <fcntl.h>
8 8
 #include <ctype.h>
9 9
 
10
-double match(const char *needle, const char *haystack){
11
-	while(*needle){
12
-		if(!*haystack)
13
-			return 0.0;
14
-		while(tolower(*needle) == tolower(*haystack++))
15
-			needle++;
16
-	}
17
-	return 1.0;
18
-}
10
+/* from match.c */
11
+double match(const char *needle, const char *haystack);
19 12
 
20 13
 #define INITIAL_CAPACITY 1
21 14
 int choices_capacity = 0;
Browse code

Don't quit on 'q'

John Hawthorn authored on 12/07/2014 06:07:58
Showing 1 changed files
... ...
@@ -176,7 +176,7 @@ void run(){
176 176
 		}else{
177 177
 			printf("'%c' (%i)\n", ch, ch);
178 178
 		}
179
-	}while(ch != 'q');
179
+	}while(1);
180 180
 }
181 181
 
182 182
 void usage(const char *argv0){
Browse code

Improve comment

John Hawthorn authored on 12/07/2014 04:46:17
Showing 1 changed files
... ...
@@ -132,7 +132,7 @@ void draw(){
132 132
 }
133 133
 
134 134
 void emit(){
135
-	/* ttyout should be flushed in the case that it is == stdout */
135
+	/* ttyout should be flushed before outputting on stdout */
136 136
 	fclose(ttyout);
137 137
 
138 138
 	int i;
Browse code

Fix output when ttyout == stdout

John Hawthorn authored on 12/07/2014 04:42:16
Showing 1 changed files
... ...
@@ -132,6 +132,9 @@ void draw(){
132 132
 }
133 133
 
134 134
 void emit(){
135
+	/* ttyout should be flushed in the case that it is == stdout */
136
+	fclose(ttyout);
137
+
135 138
 	int i;
136 139
 	for(i = 0; i < choices_n; i++){
137 140
 		double rank = match(search, choices[i]);
Browse code

Output the result on Enter

John Hawthorn authored on 12/07/2014 04:24:53
Showing 1 changed files
... ...
@@ -131,6 +131,22 @@ void draw(){
131 131
 	fflush(ttyout);
132 132
 }
133 133
 
134
+void emit(){
135
+	int i;
136
+	for(i = 0; i < choices_n; i++){
137
+		double rank = match(search, choices[i]);
138
+		if(rank > 0){
139
+			/* Output the first match */
140
+			printf("%s\n", choices[i]);
141
+			exit(EXIT_SUCCESS);
142
+		}
143
+	}
144
+
145
+	/* No match, output the query instead */
146
+	printf("%s\n", search);
147
+	exit(EXIT_SUCCESS);
148
+}
149
+
134 150
 void run(){
135 151
 	draw();
136 152
 	char ch;
... ...
@@ -153,7 +169,7 @@ void run(){
153 169
 			draw();
154 170
 		}else if(ch == 10){ /* Enter */
155 171
 			clear();
156
-			exit(0);
172
+			emit();
157 173
 		}else{
158 174
 			printf("'%c' (%i)\n", ch, ch);
159 175
 		}
Browse code

Rename fzy

John Hawthorn authored on 12/07/2014 04:21:14
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,182 @@
1
+#include <stdio.h>
2
+#include <string.h>
3
+#include <stdlib.h>
4
+#include <termios.h>
5
+#include <unistd.h>
6
+#include <sys/stat.h>
7
+#include <fcntl.h>
8
+#include <ctype.h>
9
+
10
+double match(const char *needle, const char *haystack){
11
+	while(*needle){
12
+		if(!*haystack)
13
+			return 0.0;
14
+		while(tolower(*needle) == tolower(*haystack++))
15
+			needle++;
16
+	}
17
+	return 1.0;
18
+}
19
+
20
+#define INITIAL_CAPACITY 1
21
+int choices_capacity = 0;
22
+int choices_n = 0;
23
+const char **choices = NULL;
24
+
25
+void resize_choices(int new_capacity){
26
+	choices = realloc(choices, new_capacity * sizeof(const char *));
27
+	int i = choices_capacity;
28
+	for(; i < new_capacity; i++){
29
+		choices[i] = NULL;
30
+	}
31
+	choices_capacity = new_capacity;
32
+}
33
+
34
+void add_choice(const char *choice){
35
+	if(choices_n == choices_capacity){
36
+		resize_choices(choices_capacity * 2);
37
+	}
38
+	choices[choices_n++] = choice;
39
+}
40
+
41
+void read_choices(){
42
+	char *line = NULL;
43
+	size_t len = 0;
44
+	ssize_t read;
45
+
46
+	while ((read = getline(&line, &len, stdin)) != -1) {
47
+		char *nl;
48
+		if((nl = strchr(line, '\n')))
49
+			*nl = '\0';
50
+
51
+		add_choice(line);
52
+
53
+		line = NULL;
54
+	}
55
+	free(line);
56
+}
57
+
58
+void run_search(char *needle){
59
+	int i;
60
+	for(i = 0; i < choices_n; i++){
61
+		double rank = match(needle, choices[i]);
62
+		if(rank > 0){
63
+			printf("%s\n", choices[i]);
64
+		}
65
+	}
66
+}
67
+
68
+int ttyin;
69
+FILE *ttyout;
70
+struct termios original_termios;
71
+
72
+void reset_tty(){
73
+	tcsetattr(ttyin, TCSANOW, &original_termios);
74
+}
75
+
76
+void init_tty(){
77
+	ttyin = open("/dev/tty", O_RDONLY);
78
+	ttyout = fopen("/dev/tty", "w");
79
+
80
+	tcgetattr(ttyin, &original_termios);
81
+
82
+	struct termios new_termios = original_termios;
83
+
84
+	new_termios.c_lflag &= ~(ICANON | ECHO);
85
+
86
+	tcsetattr(ttyin, TCSANOW, &new_termios);
87
+}
88
+
89
+char ttygetchar(){
90
+	char ch;
91
+	int size = read(ttyin, &ch, 1);
92
+	if(size < 0){
93
+		perror("error reading from tty");
94
+		exit(EXIT_FAILURE);
95
+	}else if(size == 0){
96
+		/* EOF */
97
+		exit(EXIT_FAILURE);
98
+	}else{
99
+		return ch;
100
+	}
101
+}
102
+
103
+int search_size;
104
+char search[4096] = {0};
105
+
106
+void clear(){
107
+	fprintf(ttyout, "%c%c0G", 0x1b, '[');
108
+	int line = 0;
109
+	while(line++ < 10 + 1){
110
+		fprintf(ttyout, "%c%cK\n", 0x1b, '[');
111
+	}
112
+	fprintf(ttyout, "%c%c%iA", 0x1b, '[', line-1);
113
+	fprintf(ttyout, "%c%c0G", 0x1b, '[');
114
+}
115
+
116
+void draw(){
117
+	int line = 0;
118
+	int i;
119
+	const char *prompt = "> ";
120
+	clear();
121
+	fprintf(ttyout, "%s%s\n", prompt, search);
122
+	for(i = 0; line < 10 && i < choices_n; i++){
123
+		double rank = match(search, choices[i]);
124
+		if(rank > 0){
125
+			fprintf(ttyout, "%s\n", choices[i]);
126
+			line++;
127
+		}
128
+	}
129
+	fprintf(ttyout, "%c%c%iA", 0x1b, '[', line + 1);
130
+	fprintf(ttyout, "%c%c%iG", 0x1b, '[', strlen(prompt) + strlen(search) + 1);
131
+	fflush(ttyout);
132
+}
133
+
134
+void run(){
135
+	draw();
136
+	char ch;
137
+	do {
138
+		ch = ttygetchar();
139
+		if(isprint(ch)){
140
+			/* FIXME: overflow */
141
+			search[search_size++] = ch;
142
+			search[search_size] = '\0';
143
+			draw();
144
+		}else if(ch == 127){ /* DEL */
145
+			if(search_size)
146
+				search[--search_size] = '\0';
147
+			draw();
148
+		}else if(ch == 23){ /* C-W */
149
+			if(search_size)
150
+				search[--search_size] = '\0';
151
+			while(search_size && !isspace(search[--search_size]))
152
+				search[search_size] = '\0';
153
+			draw();
154
+		}else if(ch == 10){ /* Enter */
155
+			clear();
156
+			exit(0);
157
+		}else{
158
+			printf("'%c' (%i)\n", ch, ch);
159
+		}
160
+	}while(ch != 'q');
161
+}
162
+
163
+void usage(const char *argv0){
164
+	fprintf(stderr, "USAGE: %s\n", argv0);
165
+	exit(EXIT_FAILURE);
166
+}
167
+
168
+int main(int argc, char *argv[]){
169
+	if(argc != 1){
170
+		usage(argv[0]);
171
+	}
172
+	atexit(reset_tty);
173
+	init_tty(reset_tty);
174
+
175
+	resize_choices(INITIAL_CAPACITY);
176
+	read_choices();
177
+
178
+	clear();
179
+	run();
180
+
181
+	return 0;
182
+}