Browse code

Fix --show-info when lines do not fit in the screen

Mārtiņš Mačs authored on 29/01/2020 16:17:06
Showing 1 changed files
... ...
@@ -53,8 +53,12 @@ int main(int argc, char *argv[]) {
53 53
 		if (options.num_lines > choices.size)
54 54
 			options.num_lines = choices.size;
55 55
 
56
-		if (options.num_lines + 1 > tty_getheight(&tty))
57
-			options.num_lines = tty_getheight(&tty) - 1;
56
+		int num_lines_adjustment = 1;
57
+		if (options.show_info)
58
+			num_lines_adjustment++;
59
+
60
+		if (options.num_lines + num_lines_adjustment > tty_getheight(&tty))
61
+			options.num_lines = tty_getheight(&tty) - num_lines_adjustment;
58 62
 
59 63
 		tty_interface_t tty_interface;
60 64
 		tty_interface_init(&tty_interface, &tty, &choices, &options);
Browse code

Simplify input_delimiter handling

John Hawthorn authored on 16/08/2019 08:09:29
Showing 1 changed files
... ...
@@ -27,11 +27,11 @@ int main(int argc, char *argv[]) {
27 27
 			fprintf(stderr, "Must specify -e/--show-matches with --benchmark\n");
28 28
 			exit(EXIT_FAILURE);
29 29
 		}
30
-		choices_fread(&choices, stdin);
30
+		choices_fread(&choices, stdin, options.input_delimiter);
31 31
 		for (int i = 0; i < options.benchmark; i++)
32 32
 			choices_search(&choices, options.filter);
33 33
 	} else if (options.filter) {
34
-		choices_fread(&choices, stdin);
34
+		choices_fread(&choices, stdin, options.input_delimiter);
35 35
 		choices_search(&choices, options.filter);
36 36
 		for (size_t i = 0; i < choices_available(&choices); i++) {
37 37
 			if (options.show_scores)
... ...
@@ -42,13 +42,13 @@ int main(int argc, char *argv[]) {
42 42
 		/* interactive */
43 43
 
44 44
 		if (isatty(STDIN_FILENO))
45
-			choices_fread(&choices, stdin);
45
+			choices_fread(&choices, stdin, options.input_delimiter);
46 46
 
47 47
 		tty_t tty;
48 48
 		tty_init(&tty, options.tty_filename);
49 49
 
50 50
 		if (!isatty(STDIN_FILENO))
51
-			choices_fread(&choices, stdin);
51
+			choices_fread(&choices, stdin, options.input_delimiter);
52 52
 
53 53
 		if (options.num_lines > choices.size)
54 54
 			options.num_lines = choices.size;
Browse code

Fix reading choices if stdin is a tty

Previously we deferred reading choices to after initializing the tty.
This makes sense only when stdin and our tty aren't the same.

John Hawthorn authored on 17/06/2018 18:58:09
Showing 1 changed files
... ...
@@ -3,6 +3,7 @@
3 3
 #include <stdlib.h>
4 4
 #include <ctype.h>
5 5
 #include <limits.h>
6
+#include <unistd.h>
6 7
 
7 8
 #include "match.h"
8 9
 #include "tty.h"
... ...
@@ -39,10 +40,15 @@ int main(int argc, char *argv[]) {
39 40
 		}
40 41
 	} else {
41 42
 		/* interactive */
43
+
44
+		if (isatty(STDIN_FILENO))
45
+			choices_fread(&choices, stdin);
46
+
42 47
 		tty_t tty;
43 48
 		tty_init(&tty, options.tty_filename);
44 49
 
45
-		choices_fread(&choices, stdin);
50
+		if (!isatty(STDIN_FILENO))
51
+			choices_fread(&choices, stdin);
46 52
 
47 53
 		if (options.num_lines > choices.size)
48 54
 			options.num_lines = choices.size;
Browse code

Initialize tty before reading choices

It's possible for user input to arrive while fzy was still reading
choices from stdin. Previously, this would happen before the correct
termios were set, causing fzy to misinterpret Enter as Ctrl-J for
example.

Fixes #81

John Hawthorn authored on 17/06/2018 18:30:11
Showing 1 changed files
... ...
@@ -20,16 +20,17 @@ int main(int argc, char *argv[]) {
20 20
 
21 21
 	choices_t choices;
22 22
 	choices_init(&choices, &options);
23
-	choices_fread(&choices, stdin);
24 23
 
25 24
 	if (options.benchmark) {
26 25
 		if (!options.filter) {
27 26
 			fprintf(stderr, "Must specify -e/--show-matches with --benchmark\n");
28 27
 			exit(EXIT_FAILURE);
29 28
 		}
29
+		choices_fread(&choices, stdin);
30 30
 		for (int i = 0; i < options.benchmark; i++)
31 31
 			choices_search(&choices, options.filter);
32 32
 	} else if (options.filter) {
33
+		choices_fread(&choices, stdin);
33 34
 		choices_search(&choices, options.filter);
34 35
 		for (size_t i = 0; i < choices_available(&choices); i++) {
35 36
 			if (options.show_scores)
... ...
@@ -41,6 +42,8 @@ int main(int argc, char *argv[]) {
41 42
 		tty_t tty;
42 43
 		tty_init(&tty, options.tty_filename);
43 44
 
45
+		choices_fread(&choices, stdin);
46
+
44 47
 		if (options.num_lines > choices.size)
45 48
 			options.num_lines = choices.size;
46 49
 
Browse code

Pass options to choices_init

John Hawthorn authored on 01/02/2017 02:06:42
Showing 1 changed files
... ...
@@ -19,7 +19,7 @@ int main(int argc, char *argv[]) {
19 19
 	options_parse(&options, argc, argv);
20 20
 
21 21
 	choices_t choices;
22
-	choices_init(&choices);
22
+	choices_init(&choices, &options);
23 23
 	choices_fread(&choices, stdin);
24 24
 
25 25
 	if (options.benchmark) {
Browse code

Return exit code from run

John Hawthorn authored on 20/06/2016 06:36:39
Showing 1 changed files
... ...
@@ -13,6 +13,8 @@
13 13
 #include "../config.h"
14 14
 
15 15
 int main(int argc, char *argv[]) {
16
+	int ret = 0;
17
+
16 18
 	options_t options;
17 19
 	options_parse(&options, argc, argv);
18 20
 
... ...
@@ -47,10 +49,10 @@ int main(int argc, char *argv[]) {
47 49
 
48 50
 		tty_interface_t tty_interface;
49 51
 		tty_interface_init(&tty_interface, &tty, &choices, &options);
50
-		tty_interface_run(&tty_interface);
52
+		ret = tty_interface_run(&tty_interface);
51 53
 	}
52 54
 
53 55
 	choices_destroy(&choices);
54 56
 
55
-	return 0;
57
+	return ret;
56 58
 }
Browse code

Remove options global variable

John Hawthorn authored on 20/06/2016 06:18:26
Showing 1 changed files
... ...
@@ -12,9 +12,8 @@
12 12
 
13 13
 #include "../config.h"
14 14
 
15
-options_t options;
16
-
17 15
 int main(int argc, char *argv[]) {
16
+	options_t options;
18 17
 	options_parse(&options, argc, argv);
19 18
 
20 19
 	choices_t choices;
Browse code

Store state in tty_interface_t

John Hawthorn authored on 20/06/2016 06:17:53
Showing 1 changed files
... ...
@@ -46,7 +46,9 @@ int main(int argc, char *argv[]) {
46 46
 		if (options.num_lines + 1 > tty_getheight(&tty))
47 47
 			options.num_lines = tty_getheight(&tty) - 1;
48 48
 
49
-		tty_interface_run(&tty, &choices, &options);
49
+		tty_interface_t tty_interface;
50
+		tty_interface_init(&tty_interface, &tty, &choices, &options);
51
+		tty_interface_run(&tty_interface);
50 52
 	}
51 53
 
52 54
 	choices_destroy(&choices);
Browse code

Extract tty interface to own file

John Hawthorn authored on 20/06/2016 06:08:00
Showing 1 changed files
... ...
@@ -8,161 +8,12 @@
8 8
 #include "tty.h"
9 9
 #include "choices.h"
10 10
 #include "options.h"
11
+#include "tty_interface.h"
11 12
 
12 13
 #include "../config.h"
13 14
 
14 15
 options_t options;
15 16
 
16
-#define SEARCH_SIZE_MAX 4096
17
-static char search[SEARCH_SIZE_MAX + 1] = {0};
18
-
19
-static void clear(tty_t *tty, options_t *options) {
20
-	tty_setcol(tty, 0);
21
-	size_t line = 0;
22
-	while (line++ < options->num_lines) {
23
-		tty_newline(tty);
24
-	}
25
-	tty_clearline(tty);
26
-	tty_moveup(tty, line - 1);
27
-	tty_flush(tty);
28
-}
29
-
30
-static void draw_match(tty_t *tty, const char *choice, int selected, options_t *options) {
31
-	int n = strlen(search);
32
-	size_t positions[n + 1];
33
-	for (int i = 0; i < n + 1; i++)
34
-		positions[i] = -1;
35
-
36
-	double score = match_positions(search, choice, &positions[0]);
37
-
38
-	size_t maxwidth = tty_getwidth(tty);
39
-
40
-	if (options->show_scores)
41
-		tty_printf(tty, "(%5.2f) ", score);
42
-
43
-	if (selected)
44
-		tty_setinvert(tty);
45
-
46
-	for (size_t i = 0, p = 0; choice[i] != '\0'; i++) {
47
-		if (i + 1 < maxwidth) {
48
-			if (positions[p] == i) {
49
-				tty_setfg(tty, TTY_COLOR_HIGHLIGHT);
50
-				p++;
51
-			} else {
52
-				tty_setfg(tty, TTY_COLOR_NORMAL);
53
-			}
54
-			tty_printf(tty, "%c", choice[i]);
55
-		} else {
56
-			tty_printf(tty, "$");
57
-			break;
58
-		}
59
-	}
60
-	tty_setnormal(tty);
61
-}
62
-
63
-static void draw(tty_t *tty, choices_t *choices, options_t *options) {
64
-	unsigned int num_lines = options->num_lines;
65
-	size_t start = 0;
66
-	size_t current_selection = choices->selection;
67
-	if (current_selection + options->scrolloff >= num_lines) {
68
-		start = current_selection + options->scrolloff - num_lines + 1;
69
-		if (start + num_lines >= choices_available(choices)) {
70
-			start = choices_available(choices) - num_lines;
71
-		}
72
-	}
73
-	tty_setcol(tty, 0);
74
-	tty_printf(tty, "%s%s", options->prompt, search);
75
-	tty_clearline(tty);
76
-	for (size_t i = start; i < start + num_lines; i++) {
77
-		tty_printf(tty, "\n");
78
-		tty_clearline(tty);
79
-		const char *choice = choices_get(choices, i);
80
-		if (choice) {
81
-			draw_match(tty, choice, i == choices->selection, options);
82
-		}
83
-	}
84
-	tty_moveup(tty, num_lines);
85
-	tty_setcol(tty, strlen(options->prompt) + strlen(search));
86
-	tty_flush(tty);
87
-}
88
-
89
-static void emit(choices_t *choices) {
90
-	const char *selection = choices_get(choices, choices->selection);
91
-	if (selection) {
92
-		/* output the selected result */
93
-		printf("%s\n", selection);
94
-	} else {
95
-		/* No match, output the query instead */
96
-		printf("%s\n", search);
97
-	}
98
-}
99
-
100
-#define KEY_CTRL(key) ((key) - ('@'))
101
-#define KEY_DEL 127
102
-#define KEY_ESC 27
103
-
104
-static void run(tty_t *tty, choices_t *choices, options_t *options) {
105
-	choices_search(choices, search);
106
-	char ch;
107
-	do {
108
-		draw(tty, choices, options);
109
-		ch = tty_getchar(tty);
110
-		size_t search_size = strlen(search);
111
-		if (isprint(ch)) {
112
-			if (search_size < SEARCH_SIZE_MAX) {
113
-				search[search_size++] = ch;
114
-				search[search_size] = '\0';
115
-				choices_search(choices, search);
116
-			}
117
-		} else if (ch == KEY_DEL || ch == KEY_CTRL('H')) { /* DEL || Backspace (C-H) */
118
-			if (search_size)
119
-				search[--search_size] = '\0';
120
-			choices_search(choices, search);
121
-		} else if (ch == KEY_CTRL('U')) { /* C-U */
122
-			search_size = 0;
123
-			search[0] = '\0';
124
-			choices_search(choices, search);
125
-		} else if (ch == KEY_CTRL('W')) { /* C-W */
126
-			if (search_size)
127
-				search[--search_size] = '\0';
128
-			while (search_size && !isspace(search[--search_size]))
129
-				search[search_size] = '\0';
130
-			choices_search(choices, search);
131
-		} else if (ch == KEY_CTRL('N')) { /* C-N */
132
-			choices_next(choices);
133
-		} else if (ch == KEY_CTRL('P')) { /* C-P */
134
-			choices_prev(choices);
135
-		} else if (ch == KEY_CTRL('I')) { /* TAB (C-I) */
136
-			strncpy(search, choices_get(choices, choices->selection), SEARCH_SIZE_MAX);
137
-			choices_search(choices, search);
138
-		} else if (ch == KEY_CTRL('C') || ch == KEY_CTRL('D')) { /* ^C || ^D */
139
-			clear(tty, options);
140
-			tty_close(tty);
141
-			exit(EXIT_FAILURE);
142
-		} else if (ch == KEY_CTRL('M')) { /* CR */
143
-			clear(tty, options);
144
-
145
-			/* ttyout should be flushed before outputting on stdout */
146
-			tty_close(tty);
147
-
148
-			emit(choices);
149
-
150
-			/* Return to eventually exit successfully */
151
-			return;
152
-		} else if (ch == KEY_ESC) { /* ESC */
153
-			ch = tty_getchar(tty);
154
-			if (ch == '[' || ch == 'O') {
155
-				ch = tty_getchar(tty);
156
-				if (ch == 'A') { /* UP ARROW */
157
-					choices_prev(choices);
158
-				} else if (ch == 'B') { /* DOWN ARROW */
159
-					choices_next(choices);
160
-				}
161
-			}
162
-		}
163
-	} while (1);
164
-}
165
-
166 17
 int main(int argc, char *argv[]) {
167 18
 	options_parse(&options, argc, argv);
168 19
 
... ...
@@ -195,10 +46,7 @@ int main(int argc, char *argv[]) {
195 46
 		if (options.num_lines + 1 > tty_getheight(&tty))
196 47
 			options.num_lines = tty_getheight(&tty) - 1;
197 48
 
198
-		if (options.init_search)
199
-			strncpy(search, options.init_search, SEARCH_SIZE_MAX);
200
-
201
-		run(&tty, &choices, &options);
49
+		tty_interface_run(&tty, &choices, &options);
202 50
 	}
203 51
 
204 52
 	choices_destroy(&choices);
Browse code

Ensure options is passed as a pointer

John Hawthorn authored on 20/06/2016 01:06:05
Showing 1 changed files
... ...
@@ -16,10 +16,10 @@ options_t options;
16 16
 #define SEARCH_SIZE_MAX 4096
17 17
 static char search[SEARCH_SIZE_MAX + 1] = {0};
18 18
 
19
-static void clear(tty_t *tty) {
19
+static void clear(tty_t *tty, options_t *options) {
20 20
 	tty_setcol(tty, 0);
21 21
 	size_t line = 0;
22
-	while (line++ < options.num_lines) {
22
+	while (line++ < options->num_lines) {
23 23
 		tty_newline(tty);
24 24
 	}
25 25
 	tty_clearline(tty);
... ...
@@ -27,7 +27,7 @@ static void clear(tty_t *tty) {
27 27
 	tty_flush(tty);
28 28
 }
29 29
 
30
-static void draw_match(tty_t *tty, const char *choice, int selected) {
30
+static void draw_match(tty_t *tty, const char *choice, int selected, options_t *options) {
31 31
 	int n = strlen(search);
32 32
 	size_t positions[n + 1];
33 33
 	for (int i = 0; i < n + 1; i++)
... ...
@@ -37,7 +37,7 @@ static void draw_match(tty_t *tty, const char *choice, int selected) {
37 37
 
38 38
 	size_t maxwidth = tty_getwidth(tty);
39 39
 
40
-	if (options.show_scores)
40
+	if (options->show_scores)
41 41
 		tty_printf(tty, "(%5.2f) ", score);
42 42
 
43 43
 	if (selected)
... ...
@@ -60,29 +60,29 @@ static void draw_match(tty_t *tty, const char *choice, int selected) {
60 60
 	tty_setnormal(tty);
61 61
 }
62 62
 
63
-static void draw(tty_t *tty, choices_t *choices) {
64
-	unsigned int num_lines = options.num_lines;
63
+static void draw(tty_t *tty, choices_t *choices, options_t *options) {
64
+	unsigned int num_lines = options->num_lines;
65 65
 	size_t start = 0;
66 66
 	size_t current_selection = choices->selection;
67
-	if (current_selection + options.scrolloff >= num_lines) {
68
-		start = current_selection + options.scrolloff - num_lines + 1;
67
+	if (current_selection + options->scrolloff >= num_lines) {
68
+		start = current_selection + options->scrolloff - num_lines + 1;
69 69
 		if (start + num_lines >= choices_available(choices)) {
70 70
 			start = choices_available(choices) - num_lines;
71 71
 		}
72 72
 	}
73 73
 	tty_setcol(tty, 0);
74
-	tty_printf(tty, "%s%s", options.prompt, search);
74
+	tty_printf(tty, "%s%s", options->prompt, search);
75 75
 	tty_clearline(tty);
76 76
 	for (size_t i = start; i < start + num_lines; i++) {
77 77
 		tty_printf(tty, "\n");
78 78
 		tty_clearline(tty);
79 79
 		const char *choice = choices_get(choices, i);
80 80
 		if (choice) {
81
-			draw_match(tty, choice, i == choices->selection);
81
+			draw_match(tty, choice, i == choices->selection, options);
82 82
 		}
83 83
 	}
84 84
 	tty_moveup(tty, num_lines);
85
-	tty_setcol(tty, strlen(options.prompt) + strlen(search));
85
+	tty_setcol(tty, strlen(options->prompt) + strlen(search));
86 86
 	tty_flush(tty);
87 87
 }
88 88
 
... ...
@@ -101,11 +101,11 @@ static void emit(choices_t *choices) {
101 101
 #define KEY_DEL 127
102 102
 #define KEY_ESC 27
103 103
 
104
-static void run(tty_t *tty, choices_t *choices) {
104
+static void run(tty_t *tty, choices_t *choices, options_t *options) {
105 105
 	choices_search(choices, search);
106 106
 	char ch;
107 107
 	do {
108
-		draw(tty, choices);
108
+		draw(tty, choices, options);
109 109
 		ch = tty_getchar(tty);
110 110
 		size_t search_size = strlen(search);
111 111
 		if (isprint(ch)) {
... ...
@@ -136,11 +136,11 @@ static void run(tty_t *tty, choices_t *choices) {
136 136
 			strncpy(search, choices_get(choices, choices->selection), SEARCH_SIZE_MAX);
137 137
 			choices_search(choices, search);
138 138
 		} else if (ch == KEY_CTRL('C') || ch == KEY_CTRL('D')) { /* ^C || ^D */
139
-			clear(tty);
139
+			clear(tty, options);
140 140
 			tty_close(tty);
141 141
 			exit(EXIT_FAILURE);
142 142
 		} else if (ch == KEY_CTRL('M')) { /* CR */
143
-			clear(tty);
143
+			clear(tty, options);
144 144
 
145 145
 			/* ttyout should be flushed before outputting on stdout */
146 146
 			tty_close(tty);
... ...
@@ -198,7 +198,7 @@ int main(int argc, char *argv[]) {
198 198
 		if (options.init_search)
199 199
 			strncpy(search, options.init_search, SEARCH_SIZE_MAX);
200 200
 
201
-		run(&tty, &choices);
201
+		run(&tty, &choices, &options);
202 202
 	}
203 203
 
204 204
 	choices_destroy(&choices);
Browse code

Extract option parsing to separate file

John Hawthorn authored on 20/06/2016 01:03:47
Showing 1 changed files
... ...
@@ -2,21 +2,16 @@
2 2
 #include <string.h>
3 3
 #include <stdlib.h>
4 4
 #include <ctype.h>
5
-#include <getopt.h>
6 5
 #include <limits.h>
7 6
 
8 7
 #include "match.h"
9 8
 #include "tty.h"
10 9
 #include "choices.h"
10
+#include "options.h"
11 11
 
12 12
 #include "../config.h"
13 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 = "> ";
14
+options_t options;
20 15
 
21 16
 #define SEARCH_SIZE_MAX 4096
22 17
 static char search[SEARCH_SIZE_MAX + 1] = {0};
... ...
@@ -24,7 +19,7 @@ static char search[SEARCH_SIZE_MAX + 1] = {0};
24 19
 static void clear(tty_t *tty) {
25 20
 	tty_setcol(tty, 0);
26 21
 	size_t line = 0;
27
-	while (line++ < num_lines) {
22
+	while (line++ < options.num_lines) {
28 23
 		tty_newline(tty);
29 24
 	}
30 25
 	tty_clearline(tty);
... ...
@@ -42,7 +37,7 @@ static void draw_match(tty_t *tty, const char *choice, int selected) {
42 37
 
43 38
 	size_t maxwidth = tty_getwidth(tty);
44 39
 
45
-	if (flag_show_scores)
40
+	if (options.show_scores)
46 41
 		tty_printf(tty, "(%5.2f) ", score);
47 42
 
48 43
 	if (selected)
... ...
@@ -66,16 +61,17 @@ static void draw_match(tty_t *tty, const char *choice, int selected) {
66 61
 }
67 62
 
68 63
 static void draw(tty_t *tty, choices_t *choices) {
64
+	unsigned int num_lines = options.num_lines;
69 65
 	size_t start = 0;
70 66
 	size_t current_selection = choices->selection;
71
-	if (current_selection + scrolloff >= num_lines) {
72
-		start = current_selection + scrolloff - num_lines + 1;
67
+	if (current_selection + options.scrolloff >= num_lines) {
68
+		start = current_selection + options.scrolloff - num_lines + 1;
73 69
 		if (start + num_lines >= choices_available(choices)) {
74 70
 			start = choices_available(choices) - num_lines;
75 71
 		}
76 72
 	}
77 73
 	tty_setcol(tty, 0);
78
-	tty_printf(tty, "%s%s", prompt, search);
74
+	tty_printf(tty, "%s%s", options.prompt, search);
79 75
 	tty_clearline(tty);
80 76
 	for (size_t i = start; i < start + num_lines; i++) {
81 77
 		tty_printf(tty, "\n");
... ...
@@ -86,7 +82,7 @@ static void draw(tty_t *tty, choices_t *choices) {
86 82
 		}
87 83
 	}
88 84
 	tty_moveup(tty, num_lines);
89
-	tty_setcol(tty, strlen(prompt) + strlen(search));
85
+	tty_setcol(tty, strlen(options.prompt) + strlen(search));
90 86
 	tty_flush(tty);
91 87
 }
92 88
 
... ...
@@ -167,119 +163,40 @@ static void run(tty_t *tty, choices_t *choices) {
167 163
 	} while (1);
168 164
 }
169 165
 
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 166
 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
-	}
167
+	options_parse(&options, argc, argv);
254 168
 
255 169
 	choices_t choices;
256 170
 	choices_init(&choices);
257 171
 	choices_fread(&choices, stdin);
258 172
 
259
-	if (benchmark) {
260
-		if (!filter) {
173
+	if (options.benchmark) {
174
+		if (!options.filter) {
261 175
 			fprintf(stderr, "Must specify -e/--show-matches with --benchmark\n");
262 176
 			exit(EXIT_FAILURE);
263 177
 		}
264
-		for (int i = 0; i < benchmark; i++)
265
-			choices_search(&choices, filter);
266
-	} else if (filter) {
267
-		choices_search(&choices, filter);
178
+		for (int i = 0; i < options.benchmark; i++)
179
+			choices_search(&choices, options.filter);
180
+	} else if (options.filter) {
181
+		choices_search(&choices, options.filter);
268 182
 		for (size_t i = 0; i < choices_available(&choices); i++) {
269
-			if (flag_show_scores)
183
+			if (options.show_scores)
270 184
 				printf("%f\t", choices_getscore(&choices, i));
271 185
 			printf("%s\n", choices_get(&choices, i));
272 186
 		}
273 187
 	} else {
274 188
 		/* interactive */
275 189
 		tty_t tty;
276
-		tty_init(&tty, tty_filename);
190
+		tty_init(&tty, options.tty_filename);
191
+
192
+		if (options.num_lines > choices.size)
193
+			options.num_lines = choices.size;
277 194
 
278
-		if (num_lines > choices.size)
279
-			num_lines = choices.size;
195
+		if (options.num_lines + 1 > tty_getheight(&tty))
196
+			options.num_lines = tty_getheight(&tty) - 1;
280 197
 
281
-		if (num_lines + 1 > tty_getheight(&tty))
282
-			num_lines = tty_getheight(&tty) - 1;
198
+		if (options.init_search)
199
+			strncpy(search, options.init_search, SEARCH_SIZE_MAX);
283 200
 
284 201
 		run(&tty, &choices);
285 202
 	}
Browse code

Move sources into src directory

John Hawthorn authored on 21/05/2016 21:56:03
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,290 @@
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
+}