feat: rename search_keyword => grep_search (#1584)
This commit is contained in:
@@ -83,8 +83,8 @@ function M.search_files(opts, on_log)
|
||||
return vim.json.encode(filepaths), nil
|
||||
end
|
||||
|
||||
---@type AvanteLLMToolFunc<{ rel_path: string, keyword: string }>
|
||||
function M.search_keyword(opts, on_log)
|
||||
---@type AvanteLLMToolFunc<{ rel_path: string, query: string, case_sensitive?: boolean, include_pattern?: string, exclude_pattern?: string }>
|
||||
function M.grep_search(opts, on_log)
|
||||
local abs_path = get_abs_path(opts.rel_path)
|
||||
if not has_permission_to_access(abs_path) then return "", "No permission to access path: " .. abs_path end
|
||||
if not Path:new(abs_path):exists() then return "", "No such file or directory: " .. abs_path end
|
||||
@@ -99,15 +99,32 @@ function M.search_keyword(opts, on_log)
|
||||
---execute the search command
|
||||
local cmd = ""
|
||||
if search_cmd:find("rg") then
|
||||
cmd = string.format("%s --files-with-matches --ignore-case --hidden --glob '!.git'", search_cmd)
|
||||
cmd = string.format("%s '%s' %s", cmd, opts.keyword, abs_path)
|
||||
cmd = string.format("%s --files-with-matches --hidden", search_cmd)
|
||||
if opts.case_sensitive then
|
||||
cmd = string.format("%s --case-sensitive", cmd)
|
||||
else
|
||||
cmd = string.format("%s --ignore-case", cmd)
|
||||
end
|
||||
if opts.include_pattern then cmd = string.format("%s --glob '%s'", cmd, opts.include_pattern) end
|
||||
if opts.exclude_pattern then cmd = string.format("%s --glob '!%s'", cmd, opts.exclude_pattern) end
|
||||
cmd = string.format("%s '%s' %s", cmd, opts.query, abs_path)
|
||||
elseif search_cmd:find("ag") then
|
||||
cmd = string.format("%s '%s' --nocolor --nogroup --hidden --ignore .git %s", search_cmd, opts.keyword, abs_path)
|
||||
cmd = string.format("%s --nocolor --nogroup --hidden", search_cmd)
|
||||
if opts.case_sensitive then cmd = string.format("%s --case-sensitive", cmd) end
|
||||
if opts.include_pattern then cmd = string.format("%s --ignore '!%s'", cmd, opts.include_pattern) end
|
||||
if opts.exclude_pattern then cmd = string.format("%s --ignore '%s'", cmd, opts.exclude_pattern) end
|
||||
cmd = string.format("%s '%s' %s", cmd, opts.query, abs_path)
|
||||
elseif search_cmd:find("ack") then
|
||||
cmd = string.format("%s --nocolor --nogroup --hidden --ignore-dir .git", search_cmd)
|
||||
cmd = string.format("%s '%s' %s", cmd, opts.keyword, abs_path)
|
||||
cmd = string.format("%s --nocolor --nogroup --hidden", search_cmd)
|
||||
if opts.case_sensitive then cmd = string.format("%s --smart-case", cmd) end
|
||||
if opts.exclude_pattern then cmd = string.format("%s --ignore-dir '%s'", cmd, opts.exclude_pattern) end
|
||||
cmd = string.format("%s '%s' %s", cmd, opts.query, abs_path)
|
||||
elseif search_cmd:find("grep") then
|
||||
cmd = string.format("%s -riH --exclude-dir=.git %s %s", search_cmd, opts.keyword, abs_path)
|
||||
cmd = string.format("cd %s && git ls-files -co --exclude-standard | xargs %s -rH", abs_path, search_cmd, abs_path)
|
||||
if not opts.case_sensitive then cmd = string.format("%s -i", cmd) end
|
||||
if opts.include_pattern then cmd = string.format("%s --include '%s'", cmd, opts.include_pattern) end
|
||||
if opts.exclude_pattern then cmd = string.format("%s --exclude '%s'", cmd, opts.exclude_pattern) end
|
||||
cmd = string.format("%s '%s'", cmd, opts.query)
|
||||
end
|
||||
|
||||
Utils.debug("cmd", cmd)
|
||||
@@ -842,8 +859,8 @@ M._tools = {
|
||||
},
|
||||
},
|
||||
{
|
||||
name = "search_keyword",
|
||||
description = "Search for a keyword in a directory",
|
||||
name = "grep_search",
|
||||
description = "Search for a keyword in a directory using grep",
|
||||
param = {
|
||||
type = "table",
|
||||
fields = {
|
||||
@@ -853,10 +870,29 @@ M._tools = {
|
||||
type = "string",
|
||||
},
|
||||
{
|
||||
name = "keyword",
|
||||
description = "Keyword to search for",
|
||||
name = "query",
|
||||
description = "Query to search for",
|
||||
type = "string",
|
||||
},
|
||||
{
|
||||
name = "case_sensitive",
|
||||
description = "Whether to search case sensitively",
|
||||
type = "boolean",
|
||||
default = false,
|
||||
optional = true,
|
||||
},
|
||||
{
|
||||
name = "include_pattern",
|
||||
description = "Glob pattern to include files",
|
||||
type = "string",
|
||||
optional = true,
|
||||
},
|
||||
{
|
||||
name = "exclude_pattern",
|
||||
description = "Glob pattern to exclude files",
|
||||
type = "string",
|
||||
optional = true,
|
||||
},
|
||||
},
|
||||
},
|
||||
returns = {
|
||||
|
||||
@@ -354,7 +354,7 @@ vim.g.avante_login = vim.g.avante_login
|
||||
---@class AvanteLLMToolParamField
|
||||
---@field name string
|
||||
---@field description string
|
||||
---@field type 'string' | 'integer'
|
||||
---@field type 'string' | 'integer' | 'boolean'
|
||||
---@field optional? boolean
|
||||
|
||||
---@class AvanteLLMToolReturn
|
||||
|
||||
@@ -767,10 +767,7 @@ function M.scan_directory(options)
|
||||
cmd = {
|
||||
"bash",
|
||||
"-c",
|
||||
string.format(
|
||||
"cd %s && cat <(git ls-files --exclude-standard) <(git ls-files --exclude-standard --others)",
|
||||
options.directory
|
||||
),
|
||||
string.format("cd %s && git ls-files -co --exclude-standard", options.directory),
|
||||
}
|
||||
end
|
||||
cmd_supports_max_depth = false
|
||||
|
||||
@@ -124,7 +124,7 @@ describe("llm_tools", function()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("search_keyword", function()
|
||||
describe("grep_search", function()
|
||||
local original_exepath = vim.fn.exepath
|
||||
|
||||
after_each(function() vim.fn.exepath = original_exepath end)
|
||||
@@ -147,10 +147,35 @@ describe("llm_tools", function()
|
||||
file:write("this is nothing")
|
||||
file:close()
|
||||
|
||||
local result, err = LlmTools.search_keyword({ rel_path = ".", keyword = "searchable" })
|
||||
local result, err = LlmTools.grep_search({ rel_path = ".", query = "Searchable", case_sensitive = false })
|
||||
assert.is_nil(err)
|
||||
assert.truthy(result:find("searchable.txt"))
|
||||
assert.falsy(result:find("nothing.txt"))
|
||||
|
||||
local result2, err2 = LlmTools.grep_search({ rel_path = ".", query = "searchable", case_sensitive = true })
|
||||
assert.is_nil(err2)
|
||||
assert.truthy(result2:find("searchable.txt"))
|
||||
assert.falsy(result2:find("nothing.txt"))
|
||||
|
||||
local result3, err3 = LlmTools.grep_search({ rel_path = ".", query = "Searchable", case_sensitive = true })
|
||||
assert.is_nil(err3)
|
||||
assert.falsy(result3:find("searchable.txt"))
|
||||
assert.falsy(result3:find("nothing.txt"))
|
||||
|
||||
local result4, err4 = LlmTools.grep_search({ rel_path = ".", query = "searchable", case_sensitive = false })
|
||||
assert.is_nil(err4)
|
||||
assert.truthy(result4:find("searchable.txt"))
|
||||
assert.falsy(result4:find("nothing.txt"))
|
||||
|
||||
local result5, err5 = LlmTools.grep_search({
|
||||
rel_path = ".",
|
||||
query = "searchable",
|
||||
case_sensitive = false,
|
||||
exclude_pattern = "search*",
|
||||
})
|
||||
assert.is_nil(err5)
|
||||
assert.falsy(result5:find("searchable.txt"))
|
||||
assert.falsy(result5:find("nothing.txt"))
|
||||
end)
|
||||
|
||||
it("should search using ag when rg is not available", function()
|
||||
@@ -166,7 +191,7 @@ describe("llm_tools", function()
|
||||
file:write("content for ag test")
|
||||
file:close()
|
||||
|
||||
local result, err = LlmTools.search_keyword({ rel_path = ".", keyword = "ag test" })
|
||||
local result, err = LlmTools.grep_search({ rel_path = ".", query = "ag test" })
|
||||
assert.is_nil(err)
|
||||
assert.is_string(result)
|
||||
assert.truthy(result:find("ag_test.txt"))
|
||||
@@ -179,27 +204,64 @@ describe("llm_tools", function()
|
||||
return ""
|
||||
end
|
||||
|
||||
local result, err = LlmTools.search_keyword({ rel_path = ".", keyword = "test" })
|
||||
-- Create a test file with searchable content
|
||||
local file = io.open(test_dir .. "/searchable.txt", "w")
|
||||
if not file then error("Failed to create test file") end
|
||||
file:write("this is searchable content")
|
||||
file:close()
|
||||
|
||||
file = io.open(test_dir .. "/nothing.txt", "w")
|
||||
if not file then error("Failed to create test file") end
|
||||
file:write("this is nothing")
|
||||
file:close()
|
||||
|
||||
local result, err = LlmTools.grep_search({ rel_path = ".", query = "Searchable", case_sensitive = false })
|
||||
assert.is_nil(err)
|
||||
assert.truthy(result:find("test.txt"))
|
||||
assert.truthy(result:find("searchable.txt"))
|
||||
assert.falsy(result:find("nothing.txt"))
|
||||
|
||||
local result2, err2 = LlmTools.grep_search({ rel_path = ".", query = "searchable", case_sensitive = true })
|
||||
assert.is_nil(err2)
|
||||
assert.truthy(result2:find("searchable.txt"))
|
||||
assert.falsy(result2:find("nothing.txt"))
|
||||
|
||||
local result3, err3 = LlmTools.grep_search({ rel_path = ".", query = "Searchable", case_sensitive = true })
|
||||
assert.is_nil(err3)
|
||||
assert.falsy(result3:find("searchable.txt"))
|
||||
assert.falsy(result3:find("nothing.txt"))
|
||||
|
||||
local result4, err4 = LlmTools.grep_search({ rel_path = ".", query = "searchable", case_sensitive = false })
|
||||
assert.is_nil(err4)
|
||||
assert.truthy(result4:find("searchable.txt"))
|
||||
assert.falsy(result4:find("nothing.txt"))
|
||||
|
||||
local result5, err5 = LlmTools.grep_search({
|
||||
rel_path = ".",
|
||||
query = "searchable",
|
||||
case_sensitive = false,
|
||||
exclude_pattern = "search*",
|
||||
})
|
||||
assert.is_nil(err5)
|
||||
assert.falsy(result5:find("searchable.txt"))
|
||||
assert.falsy(result5:find("nothing.txt"))
|
||||
end)
|
||||
|
||||
it("should return error when no search tool is available", function()
|
||||
-- Mock exepath to return nothing
|
||||
vim.fn.exepath = function() return "" end
|
||||
|
||||
local result, err = LlmTools.search_keyword({ rel_path = ".", keyword = "test" })
|
||||
local result, err = LlmTools.grep_search({ rel_path = ".", query = "test" })
|
||||
assert.equals("", result)
|
||||
assert.equals("No search command found", err)
|
||||
end)
|
||||
|
||||
it("should respect path permissions", function()
|
||||
local result, err = LlmTools.search_keyword({ rel_path = "../outside_project", keyword = "test" })
|
||||
local result, err = LlmTools.grep_search({ rel_path = "../outside_project", query = "test" })
|
||||
assert.truthy(err:find("No permission to access path"))
|
||||
end)
|
||||
|
||||
it("should handle non-existent paths", function()
|
||||
local result, err = LlmTools.search_keyword({ rel_path = "non_existent_dir", keyword = "test" })
|
||||
local result, err = LlmTools.grep_search({ rel_path = "non_existent_dir", query = "test" })
|
||||
assert.equals("", result)
|
||||
assert.truthy(err)
|
||||
assert.truthy(err:find("No such file or directory"))
|
||||
|
||||
Reference in New Issue
Block a user