Skip to content

Commit

Permalink
feat: allow customizing the search casing for ripgrep
Browse files Browse the repository at this point in the history
A minor feature is that the configuration can also now be changed in
between searches. This might be more useful in future features.
  • Loading branch information
mikavilpas committed Dec 19, 2024
1 parent 645fa97 commit 33e3517
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 16 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ return {
-- exclude files larger than that size.
max_filesize = "1M",

-- The casing to use for the search in a format that ripgrep
-- accepts. Defaults to "--ignore-case". See `rg --help` for all the
-- available options ripgrep supports, but you can try
-- "--case-sensitive" or "--smart-case".
search_casing = "--ignore-case",

-- (advanced) Any additional options you want to give to ripgrep.
-- See `rg -h` for a list of all available options. Might be
-- helpful in adjusting performance in specific situations.
Expand Down
14 changes: 14 additions & 0 deletions integration-tests/MyTestDirectory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ export const MyTestDirectorySchema = z.object({
extension: z.literal(""),
stem: z.literal(".gitkeep"),
}),
"use_case_sensitive_search.lua": z.object({
name: z.literal("use_case_sensitive_search.lua"),
type: z.literal("file"),
extension: z.literal("lua"),
stem: z.literal("use_case_sensitive_search."),
}),
}),
}),
"initial-file.txt": z.object({
Expand Down Expand Up @@ -76,6 +82,12 @@ export const MyTestDirectorySchema = z.object({
extension: z.literal("lua"),
stem: z.literal("file2."),
}),
"file3.lua": z.object({
name: z.literal("file3.lua"),
type: z.literal("file"),
extension: z.literal("lua"),
stem: z.literal("file3."),
}),
}),
}),
}),
Expand Down Expand Up @@ -108,11 +120,13 @@ export const testDirectoryFiles = z.enum([
".config/nvim",
".config",
"config-modifications/.gitkeep",
"config-modifications/use_case_sensitive_search.lua",
"config-modifications",
"initial-file.txt",
"limited/main-project-file.lua",
"limited/subproject/file1.lua",
"limited/subproject/file2.lua",
"limited/subproject/file3.lua",
"limited/subproject",
"limited",
"line-file.lua",
Expand Down
33 changes: 33 additions & 0 deletions integration-tests/cypress/e2e/blink-ripgrep/basic_spec.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,39 @@ describe("searching inside projects", () => {
)
})
})

describe("custom ripgrep options", () => {
it("allows using a custom search_casing when searching", () => {
cy.visit("/")
cy.startNeovim({
filename: "limited/subproject/file1.lua",
}).then(() => {
cy.contains("This is text from file1.lua")
createFakeGitDirectoriesToLimitRipgrepScope()

// the default is to use --ignore-case. Let's make sure that works first
cy.typeIntoTerminal("o")
cy.typeIntoTerminal("{esc}cc")
cy.typeIntoTerminal("sometext")
// the search should match in both casings
cy.contains("someTextFromFile2")
cy.contains("SomeTextFromFile3")

// now switch to using --smart-case, which should be case sensitive
// when uppercase letters are used
cy.runLuaCode({
luaCode: `vim.cmd("luafile config-modifications/use_case_sensitive_search.lua")`,
})
cy.typeIntoTerminal("{esc}cc")
// type something that does not match
cy.typeIntoTerminal("SomeText")

// the search should only match the case sensitive version
cy.contains("SomeTextFromFile3")
cy.contains("someTextFromFile2").should("not.exist")
})
})
})
})

function createFakeGitDirectoriesToLimitRipgrepScope() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
require("blink-ripgrep").setup({
search_casing = "--smart-case",
})
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
local variable = "SomeTextFromFile3 here"
43 changes: 27 additions & 16 deletions lua/blink-ripgrep/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
---@field get_prefix? fun(context: blink.cmp.Context): string
---@field context_size? number # The number of lines to show around each match in the preview (documentation) window. For example, 5 means to show 5 lines before, then the match, and another 5 lines after the match.
---@field max_filesize? string # The maximum file size that ripgrep should include in its search. Examples: "1024" (bytes by default), "200K", "1M", "1G"
---@field search_casing? string # The casing to use for the search in a format that ripgrep accepts. Defaults to "--ignore-case". See `rg --help` for all the available options ripgrep supports, but you can try "--case-sensitive" or "--smart-case".
---@field additional_rg_options? string[] # (advanced) Any options you want to give to ripgrep. See `rg -h` for a list of all available options.

---@class blink-ripgrep.RgSource : blink.cmp.Source
---@field get_command fun(context: blink.cmp.Context, prefix: string): string[]
---@field get_prefix fun(context: blink.cmp.Context): string
---@field get_completions? fun(self: blink.cmp.Source, context: blink.cmp.Context, callback: fun(response: blink.cmp.CompletionResponse | nil)): nil
---@field options blink-ripgrep.Options
local RgSource = {}
RgSource.__index = RgSource

Expand All @@ -37,6 +37,21 @@ do
)
end

---@type blink-ripgrep.Options
RgSource.config = {
prefix_min_len = 3,
context_size = 5,
max_filesize = "1M",
additional_rg_options = {},
search_casing = "--ignore-case",
}

-- 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 {})
end

---@param text_before_cursor string "The text of the entire line before the cursor"
---@return string
function RgSource.match_prefix(text_before_cursor)
Expand All @@ -57,30 +72,26 @@ end

---@param input_opts blink-ripgrep.Options
function RgSource.new(input_opts)
input_opts = input_opts or {}
local self = setmetatable({}, RgSource)

self.options = vim.tbl_deep_extend("force", {
prefix_min_len = input_opts.prefix_min_len or 3,
context_size = input_opts.context_size or 5,
max_filesize = input_opts.max_filesize or "1M",
additional_rg_options = input_opts.additional_rg_options or {},
} --[[@as blink-ripgrep.Options]], input_opts)
RgSource.config =
vim.tbl_deep_extend("force", RgSource.config, input_opts or {})

self.get_prefix = self.options.get_prefix or default_get_prefix
self.get_prefix = RgSource.config.get_prefix or default_get_prefix

self.get_command = self.options.get_command
self.get_command = RgSource.config.get_command
or function(_, prefix)
local cmd = {
"rg",
"--no-config",
"--json",
"--context=" .. self.options.context_size,
"--context=" .. RgSource.config.context_size,
"--word-regexp",
"--max-filesize=" .. self.options.max_filesize,
"--ignore-case",
"--max-filesize=" .. RgSource.config.max_filesize,
RgSource.config.search_casing,
}
for _, option in ipairs(self.options.additional_rg_options) do

for _, option in ipairs(RgSource.config.additional_rg_options) do
table.insert(cmd, option)
end

Expand All @@ -104,7 +115,7 @@ end
function RgSource:get_completions(context, resolve)
local prefix = self.get_prefix(context)

if string.len(prefix) < self.options.prefix_min_len then
if string.len(prefix) < RgSource.config.prefix_min_len then
resolve()
return
end
Expand All @@ -123,7 +134,7 @@ function RgSource:get_completions(context, resolve)
local parsed = require("blink-ripgrep.ripgrep_parser").parse(
lines,
cwd,
self.options.context_size
RgSource.config.context_size
)

---@type table<string, blink.cmp.CompletionItem>
Expand Down

0 comments on commit 33e3517

Please sign in to comment.