diff --git a/README.md b/README.md index 5cb0cf9..6e5c591 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/integration-tests/MyTestDirectory.ts b/integration-tests/MyTestDirectory.ts index d55b142..0f26df2 100644 --- a/integration-tests/MyTestDirectory.ts +++ b/integration-tests/MyTestDirectory.ts @@ -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({ @@ -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."), + }), }), }), }), @@ -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", diff --git a/integration-tests/cypress/e2e/blink-ripgrep/basic_spec.cy.ts b/integration-tests/cypress/e2e/blink-ripgrep/basic_spec.cy.ts index ac17913..9842340 100644 --- a/integration-tests/cypress/e2e/blink-ripgrep/basic_spec.cy.ts +++ b/integration-tests/cypress/e2e/blink-ripgrep/basic_spec.cy.ts @@ -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() { diff --git a/integration-tests/test-environment/config-modifications/use_case_sensitive_search.lua b/integration-tests/test-environment/config-modifications/use_case_sensitive_search.lua new file mode 100644 index 0000000..f48121f --- /dev/null +++ b/integration-tests/test-environment/config-modifications/use_case_sensitive_search.lua @@ -0,0 +1,3 @@ +require("blink-ripgrep").setup({ + search_casing = "--smart-case", +}) diff --git a/integration-tests/test-environment/limited/subproject/file3.lua b/integration-tests/test-environment/limited/subproject/file3.lua new file mode 100644 index 0000000..6669276 --- /dev/null +++ b/integration-tests/test-environment/limited/subproject/file3.lua @@ -0,0 +1 @@ +local variable = "SomeTextFromFile3 here" diff --git a/lua/blink-ripgrep/init.lua b/lua/blink-ripgrep/init.lua index 8b85e90..9a557a5 100644 --- a/lua/blink-ripgrep/init.lua +++ b/lua/blink-ripgrep/init.lua @@ -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 @@ -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) @@ -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 @@ -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 @@ -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