Skip to content

Commit

Permalink
feat: enable toggling the plugin on/off with folke/snacks.nvim
Browse files Browse the repository at this point in the history
Issue
=====

In some scenarios it's not nice to have blink-ripgrep pop up:
- if there are performance issues
- when giving a presentation
- when recording a video demo

Solution
========

Provide a way to toggle the plugin on/off with a keymap. Right now this
is off by default and depends on
https://github.com/folke/snacks.nvim/blob/main/docs/toggle.md

Users that don't want to use this feature or add snacks.nvim can simply
ignore it.
  • Loading branch information
mikavilpas committed Feb 12, 2025
1 parent ceae07f commit 7cf22a7
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 0 deletions.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ return {
dependencies = {
"mikavilpas/blink-ripgrep.nvim",
-- 👆🏻👆🏻 add the dependency here

-- optional dependency used for toggling features on/off
-- https://github.com/folke/snacks.nvim
"folke/snacks.nvim",
},
---@module 'blink.cmp'
---@type blink.cmp.Config
Expand Down Expand Up @@ -125,6 +129,20 @@ return {
-- root.
additional_paths = {},

-- Features that are not yet stable and might change in the future.
-- You can enable these to try them out beforehand, but be aware
-- that they might change. Nothing is enabled by default.
future_features = {
-- Keymaps to toggle features on/off. This can be used to alter
-- the behavior of the plugin without restarting Neovim. Nothing
-- is enabled by default.
toggles = {
-- The keymap to toggle the plugin on and off from blink
-- completion results. Example: "<leader>tg"
on_off = "<leader>tg",
},
},

-- Show debug information in `:messages` that can help in
-- diagnosing issues with the plugin.
debug = false,
Expand Down
5 changes: 5 additions & 0 deletions integration-tests/MyTestDirectory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ export const MyTestDirectorySchema = z.object({
name: z.literal("don't_use_debug_mode.lua"),
type: z.literal("file"),
}),
"enable_toggling.lua": z.object({
name: z.literal("enable_toggling.lua"),
type: z.literal("file"),
}),
"set_ignore_paths.lua": z.object({
name: z.literal("set_ignore_paths.lua"),
type: z.literal("file"),
Expand Down Expand Up @@ -156,6 +160,7 @@ export const testDirectoryFiles = z.enum([
"additional-words-dir",
"config-modifications/disable_project_root_fallback.lua",
"config-modifications/don't_use_debug_mode.lua",
"config-modifications/enable_toggling.lua",
"config-modifications/set_ignore_paths.lua",
"config-modifications/use_additional_paths.lua",
"config-modifications/use_case_sensitive_search.lua",
Expand Down
67 changes: 67 additions & 0 deletions integration-tests/cypress/e2e/blink-ripgrep/toggling.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { flavors } from "@catppuccin/palette"
import { rgbify } from "@tui-sandbox/library/dist/src/client/color-utilities"
import { createFakeGitDirectoriesToLimitRipgrepScope } from "./createFakeGitDirectoriesToLimitRipgrepScope"

describe("toggling features on/off", () => {
// Some features can be toggled on/off without restarting Neovim. This can be
// useful to combat performance issues, for example.
it("can toggle the plugin on/off in blink completions", () => {
cy.visit("/")
cy.startNeovim({
filename: "limited/main-project-file.lua",
startupScriptModifications: ["enable_toggling.lua"],
}).then((nvim) => {
// when completing from a file in a superproject, the search may descend
// to subprojects
cy.contains("this text is from main-project-file")
createFakeGitDirectoriesToLimitRipgrepScope()

// first verify that the plugin is enabled
cy.typeIntoTerminal("o")
cy.typeIntoTerminal("some")

cy.contains("here").should(
"have.css",
"color",
rgbify(flavors.macchiato.colors.green.rgb),
)

cy.typeIntoTerminal("{esc}")

// toggle the plugin off and wait for confirmation
cy.typeIntoTerminal("{esc}")
cy.typeIntoTerminal(" tg")
cy.contains("Disabled **blink-ripgrep**")

// try to complete again
cy.typeIntoTerminal("ciw")
cy.typeIntoTerminal("some")

nvim
.runLuaCode({
luaCode: `return _G.blink_ripgrep_invocations`,
})
.should((result) => {
// ripgrep should only have been invoked once
expect(result.value).to.be.an("array")
const invocations = JSON.stringify(result.value)
expect(invocations).to.contain("ignored-because-mode-is-off")
})

// toggle it back on
cy.typeIntoTerminal("{esc}")
cy.typeIntoTerminal(" tg")
cy.contains("Enabled **blink-ripgrep**")

// try to complete again and verify that the completion is there
cy.typeIntoTerminal("ciw")
cy.typeIntoTerminal("some")

cy.contains("here").should(
"have.css",
"color",
rgbify(flavors.macchiato.colors.green.rgb),
)
})
})
})
1 change: 1 addition & 0 deletions integration-tests/test-environment/.config/nvim/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ local plugins = {
end,
},

{ "folke/snacks.nvim" },
{ "catppuccin/nvim", name = "catppuccin", priority = 1000 },
}
require("lazy").setup({ spec = plugins })
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
require("blink-ripgrep").setup({
future_features = {
toggles = {
-- mnemonic: toggle grep
on_off = "<leader>tg",
},
},
})
54 changes: 54 additions & 0 deletions lua/blink-ripgrep/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@
---@field debug? boolean # Show debug information in `:messages` that can help in diagnosing issues with the plugin.
---@field ignore_paths? string[] # Absolute root paths where the rg command will not be executed. Usually you want to exclude paths using gitignore files or ripgrep specific ignore files, but this can be used to only ignore the paths in blink-ripgrep.nvim, maintaining the ability to use ripgrep for those paths on the command line. If you need to find out where the searches are executed, enable `debug` and look at `:messages`.
---@field additional_paths? string[] # Any additional paths to search in, in addition to the project root. This can be useful if you want to include dictionary files (/usr/share/dict/words), framework documentation, or any other reference material that is not available within the project root.
---@field mode? blink-ripgrep.Mode # The mode to use for showing completions. Defaults to automatically showing suggestions.
---@field future_features? blink-ripgrep.FutureFeatures # Features that are not yet stable and might change in the future. You can enable these to try them out beforehand, but be aware that they might change. Nothing is enabled by default.

---@class blink-ripgrep.FutureFeatures
---@field toggles? blink-ripgrep.ToggleKeymaps # Keymaps to toggle features on/off. This can be used to alter the behavior of the plugin without restarting Neovim. Nothing is enabled by default.

---@class blink-ripgrep.ToggleKeymaps
---@field on_off? string # The keymap to toggle the plugin on and off from blink completion results. Example: "<leader>tg"

---@alias blink-ripgrep.Mode
---| "on" # Show completions when triggered by blink
---| "off" # Don't show completions at all

---@class blink-ripgrep.RgSource : blink.cmp.Source
---@field get_command fun(context: blink.cmp.Context, prefix: string): blink-ripgrep.RipgrepCommand | nil
Expand All @@ -40,12 +52,44 @@ RgSource.config = {
ignore_paths = {},
project_root_fallback = true,
additional_paths = {},
mode = "on",
future_features = { toggles = nil },
}

-- set up default options so that they are used by the next search
---@param options? blink-ripgrep.Options
function RgSource.setup(options)
RgSource.config = vim.tbl_deep_extend("force", RgSource.config, options or {})

if not RgSource.config.future_features.toggles then
if RgSource.config.debug then
require("blink-ripgrep.debug").add_debug_message(
"not enabling toggles because the feature is not enabled"
)
end

return
end

local on_off = RgSource.config.future_features.toggles.on_off
if on_off then
require("snacks.toggle")
.new({
id = "blink-ripgrep-manual-mode",
name = "blink-ripgrep",
get = function()
return RgSource.config.mode == "on"
end,
set = function(state)
if state then
RgSource.config.mode = "on"
else
RgSource.config.mode = "off"
end
end,
})
:map(on_off, { mode = { "n" } })
end
end

---@param input_opts blink-ripgrep.Options
Expand Down Expand Up @@ -126,6 +170,16 @@ local function render_item_documentation(opts, file, match)
end

function RgSource:get_completions(context, resolve)
if RgSource.config.mode ~= "on" then
if RgSource.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

local prefix = self.get_prefix(context)

if string.len(prefix) < RgSource.config.prefix_min_len then
Expand Down

0 comments on commit 7cf22a7

Please sign in to comment.