import { Editors } from './editors' ; import { Code } from './code' ; import { QuickInput } from './quickinput' ; import { basename , isAbsolute } from 'path' ; enum QuickAccessKind { Files = 1 , Commands , Symbols } export class QuickAccess { constructor ( private code , private editors , private quickInput ) { } async openFileQuickAccessAndWait ( searchValue , expectedFirstElementNameOrExpectedResultCount ) { await this . runCommand ( 'workbench.action.clearEditorHistory' ) ; const PollingStrategy = { Stop : true , Continue : false } ; let retries = 0 ; let success = false ; while ( ++ retries < 10 ) { let retry = false ; try { await this . openQuickAccessWithRetry ( QuickAccessKind . Files , searchValue ) ; await this . quickInput . waitForQuickInputElements ( elementNames => { this . code . logger . log ( 'QuickAccess: resulting elements: ' , elementNames ) ; if ( elementNames . length === 0 ) { this . code . logger . log ( 'QuickAccess: file search returned 0 elements, will continue polling...' ) ; return PollingStrategy . Continue ; } const firstElementName = elementNames [ 0 ] ; if ( firstElementName === 'No matching results' ) { this . code . logger . log ( `QuickAccess: file search returned "No matching results", will retry...` ) ; retry = true ; return PollingStrategy . Stop ; } if ( typeof expectedFirstElementNameOrExpectedResultCount === 'number' ) { if ( elementNames . length === expectedFirstElementNameOrExpectedResultCount ) { success = true ; return PollingStrategy . Stop ; } this . code . logger . log ( `QuickAccess: file search returned ${ elementNames . length } results but was expecting ${ expectedFirstElementNameOrExpectedResultCount }, will retry...` ) ; retry = true ; return PollingStrategy . Stop ; } else { if ( firstElementName === expectedFirstElementNameOrExpectedResultCount ) { success = true ; return PollingStrategy . Stop ; } this . code . logger . log ( `QuickAccess: file search returned ${ firstElementName } as first result but was expecting ${ expectedFirstElementNameOrExpectedResultCount }, will retry...` ) ; retry = true ; return PollingStrategy . Stop ; } } ) ; } catch ( error ) { this . code . logger . log ( `QuickAccess: file search waitForQuickInputElements threw an error ${ error }, will retry...` ) ; retry = true ; } if ( ! retry ) { break ; } await this . quickInput . closeQuickInput ( ) ; } if ( ! success ) { if ( typeof expectedFirstElementNameOrExpectedResultCount === 'string' ) { throw new Error ( `Quick open file search was unable to find '${ expectedFirstElementNameOrExpectedResultCount }' after 10 attempts, giving up.` ) ; } else { throw new Error ( `Quick open file search was unable to find ${ expectedFirstElementNameOrExpectedResultCount } result items after 10 attempts, giving up.` ) ; } } } async openFile ( path ) { if ( ! isAbsolute ( path ) ) { throw new Error ( 'QuickAccess.openFile requires an absolute path' ) ; } const fileName = basename ( path ) ; await this . openFileQuickAccessAndWait ( path , basename ( path ) ) ; await this . quickInput . selectQuickInputElement ( 0 ) ; await this . editors . waitForActiveTab ( fileName ) ; await this . editors . selectTab ( fileName ) ; } private async openQuickAccessWithRetry ( kind , value ? ) { let retries = 0 ; while ( retries < 5 ) { switch ( kind ) { case QuickAccessKind . Files : await this . code . dispatchKeybinding ( process . platform === 'darwin' ? 'cmd+p' : 'ctrl+p' ) ; break ; case QuickAccessKind . Symbols : await this . code . dispatchKeybinding ( process . platform === 'darwin' ? 'cmd+shift+o' : 'ctrl+shift+o' ) ; break ; case QuickAccessKind . Commands : await this . code . dispatchKeybinding ( process . platform === 'darwin' ? 'cmd+shift+p' : 'ctrl+shift+p' ) ; break ; } try { await this . quickInput . waitForQuickInputOpened ( 10 ) ; break ; } catch ( err ) { if ( ++ retries > 5 ) { throw new Error ( `QuickAccess.openQuickAccessWithRetry(kind: ${ kind }) failed: ${ err }` ) ; } await this . code . dispatchKeybinding ( 'escape' ) ; } } if ( value ) { await this . quickInput . type ( value ) ; } } async runCommand ( commandId , keepOpen ? ) { await this . openQuickAccessWithRetry ( QuickAccessKind . Commands , `>${ commandId }` ) ; await this . quickInput . waitForQuickInputElementFocused ( ) ; await this . quickInput . selectQuickInputElement ( 0 , keepOpen ) ; } async openQuickOutline ( ) { let retries = 0 ; while ( ++ retries < 10 ) { await this . openQuickAccessWithRetry ( QuickAccessKind . Symbols ) ; const text = await this . quickInput . waitForQuickInputElementText ( ) ; if ( text === 'No symbol information for the file' ) { this . code . logger . log ( `QuickAccess: openQuickOutline indicated 'No symbol information for the file', will retry...` ) ; await this . quickInput . closeQuickInput ( ) ; continue ; } } } }