feat(picker.matcher): frecency and cwd bonus can now be enabled on any picker

This commit is contained in:
Folke Lemaitre 2025-01-22 23:12:47 +01:00
parent 5778234e39
commit 7b85dfc6f6
No known key found for this signature in database
GPG key ID: 41F8B1FBACAE2040
2 changed files with 20 additions and 0 deletions

View file

@ -27,6 +27,7 @@ local M = {}
---@field [string] any
---@field idx number
---@field score number
---@field frecency? number
---@field score_add? number
---@field score_mul? number
---@field match_tick? number
@ -110,6 +111,10 @@ local defaults = {
sort_empty = false, -- sort results when the search string is empty
filename_bonus = true, -- give bonus for matching file names (last part of the path)
file_pos = true, -- support patterns like `file:line:col` and `file:line`
-- the bonusses below, possibly require string concatenation and path normalization,
-- so this can have a performance impact for large lists and increase memory usage
cwd_bonus = false, -- give bonus for matching files in the cwd
frecency = false, -- frecency bonus
},
sort = {
-- default sort is by score, text length and index

View file

@ -11,10 +11,14 @@ local Async = require("snacks.picker.util.async")
---@field score snacks.picker.Score
---@field sorting? boolean
---@field file? {path: string, pos: snacks.picker.Pos}
---@field cwd string
---@field frecency? snacks.picker.Frecency
local M = {}
M.__index = M
M.DEFAULT_SCORE = 1000
M.INVERSE_SCORE = 1000
local BONUS_FRECENCY = 8
local BONUS_CWD = 10
local YIELD_MATCH = 1 -- ms
@ -44,6 +48,7 @@ function M.new(opts)
self.sorting = true
self.tick = 0
self.score = require("snacks.picker.core.score").new(self.opts)
self.frecency = self.opts.frecency and require("snacks.picker.core.frecency").new() or nil
return self
end
@ -71,6 +76,7 @@ function M:run(picker, opts)
self.task:abort()
picker.list:clear()
self.cwd = vim.fs.normalize(picker.opts.cwd or (vim.uv or vim.loop).cwd() or ".")
self.sorting = not self:empty() or picker.opts.matcher.sort_empty
-- PERF: fast path for empty pattern
@ -265,6 +271,15 @@ function M:update(item)
item.pos = self.file.pos
item.match_pos = true
end
if item.file then
if self.frecency then
item.frecency = item.frecency or self.frecency:get(item)
score = score + (1 - 1 / (1 + item.frecency)) * BONUS_FRECENCY
end
if self.opts.cwd_bonus and self.cwd == item.cwd or Snacks.picker.util.path(item):find(self.cwd, 1, true) == 1 then
score = score + BONUS_CWD
end
end
end
item.match_tick, item.score = self.tick, score
return true