import * as fse from "fs-extra" ; import * as path from "path" ; import * as vscode from "vscode" ; import { mavenOutputChannel } from "./mavenOutputChannel" ; import { Settings } from "./Settings" ; import { executeCommand } from "./utils/cpUtils" ; export interface ITerminalOptions { addNewLine ? : boolean ; name : string ; cwd ? : string ; env ? : { [ key ] : string ; } ; workspaceFolder ? : vscode . WorkspaceFolder ; } enum ShellType { CMD = "Command Prompt" , POWERSHELL = "PowerShell" , GIT_BASH = "Git Bash" , WSL = "WSL Bash" , OTHERS = "Others" } class MavenTerminal implements vscode . Disposable { private readonly terminals : { [ id ] : vscode . Terminal ; } = { } ; public async runInTerminal ( command , options ) { const defaultOptions = { addNewLine : true , name : "Maven" } ; const { addNewLine , name , cwd , workspaceFolder } = Object . assign ( defaultOptions , options ) ; if ( this . terminals [ name ] === undefined ) { const terminalCwd = workspaceFolder ? workspaceFolder . uri : undefined ; const env = { ... Settings . getEnvironment ( terminalCwd ) , ... options . env } ; this . terminals [ name ] = vscode . window . createTerminal ( { name , env , cwd : terminalCwd } ) ; if ( currentWindowsShell ( ) === ShellType . WSL ) { setupEnvForWSL ( this . terminals [ name ] , env ) ; } } this . terminals [ name ] . show ( ) ; if ( cwd ) { this . terminals [ name ] . sendText ( await getCDCommand ( cwd ) , true ) ; } this . terminals [ name ] . sendText ( getCommand ( command ) , addNewLine ) ; return this . terminals [ name ] ; } public async formattedPathForTerminal ( filepath ) { if ( process . platform !== "win32" ) { return filepath ; } switch ( currentWindowsShell ( ) ) { case ShellType . WSL : return await toWslPath ( filepath ) ; case ShellType . POWERSHELL : { if ( path . extname ( filepath ) === "" ) { const possibleExts = [ "cmd" , "bat" ] ; for ( const ext of possibleExts ) { const amended = `${ filepath }.${ ext }` ; if ( await fse . pathExists ( amended ) ) { return amended ; } } } return filepath ; } default : return filepath ; } } public dispose ( terminalName ? ) { if ( terminalName === undefined ) { Object . keys ( this . terminals ) . forEach ( ( id ) => { this . terminals [ id ] . dispose ( ) ; delete this . terminals [ id ] ; } ) ; } else if ( this . terminals [ terminalName ] !== undefined ) { this . terminals [ terminalName ] . dispose ( ) ; delete this . terminals [ terminalName ] ; } } public find ( terminal ) { for ( const name in this . terminals ) { if ( this . terminals [ name ] === terminal ) { return name ; } } return ; } } function getCommand ( cmd ) { if ( currentWindowsShell ( ) === ShellType . POWERSHELL ) { return `& ${ cmd }` ; } else { return cmd ; } } async function getCDCommand ( cwd ) { if ( process . platform === "win32" ) { switch ( currentWindowsShell ( ) ) { case ShellType . GIT_BASH : return `cd "${ cwd . replace ( /\\+$/ , "" ) }"` ; case ShellType . POWERSHELL : const escaped = cwd . replace ( /([\[\]])/g , "``$1" ) ; return `cd "${ escaped }"` ; case ShellType . CMD : return `cd /d "${ cwd }"` ; case ShellType . WSL : return `cd "${ await toWslPath ( cwd ) }"` ; default : return `cd "${ cwd }"` ; } } else { return `cd "${ cwd }"` ; } } function currentWindowsShell ( ) { const currentWindowsShellPath = vscode . env . shell ; const binaryName = path . basename ( currentWindowsShellPath ) ; switch ( binaryName ) { case "cmd.exe" : return ShellType . CMD ; case "pwsh.exe" : case "powershell.exe" : case "pwsh" : return ShellType . POWERSHELL ; case "bash.exe" : case "wsl.exe" : if ( currentWindowsShellPath . indexOf ( "Git" ) > 0 ) { return ShellType . GIT_BASH ; } return ShellType . WSL ; default : return ShellType . OTHERS ; } } function toDefaultWslPath ( p ) { const arr = p . split ( ":\\" ) ; if ( arr . length === 2 ) { const drive = arr [ 0 ] . toLowerCase ( ) ; const dir = arr [ 1 ] . replace ( /\\/g , "/" ) ; return `/mnt/${ drive }/${ dir }` ; } else { return p . replace ( /\\/g , "/" ) ; } } export async function toWslPath ( filepath ) { if ( path . posix . isAbsolute ( filepath ) ) { return filepath ; } try { return ( await executeCommand ( "wsl" , [ "wslpath" , "-u" , `"${ filepath . replace ( /\\/g , "/" ) }"` ] ) ) . trim ( ) ; } catch ( error ) { mavenOutputChannel . appendLine ( error , "WSL" ) ; return toDefaultWslPath ( filepath ) ; } } export async function toWinPath ( filepath ) { return ( await executeCommand ( "wsl" , [ "wslpath" , "-w" , `"${ filepath }"` ] ) ) . trim ( ) ; } export const mavenTerminal = new MavenTerminal ( ) ; function setupEnvForWSL ( terminal , env ) { if ( terminal !== undefined ) { Object . keys ( env ) . forEach ( key => { terminal . sendText ( `export ${ key }="${ env [ key ] }"` , true ) ; } ) ; } }