#include #include #include #include #include #include "Globals.h" #include "Terminal.h" #include "Input.h" int fuzzy_score(const char *s); int matches(const char *s) { if (input_len == 0) return 1; if (opts.fuzzy) { return fuzzy_score(s) >= 0; } const char *p = s; if (opts.insensitive) { while (*p) { if (strncasecmp(p, input, input_len) == 0) return 1; p++; } } else { while (*p) { if (strncmp(p, input, input_len) == 0) return 1; p++; } } return 0; } static int is_separator(char c) { return c == ' ' || c == '-' || c == '_' || c == '.' || c == '/' || c == '\\'; } int fuzzy_score(const char *s) { if (input_len == 0) return 0; int score = 0; int prev_pos = -1; const char *input_lower = NULL; const char *s_lower = NULL; char s_lower_buf[1024]; char input_lower_buf[256]; if (opts.insensitive) { for (size_t i = 0; i < input_len && i < 255; i++) { input_lower_buf[i] = tolower(input[i]); } input_lower_buf[input_len] = '\0'; input_lower = input_lower_buf; size_t slen = strlen(s); if (slen < 1024) { for (size_t i = 0; i <= slen; i++) { s_lower_buf[i] = tolower(s[i]); } s_lower = s_lower_buf; } } const char *search = input_lower ? input_lower : input; const char *search_s = s_lower ? s_lower : s; for (size_t i = 0; i < input_len; i++) { const char *found = NULL; int best_pos = -1; int best_score = -1000; const char *p = search_s; int pos = 0; while (*p) { if (*p == search[i] && (i == 0 || pos > prev_pos)) { int char_score; if (i == 0) { if (pos == 0) char_score = 25; else if (is_separator(s[pos - 1])) char_score = 3; else char_score = 1; } else { if (prev_pos + 1 == pos) char_score = 25; else if (is_separator(s[pos - 1])) char_score = 1; else char_score = 8 - (pos - prev_pos - 1) * 2; } if (char_score > best_score) { best_score = char_score; best_pos = pos; found = p; } } p++; pos++; } if (!found) return -1; score += best_score; if (score < 1) score = 1; prev_pos = best_pos; } score -= (int)(strlen(s) / 3); return score; } static int compare_scores(const void *a, const void *b) { char *const *sa = a; char *const *sb = b; int score_a = fuzzy_score(*sa); int score_b = fuzzy_score(*sb); return score_b - score_a; } void filter_items(void) { filtered.count = 0; for (size_t i = 0; i < all_items.count; i++) { if (matches(all_items.items[i])) { if (filtered.count >= filtered.capacity) { size_t new_cap = filtered.capacity == 0 ? INITIAL_CAPACITY : filtered.capacity * 2; filtered.items = realloc(filtered.items, new_cap * sizeof(char *)); filtered.capacity = new_cap; } filtered.items[filtered.count++] = all_items.items[i]; } } if (opts.fuzzy && filtered.count > 1) { qsort(filtered.items, filtered.count, sizeof(char *), compare_scores); } if ((size_t)cursor >= filtered.count) cursor = filtered.count > 0 ? (int)filtered.count - 1 : 0; if (scroll > cursor) scroll = cursor; if (scroll < cursor - DEFAULT_LINES + 1) scroll = cursor - DEFAULT_LINES + 1; if (scroll < 0) scroll = 0; needs_redraw = 1; } void handle_input(void) { char c; if (read(tty_fd, &c, 1) <= 0) return; if (c == 27) { char seq[3]; ssize_t n = read(tty_fd, &seq[0], 1); if (n > 0 && seq[0] == '[') { if (read(tty_fd, &seq[1], 1) > 0) { switch (seq[1]) { case 'A': if (cursor > 0) cursor--; break; case 'B': if (cursor < (int)filtered.count - 1) cursor++; break; case 'H': case 'F': cursor = 0; break; case 'G': cursor = filtered.count > 0 ? filtered.count - 1 : 0; break; case '5': case '6': if (read(tty_fd, &seq[2], 1) > 0 && seq[2] == '~') { int jump = DEFAULT_LINES; if (seq[1] == '5') { cursor -= jump; if (cursor < 0) cursor = 0; } else { cursor += jump; if (cursor >= (int)filtered.count) cursor = filtered.count > 0 ? (int)filtered.count - 1 : 0; } } break; } } } else { exit(1); } if (cursor < scroll) scroll = cursor; if (cursor > scroll + DEFAULT_LINES - 1) scroll = cursor - DEFAULT_LINES + 1; needs_redraw = 1; } else if (c == 127 || c == 8) { if (input_len > 0) input[--input_len] = '\0'; filter_items(); } else if (c == '\n' || c == '\r') { if (filtered.count > 0) { dprintf(tty_out_fd, "\033[?1049l\033[2J\033[?25h\033[0m"); dprintf(orig_stdout, "%s\n", filtered.items[cursor]); exit(0); } } else if (c == 4) { exit(1); } else if (c >= 32 && c < 127) { if ((int)input_len + 2 > (int)input_capacity) { size_t new_cap = input_capacity == 0 ? INITIAL_CAPACITY : input_capacity * 2; input = realloc(input, new_cap); memset(input + input_capacity, 0, new_cap - input_capacity); input_capacity = new_cap; } input[input_len++] = c; input[input_len] = '\0'; filter_items(); } }