Add setting enableRecursiveFileSearch to control @-file completion (#1290)
This commit is contained in:
parent
63f6a497cb
commit
0779697da6
|
@ -56,13 +56,15 @@ In addition to a project settings file, a project's `.gemini` directory can cont
|
|||
- **`fileFiltering`** (object):
|
||||
|
||||
- **Description:** Controls git-aware file filtering behavior for @ commands and file discovery tools.
|
||||
- **Default:** `"respectGitIgnore": true`
|
||||
- **Default:** `"respectGitIgnore": true, "enableRecursiveFileSearch": true`
|
||||
- **Properties:**
|
||||
- **`respectGitIgnore`** (boolean): Whether to respect .gitignore patterns when discovering files. When set to `true`, git-ignored files (like `node_modules/`, `dist/`, `.env`) are automatically excluded from @ commands and file listing operations.
|
||||
- **`enableRecursiveFileSearch`** (boolean): Whether to enable searching recursively for filenames under the current tree when completing @ prefixes in the prompt.
|
||||
- **Example:**
|
||||
```json
|
||||
"fileFiltering": {
|
||||
"respectGitIgnore": true
|
||||
"respectGitIgnore": true,
|
||||
"enableRecursiveFileSearch": false
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -75,7 +75,9 @@ describe('Configuration Integration Tests', () => {
|
|||
sandbox: false,
|
||||
targetDir: tempDir,
|
||||
debugMode: false,
|
||||
fileFilteringRespectGitIgnore: false,
|
||||
fileFiltering: {
|
||||
respectGitIgnore: false,
|
||||
},
|
||||
};
|
||||
|
||||
const config = new Config(configParams);
|
||||
|
@ -109,7 +111,9 @@ describe('Configuration Integration Tests', () => {
|
|||
sandbox: false,
|
||||
targetDir: tempDir,
|
||||
debugMode: false,
|
||||
fileFilteringRespectGitIgnore: false,
|
||||
fileFiltering: {
|
||||
respectGitIgnore: false,
|
||||
},
|
||||
};
|
||||
|
||||
const config = new Config(configParams);
|
||||
|
@ -178,7 +182,9 @@ describe('Configuration Integration Tests', () => {
|
|||
sandbox: false,
|
||||
targetDir: tempDir,
|
||||
debugMode: false,
|
||||
fileFilteringRespectGitIgnore: false, // CI might need to see all files
|
||||
fileFiltering: {
|
||||
respectGitIgnore: false,
|
||||
}, // CI might need to see all files
|
||||
};
|
||||
|
||||
const config = new Config(configParams);
|
||||
|
|
|
@ -228,7 +228,11 @@ export async function loadCliConfig(
|
|||
logPrompts: argv.telemetryLogPrompts ?? settings.telemetry?.logPrompts,
|
||||
},
|
||||
// Git-aware file filtering settings
|
||||
fileFilteringRespectGitIgnore: settings.fileFiltering?.respectGitIgnore,
|
||||
fileFiltering: {
|
||||
respectGitIgnore: settings.fileFiltering?.respectGitIgnore,
|
||||
enableRecursiveFileSearch:
|
||||
settings.fileFiltering?.enableRecursiveFileSearch,
|
||||
},
|
||||
checkpointing: argv.checkpointing || settings.checkpointing?.enabled,
|
||||
proxy:
|
||||
process.env.HTTPS_PROXY ||
|
||||
|
|
|
@ -56,6 +56,7 @@ export interface Settings {
|
|||
// Git-aware file filtering settings
|
||||
fileFiltering?: {
|
||||
respectGitIgnore?: boolean;
|
||||
enableRecursiveFileSearch?: boolean;
|
||||
};
|
||||
|
||||
// UI setting. Does not display the ANSI-controlled terminal title.
|
||||
|
|
|
@ -47,6 +47,7 @@ describe('useCompletion git-aware filtering integration', () => {
|
|||
mockConfig = {
|
||||
getFileFilteringRespectGitIgnore: vi.fn(() => true),
|
||||
getFileService: vi.fn().mockReturnValue(mockFileDiscoveryService),
|
||||
getEnableRecursiveFileSearch: vi.fn(() => true),
|
||||
};
|
||||
|
||||
vi.mocked(FileDiscoveryService).mockImplementation(
|
||||
|
@ -170,6 +171,35 @@ describe('useCompletion git-aware filtering integration', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('should not perform recursive search when disabled in config', async () => {
|
||||
const globResults = [`${testCwd}/data`, `${testCwd}/dist`];
|
||||
vi.mocked(glob).mockResolvedValue(globResults);
|
||||
|
||||
// Disable recursive search in the mock config
|
||||
const mockConfigNoRecursive = {
|
||||
...mockConfig,
|
||||
getEnableRecursiveFileSearch: vi.fn(() => false),
|
||||
};
|
||||
|
||||
vi.mocked(fs.readdir).mockResolvedValue([
|
||||
{ name: 'data', isDirectory: () => true },
|
||||
{ name: 'dist', isDirectory: () => true },
|
||||
] as Array<{ name: string; isDirectory: () => boolean }>);
|
||||
|
||||
renderHook(() =>
|
||||
useCompletion('@d', testCwd, true, slashCommands, mockConfigNoRecursive),
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 150));
|
||||
});
|
||||
|
||||
// `glob` should not be called because recursive search is disabled
|
||||
expect(glob).not.toHaveBeenCalled();
|
||||
// `fs.readdir` should be called for the top-level directory instead
|
||||
expect(fs.readdir).toHaveBeenCalledWith(testCwd, { withFileTypes: true });
|
||||
});
|
||||
|
||||
it('should work without config (fallback behavior)', async () => {
|
||||
vi.mocked(fs.readdir).mockResolvedValue([
|
||||
{ name: 'src', isDirectory: () => true },
|
||||
|
|
|
@ -322,10 +322,16 @@ export function useCompletion(
|
|||
let fetchedSuggestions: Suggestion[] = [];
|
||||
|
||||
const fileDiscoveryService = config ? config.getFileService() : null;
|
||||
const enableRecursiveSearch =
|
||||
config?.getEnableRecursiveFileSearch() ?? true;
|
||||
|
||||
try {
|
||||
// If there's no slash, or it's the root, do a recursive search from cwd
|
||||
if (partialPath.indexOf('/') === -1 && prefix) {
|
||||
if (
|
||||
partialPath.indexOf('/') === -1 &&
|
||||
prefix &&
|
||||
enableRecursiveSearch
|
||||
) {
|
||||
if (fileDiscoveryService) {
|
||||
fetchedSuggestions = await findFilesWithGlob(
|
||||
prefix,
|
||||
|
|
|
@ -163,7 +163,9 @@ describe('Server Config (config.ts)', () => {
|
|||
it('should set custom file filtering settings when provided', () => {
|
||||
const paramsWithFileFiltering: ConfigParameters = {
|
||||
...baseParams,
|
||||
fileFilteringRespectGitIgnore: false,
|
||||
fileFiltering: {
|
||||
respectGitIgnore: false,
|
||||
},
|
||||
};
|
||||
const config = new Config(paramsWithFileFiltering);
|
||||
expect(config.getFileFilteringRespectGitIgnore()).toBe(false);
|
||||
|
|
|
@ -104,7 +104,10 @@ export interface ConfigParameters {
|
|||
contextFileName?: string | string[];
|
||||
accessibility?: AccessibilitySettings;
|
||||
telemetry?: TelemetrySettings;
|
||||
fileFilteringRespectGitIgnore?: boolean;
|
||||
fileFiltering?: {
|
||||
respectGitIgnore?: boolean;
|
||||
enableRecursiveFileSearch?: boolean;
|
||||
};
|
||||
checkpointing?: boolean;
|
||||
proxy?: string;
|
||||
cwd: string;
|
||||
|
@ -136,7 +139,10 @@ export class Config {
|
|||
private readonly accessibility: AccessibilitySettings;
|
||||
private readonly telemetrySettings: TelemetrySettings;
|
||||
private geminiClient!: GeminiClient;
|
||||
private readonly fileFilteringRespectGitIgnore: boolean;
|
||||
private readonly fileFiltering: {
|
||||
respectGitIgnore: boolean;
|
||||
enableRecursiveFileSearch: boolean;
|
||||
};
|
||||
private fileDiscoveryService: FileDiscoveryService | null = null;
|
||||
private gitService: GitService | undefined = undefined;
|
||||
private readonly checkpointing: boolean;
|
||||
|
@ -172,8 +178,11 @@ export class Config {
|
|||
logPrompts: params.telemetry?.logPrompts ?? true,
|
||||
};
|
||||
|
||||
this.fileFilteringRespectGitIgnore =
|
||||
params.fileFilteringRespectGitIgnore ?? true;
|
||||
this.fileFiltering = {
|
||||
respectGitIgnore: params.fileFiltering?.respectGitIgnore ?? true,
|
||||
enableRecursiveFileSearch:
|
||||
params.fileFiltering?.enableRecursiveFileSearch ?? true,
|
||||
};
|
||||
this.checkpointing = params.checkpointing ?? false;
|
||||
this.proxy = params.proxy;
|
||||
this.cwd = params.cwd ?? process.cwd();
|
||||
|
@ -330,8 +339,12 @@ export class Config {
|
|||
return getProjectTempDir(this.getProjectRoot());
|
||||
}
|
||||
|
||||
getEnableRecursiveFileSearch(): boolean {
|
||||
return this.fileFiltering.enableRecursiveFileSearch;
|
||||
}
|
||||
|
||||
getFileFilteringRespectGitIgnore(): boolean {
|
||||
return this.fileFilteringRespectGitIgnore;
|
||||
return this.fileFiltering.respectGitIgnore;
|
||||
}
|
||||
|
||||
getCheckpointingEnabled(): boolean {
|
||||
|
|
Loading…
Reference in New Issue