6
6
import { renderIcon } from '../../../../../../base/browser/ui/iconLabel/iconLabels.js' ;
7
7
import { Codicon } from '../../../../../../base/common/codicons.js' ;
8
8
import { Disposable } from '../../../../../../base/common/lifecycle.js' ;
9
- import { IObservable , constObservable , derived , observableFromEvent } from '../../../../../../base/common/observable.js' ;
9
+ import { IObservable , autorun , constObservable , derived , observableFromEvent , observableValue } from '../../../../../../base/common/observable.js' ;
10
+ import { IHoverService } from '../../../../../../platform/hover/browser/hover.js' ;
11
+ import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js' ;
10
12
import { buttonBackground , buttonForeground , buttonSecondaryBackground , buttonSecondaryForeground } from '../../../../../../platform/theme/common/colorRegistry.js' ;
11
13
import { registerColor , transparent } from '../../../../../../platform/theme/common/colorUtils.js' ;
12
14
import { ObservableCodeEditor } from '../../../../../browser/observableCodeEditor.js' ;
13
15
import { Rect } from '../../../../../browser/rect.js' ;
16
+ import { HoverService } from '../../../../../browser/services/hoverService/hoverService.js' ;
17
+ import { HoverWidget } from '../../../../../browser/services/hoverService/hoverWidget.js' ;
14
18
import { EditorOption } from '../../../../../common/config/editorOptions.js' ;
15
19
import { LineRange } from '../../../../../common/core/lineRange.js' ;
16
20
import { OffsetRange } from '../../../../../common/core/offsetRange.js' ;
17
21
import { StickyScrollController } from '../../../../stickyScroll/browser/stickyScrollController.js' ;
18
22
import { InlineCompletionsModel } from '../../model/inlineCompletionsModel.js' ;
23
+ import { GutterIndicatorMenuContent } from './gutterIndicatorMenu.js' ;
19
24
import { mapOutFalsy , n , rectToProps } from './utils.js' ;
20
25
import { localize } from '../../../../../../nls.js' ;
21
26
export const inlineEditIndicatorPrimaryForeground = registerColor (
@@ -62,12 +67,14 @@ export const inlineEditIndicatorBackground = registerColor(
62
67
localize ( 'inlineEdit.gutterIndicator.background' , 'Background color for the inline edit gutter indicator.' )
63
68
) ;
64
69
65
-
66
70
export class InlineEditsGutterIndicator extends Disposable {
67
71
constructor (
68
72
private readonly _editorObs : ObservableCodeEditor ,
69
73
private readonly _originalRange : IObservable < LineRange | undefined > ,
70
74
private readonly _model : IObservable < InlineCompletionsModel | undefined > ,
75
+ private readonly _shouldShowHover : IObservable < boolean > ,
76
+ @IHoverService private readonly _hoverService : HoverService ,
77
+ @IInstantiationService private readonly _instantiationService : IInstantiationService ,
71
78
) {
72
79
super ( ) ;
73
80
@@ -77,6 +84,14 @@ export class InlineEditsGutterIndicator extends Disposable {
77
84
allowEditorOverflow : false ,
78
85
minContentWidthInPx : constObservable ( 0 ) ,
79
86
} ) ) ;
87
+
88
+ this . _register ( autorun ( reader => {
89
+ if ( this . _shouldShowHover . read ( reader ) ) {
90
+ this . _showHover ( ) ;
91
+ } else {
92
+ this . _hoverService . hideHover ( ) ;
93
+ }
94
+ } ) ) ;
80
95
}
81
96
82
97
private readonly _originalRangeObs = mapOutFalsy ( this . _originalRange ) ;
@@ -132,44 +147,88 @@ export class InlineEditsGutterIndicator extends Disposable {
132
147
133
148
private readonly _tabAction = derived ( this , reader => {
134
149
const m = this . _model . read ( reader ) ;
135
- if ( m && m . tabShouldJumpToInlineEdit . read ( reader ) ) { return 'jump' as const ; }
136
- if ( m && m . tabShouldAcceptInlineEdit . read ( reader ) ) { return 'accept' as const ; }
150
+ if ( this . _editorObs . isFocused . read ( reader ) ) {
151
+ if ( m && m . tabShouldJumpToInlineEdit . read ( reader ) ) { return 'jump' as const ; }
152
+ if ( m && m . tabShouldAcceptInlineEdit . read ( reader ) ) { return 'accept' as const ; }
153
+ }
137
154
return 'inactive' as const ;
138
155
} ) ;
139
156
140
157
private readonly _onClickAction = derived ( this , reader => {
141
158
if ( this . _layout . map ( d => d && d . docked ) . read ( reader ) ) {
142
159
return {
143
- label : 'Click to accept inline edit' ,
160
+ selectionOverride : 'accept' as const ,
144
161
action : ( ) => { this . _model . get ( ) ?. accept ( ) ; }
145
162
} ;
146
163
} else {
147
164
return {
148
- label : 'Click to jump to inline edit' ,
165
+ selectionOverride : 'jump' as const ,
149
166
action : ( ) => { this . _model . get ( ) ?. jump ( ) ; }
150
167
} ;
151
168
}
152
169
} ) ;
153
170
171
+ private readonly _iconRef = n . ref < HTMLDivElement > ( ) ;
172
+ private _hoverVisible : boolean = false ;
173
+ private readonly _isHoveredOverIcon = observableValue ( this , false ) ;
174
+ private readonly _hoverSelectionOverride = derived ( this , reader => this . _isHoveredOverIcon . read ( reader ) ? this . _onClickAction . read ( reader ) . selectionOverride : undefined ) ;
175
+
176
+ private _showHover ( ) : void {
177
+ if ( this . _hoverVisible ) {
178
+ return ;
179
+ }
180
+
181
+ const content = this . _instantiationService . createInstance (
182
+ GutterIndicatorMenuContent ,
183
+ this . _hoverSelectionOverride ,
184
+ ( focusEditor ) => {
185
+ h ?. dispose ( ) ;
186
+ if ( focusEditor ) {
187
+ this . _editorObs . editor . focus ( ) ;
188
+ }
189
+ } ,
190
+ this . _model . map ( ( m , r ) => m ?. state . read ( r ) ?. inlineCompletion ?. inlineCompletion . source . inlineCompletions . commands ) ,
191
+ ) . toDisposableLiveElement ( ) ;
192
+ const h = this . _hoverService . showHover ( {
193
+ target : this . _iconRef . element ,
194
+ content : content . element ,
195
+ } ) as HoverWidget | undefined ;
196
+ if ( h ) {
197
+ this . _hoverVisible = true ;
198
+ h . onDispose ( ( ) => {
199
+ content . dispose ( ) ;
200
+ this . _hoverVisible = false ;
201
+ } ) ;
202
+ } else {
203
+ content . dispose ( ) ;
204
+ }
205
+ }
206
+
154
207
private readonly _indicator = n . div ( {
155
208
class : 'inline-edits-view-gutter-indicator' ,
156
209
onclick : ( ) => this . _onClickAction . get ( ) . action ( ) ,
157
- title : this . _onClickAction . map ( a => a . label ) ,
158
210
style : {
159
211
position : 'absolute' ,
160
212
overflow : 'visible' ,
161
213
} ,
162
- } , mapOutFalsy ( this . _layout ) . map ( l => ! l ? [ ] : [
214
+ } , mapOutFalsy ( this . _layout ) . map ( layout => ! layout ? [ ] : [
163
215
n . div ( {
164
216
style : {
165
217
position : 'absolute' ,
166
218
background : 'var(--vscode-inlineEdit-gutterIndicator-background)' ,
167
219
borderRadius : '4px' ,
168
- ...rectToProps ( reader => l . read ( reader ) . rect ) ,
220
+ ...rectToProps ( reader => layout . read ( reader ) . rect ) ,
169
221
}
170
222
} ) ,
171
223
n . div ( {
172
224
class : 'icon' ,
225
+ ref : this . _iconRef ,
226
+ onmouseenter : ( ) => {
227
+ // TODO show hover when hovering ghost text etc.
228
+ this . _isHoveredOverIcon . set ( true , undefined ) ;
229
+ this . _showHover ( ) ;
230
+ } ,
231
+ onmouseleave : ( ) => { this . _isHoveredOverIcon . set ( false , undefined ) ; } ,
173
232
style : {
174
233
cursor : 'pointer' ,
175
234
zIndex : '1000' ,
@@ -192,12 +251,12 @@ export class InlineEditsGutterIndicator extends Disposable {
192
251
display : 'flex' ,
193
252
justifyContent : 'center' ,
194
253
transition : 'background-color 0.2s ease-in-out' ,
195
- ...rectToProps ( reader => l . read ( reader ) . iconRect ) ,
254
+ ...rectToProps ( reader => layout . read ( reader ) . iconRect ) ,
196
255
}
197
256
} , [
198
257
n . div ( {
199
258
style : {
200
- rotate : l . map ( l => {
259
+ rotate : layout . map ( l => {
201
260
switch ( l . arrowDirection ) {
202
261
case 'right' : return '0deg' ;
203
262
case 'bottom' : return '90deg' ;
@@ -207,7 +266,7 @@ export class InlineEditsGutterIndicator extends Disposable {
207
266
transition : 'rotate 0.2s ease-in-out' ,
208
267
}
209
268
} , [
210
- renderIcon ( Codicon . arrowRight ) ,
269
+ renderIcon ( Codicon . arrowRight )
211
270
] )
212
271
] ) ,
213
272
] ) ) . keepUpdated ( this . _store ) ;
0 commit comments