import { References } from './peek' ; import { Commands } from './workbench' ; import { Code } from './code' ; const RENAME_BOX = '.monaco-editor .monaco-editor.rename-box' ; const RENAME_INPUT = `${ RENAME_BOX } .rename-input` ; const EDITOR = ( filename ) => `.monaco-editor[data-uri$="${ filename }"]` ; const VIEW_LINES = ( filename ) => `${ EDITOR ( filename ) } .view-lines` ; const LINE_NUMBERS = ( filename ) => `${ EDITOR ( filename ) } .margin .margin-view-overlays .line-numbers` ; export class Editor { private static readonly FOLDING_EXPANDED = '.monaco-editor .margin .margin-view-overlays>:nth-child(${INDEX}) .folding' ; private static readonly FOLDING_COLLAPSED = `${ Editor . FOLDING_EXPANDED }.collapsed` ; constructor ( private code , private commands ) { } async findReferences ( filename , term , line ) { await this . clickOnTerm ( filename , term , line ) ; await this . commands . runCommand ( 'Peek References' ) ; const references = new References ( this . code ) ; await references . waitUntilOpen ( ) ; return references ; } async rename ( filename , line , from , to ) { await this . clickOnTerm ( filename , from , line ) ; await this . commands . runCommand ( 'Rename Symbol' ) ; await this . code . waitForActiveElement ( RENAME_INPUT ) ; await this . code . waitForSetValue ( RENAME_INPUT , to ) ; await this . code . dispatchKeybinding ( 'enter' ) ; } async gotoDefinition ( filename , term , line ) { await this . clickOnTerm ( filename , term , line ) ; await this . commands . runCommand ( 'Go to Implementations' ) ; } async peekDefinition ( filename , term , line ) { await this . clickOnTerm ( filename , term , line ) ; await this . commands . runCommand ( 'Peek Definition' ) ; const peek = new References ( this . code ) ; await peek . waitUntilOpen ( ) ; return peek ; } private async getSelector ( filename , term , line ) { const lineIndex = await this . getViewLineIndex ( filename , line ) ; const classNames = await this . getClassSelectors ( filename , term , lineIndex ) ; return `${ VIEW_LINES ( filename ) }>:nth-child(${ lineIndex }) span span.${ classNames [ 0 ] }` ; } async foldAtLine ( filename , line ) { const lineIndex = await this . getViewLineIndex ( filename , line ) ; await this . code . waitAndClick ( Editor . FOLDING_EXPANDED . replace ( '${INDEX}' , '' + lineIndex ) ) ; await this . code . waitForElement ( Editor . FOLDING_COLLAPSED . replace ( '${INDEX}' , '' + lineIndex ) ) ; } async unfoldAtLine ( filename , line ) { const lineIndex = await this . getViewLineIndex ( filename , line ) ; await this . code . waitAndClick ( Editor . FOLDING_COLLAPSED . replace ( '${INDEX}' , '' + lineIndex ) ) ; await this . code . waitForElement ( Editor . FOLDING_EXPANDED . replace ( '${INDEX}' , '' + lineIndex ) ) ; } private async clickOnTerm ( filename , term , line ) { const selector = await this . getSelector ( filename , term , line ) ; await this . code . waitAndClick ( selector ) ; } async waitForEditorFocus ( filename , lineNumber , selectorPrefix = '' ) { const editor = [ selectorPrefix || '' , EDITOR ( filename ) ] . join ( ' ' ) ; const line = `${ editor } .view-lines > .view-line:nth-child(${ lineNumber })` ; const textarea = `${ editor } textarea` ; await this . code . waitAndClick ( line , 1 , 1 ) ; await this . code . waitForActiveElement ( textarea ) ; } async waitForTypeInEditor ( filename , text , selectorPrefix = '' ) { const editor = [ selectorPrefix || '' , EDITOR ( filename ) ] . join ( ' ' ) ; await this . code . waitForElement ( editor ) ; const textarea = `${ editor } textarea` ; await this . code . waitForActiveElement ( textarea ) ; await this . code . waitForTypeInEditor ( textarea , text ) ; await this . waitForEditorContents ( filename , c => c . indexOf ( text ) > - 1 , selectorPrefix ) ; } async waitForEditorContents ( filename , accept , selectorPrefix = '' ) { const selector = [ selectorPrefix || '' , `${ EDITOR ( filename ) } .view-lines` ] . join ( ' ' ) ; return this . code . waitForTextContent ( selector , undefined , c => accept ( c . replace ( /\u00a0/g , ' ' ) ) ) ; } private async getClassSelectors ( filename , term , viewline ) { const elements = await this . code . waitForElements ( `${ VIEW_LINES ( filename ) }>:nth-child(${ viewline }) span span` , false , els => els . some ( el => el . textContent === term ) ) ; const { className } = elements . filter ( r => r . textContent === term ) [ 0 ] ; return className . split ( /\s/g ) ; } private async getViewLineIndex ( filename , line ) { const elements = await this . code . waitForElements ( LINE_NUMBERS ( filename ) , false , els => { return els . some ( el => el . textContent === `${ line }` ) ; } ) ; for ( let index = 0 ; index < elements . length ; index ++ ) { if ( elements [ index ] . textContent === `${ line }` ) { return index + 1 ; } } throw new Error ( 'Line not found' ) ; } }