Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: change the architecture to allow different search backends #131

Merged
merged 1 commit into from
Feb 21, 2025
Merged
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
146 changes: 146 additions & 0 deletions lua/blink-ripgrep/backends/ripgrep/ripgrep.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
---@class blink-ripgrep.Backend
---@field config blink-ripgrep.Options
local RipgrepBackend = {}

---@param config table
function RipgrepBackend.new(config)
local self = setmetatable({}, { __index = RipgrepBackend })
self.config = config
return self --[[@as blink-ripgrep.Backend]]
end

function RipgrepBackend:get_matches(prefix, context, resolve)
if self.config.mode ~= "on" then
if self.config.debug then
local debug = require("blink-ripgrep.debug")
debug.add_debug_message("mode is off, skipping the search")
debug.add_debug_invocation({ "ignored-because-mode-is-off" })
end
resolve()
return
end

if string.len(prefix) < self.config.prefix_min_len then
resolve()
return
end

-- builtin default command
local command_module =
require("blink-ripgrep.backends.ripgrep.ripgrep_command")
local cmd = command_module.get_command(prefix, self.config)

if cmd == nil then
if self.config.debug then
local debug = require("blink-ripgrep.debug")
debug.add_debug_message("no command returned, skipping the search")
debug.add_debug_invocation({ "ignored-because-no-command" })
end

resolve()
return
end

if vim.tbl_contains(self.config.ignore_paths, cmd.root) then
if self.config.debug then
local debug = require("blink-ripgrep.debug")
debug.add_debug_message("skipping search in ignored path" .. cmd.root)
debug.add_debug_invocation({ "ignored", cmd.root })
end
resolve()

return
end

if self.config.debug then
if cmd.debugify_for_shell then
cmd:debugify_for_shell()
end

require("blink-ripgrep.visualization").flash_search_prefix(prefix)
require("blink-ripgrep.debug").add_debug_invocation(cmd)
end

local rg = vim.system(cmd.command, nil, function(result)
vim.schedule(function()
if result.code ~= 0 then
resolve()
return
end

local lines = vim.split(result.stdout, "\n")
local cwd = vim.uv.cwd() or ""

local parsed =
require("blink-ripgrep.backends.ripgrep.ripgrep_parser").parse(
lines,
cwd,
self.config.context_size
)
local kinds = require("blink.cmp.types").CompletionItemKind

---@type table<string, blink.cmp.CompletionItem>
local items = {}
for _, file in pairs(parsed.files) do
for _, match in pairs(file.matches) do
local matchkey = match.match.text

-- PERF: only register the match once - right now there is no useful
-- way to display the same match multiple times
if not items[matchkey] then
local label = match.match.text
local docstring = ""
for _, line in ipairs(match.context_preview) do
docstring = docstring .. line.text .. "\n"
end

local draw_docs = function(draw_opts)
require("blink-ripgrep.documentation").render_item_documentation(
self.config,
draw_opts,
file,
match
)
end

---@diagnostic disable-next-line: missing-fields
items[matchkey] = {
documentation = {
kind = "markdown",
value = docstring,
draw = draw_docs,
-- legacy, will be removed in a future release of blink
-- https://github.com/Saghen/blink.cmp/issues/1113
render = draw_docs,
},
source_id = "blink-ripgrep",
kind = kinds.Text,
label = label,
insertText = matchkey,
}
end
end
end

vim.schedule(function()
resolve({
is_incomplete_forward = false,
is_incomplete_backward = false,
items = vim.tbl_values(items),
context = context,
})
end)
end)
end)

return function()
rg:kill(9)
if self.config.debug then
require("blink-ripgrep.debug").add_debug_message(
"killed previous invocation"
)
end
end
end

return RipgrepBackend
70 changes: 70 additions & 0 deletions lua/blink-ripgrep/documentation.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
local documentation = {}

local highlight_ns_id = 0
pcall(function()
highlight_ns_id = require("blink.cmp.config").appearance.highlight_ns
end)
vim.api.nvim_set_hl(0, "BlinkRipgrepMatch", { link = "Search", default = true })

---@param config blink-ripgrep.Options
---@param draw_opts blink.cmp.CompletionDocumentationDrawOpts
---@param file blink-ripgrep.RipgrepFile
---@param match blink-ripgrep.RipgrepMatch
function documentation.render_item_documentation(config, draw_opts, file, match)
local bufnr = draw_opts.window:get_buf()
---@type string[]
local text = {
file.relative_to_cwd,
string.rep(
"─",
-- TODO account for the width of the scrollbar if it's visible
draw_opts.window:get_width()
- draw_opts.window:get_border_size().horizontal
- 1
),
}
for _, data in ipairs(match.context_preview) do
table.insert(text, data.text)
end

-- TODO add extmark highlighting for the divider line like in blink
vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, text)

local filetype = vim.filetype.match({ filename = file.relative_to_cwd })
local parser_name = vim.treesitter.language.get_lang(filetype or "")
local parser_installed = parser_name
and pcall(function()
return vim.treesitter.get_parser(nil, file.language, {})
end)

if not parser_installed and config.fallback_to_regex_highlighting then
-- Can't show highlighted text because no treesitter parser
-- has been installed for this language.
--
-- Fall back to regex based highlighting that is bundled in
-- neovim. It might not be perfect but it's much better
-- than no colors at all
vim.schedule(function()
vim.api.nvim_set_option_value("filetype", file.language, { buf = bufnr })
vim.api.nvim_buf_call(bufnr, function()
vim.cmd("syntax on")
end)
end)
else
assert(parser_name, "missing parser") -- lua-language-server should narrow this but can't
require("blink.cmp.lib.window.docs").highlight_with_treesitter(
bufnr,
parser_name,
2,
#text
)
end

require("blink-ripgrep.highlighting").highlight_match_in_doc_window(
bufnr,
match,
highlight_ns_id
)
end

return documentation
Loading
Loading