@@ -12,6 +12,7 @@ import { Button } from '../../../../base/browser/ui/button/button.js';
12
12
import { IHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegate.js' ;
13
13
import { createInstantHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegateFactory.js' ;
14
14
import { renderLabelWithIcons } from '../../../../base/browser/ui/iconLabel/iconLabels.js' ;
15
+ import { ProgressBar } from '../../../../base/browser/ui/progressbar/progressbar.js' ;
15
16
import { IAction } from '../../../../base/common/actions.js' ;
16
17
import { Codicon } from '../../../../base/common/codicons.js' ;
17
18
import { Emitter , Event } from '../../../../base/common/event.js' ;
@@ -61,7 +62,7 @@ import { AccessibilityCommandId } from '../../accessibility/common/accessibility
61
62
import { getSimpleCodeEditorWidgetOptions , getSimpleEditorOptions , setupSimpleEditorSelectionStyling } from '../../codeEditor/browser/simpleEditorOptions.js' ;
62
63
import { ChatAgentLocation , IChatAgentService } from '../common/chatAgents.js' ;
63
64
import { CONTEXT_CHAT_INPUT_CURSOR_AT_TOP , CONTEXT_CHAT_INPUT_HAS_FOCUS , CONTEXT_CHAT_INPUT_HAS_TEXT , CONTEXT_IN_CHAT_INPUT } from '../common/chatContextKeys.js' ;
64
- import { IChatEditingSession , ModifiedFileEntryState } from '../common/chatEditingService.js' ;
65
+ import { ChatEditingSessionState , IChatEditingSession , ModifiedFileEntryState } from '../common/chatEditingService.js' ;
65
66
import { IChatRequestVariableEntry } from '../common/chatModel.js' ;
66
67
import { IChatFollowup } from '../common/chatService.js' ;
67
68
import { IChatResponseViewModel } from '../common/chatViewModel.js' ;
@@ -199,6 +200,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
199
200
readonly inputUri = URI . parse ( `${ ChatInputPart . INPUT_SCHEME } :input-${ ChatInputPart . _counter ++ } ` ) ;
200
201
201
202
private readonly _chatEditsDisposables = this . _register ( new DisposableStore ( ) ) ;
203
+ private _chatEditsProgress : ProgressBar | undefined ;
202
204
private _chatEditsListPool : CollapsibleListPool ;
203
205
private _chatEditList : IDisposableReference < WorkbenchList < IChatCollapsibleListItem > > | undefined ;
204
206
get selectedElements ( ) : URI [ ] {
@@ -839,30 +841,40 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
839
841
}
840
842
841
843
async renderChatEditingSessionState ( chatEditingSession : IChatEditingSession | null ) {
842
- dom . clearNode ( this . chatEditingSessionWidgetContainer ) ;
843
844
dom . setVisibility ( Boolean ( chatEditingSession ) , this . chatEditingSessionWidgetContainer ) ;
844
- this . _chatEditsDisposables . clear ( ) ;
845
- this . _chatEditList = undefined ;
845
+
846
846
if ( ! chatEditingSession ) {
847
+ dom . clearNode ( this . chatEditingSessionWidgetContainer ) ;
848
+ this . _chatEditsDisposables . clear ( ) ;
849
+ this . _chatEditList = undefined ;
850
+ this . _chatEditsProgress ?. dispose ( ) ;
851
+ this . _chatEditsProgress = undefined ;
847
852
return ;
848
853
}
849
854
850
- const innerContainer = dom . append ( this . chatEditingSessionWidgetContainer , $ ( '.chat-editing-session-container.show-file-icons' ) ) ;
855
+ if ( this . _chatEditList && chatEditingSession . state . get ( ) === ChatEditingSessionState . Idle ) {
856
+ this . _chatEditsProgress ?. stop ( ) ;
857
+ return ;
858
+ }
851
859
852
860
// Summary of number of files changed
861
+ const innerContainer = this . chatEditingSessionWidgetContainer . querySelector ( '.chat-editing-session-container.show-file-icons' ) as HTMLElement ?? dom . append ( this . chatEditingSessionWidgetContainer , $ ( '.chat-editing-session-container.show-file-icons' ) ) ;
853
862
const editedFiles = chatEditingSession . entries . get ( ) ;
854
863
const numberOfEditedEntries = editedFiles . length ;
855
- const overviewRegion = dom . append ( innerContainer , $ ( '.chat-editing-session-overview' ) ) ;
856
- const overviewText = dom . append ( overviewRegion , $ ( 'span' ) ) ;
857
- overviewText . textContent = numberOfEditedEntries === 1
858
- ? localize ( 'chatEditingSessionOverview.oneFileChanged' , "1 file changed" )
859
- : localize ( 'chatEditingSessionOverview' , "{0} files changed" , numberOfEditedEntries ) ;
864
+ const overviewRegion = innerContainer . querySelector ( '.chat-editing-session-overview' ) as HTMLElement ?? dom . append ( innerContainer , $ ( '.chat-editing-session-overview' ) ) ;
865
+ if ( numberOfEditedEntries !== this . _chatEditList ?. object . length ) {
866
+ const overviewText = overviewRegion . querySelector ( 'span' ) ?? dom . append ( overviewRegion , $ ( 'span' ) ) ;
867
+ overviewText . textContent = numberOfEditedEntries === 1
868
+ ? localize ( 'chatEditingSessionOverview.oneFileChanged' , "1 file changed" )
869
+ : localize ( 'chatEditingSessionOverview' , "{0} files changed" , numberOfEditedEntries ) ;
870
+ }
860
871
861
872
// Chat editing session actions
862
- const actionsContainer = dom . append ( overviewRegion , $ ( '.chat-editing-session-actions' ) ) ;
873
+ let actionsContainer = overviewRegion . querySelector ( '.chat-editing-session-actions' ) as HTMLElement ;
863
874
const actions = [ ] ;
864
- // Don't show Accept All / Discard All actions if user already selected Accept All / Discard All
865
- if ( editedFiles . find ( ( e ) => e . state . get ( ) === ModifiedFileEntryState . Undecided ) ) {
875
+ if ( ! actionsContainer && editedFiles . find ( ( e ) => e . state . get ( ) === ModifiedFileEntryState . Undecided ) ) {
876
+ // Don't show Accept All / Discard All actions if user already selected Accept All / Discard All
877
+ actionsContainer = dom . append ( overviewRegion , $ ( '.chat-editing-session-actions' ) ) ;
866
878
actions . push (
867
879
{
868
880
command : ChatEditingShowChangesAction . ID ,
@@ -880,60 +892,68 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
880
892
isSecondary : false
881
893
}
882
894
) ;
883
- }
884
895
885
- for ( const action of actions ) {
886
- const button = this . _register ( new Button ( actionsContainer , {
887
- supportIcons : false ,
888
- secondary : action . isSecondary
889
- } ) ) ;
890
- button . label = action . label ;
891
- this . _register ( button . onDidClick ( ( ) => {
892
- this . commandService . executeCommand ( action . command ) ;
893
- } ) ) ;
894
- dom . append ( actionsContainer , button . element ) ;
896
+ for ( const action of actions ) {
897
+ const button = this . _register ( new Button ( actionsContainer , {
898
+ supportIcons : false ,
899
+ secondary : action . isSecondary
900
+ } ) ) ;
901
+ button . label = action . label ;
902
+ this . _register ( button . onDidClick ( ( ) => {
903
+ this . commandService . executeCommand ( action . command ) ;
904
+ } ) ) ;
905
+ dom . append ( actionsContainer , button . element ) ;
906
+ }
907
+
908
+ const clearButton = new Button ( actionsContainer , { supportIcons : true } ) ;
909
+ this . _chatEditsDisposables . add ( clearButton ) ;
910
+ clearButton . icon = Codicon . close ;
911
+ const disp = clearButton . onDidClick ( ( e ) => {
912
+ disp . dispose ( ) ;
913
+ chatEditingSession . dispose ( ) ;
914
+ } ) ;
915
+ dom . append ( actionsContainer , clearButton . element ) ;
895
916
}
896
917
897
- const clearButton = new Button ( actionsContainer , { supportIcons : true } ) ;
898
- this . _chatEditsDisposables . add ( clearButton ) ;
899
- clearButton . icon = Codicon . close ;
900
- const disp = clearButton . onDidClick ( ( e ) => {
901
- disp . dispose ( ) ;
902
- chatEditingSession . dispose ( ) ;
903
- } ) ;
904
- dom . append ( actionsContainer , clearButton . element ) ;
918
+ if ( ! this . _chatEditsProgress && chatEditingSession . state . get ( ) === ChatEditingSessionState . StreamingEdits ) {
919
+ this . _chatEditsProgress = new ProgressBar ( innerContainer ) ;
920
+ this . _chatEditsProgress . infinite ( ) . show ( 500 ) ;
921
+ }
905
922
906
923
// List of edited files
907
- if ( ! editedFiles . length ) {
924
+ if ( ! editedFiles . length || editedFiles . length === this . _chatEditList ?. object . length ) {
908
925
return ;
909
926
}
910
927
const entries : IChatCollapsibleListItem [ ] = editedFiles . map ( ( entry ) => ( {
911
928
reference : entry . modifiedURI ,
912
929
kind : 'reference' ,
913
930
} ) ) ;
914
- const editedFilesList = this . _chatEditsListPool . get ( ) ;
915
- this . _chatEditList = editedFilesList ;
916
- const list = editedFilesList . object ;
917
- this . _chatEditsDisposables . add ( editedFilesList ) ;
918
- this . _chatEditsDisposables . add ( list . onDidOpen ( ( e ) => {
919
- if ( e . element ?. kind === 'reference' && URI . isUri ( e . element . reference ) ) {
920
- const modifiedFileUri = e . element . reference ;
921
- const editedFile = editedFiles . find ( ( e ) => e . modifiedURI . toString ( ) === modifiedFileUri . toString ( ) ) ;
922
- if ( editedFile ) {
923
- void this . editorService . openEditor ( {
924
- original : { resource : URI . from ( editedFile . originalURI , true ) } ,
925
- modified : { resource : URI . from ( editedFile . modifiedURI , true ) } ,
926
- } ) ;
931
+ if ( ! this . _chatEditList ) {
932
+ this . _chatEditList = this . _chatEditsListPool . get ( ) ;
933
+ const list = this . _chatEditList . object ;
934
+ this . _chatEditsDisposables . add ( this . _chatEditList ) ;
935
+ this . _chatEditsDisposables . add ( list . onDidOpen ( ( e ) => {
936
+ if ( e . element ?. kind === 'reference' && URI . isUri ( e . element . reference ) ) {
937
+ const modifiedFileUri = e . element . reference ;
938
+ const editedFile = editedFiles . find ( ( e ) => e . modifiedURI . toString ( ) === modifiedFileUri . toString ( ) ) ;
939
+ if ( editedFile ) {
940
+ void this . editorService . openEditor ( {
941
+ original : { resource : URI . from ( editedFile . originalURI , true ) } ,
942
+ modified : { resource : URI . from ( editedFile . modifiedURI , true ) } ,
943
+ } ) ;
944
+ }
927
945
}
928
- }
929
- } ) ) ;
946
+ } ) ) ;
947
+ dom . append ( innerContainer , list . getHTMLElement ( ) ) ;
948
+ }
949
+
930
950
const maxItemsShown = 6 ;
931
951
const itemsShown = Math . min ( numberOfEditedEntries , maxItemsShown ) ;
932
952
const height = itemsShown * 22 ;
953
+ const list = this . _chatEditList . object ;
933
954
list . layout ( height ) ;
934
955
list . getHTMLElement ( ) . style . height = `${ height } px` ;
935
956
list . splice ( 0 , list . length , entries ) ;
936
- dom . append ( innerContainer , editedFilesList . object . getHTMLElement ( ) ) ;
937
957
}
938
958
939
959
async renderFollowups ( items : IChatFollowup [ ] | undefined , response : IChatResponseViewModel | undefined ) : Promise < void > {
0 commit comments