Skip to content

Commit

Permalink
refactor: change the architecture to allow different search backends
Browse files Browse the repository at this point in the history
Right now this solves no issue, but I want to experiment with adding
more search backends in the future. For this to be easier, it's probably
good to have an idea of what a "backend" actually is 🙂

I think they can help solve performance issues in massive
repositories. For example, I found out that "git grep" is much faster
than ripgrep in some cases (5s vs 40s).

Related to #110
  • Loading branch information
mikavilpas committed Feb 21, 2025
1 parent d8d4945 commit 2b6834b
Show file tree
Hide file tree
Showing 7 changed files with 225 additions and 201 deletions.
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
File renamed without changes.
File renamed without changes.
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

0 comments on commit 2b6834b

Please sign in to comment.