From 52f091dfd559ba6f4ad9ddeb40411423c4914cd4 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Sun, 19 Jun 2016 23:08:00 -0700 Subject: Extract tty interface to own file --- src/fzy.c | 156 +------------------------------------------------- src/tty_interface.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tty_interface.h | 12 ++++ 3 files changed, 174 insertions(+), 154 deletions(-) create mode 100644 src/tty_interface.c create mode 100644 src/tty_interface.h (limited to 'src') diff --git a/src/fzy.c b/src/fzy.c index ef4a0de..544afbe 100644 --- a/src/fzy.c +++ b/src/fzy.c @@ -8,161 +8,12 @@ #include "tty.h" #include "choices.h" #include "options.h" +#include "tty_interface.h" #include "../config.h" options_t options; -#define SEARCH_SIZE_MAX 4096 -static char search[SEARCH_SIZE_MAX + 1] = {0}; - -static void clear(tty_t *tty, options_t *options) { - tty_setcol(tty, 0); - size_t line = 0; - while (line++ < options->num_lines) { - tty_newline(tty); - } - tty_clearline(tty); - tty_moveup(tty, line - 1); - tty_flush(tty); -} - -static void draw_match(tty_t *tty, const char *choice, int selected, options_t *options) { - int n = strlen(search); - size_t positions[n + 1]; - for (int i = 0; i < n + 1; i++) - positions[i] = -1; - - double score = match_positions(search, choice, &positions[0]); - - size_t maxwidth = tty_getwidth(tty); - - if (options->show_scores) - tty_printf(tty, "(%5.2f) ", score); - - if (selected) - tty_setinvert(tty); - - for (size_t i = 0, p = 0; choice[i] != '\0'; i++) { - if (i + 1 < maxwidth) { - if (positions[p] == i) { - tty_setfg(tty, TTY_COLOR_HIGHLIGHT); - p++; - } else { - tty_setfg(tty, TTY_COLOR_NORMAL); - } - tty_printf(tty, "%c", choice[i]); - } else { - tty_printf(tty, "$"); - break; - } - } - tty_setnormal(tty); -} - -static void draw(tty_t *tty, choices_t *choices, options_t *options) { - unsigned int num_lines = options->num_lines; - size_t start = 0; - size_t current_selection = choices->selection; - if (current_selection + options->scrolloff >= num_lines) { - start = current_selection + options->scrolloff - num_lines + 1; - if (start + num_lines >= choices_available(choices)) { - start = choices_available(choices) - num_lines; - } - } - tty_setcol(tty, 0); - tty_printf(tty, "%s%s", options->prompt, search); - tty_clearline(tty); - for (size_t i = start; i < start + num_lines; i++) { - tty_printf(tty, "\n"); - tty_clearline(tty); - const char *choice = choices_get(choices, i); - if (choice) { - draw_match(tty, choice, i == choices->selection, options); - } - } - tty_moveup(tty, num_lines); - tty_setcol(tty, strlen(options->prompt) + strlen(search)); - tty_flush(tty); -} - -static void emit(choices_t *choices) { - const char *selection = choices_get(choices, choices->selection); - if (selection) { - /* output the selected result */ - printf("%s\n", selection); - } else { - /* No match, output the query instead */ - printf("%s\n", search); - } -} - -#define KEY_CTRL(key) ((key) - ('@')) -#define KEY_DEL 127 -#define KEY_ESC 27 - -static void run(tty_t *tty, choices_t *choices, options_t *options) { - choices_search(choices, search); - char ch; - do { - draw(tty, choices, options); - ch = tty_getchar(tty); - size_t search_size = strlen(search); - if (isprint(ch)) { - if (search_size < SEARCH_SIZE_MAX) { - search[search_size++] = ch; - search[search_size] = '\0'; - choices_search(choices, search); - } - } else if (ch == KEY_DEL || ch == KEY_CTRL('H')) { /* DEL || Backspace (C-H) */ - if (search_size) - search[--search_size] = '\0'; - choices_search(choices, search); - } else if (ch == KEY_CTRL('U')) { /* C-U */ - search_size = 0; - search[0] = '\0'; - choices_search(choices, search); - } else if (ch == KEY_CTRL('W')) { /* C-W */ - if (search_size) - search[--search_size] = '\0'; - while (search_size && !isspace(search[--search_size])) - search[search_size] = '\0'; - choices_search(choices, search); - } else if (ch == KEY_CTRL('N')) { /* C-N */ - choices_next(choices); - } else if (ch == KEY_CTRL('P')) { /* C-P */ - choices_prev(choices); - } else if (ch == KEY_CTRL('I')) { /* TAB (C-I) */ - strncpy(search, choices_get(choices, choices->selection), SEARCH_SIZE_MAX); - choices_search(choices, search); - } else if (ch == KEY_CTRL('C') || ch == KEY_CTRL('D')) { /* ^C || ^D */ - clear(tty, options); - tty_close(tty); - exit(EXIT_FAILURE); - } else if (ch == KEY_CTRL('M')) { /* CR */ - clear(tty, options); - - /* ttyout should be flushed before outputting on stdout */ - tty_close(tty); - - emit(choices); - - /* Return to eventually exit successfully */ - return; - } else if (ch == KEY_ESC) { /* ESC */ - ch = tty_getchar(tty); - if (ch == '[' || ch == 'O') { - ch = tty_getchar(tty); - if (ch == 'A') { /* UP ARROW */ - choices_prev(choices); - } else if (ch == 'B') { /* DOWN ARROW */ - choices_next(choices); - } - } - } - } while (1); -} - int main(int argc, char *argv[]) { options_parse(&options, argc, argv); @@ -195,10 +46,7 @@ int main(int argc, char *argv[]) { if (options.num_lines + 1 > tty_getheight(&tty)) options.num_lines = tty_getheight(&tty) - 1; - if (options.init_search) - strncpy(search, options.init_search, SEARCH_SIZE_MAX); - - run(&tty, &choices, &options); + tty_interface_run(&tty, &choices, &options); } choices_destroy(&choices); diff --git a/src/tty_interface.c b/src/tty_interface.c new file mode 100644 index 0000000..69c3ab1 --- /dev/null +++ b/src/tty_interface.c @@ -0,0 +1,160 @@ +#include +#include +#include +#include + +#include "match.h" +#include "tty_interface.h" +#include "../config.h" + +static char search[SEARCH_SIZE_MAX + 1]; + +static void clear(tty_t *tty, options_t *options) { + tty_setcol(tty, 0); + size_t line = 0; + while (line++ < options->num_lines) { + tty_newline(tty); + } + tty_clearline(tty); + tty_moveup(tty, line - 1); + tty_flush(tty); +} + +static void draw_match(tty_t *tty, const char *choice, int selected, options_t *options) { + int n = strlen(search); + size_t positions[n + 1]; + for (int i = 0; i < n + 1; i++) + positions[i] = -1; + + double score = match_positions(search, choice, &positions[0]); + + size_t maxwidth = tty_getwidth(tty); + + if (options->show_scores) + tty_printf(tty, "(%5.2f) ", score); + + if (selected) + tty_setinvert(tty); + + for (size_t i = 0, p = 0; choice[i] != '\0'; i++) { + if (i + 1 < maxwidth) { + if (positions[p] == i) { + tty_setfg(tty, TTY_COLOR_HIGHLIGHT); + p++; + } else { + tty_setfg(tty, TTY_COLOR_NORMAL); + } + tty_printf(tty, "%c", choice[i]); + } else { + tty_printf(tty, "$"); + break; + } + } + tty_setnormal(tty); +} + +static void draw(tty_t *tty, choices_t *choices, options_t *options) { + unsigned int num_lines = options->num_lines; + size_t start = 0; + size_t current_selection = choices->selection; + if (current_selection + options->scrolloff >= num_lines) { + start = current_selection + options->scrolloff - num_lines + 1; + if (start + num_lines >= choices_available(choices)) { + start = choices_available(choices) - num_lines; + } + } + tty_setcol(tty, 0); + tty_printf(tty, "%s%s", options->prompt, search); + tty_clearline(tty); + for (size_t i = start; i < start + num_lines; i++) { + tty_printf(tty, "\n"); + tty_clearline(tty); + const char *choice = choices_get(choices, i); + if (choice) { + draw_match(tty, choice, i == choices->selection, options); + } + } + tty_moveup(tty, num_lines); + tty_setcol(tty, strlen(options->prompt) + strlen(search)); + tty_flush(tty); +} + +static void emit(choices_t *choices) { + const char *selection = choices_get(choices, choices->selection); + if (selection) { + /* output the selected result */ + printf("%s\n", selection); + } else { + /* No match, output the query instead */ + printf("%s\n", search); + } +} + +#define KEY_CTRL(key) ((key) - ('@')) +#define KEY_DEL 127 +#define KEY_ESC 27 + +void tty_interface_run(tty_t *tty, choices_t *choices, options_t *options) { + if (options->init_search) + strncpy(search, options->init_search, SEARCH_SIZE_MAX); + + choices_search(choices, search); + char ch; + do { + draw(tty, choices, options); + ch = tty_getchar(tty); + size_t search_size = strlen(search); + if (isprint(ch)) { + if (search_size < SEARCH_SIZE_MAX) { + search[search_size++] = ch; + search[search_size] = '\0'; + choices_search(choices, search); + } + } else if (ch == KEY_DEL || ch == KEY_CTRL('H')) { /* DEL || Backspace (C-H) */ + if (search_size) + search[--search_size] = '\0'; + choices_search(choices, search); + } else if (ch == KEY_CTRL('U')) { /* C-U */ + search_size = 0; + search[0] = '\0'; + choices_search(choices, search); + } else if (ch == KEY_CTRL('W')) { /* C-W */ + if (search_size) + search[--search_size] = '\0'; + while (search_size && !isspace(search[--search_size])) + search[search_size] = '\0'; + choices_search(choices, search); + } else if (ch == KEY_CTRL('N')) { /* C-N */ + choices_next(choices); + } else if (ch == KEY_CTRL('P')) { /* C-P */ + choices_prev(choices); + } else if (ch == KEY_CTRL('I')) { /* TAB (C-I) */ + strncpy(search, choices_get(choices, choices->selection), SEARCH_SIZE_MAX); + choices_search(choices, search); + } else if (ch == KEY_CTRL('C') || ch == KEY_CTRL('D')) { /* ^C || ^D */ + clear(tty, options); + tty_close(tty); + exit(EXIT_FAILURE); + } else if (ch == KEY_CTRL('M')) { /* CR */ + clear(tty, options); + + /* ttyout should be flushed before outputting on stdout */ + tty_close(tty); + + emit(choices); + + /* Return to eventually exit successfully */ + return; + } else if (ch == KEY_ESC) { /* ESC */ + ch = tty_getchar(tty); + if (ch == '[' || ch == 'O') { + ch = tty_getchar(tty); + if (ch == 'A') { /* UP ARROW */ + choices_prev(choices); + } else if (ch == 'B') { /* DOWN ARROW */ + choices_next(choices); + } + } + } + } while (1); +} diff --git a/src/tty_interface.h b/src/tty_interface.h new file mode 100644 index 0000000..e1240c3 --- /dev/null +++ b/src/tty_interface.h @@ -0,0 +1,12 @@ +#ifndef TTY_INTERFACE_H +#define TTY_INTERFACE_H TTY_INTERFACE_H + +#include "choices.h" +#include "options.h" +#include "tty.h" + +#define SEARCH_SIZE_MAX 4096 + +void tty_interface_run(tty_t *tty, choices_t *choices, options_t *options); + +#endif -- cgit v1.2.3