From de0bf6a5b499666d1b91c5a78f7afe0c00637b49 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Wed, 17 Apr 2019 21:39:44 -0400 Subject: [PATCH] tweaked UI handling so only one item will not show the GUI --- src/pick.c | 141 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 86 insertions(+), 55 deletions(-) diff --git a/src/pick.c b/src/pick.c index c098f1b..4dd6de8 100644 --- a/src/pick.c +++ b/src/pick.c @@ -5,6 +5,11 @@ #define INCLUDE_DEFS #include "config.h" +static void xkeypress(XConf* x, XEvent* e); +static void xbtnpress(XConf* x, XEvent* e); +static void redraw(XConf* x); +static void xinit(XConf* x); + typedef struct { float score; char* string; @@ -19,23 +24,30 @@ vec_t Choices = {0}; size_t ChoiceIdx = 0; size_t Offset = 0; -static char* rdline(FILE* fin) { +static int peekc(FILE* in) { + int c = fgetc(in); + ungetc(c, in); + return c; +} + +static char* rdline(FILE* fin, size_t* len) { if (feof(fin) || ferror(fin)) return NULL; size_t size = 256; size_t index = 0; - char* str = (char*)malloc(size); - while (true) { - char ch = fgetc(fin); - if (ch == EOF) break; - str[index++] = ch; - str[index] = '\0'; - if (index+1 >= size) { + char* str = (char*)calloc(size,1); + while (!feof(stdin)) { + if (index+2 >= size) { size = size << 1; str = realloc(str, size); } - if (ch == '\n') break; + char ch = fgetc(fin); + if (ch == '\r') continue; + if (ch == EOF || ch == '\n') break; + str[index++] = ch; + str[index] = '\0'; } + if (len) *len = index; return str; } @@ -47,59 +59,79 @@ static int by_score(const void* a, const void* b) { else if (ca->score > cb->score) return -1; else - return strcmp(ca->string, cb->string); + return 0; } -static void load_choices(void) { +static void load_choices(XConf* x) { + size_t choice_len; char* choice_text; + bool shown = false; Choice choice = {0}; vec_init(&Choices, sizeof(Choice)); - while ((choice_text = rdline(stdin)) != NULL) { - choice_text[strlen(choice_text)-1] = '\0'; - if (strlen(choice_text) > 0) { + while ((choice_text = rdline(stdin, &choice_len)) != NULL) { + if (choice_len > 0) { choice.string = choice_text; choice.length = strlen(choice_text); choice.score = 1.0; + if (!shown && peekc(stdin) != EOF) { + x11_show(x); + redraw(x); + shown = true; + } vec_push_back(&Choices, &choice); + } else { + free(choice_text); } } - vec_sort(&Choices, by_score); } -static char* find_match_start(char *str, int ch) { +static char* find_char(char* str, int ch) { for (; *str; str++) if (tolower(*str) == tolower(ch)) return str; return NULL; } -static bool match(char *string, size_t offset, size_t *start, size_t *end) { - char* q = Query; - char* s = find_match_start(&string[offset], *q); - char* e = s; - /* bail if no match for first char */ - if (s == NULL) return 0; +static inline bool find_match(char *string, char* query, size_t offset, char **start, char **end) { + char *s, *e; + /* find first match char or bail */ + s = e = find_char(&string[offset], *query); + if (s == NULL) return false; + /* find the end of the match */ - for (; *q; q++) - if ((e = find_match_start(e, *q)) == NULL) + for (query++; *query; query++) + if ((e = find_char(e+1, *query)) == NULL) return false; - /* make note of the matching range */ - *start = s - string; - *end = e - string; - /* Less than or equal is used in order to obtain the left-most match. */ - if (match(string, offset + 1, start, end) && (size_t)(e - s) <= *end - *start) { - *start = s - string; - *end = e - string; - } + + /* if we made it this far, we found a match */ + *start = s, *end = e; + return true; +} + +static bool match(char *string, size_t offset, size_t *start, size_t *end) { + char *s1 = 0, *e1 = 0, *s2, *e2; + /* first check if we match at all */ + if (!find_match(string, Query, offset, &s1, &e1)) + return false; + s2 = s1, e2 = e1; // Init s2 and e2 before use below + + /* next find the longest match. If multiple, take the left most one */ + while (find_match(string, Query, ++offset, &s1, &e1) && ((e1-s1) <= (e2-s2))) + s1 = s2, e1 = e2; + + /* return the best match */ + *start = s1 - string; + *end = e1 - string; return true; } static void score(void) { - for (unsigned int i = 0; i < vec_size(&Choices); i++) { + unsigned int nchoices = vec_size(&Choices); + for (unsigned int i = 0; i < nchoices; i++) { Choice* choice = (Choice*)vec_at(&Choices, i); float qlen = (float)QueryIdx; if (match(choice->string, 0, &choice->match_start, &choice->match_end)) { - float clen = (float)(choice->match_end - choice->match_start); + float clen = (float)(choice->match_end - choice->match_start) + 1; choice->score = qlen / clen / (float)(choice->length); } else { choice->match_start = 0; @@ -110,6 +142,24 @@ static void score(void) { vec_sort(&Choices, by_score); } +int main(int argc, char** argv) { + XConf x = {0}; + if (argc >= 2) { + size_t sz = min(strlen(argv[1]), sizeof(Query)-1); + strncpy(Query, argv[1], sz); + QueryIdx = sz; + } + xinit(&x); + load_choices(&x); + score(); + if (vec_size(&Choices) > 1) + x11_event_loop(&x, redraw); + Choice* choice = (Choice*)vec_at(&Choices, ChoiceIdx); + if (vec_size(&Choices) && ChoiceIdx != SIZE_MAX) + printf("%s\n", choice->string); + return 0; +} + static void xkeypress(XConf* x, XEvent* e) { KeySym key = x11_getkey(x, e); if (key == XK_Return) { @@ -132,12 +182,13 @@ static void xkeypress(XConf* x, XEvent* e) { } else if (key == XK_BackSpace) { if (QueryIdx > 0) Query[--QueryIdx] = '\0'; + score(); } else if (key >= 0x20 && key <= 0x7F) { if (QueryIdx < sizeof(Query)-1) Query[QueryIdx++] = key; Offset = ChoiceIdx = 0; + score(); } - score(); } static void xbtnpress(XConf* x, XEvent* e) { @@ -211,26 +262,6 @@ static void xinit(XConf* x) { perror("unable to load base font"); exit(EXIT_FAILURE); } - x11_show(x); x->eventfns[KeyPress] = xkeypress; x->eventfns[ButtonPress] = xbtnpress; - redraw(x); -} - -int main(int argc, char** argv) { - XConf x = {0}; - if (argc >= 2) { - size_t sz = min(strlen(argv[1]), sizeof(Query)-1); - strncpy(Query, argv[1], sz); - QueryIdx = sz; - } - xinit(&x); - load_choices(); - score(); - if (vec_size(&Choices) > 1) - x11_event_loop(&x, redraw); - Choice* choice = (Choice*)vec_at(&Choices, ChoiceIdx); - if (vec_size(&Choices) && ChoiceIdx != SIZE_MAX) - printf("%s\n", choice->string); - return 0; } -- 2.52.0