import os = require ( 'os' ) ; import fs = require ( 'fs' ) ; import net = require ( 'net' ) ; import path = require ( 'path' ) ; import utils = require ( './utils' ) ; import stream = require ( 'stream' ) ; import cp = require ( 'child_process' ) ; import { Logger } from './logging' ; import { Disposable } from 'atom' ; import { EventEmitter } from 'events' ; import { ITerminal , ITerminalService } from './terminalService' ; export interface LanguageServerProcess extends EventEmitter { stderr : stream . Readable ; pid : number ; kill ( signal ? ) : void ; on ( event , listener ) : this ; on ( event , listener ) : this ; } export class PowerShellProcess { private languageServerProcess : LanguageServerProcess ; private consoleTerminal : ITerminal = undefined ; private consoleCloseSubscription : Disposable ; private sessionDetails : utils . EditorServicesSessionDetails ; constructor ( public exePath , private title , private log , private startArgs , private sessionFilePath , private sessionSettings , private terminalTabService ) { } public start ( logFileName ) { return new Promise < utils . EditorServicesSessionDetails > ( ( resolve , reject ) => { try { let startScriptPath = path . resolve ( __dirname , '../scripts/Start-EditorServices.ps1' ) ; var editorServicesLogPath = this . log . getLogFilePath ( logFileName ) ; var featureFlags = "" ; this . sessionSettings . developer . featureFlags !== undefined ? this . sessionSettings . developer . featureFlags . map ( f => `'${ f }'` ) . join ( ', ' ) : "" ; this . startArgs += `-LogPath '${ editorServicesLogPath }' ` + `-SessionDetailsPath '${ this . sessionFilePath }' ` + `-FeatureFlags @(${ featureFlags })` ; var powerShellArgs = [ "-NoProfile" , "-NonInteractive" ] ; if ( utils . isWindowsOS ( ) ) { powerShellArgs . push ( "-ExecutionPolicy" , "Bypass" ) ; } powerShellArgs . push ( "-Command" , "& '" + startScriptPath + "' " + this . startArgs ) ; var powerShellExePath = this . exePath ; this . log . write ( "Language server starting --" , "    exe: " + powerShellExePath , "    args: " + startScriptPath + ' ' + this . startArgs ) ; utils . deleteSessionFile ( this . sessionFilePath ) ; this . terminalTabService . openTerminal ( { shell : powerShellExePath , args : powerShellArgs , title : this . title } ) . then ( ( terminal ) => { this . consoleTerminal = terminal ; this . languageServerProcess = this . createLanguageServerProcess ( this . consoleTerminal . getProcess ( ) ) ; utils . waitForSessionFile ( this . sessionFilePath , ( sessionDetails , error ) => { utils . deleteSessionFile ( this . sessionFilePath ) ; if ( error ) { reject ( error ) ; } else { this . sessionDetails = sessionDetails ; resolve ( this . sessionDetails ) ; } } ) ; } ) ; } catch ( e ) { reject ( e ) ; } } ) ; } public getProcess ( ) { return this . languageServerProcess ; } public showConsole ( preserveFocus ) { if ( this . consoleTerminal ) { this . consoleTerminal . show ( preserveFocus ) ; } } public dispose ( ) { utils . deleteSessionFile ( this . sessionFilePath ) ; if ( this . consoleCloseSubscription ) { this . consoleCloseSubscription . dispose ( ) ; this . consoleCloseSubscription = undefined ; } if ( this . consoleTerminal ) { this . log . write ( "Terminating PowerShell process..." ) ; this . consoleTerminal . dispose ( ) ; this . consoleTerminal = undefined ; } } private createLanguageServerProcess ( pty ) { class PSLanguageServerProcess extends EventEmitter implements LanguageServerProcess { public stderr : stream . Readable ; public pid : number ; constructor ( private pty , private log ) { super ( ) ; var Readable = require ( 'stream' ) . Readable ; this . stderr = new Readable ( ) ; this . stderr . _read = function fake ( ) { } ; pty . on ( 'exit' , this . handleExit . bind ( this ) ) ; pty . on ( 'error' , this . handleError . bind ( this ) ) ; } public kill ( signal ? ) { this . pty . kill ( signal ) ; } private handleExit ( code , signal ) { this . log . write ( `powershell.exe exited: code ${ code }, signal ${ signal }` ) ; this . emit ( 'exit' , code , signal ) ; } private handleError ( err ) { if ( err . message === 'read EIO' ) { } else { this . log . writeError ( "powershell.exe exited due to an error:" , err . toString ( ) ) ; this . emit ( 'error' , err ) ; } } } return new PSLanguageServerProcess ( pty , this . log ) ; } }