@@ -15,7 +15,6 @@ import { CompletionContext, CompletionItem, CompletionItemKind, CompletionList }
15
15
import { ITextModel } from 'vs/editor/common/model' ;
16
16
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures' ;
17
17
import { localize } from 'vs/nls' ;
18
- import { IConfigurationService } from 'vs/platform/configuration/common/configuration' ;
19
18
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation' ;
20
19
import { Registry } from 'vs/platform/registry/common/platform' ;
21
20
import { inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry' ;
@@ -33,7 +32,6 @@ import { ChatRequestParser } from 'vs/workbench/contrib/chat/common/chatRequestP
33
32
import { IChatService } from 'vs/workbench/contrib/chat/common/chatService' ;
34
33
import { IChatSlashCommandService } from 'vs/workbench/contrib/chat/common/chatSlashCommands' ;
35
34
import { IChatVariablesService } from 'vs/workbench/contrib/chat/common/chatVariables' ;
36
- import { isResponseVM } from 'vs/workbench/contrib/chat/common/chatViewModel' ;
37
35
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle' ;
38
36
39
37
const decorationDescription = 'chat' ;
@@ -55,7 +53,6 @@ class InputEditorDecorations extends Disposable {
55
53
56
54
constructor (
57
55
private readonly widget : IChatWidget ,
58
- @IInstantiationService private readonly instantiationService : IInstantiationService ,
59
56
@ICodeEditorService private readonly codeEditorService : ICodeEditorService ,
60
57
@IThemeService private readonly themeService : IThemeService ,
61
58
@IChatService private readonly chatService : IChatService ,
@@ -154,7 +151,7 @@ class InputEditorDecorations extends Disposable {
154
151
return ;
155
152
}
156
153
157
- const parsedRequest = ( await this . instantiationService . createInstance ( ChatRequestParser ) . parseChatRequest ( viewModel . sessionId , inputValue ) ) . parts ;
154
+ const parsedRequest = this . widget . parsedInput . parts ;
158
155
159
156
let placeholderDecoration : IDecorationOptions [ ] | undefined ;
160
157
const agentPart = parsedRequest . find ( ( p ) : p is ChatRequestAgentPart => p instanceof ChatRequestAgentPart ) ;
@@ -294,7 +291,6 @@ class SlashCommandCompletions extends Disposable {
294
291
constructor (
295
292
@ILanguageFeaturesService private readonly languageFeaturesService : ILanguageFeaturesService ,
296
293
@IChatWidgetService private readonly chatWidgetService : IChatWidgetService ,
297
- @IInstantiationService private readonly instantiationService : IInstantiationService ,
298
294
@IChatSlashCommandService private readonly chatSlashCommandService : IChatSlashCommandService
299
295
) {
300
296
super ( ) ;
@@ -313,7 +309,7 @@ class SlashCommandCompletions extends Disposable {
313
309
return null ;
314
310
}
315
311
316
- const parsedRequest = ( await this . instantiationService . createInstance ( ChatRequestParser ) . parseChatRequest ( widget . viewModel . sessionId , model . getValue ( ) ) ) . parts ;
312
+ const parsedRequest = widget . parsedInput . parts ;
317
313
const usedAgent = parsedRequest . find ( p => p instanceof ChatRequestAgentPart ) ;
318
314
if ( usedAgent ) {
319
315
// No (classic) global slash commands when an agent is used
@@ -351,7 +347,6 @@ class AgentCompletions extends Disposable {
351
347
@ILanguageFeaturesService private readonly languageFeaturesService : ILanguageFeaturesService ,
352
348
@IChatWidgetService private readonly chatWidgetService : IChatWidgetService ,
353
349
@IChatAgentService private readonly chatAgentService : IChatAgentService ,
354
- @IInstantiationService private readonly instantiationService : IInstantiationService ,
355
350
) {
356
351
super ( ) ;
357
352
@@ -364,7 +359,7 @@ class AgentCompletions extends Disposable {
364
359
return null ;
365
360
}
366
361
367
- const parsedRequest = ( await this . instantiationService . createInstance ( ChatRequestParser ) . parseChatRequest ( widget . viewModel . sessionId , model . getValue ( ) ) ) . parts ;
362
+ const parsedRequest = widget . parsedInput . parts ;
368
363
const usedAgent = parsedRequest . find ( p => p instanceof ChatRequestAgentPart ) ;
369
364
if ( usedAgent && ! Range . containsPosition ( usedAgent . editorRange , position ) ) {
370
365
// Only one agent allowed
@@ -407,7 +402,7 @@ class AgentCompletions extends Disposable {
407
402
return null ;
408
403
}
409
404
410
- const parsedRequest = ( await this . instantiationService . createInstance ( ChatRequestParser ) . parseChatRequest ( widget . viewModel . sessionId , model . getValue ( ) ) ) . parts ;
405
+ const parsedRequest = widget . parsedInput . parts ;
411
406
const usedAgentIdx = parsedRequest . findIndex ( ( p ) : p is ChatRequestAgentPart => p instanceof ChatRequestAgentPart ) ;
412
407
if ( usedAgentIdx < 0 ) {
413
408
return ;
@@ -428,7 +423,7 @@ class AgentCompletions extends Disposable {
428
423
}
429
424
430
425
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
432
427
433
428
return < CompletionList > {
434
429
suggestions : commands . map ( ( c , i ) => {
@@ -576,7 +571,6 @@ class VariableCompletions extends Disposable {
576
571
@ILanguageFeaturesService private readonly languageFeaturesService : ILanguageFeaturesService ,
577
572
@IChatWidgetService private readonly chatWidgetService : IChatWidgetService ,
578
573
@IChatVariablesService private readonly chatVariablesService : IChatVariablesService ,
579
- @IConfigurationService private readonly configurationService : IConfigurationService ,
580
574
) {
581
575
super ( ) ;
582
576
@@ -595,33 +589,24 @@ class VariableCompletions extends Disposable {
595
589
return null ;
596
590
}
597
591
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
+ } ) ;
622
607
623
608
return < CompletionList > {
624
- suggestions : [ ... variableItems , ... historyItems ]
609
+ suggestions : variableItems
625
610
} ;
626
611
}
627
612
} ) ) ;
@@ -655,22 +640,22 @@ class ChatTokenDeleter extends Disposable {
655
640
656
641
// If this was a simple delete, try to find out whether it was inside a token
657
642
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
+ }
674
659
} ) ;
675
660
}
676
661
0 commit comments