From b2b3389b5ff7f73eae2a916503154fa33ff49eea Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Thu, 5 Jun 2025 18:14:30 +0200 Subject: [PATCH] Instruction files - comma separated list of glob patterns not working in applyTo property (#250754) * Instruction files - comma separated list of glob patterns not working in applyTo property * use path, not fsPath * fix test --- .../parsers/promptHeader/metadata/applyTo.ts | 12 +++-- .../promptSyntax/service/promptsService.ts | 45 ++++++++++++------- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/applyTo.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/applyTo.ts index 5e481eb9eed..b97dd2f0f63 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/applyTo.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/parsers/promptHeader/metadata/applyTo.ts @@ -6,7 +6,7 @@ import { PromptStringMetadata } from './base/string.js'; import { localize } from '../../../../../../../../nls.js'; import { INSTRUCTIONS_LANGUAGE_ID } from '../../../constants.js'; -import { isEmptyPattern, parse } from '../../../../../../../../base/common/glob.js'; +import { isEmptyPattern, parse, splitGlobAware } from '../../../../../../../../base/common/glob.js'; import { PromptMetadataDiagnostic, PromptMetadataError, PromptMetadataWarning } from '../diagnostics.js'; import { FrontMatterRecord, FrontMatterToken } from '../../../../../../../../editor/common/codecs/frontMatterCodec/tokens/index.js'; @@ -85,11 +85,17 @@ export class PromptApplyToMetadata extends PromptStringMetadata { pattern: string, ): boolean { try { - const globPattern = parse(pattern); - if (isEmptyPattern(globPattern)) { + const patterns = splitGlobAware(pattern, ','); + if (patterns.length === 0) { return false; } + for (const pattern of patterns) { + const globPattern = parse(pattern); + if (isEmptyPattern(globPattern)) { + return false; + } + } return true; } catch (_error) { return false; diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts index 1983df48d2d..75baed4e1eb 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts @@ -7,7 +7,7 @@ import { flatten } from '../utils/treeUtils.js'; import { localize } from '../../../../../../nls.js'; import { PROMPT_LANGUAGE_ID } from '../constants.js'; import { PromptParser } from '../parsers/promptParser.js'; -import { match } from '../../../../../../base/common/glob.js'; +import { match, splitGlobAware } from '../../../../../../base/common/glob.js'; import { pick } from '../../../../../../base/common/arrays.js'; import { type URI } from '../../../../../../base/common/uri.js'; import { type IPromptFileReference } from '../parsers/types.js'; @@ -268,23 +268,38 @@ export class PromptsService extends Disposable implements IPromptsService { continue; } - // if glob pattern is one of the special wildcard values, - // add the instructions file event if no files are attached - if ((applyTo === '**') || (applyTo === '**/*')) { - foundFiles.add(uri); - - continue; - } - - // match each attached file with each glob pattern and - // add the instructions file if its rule matches the file - for (const file of files) { - if (match(applyTo, file.fsPath)) { - foundFiles.add(uri); + const patterns = splitGlobAware(applyTo, ','); + const patterMatches = (pattern: string) => { + pattern = pattern.trim(); + if (pattern.length === 0) { + // if glob pattern is empty, skip it + return false; } + if (pattern === '**' || pattern === '**/*' || pattern === '*') { + // if glob pattern is one of the special wildcard values, + // add the instructions file event if no files are attached + return true; + } + if (!pattern.startsWith('/') && !pattern.startsWith('**/')) { + // support relative glob patterns, e.g. `src/**/*.js` + pattern = '**/' + pattern; + } + + // match each attached file with each glob pattern and + // add the instructions file if its rule matches the file + for (const file of files) { + // if the file is not a valid URI, skip it + if (match(pattern, file.path)) { + return true; + } + } + return false; + }; + + if (patterns.some(patterMatches)) { + foundFiles.add(uri); } } - return [...foundFiles]; }