@@ -15,7 +15,6 @@ import { CompletionContext, CompletionItem, CompletionItemKind, CompletionList }
1515import { ITextModel } from 'vs/editor/common/model' ;
1616import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures' ;
1717import { localize } from 'vs/nls' ;
18- import { IConfigurationService } from 'vs/platform/configuration/common/configuration' ;
1918import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation' ;
2019import { Registry } from 'vs/platform/registry/common/platform' ;
2120import { inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry' ;
@@ -33,7 +32,6 @@ import { ChatRequestParser } from 'vs/workbench/contrib/chat/common/chatRequestP
3332import { IChatService } from 'vs/workbench/contrib/chat/common/chatService' ;
3433import { IChatSlashCommandService } from 'vs/workbench/contrib/chat/common/chatSlashCommands' ;
3534import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables' ;
36- import { isResponseVM } from 'vs/workbench/contrib/chat/common/chatViewModel' ;
3735import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle' ;
3836
3937const decorationDescription = 'chat' ;
@@ -55,7 +53,6 @@ class InputEditorDecorations extends Disposable {
5553
5654 constructor (
5755 private readonly widget : IChatWidget ,
58- @IInstantiationService private readonly instantiationService : IInstantiationService ,
5956 @ICodeEditorService private readonly codeEditorService : ICodeEditorService ,
6057 @IThemeService private readonly themeService : IThemeService ,
6158 @IChatService private readonly chatService : IChatService ,
@@ -154,7 +151,7 @@ class InputEditorDecorations extends Disposable {
154151 return ;
155152 }
156153
157- const parsedRequest = ( await this . instantiationService . createInstance ( ChatRequestParser ) . parseChatRequest ( viewModel . sessionId , inputValue ) ) . parts ;
154+ const parsedRequest = this . widget . parsedInput . parts ;
158155
159156 let placeholderDecoration : IDecorationOptions [ ] | undefined ;
160157 const agentPart = parsedRequest . find ( ( p ) : p is ChatRequestAgentPart => p instanceof ChatRequestAgentPart ) ;
@@ -294,7 +291,6 @@ class SlashCommandCompletions extends Disposable {
294291 constructor (
295292 @ILanguageFeaturesService private readonly languageFeaturesService : ILanguageFeaturesService ,
296293 @IChatWidgetService private readonly chatWidgetService : IChatWidgetService ,
297- @IInstantiationService private readonly instantiationService : IInstantiationService ,
298294 @IChatSlashCommandService private readonly chatSlashCommandService : IChatSlashCommandService
299295 ) {
300296 super ( ) ;
@@ -313,7 +309,7 @@ class SlashCommandCompletions extends Disposable {
313309 return null ;
314310 }
315311
316- const parsedRequest = ( await this . instantiationService . createInstance ( ChatRequestParser ) . parseChatRequest ( widget . viewModel . sessionId , model . getValue ( ) ) ) . parts ;
312+ const parsedRequest = widget . parsedInput . parts ;
317313 const usedAgent = parsedRequest . find ( p => p instanceof ChatRequestAgentPart ) ;
318314 if ( usedAgent ) {
319315 // No (classic) global slash commands when an agent is used
@@ -351,7 +347,6 @@ class AgentCompletions extends Disposable {
351347 @ILanguageFeaturesService private readonly languageFeaturesService : ILanguageFeaturesService ,
352348 @IChatWidgetService private readonly chatWidgetService : IChatWidgetService ,
353349 @IChatAgentService private readonly chatAgentService : IChatAgentService ,
354- @IInstantiationService private readonly instantiationService : IInstantiationService ,
355350 ) {
356351 super ( ) ;
357352
@@ -364,7 +359,7 @@ class AgentCompletions extends Disposable {
364359 return null ;
365360 }
366361
367- const parsedRequest = ( await this . instantiationService . createInstance ( ChatRequestParser ) . parseChatRequest ( widget . viewModel . sessionId , model . getValue ( ) ) ) . parts ;
362+ const parsedRequest = widget . parsedInput . parts ;
368363 const usedAgent = parsedRequest . find ( p => p instanceof ChatRequestAgentPart ) ;
369364 if ( usedAgent && ! Range . containsPosition ( usedAgent . editorRange , position ) ) {
370365 // Only one agent allowed
@@ -407,7 +402,7 @@ class AgentCompletions extends Disposable {
407402 return null ;
408403 }
409404
410- const parsedRequest = ( await this . instantiationService . createInstance ( ChatRequestParser ) . parseChatRequest ( widget . viewModel . sessionId , model . getValue ( ) ) ) . parts ;
405+ const parsedRequest = widget . parsedInput . parts ;
411406 const usedAgentIdx = parsedRequest . findIndex ( ( p ) : p is ChatRequestAgentPart => p instanceof ChatRequestAgentPart ) ;
412407 if ( usedAgentIdx < 0 ) {
413408 return ;
@@ -428,7 +423,7 @@ class AgentCompletions extends Disposable {
428423 }
429424
430425 const usedAgent = parsedRequest [ usedAgentIdx ] as ChatRequestAgentPart ;
431- const commands = await usedAgent . agent . provideSlashCommands ( token ) ;
426+ const commands = await usedAgent . agent . provideSlashCommands ( token ) ; // Refresh the cache here
432427
433428 return < CompletionList > {
434429 suggestions : commands . map ( ( c , i ) => {
@@ -576,7 +571,6 @@ class VariableCompletions extends Disposable {
576571 @ILanguageFeaturesService private readonly languageFeaturesService : ILanguageFeaturesService ,
577572 @IChatWidgetService private readonly chatWidgetService : IChatWidgetService ,
578573 @IChatVariablesService private readonly chatVariablesService : IChatVariablesService ,
579- @IConfigurationService private readonly configurationService : IConfigurationService ,
580574 ) {
581575 super ( ) ;
582576
@@ -595,33 +589,24 @@ class VariableCompletions extends Disposable {
595589 return null ;
596590 }
597591
598- const history = widget . viewModel ! . getItems ( )
599- . filter ( isResponseVM ) ;
600-
601- // TODO@roblourens work out a real API for this- maybe it can be part of the two-step flow that @file will probably use
602- const historyVariablesEnabled = this . configurationService . getValue ( 'chat.experimental.historyVariables' ) ;
603- const historyItems = historyVariablesEnabled ? history . map ( ( h , i ) : CompletionItem => ( {
604- label : `${ chatVariableLeader } response:${ i + 1 } ` ,
605- detail : h . response . asString ( ) ,
606- insertText : `${ chatVariableLeader } response:${ String ( i + 1 ) . padStart ( String ( history . length ) . length , '0' ) } ` ,
607- kind : CompletionItemKind . Text ,
608- range,
609- } ) ) : [ ] ;
610-
611- const variableItems = Array . from ( this . chatVariablesService . getVariables ( ) ) . map ( v => {
612- const withLeader = `${ chatVariableLeader } ${ v . name } ` ;
613- return < CompletionItem > {
614- label : withLeader ,
615- range,
616- insertText : withLeader + ' ' ,
617- detail : v . description ,
618- kind : CompletionItemKind . Text , // The icons are disabled here anyway
619- sortText : 'z'
620- } ;
621- } ) ;
592+ const usedVariables = widget . parsedInput . parts . filter ( ( p ) : p is ChatRequestVariablePart => p instanceof ChatRequestVariablePart ) ;
593+ const variableItems = Array . from ( this . chatVariablesService . getVariables ( ) )
594+ // This doesn't look at dynamic variables like `file`, where multiple makes sense.
595+ . filter ( v => ! usedVariables . some ( usedVar => usedVar . variableName === v . name ) )
596+ . map ( v => {
597+ const withLeader = `${ chatVariableLeader } ${ v . name } ` ;
598+ return < CompletionItem > {
599+ label : withLeader ,
600+ range,
601+ insertText : withLeader + ' ' ,
602+ detail : v . description ,
603+ kind : CompletionItemKind . Text , // The icons are disabled here anyway
604+ sortText : 'z'
605+ } ;
606+ } ) ;
622607
623608 return < CompletionList > {
624- suggestions : [ ... variableItems , ... historyItems ]
609+ suggestions : variableItems
625610 } ;
626611 }
627612 } ) ) ;
@@ -655,22 +640,22 @@ class ChatTokenDeleter extends Disposable {
655640
656641 // If this was a simple delete, try to find out whether it was inside a token
657642 if ( ! change . text && this . widget . viewModel ) {
658- parser . parseChatRequest ( this . widget . viewModel . sessionId , previousInputValue ) . then ( previousParsedValue => {
659- // For dynamic variables, this has to happen in ChatDynamicVariableModel with the other bookkeeping
660- const deletableTokens = previousParsedValue . parts . filter ( p => p instanceof ChatRequestAgentPart || p instanceof ChatRequestAgentSubcommandPart || p instanceof ChatRequestSlashCommandPart || p instanceof ChatRequestVariablePart ) ;
661- deletableTokens . forEach ( token => {
662- const deletedRangeOfToken = Range . intersectRanges ( token . editorRange , change . range ) ;
663- // Part of this token was deleted, and the deletion range doesn't go off the front of the token, for simpler math
664- if ( ( deletedRangeOfToken && ! deletedRangeOfToken . isEmpty ( ) ) && Range . compareRangesUsingStarts ( token . editorRange , change . range ) < 0 ) {
665- // Assume single line tokens
666- const length = deletedRangeOfToken . endColumn - deletedRangeOfToken . startColumn ;
667- const rangeToDelete = new Range ( token . editorRange . startLineNumber , token . editorRange . startColumn , token . editorRange . endLineNumber , token . editorRange . endColumn - length ) ;
668- this . widget . inputEditor . executeEdits ( this . id , [ {
669- range : rangeToDelete ,
670- text : '' ,
671- } ] ) ;
672- }
673- } ) ;
643+ const previousParsedValue = parser . parseChatRequest ( this . widget . viewModel . sessionId , previousInputValue ) ;
644+
645+ // For dynamic variables, this has to happen in ChatDynamicVariableModel with the other bookkeeping
646+ const deletableTokens = previousParsedValue . parts . filter ( p => p instanceof ChatRequestAgentPart || p instanceof ChatRequestAgentSubcommandPart || p instanceof ChatRequestSlashCommandPart || p instanceof ChatRequestVariablePart ) ;
647+ deletableTokens . forEach ( token => {
648+ const deletedRangeOfToken = Range . intersectRanges ( token . editorRange , change . range ) ;
649+ // Part of this token was deleted, and the deletion range doesn't go off the front of the token, for simpler math
650+ if ( ( deletedRangeOfToken && ! deletedRangeOfToken . isEmpty ( ) ) && Range . compareRangesUsingStarts ( token . editorRange , change . range ) < 0 ) {
651+ // Assume single line tokens
652+ const length = deletedRangeOfToken . endColumn - deletedRangeOfToken . startColumn ;
653+ const rangeToDelete = new Range ( token . editorRange . startLineNumber , token . editorRange . startColumn , token . editorRange . endLineNumber , token . editorRange . endColumn - length ) ;
654+ this . widget . inputEditor . executeEdits ( this . id , [ {
655+ range : rangeToDelete ,
656+ text : '' ,
657+ } ] ) ;
658+ }
674659 } ) ;
675660 }
676661
0 commit comments