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

feat: allow customizing the search casing for ripgrep #66

Merged
merged 1 commit into from
Dec 19, 2024
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
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
Loading