@ can be used to reference context, just like ##294777
@ can be used to reference context, just like ##294777pierceboggan wants to merge 4 commits intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Extends chat input completions so @ can trigger the same “context reference” completions as #.
Changes:
- Broadened completion word patterns and trigger characters to include
@in addition to#. - Adjusted filtering/matching to consider the typed leader and (in some cases) match against both basename and URI label.
- Added pattern-based filtering for tool completions when a leader-prefixed prefix is present.
| return { | ||
| label: { label: basename, description: labelDescription }, | ||
| filterText: `${chatVariableLeader}${basename}`, | ||
| filterText: `${basename} ${typedLeader}${basename} ${uriLabel}`, |
There was a problem hiding this comment.
uriLabel is referenced in filterText but is not defined in this scope, which will cause a TypeScript compile error. Use labelDescription (already computed) or introduce a const uriLabel = this.labelService.getUriLabel(resource, { relative: true }); before constructing the completion item.
| filterText: `${basename} ${typedLeader}${basename} ${uriLabel}`, | |
| filterText: `${basename} ${typedLeader}${basename} ${labelDescription}`, |
| const typedLeader = range.varWord?.word?.charAt(0) === chatAgentLeader ? chatAgentLeader : chatVariableLeader; | ||
| const basename = this.labelService.getUriBasenameLabel(currentResource); | ||
| const text = `${chatVariableLeader}file:${basename}:${currentSelection.startLineNumber}-${currentSelection.endLineNumber}`; |
There was a problem hiding this comment.
When the user types @, filterText is adjusted to @… but the inserted text (text) and the displayed label still hardcode chatVariableLeader (#). This makes @ behave differently from # (and contradicts the PR intent of “just like #”). Consider building text and label with typedLeader so the completion both matches and inserts using the leader the user typed.
See below for a potential fix:
const text = `${typedLeader}file:${basename}:${currentSelection.startLineNumber}-${currentSelection.endLineNumber}`;
const fullRangeText = `:${currentSelection.startLineNumber}:${currentSelection.startColumn}-${currentSelection.endLineNumber}:${currentSelection.endColumn}`;
const description = this.labelService.getUriLabel(currentResource, { relative: true }) + fullRangeText;
const result: CompletionList = { suggestions: [] };
result.suggestions.push({
label: { label: `${typedLeader}selection`, description },
| label: { label: `${chatVariableLeader}selection`, description }, | ||
| filterText: `${chatVariableLeader}selection`, | ||
| filterText: `${typedLeader}selection`, | ||
| insertText: range.varWord?.endColumn === range.replace.endColumn ? `${text} ` : text, |
There was a problem hiding this comment.
When the user types @, filterText is adjusted to @… but the inserted text (text) and the displayed label still hardcode chatVariableLeader (#). This makes @ behave differently from # (and contradicts the PR intent of “just like #”). Consider building text and label with typedLeader so the completion both matches and inserts using the leader the user typed.
See below for a potential fix:
const text = `${typedLeader}file:${basename}:${currentSelection.startLineNumber}-${currentSelection.endLineNumber}`;
const fullRangeText = `:${currentSelection.startLineNumber}:${currentSelection.startColumn}-${currentSelection.endLineNumber}:${currentSelection.endColumn}`;
const description = this.labelService.getUriLabel(currentResource, { relative: true }) + fullRangeText;
const result: CompletionList = { suggestions: [] };
result.suggestions.push({
label: { label: `${typedLeader}selection`, description },
| const typedLeader = info.varWord?.word?.charAt(0) === chatAgentLeader ? chatAgentLeader : chatVariableLeader; | ||
|
|
||
| const makeSymbolCompletionItem = (symbolItem: { name: string; location: Location; kind: SymbolKind }, pattern: string): CompletionItem => { | ||
| const text = `${chatVariableLeader}sym:${symbolItem.name}`; |
There was a problem hiding this comment.
Similar to the selection completion: filterText uses typedLeader, but the inserted text always uses chatVariableLeader (#). If @sym:… is intended to be a first-class equivalent to #sym:…, text should be derived from typedLeader (or, alternatively, keep filterText aligned with the inserted leader).
| const text = `${chatVariableLeader}sym:${symbolItem.name}`; | |
| const text = `${typedLeader}sym:${symbolItem.name}`; |
| label: { label: symbolItem.name, description: uriLabel }, | ||
| filterText: `${chatVariableLeader}${symbolItem.name}`, | ||
| filterText: `${typedLeader}${symbolItem.name}`, | ||
| insertText: info.varWord?.endColumn === info.replace.endColumn ? `${text} ` : text, |
There was a problem hiding this comment.
Similar to the selection completion: filterText uses typedLeader, but the inserted text always uses chatVariableLeader (#). If @sym:… is intended to be a first-class equivalent to #sym:…, text should be derived from typedLeader (or, alternatively, keep filterText aligned with the inserted leader).
| const withLeader = `${chatVariableLeader}${name}`; | ||
| suggestions.push({ | ||
| label: withLeader, | ||
| range, | ||
| detail, | ||
| documentation, | ||
| filterText: `${typedLeader}${name}`, | ||
| insertText: withLeader + ' ', | ||
| kind: CompletionItemKind.Tool, |
There was a problem hiding this comment.
Tool completions will still insert #toolName even when triggered by @, because withLeader is always built from chatVariableLeader. To make @ behave “just like #”, compute withLeader using typedLeader (and consider also updating label so the UI matches what will be inserted).
| class BuiltinDynamicCompletions extends Disposable { | ||
| private static readonly addReferenceCommand = '_addReferenceCmd'; | ||
| private static readonly VariableNameDef = new RegExp(`${chatVariableLeader}[\\w:-]*`, 'g'); // MUST be using `g`-flag | ||
| private static readonly VariableNameDef = new RegExp(`[${chatVariableLeader}${chatAgentLeader}][\\w:-]*`, 'g'); // MUST be using `g`-flag |
There was a problem hiding this comment.
Building a character class via interpolation can become fragile if either leader ever changes to a regex-special character inside [] (e.g. -, ], ^, \). Consider escaping the leaders before interpolating them into the regex to keep this robust.
See below for a potential fix:
function escapeForCharClass(text: string): string {
return text.replace(/[-\\\]^]/g, '\\$&');
}
class BuiltinDynamicCompletions extends Disposable {
private static readonly addReferenceCommand = '_addReferenceCmd';
private static readonly VariableNameDef = new RegExp(`[${escapeForCharClass(chatVariableLeader)}${escapeForCharClass(chatAgentLeader)}][\\w:-]*`, 'g'); // MUST be using `g`-flag
|
Moving this to 1.112 and disabling auto merge so that we can get the 1.111 milestone into good shape by the end of Thursday Please take this in as a candidate if it must go into 1.111 |
…asses Add escapeForCharClass helper to safely interpolate chatVariableLeader and chatAgentLeader into regex character classes, preventing breakage if either leader changes to a regex-special character.
…eader support Test escapeForCharClass for regex character class escaping and computeCompletionRanges with the new regex patterns that accept both leaders. Export escapeForCharClass to enable direct unit testing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
6f9813c to
632998f
Compare
@.mov