From 6aee38e622402e874e5940d4f220ed4920bf1c13 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Tue, 16 Apr 2019 17:35:22 -0400 Subject: [PATCH] fixed some inefficiencies in pick --- .gitignore | 1 + build.sh | 2 +- c.h | 38 ++++++--------------- pick.c | 98 +++++++++++++++++++++++++++++++++++------------------- 4 files changed, 77 insertions(+), 62 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5df8edf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +pick diff --git a/build.sh b/build.sh index 8a183dc..7e679cb 100755 --- a/build.sh +++ b/build.sh @@ -1,2 +1,2 @@ #!/bin/sh -gcc -D_XOPEN_SOURCE *.c -I . -o pick +gcc -D_XOPEN_SOURCE=700 *.c -I . -o pick -g -fsanitize=address,undefined -lasan -lm diff --git a/c.h b/c.h index 086d347..26b5396 100644 --- a/c.h +++ b/c.h @@ -1,6 +1,9 @@ #include #include #include +#include +#include +#include #define nelem(x) (sizeof(x) / sizeof((x)[0])) @@ -83,31 +86,12 @@ static inline char* _getopt_(int* p_argc, char*** p_argv) { #define OPTLONG case '-' -/******************************************************************************/ - -#include -#include -#include +#ifndef min + #define min(x,y) \ + ((x) < (y) ? (x) : (y)) +#endif -static char* rdline(FILE* input) { - size_t size = 8; - size_t index = 0; - char* str = (char*)malloc(size); - memset(str, 0, 8); - if (feof(input)) { - free(str); - return NULL; - } - while (true) { - char ch = fgetc(input); - if (ch == EOF) break; - str[index++] = ch; - str[index] = '\0'; - if (index+1 >= size) { - size = size << 1; - str = realloc(str, size); - } - if (ch == '\n') break; - } - return str; -} +#ifndef max + #define max(x,y) \ + ((x) > (y) ? (x) : (y)) +#endif diff --git a/pick.c b/pick.c index 38abde8..6ad9f43 100644 --- a/pick.c +++ b/pick.c @@ -2,6 +2,10 @@ #include #include #include +#include + +static void redraw(void); +static void filter(void); typedef struct { float score; @@ -13,12 +17,32 @@ typedef struct { char* ARGV0; int AltFlag = 1; // Disable alternate screen usage -char Query[1024] = {0}; +char Query[8192] = {0}; size_t QueryIdx = 0; vec_t Choices = {0}; -size_t ChoiceIdx = 2; +size_t ChoiceIdx = 0; + +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*)calloc(size,1); + while (!feof(stdin)) { + if (index+2 >= size) { + size = size << 1; + str = realloc(str, size); + } + char ch = fgetc(fin); + if (ch == EOF || ch == '\r' || ch == '\n') break; + str[index++] = ch; + str[index] = '\0'; + } + if (len) *len = index; + return str; +} -int by_score(const void* a, const void* b) { +static int by_score(const void* a, const void* b) { Choice* ca = ((Choice*)a); Choice* cb = ((Choice*)b); if (ca->score < cb->score) @@ -29,37 +53,38 @@ int by_score(const void* a, const void* b) { return strcmp(ca->string, cb->string); } -void load_choices(void) { +static void load_choices(void) { + size_t choice_len; char* choice_text; 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; vec_push_back(&Choices, &choice); + } else { + free(choice_text); } } - vec_sort(&Choices, by_score); } -char* find_match_start(char *str, int ch) { +static char* find_match_start(char *str, int ch) { for (; *str; str++) if (tolower(*str) == tolower(ch)) return str; return NULL; } -bool match(char *string, size_t offset, size_t *start, size_t *end) { +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; /* find the end of the match */ - for (; *q; q++) + for (q++, e++; *q; q++) if ((e = find_match_start(e, *q)) == NULL) return false; /* make note of the matching range */ @@ -73,8 +98,8 @@ bool match(char *string, size_t offset, size_t *start, size_t *end) { return true; } -void score(void) { - for (int i = 0; i < vec_size(&Choices); i++) { +static void score(void) { + for (unsigned int i = 0; i < vec_size(&Choices); i++) { Choice* choice = (Choice*)vec_at(&Choices, i); float qlen = (float)QueryIdx; if (match(choice->string, 0, &choice->match_start, &choice->match_end)) { @@ -89,7 +114,26 @@ void score(void) { vec_sort(&Choices, by_score); } -void redraw(void) { +int main(int argc, char** argv) { + OPTBEGIN { + case 'a': AltFlag = 0; break; + } OPTEND; + if (argc >= 1) { + size_t sz = min(strlen(argv[0]), sizeof(Query)-1); + strncpy(Query, argv[0], sz); + QueryIdx = sz; + } + load_choices(); + score(); + if (vec_size(&Choices) > 1) + filter(); + Choice* choice = (Choice*)vec_at(&Choices, ChoiceIdx); + if (vec_size(&Choices) && ChoiceIdx != SIZE_MAX) + printf("%s\n", choice->string); + return 0; +} + +static void redraw(void) { tb_clear(); /* Draw query and cursor */ int max_x = (tb_width() < 1023 ? tb_width() : 1023); @@ -100,25 +144,24 @@ void redraw(void) { for (int x = 0; x < tb_width(); x++) tb_change_cell(x, 1, 0x2500, TB_DEFAULT, TB_DEFAULT); /* Draw the scored and sorted results */ - for (int i = 0, y = 2; (i < vec_size(&Choices)) && (y < tb_height()); i++) { - bool selected = (y == ChoiceIdx); + for (int i = 0, y = 2; (i < vec_size(&Choices)) && (y < tb_height()); i++, y++) { + bool selected = (i == ChoiceIdx); Choice* choice = (Choice*)vec_at(&Choices, i); if (choice->score >= 0.0) { for (int x = 0; choice->string[x] && x < tb_width(); x++) { bool inmatch = (choice->match_end && x >= choice->match_start && x <= choice->match_end); - tb_change_cell(x, i+2, choice->string[x], + tb_change_cell(x, y, choice->string[x], (inmatch ? TB_UNDERLINE|TB_BLUE : TB_DEFAULT), (selected ? TB_WHITE : TB_DEFAULT)); } for (int x = choice->length; selected && (x < tb_width()); x++) tb_change_cell(x, y, ' ', TB_DEFAULT, TB_WHITE); - y++; } } tb_present(); } -void filter(void) { +static void filter(void) { struct tb_event ev = {0}; tb_init_with(AltFlag ? TB_INIT_EVERYTHING : 0); do { @@ -132,10 +175,10 @@ void filter(void) { if (QueryIdx > 0) Query[--QueryIdx] = '\0'; } else if (ev.key == TB_KEY_ARROW_DOWN) { - if (ChoiceIdx < tb_width() && ChoiceIdx <= vec_size(&Choices)) + if (ChoiceIdx < tb_width() && ChoiceIdx < vec_size(&Choices)-1) ChoiceIdx++; } else if (ev.key == TB_KEY_ARROW_UP) { - if (ChoiceIdx > 2) + if (ChoiceIdx > 0) ChoiceIdx--; } else if (ev.ch) { if (QueryIdx < sizeof(Query)-1) @@ -147,16 +190,3 @@ void filter(void) { } while (tb_poll_event(&ev)); tb_shutdown(); } - -int main(int argc, char** argv) { - OPTBEGIN { - case 'a': AltFlag = 0; break; - } OPTEND; - load_choices(); - if (vec_size(&Choices) > 1) - filter(); - Choice* choice = (Choice*)vec_at(&Choices, ChoiceIdx-2); - if (vec_size(&Choices) && ChoiceIdx != SIZE_MAX) - printf("%s\n", choice->string); - return 0; -} -- 2.52.0