From 1f10c899acdf418e9b47f1e236d58b80a7b03e8a Mon Sep 17 00:00:00 2001 From: Bryan Chen Date: Fri, 7 Nov 2025 15:59:10 -0800 Subject: [PATCH 1/3] feat: add option to include ignored files in search results --- package.json | 4 ++++ .../tools/node/findTextInFilesTool.tsx | 22 ++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index dd4626df5a..d71176d159 100644 --- a/package.json +++ b/package.json @@ -290,6 +290,10 @@ "maxResults": { "type": "number", "description": "The maximum number of results to return. Do not use this unless necessary, it can slow things down. By default, only some matches are returned. If you use this and don't see what you're looking for, you can try again with a more specific query or a larger maxResults." + }, + "includeIgnoredFiles": { + "type": "boolean", + "description": "Whether to include files that would normally be ignored according to .gitignore, other ignore files and `files.exclude` and `search.exclude` settings." } }, "required": [ diff --git a/src/extension/tools/node/findTextInFilesTool.tsx b/src/extension/tools/node/findTextInFilesTool.tsx index 337d3ad664..e16c4be6a8 100644 --- a/src/extension/tools/node/findTextInFilesTool.tsx +++ b/src/extension/tools/node/findTextInFilesTool.tsx @@ -18,7 +18,7 @@ import { count } from '../../../util/vs/base/common/strings'; import { URI } from '../../../util/vs/base/common/uri'; import { Position as EditorPosition } from '../../../util/vs/editor/common/core/position'; import { IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation'; -import { ExtendedLanguageModelToolResult, LanguageModelPromptTsxPart, Location, MarkdownString, Range } from '../../../vscodeTypes'; +import { ExcludeSettingOptions, ExtendedLanguageModelToolResult, LanguageModelPromptTsxPart, Location, MarkdownString, Range } from '../../../vscodeTypes'; import { IBuildPromptContext } from '../../prompt/common/intents'; import { renderPromptElementJSON } from '../../prompts/node/base/promptRenderer'; import { Tag } from '../../prompts/node/base/tag'; @@ -31,6 +31,8 @@ interface IFindTextInFilesToolParams { isRegexp?: boolean; includePattern?: string; maxResults?: number; + /** Whether to include files that would normally be ignored according to .gitignore, other ignore files and `files.exclude` and `search.exclude` settings. */ + includeIgnoredFiles?: boolean; } const MaxResultsCap = 200; @@ -62,7 +64,7 @@ export class FindTextInFilesTool implements ICopilotTool this.searchAndCollectResults(options.input.query, isRegExp, patterns, maxResults, searchToken), + (searchToken) => this.searchAndCollectResults(options.input.query, isRegExp, patterns, maxResults, options.input.includeIgnoredFiles, searchToken), token, timeoutInMs, // embed message to give LLM hint about what to do next @@ -72,7 +74,7 @@ export class FindTextInFilesTool implements ICopilotTool this.searchAndCollectResults(options.input.query, !isRegExp, patterns, maxResults, searchToken), + (searchToken) => this.searchAndCollectResults(options.input.query, !isRegExp, patterns, maxResults, options.input.includeIgnoredFiles, searchToken), token, timeoutInMs, // embed message to give LLM hint about what to do next @@ -126,16 +128,20 @@ export class FindTextInFilesTool implements ICopilotTool { + private async searchAndCollectResults(query: string, isRegExp: boolean, patterns: vscode.GlobPattern[] | undefined, maxResults: number, includeIgnoredFiles: boolean | undefined, token: CancellationToken): Promise { + const findOptions = { + include: patterns ? patterns : undefined, + maxResults: maxResults + 1, + useExcludeSettings: includeIgnoredFiles ? ExcludeSettingOptions.None : ExcludeSettingOptions.SearchAndFilesExclude, + useIgnoreFiles: includeIgnoredFiles ? { local: false, parent: false, global: false } : undefined, + } as vscode.FindTextInFilesOptions2; + const searchResult = this.searchService.findTextInFiles2( { pattern: query, isRegExp, }, - { - include: patterns ? patterns : undefined, - maxResults: maxResults + 1 - }, + findOptions, token); const results: vscode.TextSearchResult2[] = []; for await (const item of searchResult.results) { From 3317dda2bb88f006f5ab202e60f97685b645f3e8 Mon Sep 17 00:00:00 2001 From: Bryan Chen Date: Thu, 13 Nov 2025 08:11:23 -0800 Subject: [PATCH 2/3] Provide instruction of includeIgnoredFiles to models in case of missing match --- package.json | 6 +-- .../tools/node/findTextInFilesTool.tsx | 37 +++++++++++++++---- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index d71176d159..c3efacf113 100644 --- a/package.json +++ b/package.json @@ -268,7 +268,7 @@ "name": "copilot_findTextInFiles", "toolReferenceName": "textSearch", "displayName": "%copilot.tools.findTextInFiles.name%", - "modelDescription": "Do a fast text search in the workspace. Use this tool when you want to search with an exact string or regex. If you are not sure what words will appear in the workspace, prefer using regex patterns with alternation (|) or character classes to search for multiple potential words at once instead of making separate searches. For example, use 'function|method|procedure' to look for all of those words at once. Use includePattern to search within files matching a specific pattern, or in a specific file, using a relative path. Use this tool when you want to see an overview of a particular file, instead of using read_file many times to look for code within a file.", + "modelDescription": "Do a fast text search in the workspace. Use this tool when you want to search with an exact string or regex. If you are not sure what words will appear in the workspace, prefer using regex patterns with alternation (|) or character classes to search for multiple potential words at once instead of making separate searches. For example, use 'function|method|procedure' to look for all of those words at once. Use includePattern to search within files matching a specific pattern, or in a specific file, using a relative path. Use 'includeIgnoredFiles' to include files normally ignored by .gitignore, other ignore files, and `files.exclude` and `search.exclude` settings. Warning: using this may cause the search to be slower, only set it when you want to search in ignored folders like node_modules or build outputs. Use this tool when you want to see an overview of a particular file, instead of using read_file many times to look for code within a file.", "tags": [ "vscode_codesearch" ], @@ -293,7 +293,7 @@ }, "includeIgnoredFiles": { "type": "boolean", - "description": "Whether to include files that would normally be ignored according to .gitignore, other ignore files and `files.exclude` and `search.exclude` settings." + "description": "Whether to include files that would normally be ignored according to .gitignore, other ignore files and `files.exclude` and `search.exclude` settings. Warning: using this may cause the search to be slower. Only set it when you want to search in ignored folders like node_modules or build outputs." } }, "required": [ @@ -4614,4 +4614,4 @@ "string_decoder": "npm:string_decoder@1.2.0", "node-gyp": "npm:node-gyp@10.3.1" } -} \ No newline at end of file +} diff --git a/src/extension/tools/node/findTextInFilesTool.tsx b/src/extension/tools/node/findTextInFilesTool.tsx index e16c4be6a8..c4e5449570 100644 --- a/src/extension/tools/node/findTextInFilesTool.tsx +++ b/src/extension/tools/node/findTextInFilesTool.tsx @@ -6,6 +6,7 @@ import * as l10n from '@vscode/l10n'; import { BasePromptElementProps, PromptElement, PromptElementProps, PromptPiece, PromptReference, PromptSizing, TextChunk } from '@vscode/prompt-tsx'; import type * as vscode from 'vscode'; +import { IConfigurationService } from '../../../platform/configuration/common/configurationService'; import { OffsetLineColumnConverter } from '../../../platform/editing/common/offsetLineColumnConverter'; import { IEndpointProvider } from '../../../platform/endpoint/common/endpointProvider'; import { IPromptPathRepresentationService } from '../../../platform/prompts/common/promptPathRepresentationService'; @@ -45,6 +46,7 @@ export class FindTextInFilesTool implements ICopilotTool, token: CancellationToken) { @@ -59,12 +61,13 @@ export class FindTextInFilesTool implements ICopilotTool this.searchAndCollectResults(options.input.query, isRegExp, patterns, maxResults, options.input.includeIgnoredFiles, searchToken), + (searchToken) => this.searchAndCollectResults(options.input.query, isRegExp, patterns, maxResults, includeIgnoredFiles, searchToken), token, timeoutInMs, // embed message to give LLM hint about what to do next @@ -74,7 +77,7 @@ export class FindTextInFilesTool implements ICopilotTool this.searchAndCollectResults(options.input.query, !isRegExp, patterns, maxResults, options.input.includeIgnoredFiles, searchToken), + (searchToken) => this.searchAndCollectResults(options.input.query, !isRegExp, patterns, maxResults, includeIgnoredFiles, searchToken), token, timeoutInMs, // embed message to give LLM hint about what to do next @@ -82,9 +85,27 @@ export class FindTextInFilesTool implements ICopilotTool>('search.exclude'); + const excludePaths: string[] = []; + if (excludeSettings) { + for (const [path, isExcluded] of Object.entries(excludeSettings)) { + if (isExcluded) { + excludePaths.push(path); + } + } + } + + noMatchInstructions = `Your search pattern might be excluded completedly by either the search.exclude settings or .*ignore files. + If you believe that it should have results, you can check into the .*ignore files and the exclude setting (here are some excluded patterns for reference:[${excludePaths.join(';')}] separated by ';'). + Then if you want to include those files you can call the tool again by setting "includeIgnoredFiles" to true.`; + } + const prompt = await renderPromptElementJSON(this.instantiationService, FindTextInFilesResult, - { textResults: results, maxResults, askedForTooManyResults: Boolean(askedForTooManyResults) }, + { textResults: results, maxResults, askedForTooManyResults: Boolean(askedForTooManyResults), noMatchInstructions }, options.tokenizationOptions, token); @@ -129,12 +150,12 @@ export class FindTextInFilesTool implements ICopilotTool { - const findOptions = { + const findOptions: vscode.FindTextInFilesOptions2 = { include: patterns ? patterns : undefined, maxResults: maxResults + 1, useExcludeSettings: includeIgnoredFiles ? ExcludeSettingOptions.None : ExcludeSettingOptions.SearchAndFilesExclude, useIgnoreFiles: includeIgnoredFiles ? { local: false, parent: false, global: false } : undefined, - } as vscode.FindTextInFilesOptions2; + }; const searchResult = this.searchService.findTextInFiles2( { @@ -214,6 +235,7 @@ export interface FindTextInFilesResultProps extends BasePromptElementProps { textResults: vscode.TextSearchResult2[]; maxResults: number; askedForTooManyResults?: boolean; + noMatchInstructions?: string; } /** Max number of characters between matching ranges. */ @@ -226,14 +248,15 @@ export class FindTextInFilesResult extends PromptElement { const textMatches = this.props.textResults.filter(isTextSearchMatch); if (textMatches.length === 0) { - return <>No matches found; + const noMatchInstructions = this.props.noMatchInstructions ?? ''; + return <>No matches found.{noMatchInstructions}; } const numResults = textMatches.reduce((acc, result) => acc + result.ranges.length, 0); const resultCountToDisplay = Math.min(numResults, this.props.maxResults); const numResultsText = numResults === 1 ? '1 match' : `${resultCountToDisplay} matches`; - const maxResultsTooLargeText = this.props.askedForTooManyResults ? ` (maxResults capped at ${MaxResultsCap})` : ''; const maxResultsText = numResults > this.props.maxResults ? ` (more results are available)` : ''; + const maxResultsTooLargeText = this.props.askedForTooManyResults ? ` (maxResults capped at ${MaxResultsCap})` : ''; return <> {{numResultsText}{maxResultsText}{maxResultsTooLargeText}} {textMatches.flatMap(result => { From 77924c48bb7bd2a2b2ebf0a5c97f90ba449c3ca2 Mon Sep 17 00:00:00 2001 From: Bryan Chen Date: Mon, 17 Nov 2025 14:19:09 -0800 Subject: [PATCH 3/3] updated warnings --- src/extension/tools/node/findTextInFilesTool.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/extension/tools/node/findTextInFilesTool.tsx b/src/extension/tools/node/findTextInFilesTool.tsx index c4e5449570..5882bc75ad 100644 --- a/src/extension/tools/node/findTextInFilesTool.tsx +++ b/src/extension/tools/node/findTextInFilesTool.tsx @@ -98,9 +98,9 @@ export class FindTextInFilesTool implements ICopilotTool