kickstart.nvim/lua/theme-switcher/fuzzy.lua

102 lines
2.2 KiB
Lua

local M = {}
-- Simple fuzzy match algorithm
-- Returns score (higher is better) or nil if no match
function M.fuzzy_match(str, pattern)
if pattern == '' then
return 1000 -- Empty pattern matches everything with high score
end
str = str:lower()
pattern = pattern:lower()
local str_idx = 1
local pattern_idx = 1
local score = 0
local consecutive = 0
local last_match_idx = 0
while pattern_idx <= #pattern do
local pattern_char = pattern:sub(pattern_idx, pattern_idx)
local found = false
-- Search for pattern character in remaining string
while str_idx <= #str do
local str_char = str:sub(str_idx, str_idx)
if str_char == pattern_char then
found = true
-- Score bonuses
score = score + 1
-- Bonus for consecutive matches
if str_idx == last_match_idx + 1 then
consecutive = consecutive + 1
score = score + consecutive * 5
else
consecutive = 0
end
-- Bonus for matching at start
if str_idx == 1 then
score = score + 10
end
-- Bonus for matching after separator
if str_idx > 1 then
local prev_char = str:sub(str_idx - 1, str_idx - 1)
if prev_char == '-' or prev_char == '_' or prev_char == ' ' then
score = score + 8
end
end
last_match_idx = str_idx
str_idx = str_idx + 1
break
end
str_idx = str_idx + 1
end
if not found then
return nil -- Pattern doesn't match
end
pattern_idx = pattern_idx + 1
end
return score
end
-- Filter and sort themes by fuzzy match
function M.filter_themes(themes, query)
if query == '' then
return themes
end
local matches = {}
for _, theme in ipairs(themes) do
local score = M.fuzzy_match(theme, query)
if score then
table.insert(matches, { theme = theme, score = score })
end
end
-- Sort by score (descending)
table.sort(matches, function(a, b)
return a.score > b.score
end)
-- Extract just the theme names
local filtered = {}
for _, match in ipairs(matches) do
table.insert(filtered, match.theme)
end
return filtered
end
return M