mirror of
https://github.com/MihailRis/voxelcore.git
synced 2026-10-08 12:31:51 +00:00
Merge 82801c52bc into dacebf94bc
This commit is contained in:
commit
258671b7fd
4 changed files with 254 additions and 47 deletions
102
res/modules/search_utils.lua
Normal file
102
res/modules/search_utils.lua
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
local M = {}
|
||||
|
||||
M.MATCHED_COLOR_DEFAULT = "[#4FC3F7]"
|
||||
M.NORMAL_COLOR_DEFAULT = "[#FFFFFF]"
|
||||
|
||||
---Calculate fuzzy score
|
||||
---@param sample str
|
||||
---@param pattern str
|
||||
---@param do_coloring? bool if passed, then function will also return colored_sample, where matched
|
||||
---characters batched will be wrapped in color_matched and color_normal strings
|
||||
---@param color_matched? str if not passed, uses the default M.MATCHED_COLOR_DEFAULT
|
||||
---@param color_normal? str if not passed, uses the default M.NORMAL_COLOR_DEFAULT
|
||||
---@return int match pattern match intensity, 0 for absence
|
||||
---@return str? colored_sample
|
||||
function M.fuzzy_score(sample, pattern, do_coloring, color_matched, color_normal)
|
||||
if pattern == "" then return 0 end
|
||||
|
||||
color_matched = color_matched or M.MATCHED_COLOR_DEFAULT
|
||||
color_normal = color_normal or M.NORMAL_COLOR_DEFAULT
|
||||
local colored_sample
|
||||
if do_coloring then
|
||||
colored_sample = ""
|
||||
end
|
||||
|
||||
local sample_lower = string.lower(sample)
|
||||
local pattern_lower = string.lower(pattern)
|
||||
|
||||
local sample_len = #sample_lower
|
||||
local pattern_len = #pattern_lower
|
||||
|
||||
if pattern_len > sample_len then return 0 end
|
||||
|
||||
local pattern_idx = 1
|
||||
local consecutive = 0
|
||||
local max_consecutive = 0
|
||||
local matched_chars = 0
|
||||
local total_distance = 0
|
||||
local last_match_pos = -1
|
||||
|
||||
for i = 1, sample_len do
|
||||
if pattern_idx <= pattern_len and (
|
||||
sample_lower:sub(i, i) ==
|
||||
pattern_lower:sub(pattern_idx, pattern_idx)) then
|
||||
matched_chars = matched_chars + 1
|
||||
if consecutive == 0 and do_coloring then
|
||||
colored_sample = colored_sample .. color_matched
|
||||
end
|
||||
consecutive = consecutive + 1
|
||||
if consecutive > max_consecutive then
|
||||
max_consecutive = consecutive
|
||||
end
|
||||
|
||||
if last_match_pos ~= -1 then
|
||||
total_distance = total_distance + (i - last_match_pos - 1)
|
||||
end
|
||||
last_match_pos = i
|
||||
|
||||
pattern_idx = pattern_idx + 1
|
||||
else
|
||||
if consecutive ~= 0 and do_coloring then
|
||||
colored_sample = colored_sample .. color_normal
|
||||
end
|
||||
consecutive = 0
|
||||
end
|
||||
if do_coloring then
|
||||
colored_sample = colored_sample .. sample:sub(i, i)
|
||||
end
|
||||
end
|
||||
if consecutive ~= 0 and do_coloring then
|
||||
colored_sample = colored_sample .. color_normal
|
||||
end
|
||||
|
||||
if pattern_idx <= pattern_len then
|
||||
return 0
|
||||
end
|
||||
|
||||
local coverage = matched_chars / pattern_len * 20
|
||||
|
||||
local consecutive_bonus = max_consecutive * 10
|
||||
|
||||
local start_bonus = 0
|
||||
if sample_lower:sub(1, 1) == pattern_lower:sub(1, 1) then
|
||||
start_bonus = 15
|
||||
end
|
||||
|
||||
local prefix_bonus = 0
|
||||
if sample_lower:find(pattern_lower, 1, true) == 1 then
|
||||
prefix_bonus = 25
|
||||
end
|
||||
|
||||
local distance_penalty = total_distance * 2
|
||||
|
||||
local score = coverage + consecutive_bonus + start_bonus + prefix_bonus - distance_penalty
|
||||
|
||||
if sample_lower:find(pattern_lower, 1, true) then
|
||||
score = score + 30
|
||||
end
|
||||
|
||||
return math.max(0, score), colored_sample
|
||||
end
|
||||
|
||||
return M
|
||||
Loading…
Add table
Add a link
Reference in a new issue