#include "completion.h" #include #include static int ecex_ascii_lower(int c) { if (c >= 'A' && c <= 'Z') return c - 'A' + 'a'; return c; } int ecex_ascii_strncasecmp(const char *a, const char *b, size_t n) { if (!a || !b) return a == b ? 0 : (a ? 1 : -1); for (size_t i = 0; i < n; i++) { int ac = ecex_ascii_lower((unsigned char)a[i]); int bc = ecex_ascii_lower((unsigned char)b[i]); if (ac != bc || ac == '\0' || bc == '\0') return ac - bc; } return 0; } int ecex_ascii_contains_ci(const char *haystack, const char *needle) { if (!haystack || !needle) return 0; if (needle[0] == '\0') return 1; size_t needle_len = strlen(needle); for (size_t i = 0; haystack[i]; i++) { if (ecex_ascii_strncasecmp(haystack + i, needle, needle_len) == 0) return 1; } return 0; } int ecex_fuzzy_score(const char *candidate, const char *query) { if (!candidate || !query) return -1; if (query[0] == '\0') return 0; int score = 0; int consecutive = 0; int last_match = -1; size_t ci = 0; size_t qi = 0; while (candidate[ci] && query[qi]) { char c = candidate[ci]; char q = query[qi]; if (c >= 'A' && c <= 'Z') c = (char)(c - 'A' + 'a'); if (q >= 'A' && q <= 'Z') q = (char)(q - 'A' + 'a'); if (c == q) { score += 10; if ((int)ci == last_match + 1) { consecutive++; score += 5 * consecutive; } else { consecutive = 0; } if (ci == 0) score += 20; if (ci > 0 && (candidate[ci - 1] == '-' || candidate[ci - 1] == '_' || candidate[ci - 1] == ' ')) { score += 15; } last_match = (int)ci; qi++; } ci++; } if (query[qi] != '\0') return -1; score -= (int)strlen(candidate); if (strncmp(candidate, query, strlen(query)) == 0) score += 100; if (ecex_ascii_contains_ci(candidate, query)) score += 75; return score; } int ecex_completion_item_compare(const void *a, const void *b) { const ecex_completion_item_t *pa = (const ecex_completion_item_t *)a; const ecex_completion_item_t *pb = (const ecex_completion_item_t *)b; if (pa->score != pb->score) return pb->score - pa->score; if (pa->is_dir != pb->is_dir) return pb->is_dir - pa->is_dir; int cmp = strcmp(pa->value ? pa->value : "", pb->value ? pb->value : ""); if (cmp != 0) return cmp; if (pa->order < pb->order) return -1; if (pa->order > pb->order) return 1; return 0; } void ecex_completion_items_free(ecex_completion_item_t *items, size_t count) { if (!items) return; for (size_t i = 0; i < count; i++) free(items[i].value); free(items); }