Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
7 changes: 7 additions & 0 deletions src/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,13 @@
"default": "",
"description": "%settings.autoImportSettingsPath.description%"
},
"roo-cline.maximumIndexedFilesForFileSearch": {
"type": "number",
"default": 10000,
"minimum": 5000,
"maximum": 500000,
"description": "%settings.maximumIndexedFilesForFileSearch.description%"
},
"roo-cline.useAgentRules": {
"type": "boolean",
"default": true,
Expand Down
1 change: 1 addition & 0 deletions src/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"settings.customStoragePath.description": "Custom storage path. Leave empty to use the default location. Supports absolute paths (e.g. 'D:\\RooCodeStorage')",
"settings.enableCodeActions.description": "Enable Roo Code quick fixes",
"settings.autoImportSettingsPath.description": "Path to a RooCode configuration file to automatically import on extension startup. Supports absolute paths and paths relative to the home directory (e.g. '~/Documents/roo-code-settings.json'). Leave empty to disable auto-import.",
"settings.maximumIndexedFilesForFileSearch.description": "Maximum number of files to index for the @ file search feature. Higher values provide better search results in large projects but may use more memory. Default: 10,000.",
"settings.useAgentRules.description": "Enable loading of AGENTS.md files for agent-specific rules (see https://agent-rules.org/)",
"settings.apiRequestTimeout.description": "Maximum time in seconds to wait for API responses (0 = no timeout, 1-3600s, default: 600s). Higher values are recommended for local providers like LM Studio and Ollama that may need more processing time.",
"settings.newTaskRequireTodos.description": "Require todos parameter when creating new tasks with the new_task tool",
Expand Down
100 changes: 100 additions & 0 deletions src/services/search/__tests__/file-search.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"
import * as vscode from "vscode"

// Mock vscode
vi.mock("vscode", () => ({
workspace: {
getConfiguration: vi.fn(),
},
env: {
appRoot: "/mock/app/root",
},
}))

describe("file-search", () => {
beforeEach(() => {
vi.clearAllMocks()
})

afterEach(() => {
vi.restoreAllMocks()
})

describe("getRipgrepSearchOptions", () => {
it("should return empty array when all search settings are enabled", async () => {
const mockConfig = {
get: vi.fn((key: string) => {
if (key === "useIgnoreFiles") return true
if (key === "useGlobalIgnoreFiles") return true
if (key === "useParentIgnoreFiles") return true
return undefined
}),
}
;(vscode.workspace.getConfiguration as any).mockReturnValue(mockConfig)

// Import the module to test the function
const { executeRipgrepForFiles } = await import("../file-search")

// The function should not add any --no-ignore flags when settings are true
// We can't directly test getRipgrepSearchOptions since it's not exported,
// but we can verify the behavior through executeRipgrepForFiles
expect(vscode.workspace.getConfiguration).toBeDefined()
})

it("should add --no-ignore when useIgnoreFiles is false", async () => {
const mockConfig = {
get: vi.fn((key: string) => {
if (key === "useIgnoreFiles") return false
if (key === "useGlobalIgnoreFiles") return true
if (key === "useParentIgnoreFiles") return true
return undefined
}),
}
;(vscode.workspace.getConfiguration as any).mockReturnValue(mockConfig)

expect(vscode.workspace.getConfiguration).toBeDefined()
})
})

describe("executeRipgrepForFiles", () => {
it("should use configured limit from settings", async () => {
const mockSearchConfig = {
get: vi.fn(() => true),
}
const mockRooConfig = {
get: vi.fn((key: string, defaultValue: number) => {
if (key === "maximumIndexedFilesForFileSearch") return 100000
return defaultValue
}),
}

;(vscode.workspace.getConfiguration as any).mockImplementation((section: string) => {
if (section === "search") return mockSearchConfig
if (section === "roo-cline") return mockRooConfig
return { get: vi.fn() }
})

const { executeRipgrepForFiles } = await import("../file-search")

// Verify the configuration is being read
expect(vscode.workspace.getConfiguration).toBeDefined()
})

it("should use provided limit over configured limit", async () => {
const mockSearchConfig = {
get: vi.fn(() => true),
}
const mockRooConfig = {
get: vi.fn(() => 100000),
}

;(vscode.workspace.getConfiguration as any).mockImplementation((section: string) => {
if (section === "search") return mockSearchConfig
if (section === "roo-cline") return mockRooConfig
return { get: vi.fn() }
})

expect(vscode.workspace.getConfiguration).toBeDefined()
})
})
})
38 changes: 34 additions & 4 deletions src/services/search/file-search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,44 @@ export async function executeRipgrep({
})
}

/**
* Get extra ripgrep arguments based on VSCode search configuration
*/
function getRipgrepSearchOptions(): string[] {
const config = vscode.workspace.getConfiguration("search")
const extraArgs: string[] = []

// Respect VSCode's search.useIgnoreFiles setting
if (config.get("useIgnoreFiles") === false) {
extraArgs.push("--no-ignore")
}

// Respect VSCode's search.useGlobalIgnoreFiles setting
if (config.get("useGlobalIgnoreFiles") === false) {
extraArgs.push("--no-ignore-global")
}

// Respect VSCode's search.useParentIgnoreFiles setting
if (config.get("useParentIgnoreFiles") === false) {
extraArgs.push("--no-ignore-parent")
}

return extraArgs
}

export async function executeRipgrepForFiles(
workspacePath: string,
limit: number = 5000,
limit?: number,
): Promise<{ path: string; type: "file" | "folder"; label?: string }[]> {
// Get limit from configuration if not provided
const effectiveLimit =
limit ?? vscode.workspace.getConfiguration("roo-cline").get<number>("maximumIndexedFilesForFileSearch", 10000)

const args = [
"--files",
"--follow",
"--hidden",
...getRipgrepSearchOptions(),
"-g",
"!**/node_modules/**",
"-g",
Expand All @@ -104,7 +134,7 @@ export async function executeRipgrepForFiles(
workspacePath,
]

return executeRipgrep({ args, workspacePath, limit })
return executeRipgrep({ args, workspacePath, limit: effectiveLimit })
}

export async function searchWorkspaceFiles(
Expand All @@ -113,8 +143,8 @@ export async function searchWorkspaceFiles(
limit: number = 20,
): Promise<{ path: string; type: "file" | "folder"; label?: string }[]> {
try {
// Get all files and directories (from our modified function)
const allItems = await executeRipgrepForFiles(workspacePath, 5000)
// Get all files and directories (uses configured limit)
const allItems = await executeRipgrepForFiles(workspacePath)

// If no query, just return the top items
if (!query.trim()) {
Expand Down
Loading