Skip to content

Commit

Permalink
feat(opt-in): kill previous searches when a new search is started (#100)
Browse files Browse the repository at this point in the history
Issue
=====

When typing text, if there are no matches for a ripgrep search, each
keypresses starts a new ripgrep search. This can lead to many searches
being active at the same time. This takes up resources and is not useful
(if the word did not match previously, it will never match with a longer
search string).

Solution
========

Stop previously running searches when a new search is started. This is
currently disabled by default (soft launch). To opt in, see the README.

If this works well for some time, it might become the default in the
future.
  • Loading branch information
mikavilpas authored Jan 9, 2025
1 parent af33f54 commit 705069a
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 9 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ return {
sources = {
default = {
"buffer",
"ripgrep", -- 👈🏻 add "ripgrep" here
"ripgrep", -- 👈🏻 add "ripgrep" here
},
providers = {
-- 👇🏻👇🏻 add the ripgrep provider config below
Expand Down Expand Up @@ -108,6 +108,14 @@ return {
-- Show debug information in `:messages` that can help in
-- diagnosing issues with the plugin.
debug = false,

-- Features that are not yet stable and might change in the future.
future_features = {
-- Kill previous searches when a new search is started. This is
-- useful to save resources and might become the default in the
-- future.
kill_previous_searches = false,
},
},
-- (optional) customize how the results are displayed. Many options
-- are available - make sure your lua LSP is set up so you get
Expand Down
16 changes: 15 additions & 1 deletion integration-tests/cypress/support/tui-sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,5 +127,19 @@ declare global {

afterEach(async () => {
if (!testWindow) return
await testWindow.runExCommand({ command: "messages", log: true })
const timeout = new Promise<void>((resolve, reject) =>
setTimeout(() => {
Cypress.log({
name: "timeout when waiting for :messages to finish. Neovim might be stuck.",
})
reject(
"timeout when waiting for :messages to finish. Neovim might be stuck.",
)
}, 5_000),
)

await Promise.race([
timeout,
testWindow.runExCommand({ command: "messages" }),
])
})
2 changes: 1 addition & 1 deletion integration-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"zod": "3.24.1"
},
"devDependencies": {
"@tui-sandbox/library": "7.5.5",
"@tui-sandbox/library": "7.5.6",
"@types/node": "22.10.3",
"@types/tinycolor2": "1.4.6",
"@typescript-eslint/eslint-plugin": "8.19.0",
Expand Down
3 changes: 3 additions & 0 deletions integration-tests/test-environment/.config/nvim/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ local plugins = {
---@type blink-ripgrep.Options
opts = {
debug = true,
future_features = {
kill_previous_searches = true,
},
},
},
},
Expand Down
33 changes: 32 additions & 1 deletion lua/blink-ripgrep/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
---@field fallback_to_regex_highlighting? boolean # (default: true) When a result is found for a file whose filetype does not have a treesitter parser installed, fall back to regex based highlighting that is bundled in Neovim.
---@field project_root_marker? unknown # Specifies how to find the root of the project where the ripgrep search will start from. Accepts the same options as the marker given to `:h vim.fs.root()` which offers many possibilities for configuration. Defaults to ".git".
---@field debug? boolean # Show debug information in `:messages` that can help in diagnosing issues with the plugin.
---@field future_features? blink-ripgrep.FutureFeatures # Features that are not yet stable and might change in the future.

---@class blink-ripgrep.FutureFeatures
---@field kill_previous_searches? boolean # Kill previous searches when a new search is started. This is useful to save resources and might become the default in the future.

---@class blink-ripgrep.RgSource : blink.cmp.Source
---@field get_command fun(context: blink.cmp.Context, prefix: string): string[]
Expand Down Expand Up @@ -55,6 +59,9 @@ RgSource.config = {
search_casing = "--ignore-case",
fallback_to_regex_highlighting = true,
project_root_marker = ".git",
future_features = {
kill_previous_searches = false,
},
}

-- set up default options so that they are used by the next search
Expand Down Expand Up @@ -157,6 +164,9 @@ local function render_item_documentation(opts, file, match)
)
end

---@type vim.Ringbuf<vim.SystemObj>
local ripgrep_invocations = vim.ringbuf(3)

function RgSource:get_completions(context, resolve)
local prefix = self.get_prefix(context)

Expand Down Expand Up @@ -184,7 +194,24 @@ function RgSource:get_completions(context, resolve)
end
end

vim.system(cmd, nil, function(result)
local kill_previous_searches = (
RgSource.config.future_features
and RgSource.config.future_features.kill_previous_searches
) or false

if kill_previous_searches then
-- drain all previous invocations and kill them to save resources
for val in ripgrep_invocations do
---@cast val vim.SystemObj
val:kill(9)
if RgSource.config.debug then
vim.api.nvim_exec2("echomsg 'killed previous invocation'", {})
end
end
assert(#ripgrep_invocations == 0)
end

local rg = vim.system(cmd, nil, function(result)
vim.schedule(function()
if result.code ~= 0 then
resolve()
Expand Down Expand Up @@ -244,6 +271,10 @@ function RgSource:get_completions(context, resolve)
end)
end)
end)

if kill_previous_searches then
ripgrep_invocations:push(rg)
end
end

return RgSource
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions vim.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ type = "function"
[[after_each.args]]
type = "function"

[assert]
any = true

[assert.is_not]
any = true

Expand Down

0 comments on commit 705069a

Please sign in to comment.