Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 23 additions & 23 deletions lua/fff/location_utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,13 @@ function M.highlight_location(bufnr, location, namespace)
end

--- Highlight all occurrences of a grep pattern in the preview buffer.
--- For plain text and regex modes: highlights every match on all loaded lines
--- using Lua string.find with the query text.
--- For fuzzy mode: uses the pre-computed match byte offsets from Rust on the
--- target line only, since the fuzzy needle (e.g. "shcema") won't match via
--- literal search against the actual content (e.g. "schema").
--- Preferred path: location.file_matches contains per-line ranges supplied by
--- ripgrep (or fuzzy Smith-Waterman traceback) for every match in the file —
--- highlights all of them using exact byte offsets.
--- Fallback (no file_matches): scan ±200 lines around the target with
--- vim.pesc + smart-case literal search.
--- @param bufnr number Buffer number
--- @param location table Location with .grep_query, .line, optional .col, optional .fuzzy_match_ranges
--- @param location table Location with .grep_query, .line, optional .col, optional .file_matches
--- @param namespace number Namespace for extmarks
--- @return table|nil Highlight extmark details for cleanup
function M.highlight_grep_matches(bufnr, location, namespace)
Expand All @@ -169,24 +169,24 @@ function M.highlight_grep_matches(bufnr, location, namespace)
if ok then table.insert(extmarks, { id = mark_id, line = target_line - 1 }) end
end

-- Fuzzy mode: use pre-computed byte offsets from Rust's match_indices.
-- These are the exact matched character positions within the line, already
-- computed by the SIMD scoring + reference smith-waterman traceback.
-- We only highlight the target line since each fuzzy result has its own
-- unique set of matched positions.
if location.fuzzy_match_ranges and location.line then
local target_line = math.max(1, math.min(location.line, line_count))
for _, range in ipairs(location.fuzzy_match_ranges) do
local start_byte = range[1] -- 0-based byte offset
local end_byte = range[2] -- 0-based exclusive end
local ok, mark_id = pcall(vim.api.nvim_buf_set_extmark, bufnr, namespace, target_line - 1, start_byte, {
end_col = end_byte,
hl_group = 'IncSearch',
priority = 1000,
})
if ok then table.insert(extmarks, { id = mark_id, line = target_line - 1 }) end
-- Use ripgrep-supplied byte offsets for every match in the file. Works for
-- both plain/regex (literal byte spans) and fuzzy (Smith-Waterman traceback
-- positions) modes since both populate match_byte_offsets in Rust.
if location.file_matches and #location.file_matches > 0 then
for _, m in ipairs(location.file_matches) do
if m.line and m.line >= 1 and m.line <= line_count and m.ranges then
for _, range in ipairs(m.ranges) do
local start_byte = range[1]
local end_byte = range[2]
local ok, mark_id = pcall(vim.api.nvim_buf_set_extmark, bufnr, namespace, m.line - 1, start_byte, {
end_col = end_byte,
hl_group = 'IncSearch',
priority = 1000,
})
if ok then table.insert(extmarks, { id = mark_id, line = m.line - 1 }) end
end
end
end
-- Fuzzy mode: only target line has matches; skip the plain-text scan below.
return #extmarks > 0 and extmarks or nil
end

Expand Down
19 changes: 15 additions & 4 deletions lua/fff/picker_ui.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1438,12 +1438,23 @@ function M.update_preview()
effective_location.col = item.col + 1 -- Convert 0-based byte col to 1-based for highlight_location
end
-- Pass the query for multi-occurrence highlighting in preview (plain/regex modes).
-- For fuzzy mode, also pass the per-match byte offsets so the preview can highlight
-- the exact matched characters on the target line without re-searching.
effective_location.grep_query = M.state.query
if M.state.grep_mode == 'fuzzy' and item.match_ranges then
effective_location.fuzzy_match_ranges = item.match_ranges

-- Collect every match in the same file across all loaded items so the preview
-- can highlight ALL hits (not just the cursor's), using ripgrep-supplied byte
-- offsets — exact for both fuzzy and plain/regex modes.
local file_matches = {}
for _, it in ipairs(M.state.items or {}) do
if
it.relative_path == item.relative_path
and it.line_number
and it.line_number > 0
and it.match_ranges
then
table.insert(file_matches, { line = it.line_number, ranges = it.match_ranges })
end
end
if #file_matches > 0 then effective_location.file_matches = file_matches end
end

local location_changed = not vim.deep_equal(M.state.last_preview_location, effective_location)
Expand Down
Loading