@@ -17,17 +17,19 @@ import { ILabelService } from 'vs/platform/label/common/label';
1717import { WorkbenchCompressibleObjectTree , getSelectionKeyboardEvent } from 'vs/platform/list/browser/listService' ;
1818import { FastAndSlowPicks , IPickerQuickAccessItem , PickerQuickAccessProvider , Picks , TriggerAction } from 'vs/platform/quickinput/browser/pickerQuickAccess' ;
1919import { 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' ;
2121import { IWorkspaceContextService , IWorkspaceFolder } from 'vs/platform/workspace/common/workspace' ;
2222import { IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor' ;
23- import { IViewsService } from 'vs/workbench/services/views/common/viewsService' ;
2423import { searchDetailsIcon , searchOpenInFileIcon , searchActivityBarIcon } from 'vs/workbench/contrib/search/browser/searchIcons' ;
2524import { FileMatch , Match , RenderableMatch , SearchModel , SearchModelLocation , searchComparer } from 'vs/workbench/contrib/search/browser/searchModel' ;
2625import { SearchView , getEditorSelectionFromMatch } from 'vs/workbench/contrib/search/browser/searchView' ;
2726import { IWorkbenchSearchConfiguration , getOutOfWorkspaceEditorResources } from 'vs/workbench/contrib/search/common/search' ;
2827import { ACTIVE_GROUP , IEditorService , SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService' ;
2928import { ITextQueryBuilderOptions , QueryBuilder } from 'vs/workbench/services/search/common/queryBuilder' ;
3029import { 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' ;
3133
3234export const TEXT_SEARCH_QUICK_ACCESS_PREFIX = '%' ;
3335
@@ -42,13 +44,20 @@ const DEFAULT_TEXT_QUERY_BUILDER_OPTIONS: ITextQueryBuilderOptions = {
4244const MAX_FILES_SHOWN = 30 ;
4345const MAX_RESULTS_PER_FILE = 10 ;
4446
45- export class TextSearchQuickAccess extends PickerQuickAccessProvider < IPickerQuickAccessItem > {
47+ interface ITextSearchQuickAccessItem extends IPickerQuickAccessItem {
48+ match ?: Match ;
49+ }
50+ export class TextSearchQuickAccess extends PickerQuickAccessProvider < ITextSearchQuickAccessItem > {
4651 private queryBuilder : QueryBuilder ;
4752 private searchModel : SearchModel ;
4853 private currentAsyncSearch : Promise < ISearchComplete > = Promise . resolve ( {
4954 results : [ ] ,
5055 messages : [ ]
5156 } ) ;
57+ private storedOriginalLocation = false ;
58+ private readonly editorViewState = new EditorViewState (
59+ this . _editorService
60+ ) ;
5261
5362 private _getTextQueryBuilderOptions ( charsPerLine : number ) : ITextQueryBuilderOptions {
5463 return {
@@ -72,7 +81,7 @@ export class TextSearchQuickAccess extends PickerQuickAccessProvider<IPickerQuic
7281 @IEditorService private readonly _editorService : IEditorService ,
7382 @ILabelService private readonly _labelService : ILabelService ,
7483 @IViewsService private readonly _viewsService : IViewsService ,
75- @IConfigurationService private readonly _configurationService : IConfigurationService ,
84+ @IConfigurationService private readonly _configurationService : IConfigurationService
7685 ) {
7786 super ( TEXT_SEARCH_QUICK_ACCESS_PREFIX , { canAcceptInBackground : true , shouldSkipTrimPickFilter : true } ) ;
7887
@@ -86,23 +95,51 @@ export class TextSearchQuickAccess extends PickerQuickAccessProvider<IPickerQuic
8695 super . dispose ( ) ;
8796 }
8897
89- override provide ( picker : IQuickPick < IPickerQuickAccessItem > , token : CancellationToken , runOptions ?: IQuickAccessProviderRunOptions ) : IDisposable {
98+ override provide ( picker : IQuickPick < ITextSearchQuickAccessItem > , token : CancellationToken , runOptions ?: IQuickAccessProviderRunOptions ) : IDisposable {
9099 const disposables = new DisposableStore ( ) ;
91100 if ( TEXT_SEARCH_QUICK_ACCESS_PREFIX . length < picker . value . length ) {
92101 picker . valueSelection = [ TEXT_SEARCH_QUICK_ACCESS_PREFIX . length , picker . value . length ] ;
93102 }
94103 picker . customButton = true ;
95104 picker . customLabel = '$(link-external)' ;
96- picker . onDidCustom ( ( ) => {
105+ disposables . add ( picker . onDidCustom ( ( ) => {
97106 if ( this . searchModel . searchResult . count ( ) > 0 ) {
98107 this . moveToSearchViewlet ( undefined ) ;
99108 } else {
100109 this . _viewsService . openView ( VIEW_ID , true ) ;
101110 }
102111 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+
104142 disposables . add ( super . provide ( picker , token , runOptions ) ) ;
105- disposables . add ( picker . onDidHide ( ( ) => this . searchModel . searchResult . toggleHighlights ( false ) ) ) ;
106143 disposables . add ( picker . onDidAccept ( ( ) => this . searchModel . searchResult . toggleHighlights ( false ) ) ) ;
107144 return disposables ;
108145 }
@@ -177,11 +214,11 @@ export class TextSearchQuickAccess extends PickerQuickAccessProvider<IPickerQuic
177214 }
178215 }
179216
180- private _getPicksFromMatches ( matches : FileMatch [ ] , limit : number ) : ( IQuickPickSeparator | IPickerQuickAccessItem ) [ ] {
217+ private _getPicksFromMatches ( matches : FileMatch [ ] , limit : number ) : ( IQuickPickSeparator | ITextSearchQuickAccessItem ) [ ] {
181218 matches = matches . sort ( searchComparer ) ;
182219
183220 const files = matches . length > limit ? matches . slice ( 0 , limit ) : matches ;
184- const picks : Array < IPickerQuickAccessItem | IQuickPickSeparator > = [ ] ;
221+ const picks : Array < ITextSearchQuickAccessItem | IQuickPickSeparator > = [ ] ;
185222
186223 for ( let fileIndex = 0 ; fileIndex < matches . length ; fileIndex ++ ) {
187224 if ( fileIndex === limit ) {
@@ -258,7 +295,8 @@ export class TextSearchQuickAccess extends PickerQuickAccessProvider<IPickerQuic
258295 trigger : ( ) : TriggerAction => {
259296 this . moveToSearchViewlet ( element ) ;
260297 return TriggerAction . CLOSE_PICKER ;
261- }
298+ } ,
299+ match : element
262300 } ) ;
263301 }
264302 }
0 commit comments