mirror of
https://github.com/folke/snacks.nvim
synced 2025-08-05 03:08:13 +00:00
feat(picker.matcher): new opts.matcher.file_pos
which defaults to true
to support patterns like file:line:col
or file:line
. Closes #517. Closes #496. Closes #651
This commit is contained in:
parent
01b70b9f01
commit
5e00b0ab27
5 changed files with 38 additions and 3 deletions
|
@ -109,6 +109,7 @@ local defaults = {
|
||||||
ignorecase = true, -- use ignorecase
|
ignorecase = true, -- use ignorecase
|
||||||
sort_empty = false, -- sort results when the search string is empty
|
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)
|
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`
|
||||||
},
|
},
|
||||||
sort = {
|
sort = {
|
||||||
-- default sort is by score, text length and index
|
-- default sort is by score, text length and index
|
||||||
|
|
|
@ -205,6 +205,7 @@ function M:clear()
|
||||||
self.topk:clear()
|
self.topk:clear()
|
||||||
self.top, self.cursor = 1, 1
|
self.top, self.cursor = 1, 1
|
||||||
self.items = {}
|
self.items = {}
|
||||||
|
self._current = nil
|
||||||
self.dirty = true
|
self.dirty = true
|
||||||
if next(self.items) == nil then
|
if next(self.items) == nil then
|
||||||
return
|
return
|
||||||
|
|
|
@ -10,6 +10,7 @@ local Async = require("snacks.picker.util.async")
|
||||||
---@field live? boolean
|
---@field live? boolean
|
||||||
---@field score snacks.picker.Score
|
---@field score snacks.picker.Score
|
||||||
---@field sorting? boolean
|
---@field sorting? boolean
|
||||||
|
---@field file? {path: string, pos: snacks.picker.Pos}
|
||||||
local M = {}
|
local M = {}
|
||||||
M.__index = M
|
M.__index = M
|
||||||
M.DEFAULT_SCORE = 1000
|
M.DEFAULT_SCORE = 1000
|
||||||
|
@ -114,6 +115,7 @@ end
|
||||||
function M:init(opts)
|
function M:init(opts)
|
||||||
opts = opts or {}
|
opts = opts or {}
|
||||||
self.tick = self.tick + 1
|
self.tick = self.tick + 1
|
||||||
|
self.file = nil
|
||||||
local pattern = vim.trim(opts.pattern or self.pattern)
|
local pattern = vim.trim(opts.pattern or self.pattern)
|
||||||
self.mods = {}
|
self.mods = {}
|
||||||
self.pattern = pattern
|
self.pattern = pattern
|
||||||
|
@ -158,7 +160,29 @@ end
|
||||||
function M:_prepare(pattern)
|
function M:_prepare(pattern)
|
||||||
---@type snacks.picker.matcher.Mods
|
---@type snacks.picker.matcher.Mods
|
||||||
local mods = { pattern = pattern, entropy = 0, chars = {} }
|
local mods = { pattern = pattern, entropy = 0, chars = {} }
|
||||||
local field, p = pattern:match("^([%w_]+):(.*)$")
|
|
||||||
|
local file_patterns = {
|
||||||
|
"^(.*[/\\].*):(%d*):(%d*)$",
|
||||||
|
"^(.*[/\\].*):(%d*)$",
|
||||||
|
"^(.+%.[a-z_]+):(%d*):(%d*)$",
|
||||||
|
"^(.+%.[a-z_]+):(%d*)$",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p in ipairs(file_patterns) do
|
||||||
|
local file, line, col = pattern:match(p)
|
||||||
|
if file then
|
||||||
|
mods.field = "file"
|
||||||
|
mods.pattern = file .. "$"
|
||||||
|
self.file = {
|
||||||
|
path = file,
|
||||||
|
pos = { tonumber(line) or 1, tonumber(col) or 0 },
|
||||||
|
}
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- minimum two chars for field pattern
|
||||||
|
local field, p = pattern:match("^([%w_][%w_]+):(.*)$")
|
||||||
if field then
|
if field then
|
||||||
mods.field = field
|
mods.field = field
|
||||||
mods.pattern = p
|
mods.pattern = p
|
||||||
|
@ -217,6 +241,9 @@ function M:update(item)
|
||||||
if item.match_tick == self.tick then
|
if item.match_tick == self.tick then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
if item.match_pos then
|
||||||
|
item.pos = nil
|
||||||
|
end
|
||||||
local score = self:match(item)
|
local score = self:match(item)
|
||||||
if score ~= 0 then
|
if score ~= 0 then
|
||||||
if item.score_add then
|
if item.score_add then
|
||||||
|
@ -225,6 +252,10 @@ function M:update(item)
|
||||||
if item.score_mul then
|
if item.score_mul then
|
||||||
score = score * item.score_mul
|
score = score * item.score_mul
|
||||||
end
|
end
|
||||||
|
if self.file and not item.pos then
|
||||||
|
item.pos = self.file.pos
|
||||||
|
item.match_pos = true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
item.match_tick, item.score = self.tick, score
|
item.match_tick, item.score = self.tick, score
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
---@class snacks.picker.Preview
|
---@class snacks.picker.Preview
|
||||||
---@field item? snacks.picker.Item
|
---@field item? snacks.picker.Item
|
||||||
|
---@field pos? snacks.picker.Pos
|
||||||
---@field win snacks.win
|
---@field win snacks.win
|
||||||
---@field preview snacks.picker.preview
|
---@field preview snacks.picker.preview
|
||||||
---@field state table<string, any>
|
---@field state table<string, any>
|
||||||
|
@ -101,11 +102,12 @@ end
|
||||||
---@param picker snacks.Picker
|
---@param picker snacks.Picker
|
||||||
function M:show(picker)
|
function M:show(picker)
|
||||||
local item, prev = picker:current({ resolve = false }), self.item
|
local item, prev = picker:current({ resolve = false }), self.item
|
||||||
if self.item == item then
|
if self.item == item and self.pos == (item and item.pos or nil) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
Snacks.picker.util.resolve(item)
|
Snacks.picker.util.resolve(item)
|
||||||
self.item = item
|
self.item = item
|
||||||
|
self.pos = item and item.pos or nil
|
||||||
if item then
|
if item then
|
||||||
local buf = self.win.buf
|
local buf = self.win.buf
|
||||||
local ok, err = pcall(
|
local ok, err = pcall(
|
||||||
|
|
|
@ -182,7 +182,7 @@ function M.parse(str)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Resolves the item if it has a resolve function
|
--- Resolves the item if it has a resolve function
|
||||||
---@param item snacks.picker.Item
|
---@param item snacks.picker.Item?
|
||||||
function M.resolve(item)
|
function M.resolve(item)
|
||||||
if item and item.resolve then
|
if item and item.resolve then
|
||||||
item.resolve(item)
|
item.resolve(item)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue