@@ -12,18 +12,21 @@ import { Emitter, Event, MicrotaskEmitter } from 'vs/base/common/event';
12
12
import { IMarkdownString , MarkdownString } from 'vs/base/common/htmlContent' ;
13
13
import { Lazy } from 'vs/base/common/lazy' ;
14
14
import { DisposableStore , MutableDisposable , toDisposable } from 'vs/base/common/lifecycle' ;
15
+ import { ISettableObservable , constObservable , derived , observableValue } from 'vs/base/common/observable' ;
15
16
import { assertType } from 'vs/base/common/types' ;
16
17
import { URI } from 'vs/base/common/uri' ;
17
18
import 'vs/css!./inlineChat' ;
18
19
import { IEditorConstructionOptions } from 'vs/editor/browser/config/editorConfiguration' ;
19
20
import { IActiveCodeEditor , ICodeEditor , IDiffEditorConstructionOptions } from 'vs/editor/browser/editorBrowser' ;
20
21
import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions' ;
21
22
import { ICodeEditorWidgetOptions } from 'vs/editor/browser/widget/codeEditorWidget' ;
23
+ import { AccessibleDiffViewer , IAccessibleDiffViewerModel } from 'vs/editor/browser/widget/diffEditor/components/accessibleDiffViewer' ;
22
24
import { EmbeddedCodeEditorWidget , EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget' ;
23
- import { EditorLayoutInfo , EditorOption } from 'vs/editor/common/config/editorOptions' ;
25
+ import { EditorLayoutInfo , EditorOption , IComputedEditorOptions } from 'vs/editor/common/config/editorOptions' ;
24
26
import { LineRange } from 'vs/editor/common/core/lineRange' ;
25
27
import { Position } from 'vs/editor/common/core/position' ;
26
28
import { IRange , Range } from 'vs/editor/common/core/range' ;
29
+ import { DetailedLineRangeMapping , RangeMapping } from 'vs/editor/common/diff/rangeMapping' ;
27
30
import { ICodeEditorViewState , ScrollType } from 'vs/editor/common/editorCommon' ;
28
31
import { LanguageSelector } from 'vs/editor/common/languageSelector' ;
29
32
import { CompletionItem , CompletionItemInsertTextRule , CompletionItemKind , CompletionItemProvider , CompletionList , ProviderResult } from 'vs/editor/common/languages' ;
@@ -58,7 +61,7 @@ import { SlashCommandContentWidget } from 'vs/workbench/contrib/chat/browser/cha
58
61
import { IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents' ;
59
62
import { ChatModel , ChatResponseModel } from 'vs/workbench/contrib/chat/common/chatModel' ;
60
63
import { ChatResponseViewModel } from 'vs/workbench/contrib/chat/common/chatViewModel' ;
61
- import { ExpansionState , HunkData } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession' ;
64
+ import { ExpansionState , HunkData , HunkInformation , Session } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession' ;
62
65
import { asRange , invertLineRange } from 'vs/workbench/contrib/inlineChat/browser/utils' ;
63
66
import { ACTION_ACCEPT_CHANGES , ACTION_REGENERATE_RESPONSE , ACTION_VIEW_IN_CHAT , CTX_INLINE_CHAT_EMPTY , CTX_INLINE_CHAT_FOCUSED , CTX_INLINE_CHAT_INNER_CURSOR_END , CTX_INLINE_CHAT_INNER_CURSOR_FIRST , CTX_INLINE_CHAT_INNER_CURSOR_LAST , CTX_INLINE_CHAT_INNER_CURSOR_START , CTX_INLINE_CHAT_MESSAGE_CROP_STATE , CTX_INLINE_CHAT_OUTER_CURSOR_POSITION , CTX_INLINE_CHAT_RESPONSE_FOCUSED , CTX_INLINE_CHAT_VISIBLE , IInlineChatFollowup , IInlineChatSlashCommand , MENU_INLINE_CHAT_INPUT , MENU_INLINE_CHAT_WIDGET , MENU_INLINE_CHAT_WIDGET_FEEDBACK , MENU_INLINE_CHAT_WIDGET_MARKDOWN_MESSAGE , MENU_INLINE_CHAT_WIDGET_STATUS } from 'vs/workbench/contrib/inlineChat/common/inlineChat' ;
64
67
import { IUntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel' ;
@@ -182,6 +185,7 @@ export class InlineChatWidget {
182
185
h ( 'div.label.status.hidden@statusLabel' ) ,
183
186
h ( 'div.actions.hidden@feedbackToolbar' ) ,
184
187
] ) ,
188
+ h ( 'div.accessibleViewer@accessibleViewer' )
185
189
]
186
190
) ;
187
191
@@ -204,6 +208,8 @@ export class InlineChatWidget {
204
208
private readonly _previewDiffEditor : Lazy < EmbeddedDiffEditorWidget > ;
205
209
private readonly _previewDiffModel = this . _store . add ( new MutableDisposable ( ) ) ;
206
210
211
+ private readonly _accessibleViewer = this . _store . add ( new MutableDisposable < HunkAccessibleDiffViewer > ( ) ) ;
212
+
207
213
private readonly _previewCreateTitle : ResourceLabel ;
208
214
private readonly _previewCreateEditor : Lazy < ICodeEditor > ;
209
215
private readonly _previewCreateDispoable = this . _store . add ( new MutableDisposable ( ) ) ;
@@ -467,6 +473,9 @@ export class InlineChatWidget {
467
473
layout ( _dim : Dimension ) {
468
474
this . _isLayouting = true ;
469
475
try {
476
+ if ( this . _accessibleViewer . value ) {
477
+ this . _accessibleViewer . value . width = _dim . width - 12 ;
478
+ }
470
479
const widgetToolbarWidth = getTotalWidth ( this . _elements . widgetToolbar ) ;
471
480
const editorToolbarWidth = getTotalWidth ( this . _elements . editorToolbar ) + 8 /* L/R-padding */ ;
472
481
const innerEditorWidth = _dim . width - editorToolbarWidth - widgetToolbarWidth ;
@@ -489,6 +498,7 @@ export class InlineChatWidget {
489
498
this . _elements . previewCreate . style . height = `${ previewCreateDim . height } px` ;
490
499
}
491
500
501
+
492
502
const lineHeight = this . parentEditor . getOption ( EditorOption . lineHeight ) ;
493
503
const editorHeight = this . parentEditor . getLayoutInfo ( ) . height ;
494
504
const editorHeightInLines = Math . floor ( editorHeight / lineHeight ) ;
@@ -510,7 +520,8 @@ export class InlineChatWidget {
510
520
const previewDiffHeight = this . _previewDiffEditor . hasValue && this . _previewDiffEditor . value . getModel ( ) ? 12 + Math . min ( 300 , Math . max ( 0 , this . _previewDiffEditor . value . getContentHeight ( ) ) ) : 0 ;
511
521
const previewCreateTitleHeight = getTotalHeight ( this . _elements . previewCreateTitle ) ;
512
522
const previewCreateHeight = this . _previewCreateEditor . hasValue && this . _previewCreateEditor . value . getModel ( ) ? 18 + Math . min ( 300 , Math . max ( 0 , this . _previewCreateEditor . value . getContentHeight ( ) ) ) : 0 ;
513
- return base + editorHeight + detectedIntentHeight + followUpsHeight + chatResponseHeight + previewDiffHeight + previewCreateTitleHeight + previewCreateHeight + 18 /* padding */ + 8 /*shadow*/ ;
523
+ const accessibleViewHeight = this . _accessibleViewer . value ?. height ?? 0 ;
524
+ return base + editorHeight + detectedIntentHeight + followUpsHeight + chatResponseHeight + previewDiffHeight + previewCreateTitleHeight + previewCreateHeight + accessibleViewHeight + 18 /* padding */ + 8 /*shadow*/ ;
514
525
}
515
526
516
527
updateProgress ( show : boolean ) {
@@ -735,6 +746,10 @@ export class InlineChatWidget {
735
746
this . updateInfo ( '' ) ;
736
747
this . hideCreatePreview ( ) ;
737
748
this . hideEditsPreview ( ) ;
749
+
750
+ this . _accessibleViewer . clear ( ) ;
751
+ this . _elements . accessibleViewer . classList . toggle ( 'hidden' , true ) ;
752
+
738
753
this . _onDidChangeHeight . fire ( ) ;
739
754
}
740
755
@@ -908,6 +923,25 @@ export class InlineChatWidget {
908
923
this . _slashCommands . add ( this . _inputEditor . onDidChangeModelContent ( updateSlashDecorations ) ) ;
909
924
updateSlashDecorations ( ) ;
910
925
}
926
+
927
+
928
+ // --- accessible viewer
929
+
930
+ showAccessibleHunk ( session : Session , hunkData : HunkInformation ) : void {
931
+
932
+ this . _elements . accessibleViewer . classList . remove ( 'hidden' ) ;
933
+ this . _accessibleViewer . clear ( ) ;
934
+
935
+ this . _accessibleViewer . value = this . _instantiationService . createInstance ( HunkAccessibleDiffViewer ,
936
+ this . _elements . accessibleViewer ,
937
+ session ,
938
+ hunkData ,
939
+ new AccessibleHunk ( this . parentEditor , session , hunkData )
940
+ ) ;
941
+
942
+ this . _onDidChangeHeight . fire ( ) ;
943
+
944
+ }
911
945
}
912
946
913
947
export class InlineChatZoneWidget extends ZoneWidget {
@@ -1063,3 +1097,88 @@ export class InlineChatZoneWidget extends ZoneWidget {
1063
1097
aria . status ( localize ( 'inlineChatClosed' , 'Closed inline chat widget' ) ) ;
1064
1098
}
1065
1099
}
1100
+
1101
+ class HunkAccessibleDiffViewer extends AccessibleDiffViewer {
1102
+
1103
+ readonly height : number ;
1104
+
1105
+ set width ( value : number ) {
1106
+ this . _width2 . set ( value , undefined ) ;
1107
+ }
1108
+
1109
+ private readonly _width2 : ISettableObservable < number > ;
1110
+
1111
+ constructor (
1112
+ parentNode : HTMLElement ,
1113
+ session : Session ,
1114
+ hunk : HunkInformation ,
1115
+ models : IAccessibleDiffViewerModel ,
1116
+ @IInstantiationService instantiationService : IInstantiationService ,
1117
+ ) {
1118
+ const width = observableValue ( 'width' , 0 ) ;
1119
+ const diff = observableValue ( 'diff' , HunkAccessibleDiffViewer . _asMapping ( hunk ) ) ;
1120
+ const diffs = derived ( r => [ diff . read ( r ) ] ) ;
1121
+ const lines = Math . min ( 6 , 3 * diff . get ( ) . changedLineCount ) ;
1122
+ const height = models . getModifiedOptions ( ) . get ( EditorOption . lineHeight ) * lines ;
1123
+
1124
+ super ( parentNode , constObservable ( true ) , ( ) => { } , constObservable ( false ) , width , constObservable ( height ) , diffs , models , instantiationService ) ;
1125
+
1126
+ this . height = height ;
1127
+ this . _width2 = width ;
1128
+
1129
+ this . _store . add ( session . textModelN . onDidChangeContent ( ( ) => {
1130
+ diff . set ( HunkAccessibleDiffViewer . _asMapping ( hunk ) , undefined ) ;
1131
+ } ) ) ;
1132
+ }
1133
+
1134
+ private static _asMapping ( hunk : HunkInformation ) : DetailedLineRangeMapping {
1135
+ const ranges0 = hunk . getRanges0 ( ) ;
1136
+ const rangesN = hunk . getRangesN ( ) ;
1137
+ const originalLineRange = LineRange . fromRangeInclusive ( ranges0 [ 0 ] ) ;
1138
+ const modifiedLineRange = LineRange . fromRangeInclusive ( rangesN [ 0 ] ) ;
1139
+ const innerChanges : RangeMapping [ ] = [ ] ;
1140
+ for ( let i = 1 ; i < ranges0 . length ; i ++ ) {
1141
+ innerChanges . push ( new RangeMapping ( ranges0 [ i ] , rangesN [ i ] ) ) ;
1142
+ }
1143
+ return new DetailedLineRangeMapping ( originalLineRange , modifiedLineRange , innerChanges ) ;
1144
+ }
1145
+
1146
+ }
1147
+
1148
+ class AccessibleHunk implements IAccessibleDiffViewerModel {
1149
+
1150
+ constructor (
1151
+ private readonly _editor : ICodeEditor ,
1152
+ private readonly _session : Session ,
1153
+ private readonly _hunk : HunkInformation
1154
+ ) { }
1155
+
1156
+ getOriginalModel ( ) : ITextModel {
1157
+ return this . _session . textModel0 ;
1158
+ }
1159
+ getModifiedModel ( ) : ITextModel {
1160
+ return this . _session . textModelN ;
1161
+ }
1162
+ getOriginalOptions ( ) : IComputedEditorOptions {
1163
+ return this . _editor . getOptions ( ) ;
1164
+ }
1165
+ getModifiedOptions ( ) : IComputedEditorOptions {
1166
+ return this . _editor . getOptions ( ) ;
1167
+ }
1168
+ originalReveal ( range : Range ) : void {
1169
+ // throw new Error('Method not implemented.');
1170
+ }
1171
+ modifiedReveal ( range ?: Range | undefined ) : void {
1172
+ this . _editor . revealRangeInCenterIfOutsideViewport ( range || this . _hunk . getRangesN ( ) [ 0 ] , ScrollType . Smooth ) ;
1173
+ }
1174
+ modifiedSetSelection ( range : Range ) : void {
1175
+ // this._editor.revealRangeInCenterIfOutsideViewport(range, ScrollType.Smooth);
1176
+ // this._editor.setSelection(range);
1177
+ }
1178
+ modifiedFocus ( ) : void {
1179
+ this . _editor . focus ( ) ;
1180
+ }
1181
+ getModifiedPosition ( ) : Position | undefined {
1182
+ return this . _hunk . getRangesN ( ) [ 0 ] . getStartPosition ( ) ;
1183
+ }
1184
+ }
0 commit comments