import { ChildProcess , spawn } from "child_process" ; import kill = require ( "tree-kill" ) ; import path = require ( "path" ) ; import vscode = require ( "vscode" ) ; export class CaddyfileDocumentFormattingEditProvider implements vscode . DocumentFormattingEditProvider { public provideDocumentFormattingEdits ( document , _ , token ) { if ( vscode . window . visibleTextEditors . every ( ( e ) => e . document . fileName !== document . fileName ) ) { return [ ] ; } return this . runFormatter ( document , token ) . then ( ( edits ) => edits , ( err ) => { if ( err ) { console . log ( err ) ; return Promise . reject ( "Check the console in dev tools to find errors when formatting." ) ; } } ) ; } private runFormatter ( document , token ) { const executablePath = vscode . workspace . getConfiguration ( "caddyfile" ) . get ( "executable" ) ; return new Promise < vscode . TextEdit [ ] > ( ( resolve , reject ) => { let executable ; if ( executablePath !== undefined && executablePath !== null && executablePath !== "" ) { if ( ! path . isAbsolute ( executablePath ) ) { vscode . window . showInformationMessage ( "Invalid executable path for caddy." ) ; return reject ( ) ; } executable = executablePath ; } else { executable = "caddy" ; } const cwd = path . dirname ( document . fileName ) ; let stdout = "" ; let stderr = "" ; const p = spawn ( executable , [ "fmt" , "-" ] , { cwd } ) ; token . onCancellationRequested ( ( ) => ! p . killed && killProcessTree ( p ) ) ; p . stdout . setEncoding ( "utf8" ) ; p . stdout . on ( "data" , ( data ) => ( stdout += data ) ) ; p . stderr . on ( "data" , ( data ) => ( stderr += data ) ) ; p . on ( "error" , ( err ) => { if ( err && ( < any > err ) . code === "ENOENT" ) { vscode . window . showInformationMessage ( "Caddy was not found in your $PATH" ) ; return reject ( ) ; } } ) ; p . on ( "close" , ( code ) => { if ( code !== 0 ) { return reject ( stderr ) ; } const fileStart = new vscode . Position ( 0 , 0 ) ; const fileEnd = document . lineAt ( document . lineCount - 1 ) . range . end ; const textEdits = [ new vscode . TextEdit ( new vscode . Range ( fileStart , fileEnd ) , stdout ) ] ; return resolve ( textEdits ) ; } ) ; if ( p . pid ) { p . stdin . end ( document . getText ( ) ) ; } } ) ; } } ; export function killProcessTree ( p , logger ? ) { if ( ! logger ) { logger = console . log ; } if ( ! p || ! p . pid || p . exitCode !== null ) { return Promise . resolve ( ) ; } return new Promise ( ( resolve ) => { kill ( p . pid , ( err ) => { if ( err ) { logger ( `Error killing process ${ p . pid }: ${ err }` ) ; } return resolve ( ) ; } ) ; } ) ; }