]> git.mdlowis.com Git - projs/tide.git/commitdiff
tweaked UI handling so only one item will not show the GUI
authorMichael D. Lowis <mike.lowis@gentex.com>
Thu, 18 Apr 2019 01:39:44 +0000 (21:39 -0400)
committerMichael D. Lowis <mike.lowis@gentex.com>
Thu, 18 Apr 2019 01:39:44 +0000 (21:39 -0400)
src/pick.c

index c098f1b7ddd4d59bad4dbba4952559479ac548a7..4dd6de80643fc46692f93e76bc46e9acb685c32e 100644 (file)
@@ -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;
 }