@@ -17,17 +17,19 @@ import { ILabelService } from 'vs/platform/label/common/label';
17
17
import { WorkbenchCompressibleObjectTree , getSelectionKeyboardEvent } from 'vs/platform/list/browser/listService' ;
18
18
import { FastAndSlowPicks , IPickerQuickAccessItem , PickerQuickAccessProvider , Picks , TriggerAction } from 'vs/platform/quickinput/browser/pickerQuickAccess' ;
19
19
import { DefaultQuickAccessFilterValue , IQuickAccessProviderRunOptions } from 'vs/platform/quickinput/common/quickAccess' ;
20
- import { IKeyMods , IQuickPick , IQuickPickItem , IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput' ;
20
+ import { IKeyMods , IQuickPick , IQuickPickItem , IQuickPickSeparator , QuickInputHideReason } from 'vs/platform/quickinput/common/quickInput' ;
21
21
import { IWorkspaceContextService , IWorkspaceFolder } from 'vs/platform/workspace/common/workspace' ;
22
22
import { IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor' ;
23
- import { IViewsService } from 'vs/workbench/services/views/common/viewsService' ;
24
23
import { searchDetailsIcon , searchOpenInFileIcon , searchActivityBarIcon } from 'vs/workbench/contrib/search/browser/searchIcons' ;
25
24
import { FileMatch , Match , RenderableMatch , SearchModel , SearchModelLocation , searchComparer } from 'vs/workbench/contrib/search/browser/searchModel' ;
26
25
import { SearchView , getEditorSelectionFromMatch } from 'vs/workbench/contrib/search/browser/searchView' ;
27
26
import { IWorkbenchSearchConfiguration , getOutOfWorkspaceEditorResources } from 'vs/workbench/contrib/search/common/search' ;
28
27
import { ACTIVE_GROUP , IEditorService , SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService' ;
29
28
import { ITextQueryBuilderOptions , QueryBuilder } from 'vs/workbench/services/search/common/queryBuilder' ;
30
29
import { IPatternInfo , ISearchComplete , ITextQuery , VIEW_ID } from 'vs/workbench/services/search/common/search' ;
30
+ import { Event } from 'vs/base/common/event' ;
31
+ import { EditorViewState } from 'vs/workbench/browser/quickaccess' ;
32
+ import { IViewsService } from 'vs/workbench/services/views/common/viewsService' ;
31
33
32
34
export const TEXT_SEARCH_QUICK_ACCESS_PREFIX = '%' ;
33
35
@@ -42,13 +44,20 @@ const DEFAULT_TEXT_QUERY_BUILDER_OPTIONS: ITextQueryBuilderOptions = {
42
44
const MAX_FILES_SHOWN = 30 ;
43
45
const MAX_RESULTS_PER_FILE = 10 ;
44
46
45
- export class TextSearchQuickAccess extends PickerQuickAccessProvider < IPickerQuickAccessItem > {
47
+ interface ITextSearchQuickAccessItem extends IPickerQuickAccessItem {
48
+ match ?: Match ;
49
+ }
50
+ export class TextSearchQuickAccess extends PickerQuickAccessProvider < ITextSearchQuickAccessItem > {
46
51
private queryBuilder : QueryBuilder ;
47
52
private searchModel : SearchModel ;
48
53
private currentAsyncSearch : Promise < ISearchComplete > = Promise . resolve ( {
49
54
results : [ ] ,
50
55
messages : [ ]
51
56
} ) ;
57
+ private storedOriginalLocation = false ;
58
+ private readonly editorViewState = new EditorViewState (
59
+ this . _editorService
60
+ ) ;
52
61
53
62
private _getTextQueryBuilderOptions ( charsPerLine : number ) : ITextQueryBuilderOptions {
54
63
return {
@@ -72,7 +81,7 @@ export class TextSearchQuickAccess extends PickerQuickAccessProvider<IPickerQuic
72
81
@IEditorService private readonly _editorService : IEditorService ,
73
82
@ILabelService private readonly _labelService : ILabelService ,
74
83
@IViewsService private readonly _viewsService : IViewsService ,
75
- @IConfigurationService private readonly _configurationService : IConfigurationService ,
84
+ @IConfigurationService private readonly _configurationService : IConfigurationService
76
85
) {
77
86
super ( TEXT_SEARCH_QUICK_ACCESS_PREFIX , { canAcceptInBackground : true , shouldSkipTrimPickFilter : true } ) ;
78
87
@@ -86,23 +95,51 @@ export class TextSearchQuickAccess extends PickerQuickAccessProvider<IPickerQuic
86
95
super . dispose ( ) ;
87
96
}
88
97
89
- override provide ( picker : IQuickPick < IPickerQuickAccessItem > , token : CancellationToken , runOptions ?: IQuickAccessProviderRunOptions ) : IDisposable {
98
+ override provide ( picker : IQuickPick < ITextSearchQuickAccessItem > , token : CancellationToken , runOptions ?: IQuickAccessProviderRunOptions ) : IDisposable {
90
99
const disposables = new DisposableStore ( ) ;
91
100
if ( TEXT_SEARCH_QUICK_ACCESS_PREFIX . length < picker . value . length ) {
92
101
picker . valueSelection = [ TEXT_SEARCH_QUICK_ACCESS_PREFIX . length , picker . value . length ] ;
93
102
}
94
103
picker . customButton = true ;
95
104
picker . customLabel = '$(link-external)' ;
96
- picker . onDidCustom ( ( ) => {
105
+ disposables . add ( picker . onDidCustom ( ( ) => {
97
106
if ( this . searchModel . searchResult . count ( ) > 0 ) {
98
107
this . moveToSearchViewlet ( undefined ) ;
99
108
} else {
100
109
this . _viewsService . openView ( VIEW_ID , true ) ;
101
110
}
102
111
picker . hide ( ) ;
103
- } ) ;
112
+ } ) ) ;
113
+ disposables . add ( picker . onDidChangeActive ( ( ) => {
114
+ const [ item ] = picker . activeItems ;
115
+
116
+ if ( item ?. match ) {
117
+ // only store location once, or else it will store new state every time we change active pick
118
+ if ( ! this . storedOriginalLocation ) {
119
+ // we must remember our curret view state to be able to restore
120
+ this . editorViewState . set ( ) ;
121
+ this . storedOriginalLocation = true ;
122
+ }
123
+ // open it
124
+ this . _editorService . openEditor ( {
125
+ resource : item . match . parent ( ) . resource ,
126
+ options : { preserveFocus : true , revealIfOpened : true , ignoreError : true , selection : item . match . range ( ) }
127
+ } ) ;
128
+ }
129
+ } ) ) ;
130
+
131
+ disposables . add ( Event . once ( picker . onDidHide ) ( ( { reason } ) => {
132
+ // Restore view state upon cancellation if we changed it
133
+ // but only when the picker was closed via explicit user
134
+ // gesture and not e.g. when focus was lost because that
135
+ // could mean the user clicked into the editor directly.
136
+ if ( reason === QuickInputHideReason . Gesture ) {
137
+ this . editorViewState . restore ( ) ;
138
+ }
139
+ this . searchModel . searchResult . toggleHighlights ( false ) ;
140
+ } ) ) ;
141
+
104
142
disposables . add ( super . provide ( picker , token , runOptions ) ) ;
105
- disposables . add ( picker . onDidHide ( ( ) => this . searchModel . searchResult . toggleHighlights ( false ) ) ) ;
106
143
disposables . add ( picker . onDidAccept ( ( ) => this . searchModel . searchResult . toggleHighlights ( false ) ) ) ;
107
144
return disposables ;
108
145
}
@@ -177,11 +214,11 @@ export class TextSearchQuickAccess extends PickerQuickAccessProvider<IPickerQuic
177
214
}
178
215
}
179
216
180
- private _getPicksFromMatches ( matches : FileMatch [ ] , limit : number ) : ( IQuickPickSeparator | IPickerQuickAccessItem ) [ ] {
217
+ private _getPicksFromMatches ( matches : FileMatch [ ] , limit : number ) : ( IQuickPickSeparator | ITextSearchQuickAccessItem ) [ ] {
181
218
matches = matches . sort ( searchComparer ) ;
182
219
183
220
const files = matches . length > limit ? matches . slice ( 0 , limit ) : matches ;
184
- const picks : Array < IPickerQuickAccessItem | IQuickPickSeparator > = [ ] ;
221
+ const picks : Array < ITextSearchQuickAccessItem | IQuickPickSeparator > = [ ] ;
185
222
186
223
for ( let fileIndex = 0 ; fileIndex < matches . length ; fileIndex ++ ) {
187
224
if ( fileIndex === limit ) {
@@ -258,7 +295,8 @@ export class TextSearchQuickAccess extends PickerQuickAccessProvider<IPickerQuic
258
295
trigger : ( ) : TriggerAction => {
259
296
this . moveToSearchViewlet ( element ) ;
260
297
return TriggerAction . CLOSE_PICKER ;
261
- }
298
+ } ,
299
+ match : element
262
300
} ) ;
263
301
}
264
302
}
0 commit comments