import * as fse from "fs-extra" ; import * as path from "path" ; import { commands , Extension , extensions , languages , QuickPickItem , SnippetString , TextEditor , Uri , window , workspace , WorkspaceEdit , WorkspaceFolder } from "vscode" ; import { sendInfo } from "vscode-extension-telemetry-wrapper" ; import { Commands } from "../../extension.bundle" ; import { ExtensionName } from "../constants" ; import { NodeKind } from "../java/nodeData" ; import { DataNode } from "../views/dataNode" ; import { checkJavaQualifiedName } from "./utility" ; export async function newJavaClass ( node ? ) { let packageFsPath ; if ( ! node ) { sendInfo ( "" , { triggerNewFileFrom : "menuBar" , } ) ; packageFsPath = await inferPackageFsPath ( ) ; } else { sendInfo ( "" , { triggerNewFileFrom : "projectExplorer" , } ) ; if ( ! node ?. uri || ! canCreateClass ( node ) ) { return ; } packageFsPath = await getPackageFsPath ( node ) ; } if ( packageFsPath === undefined ) { return ; } else if ( packageFsPath . length === 0 ) { return newUntiledJavaFile ( ) ; } const className = await window . showInputBox ( { placeHolder : "Input the class name" , ignoreFocusOut : true , validateInput : async ( value ) : Promise < string > => { const checkMessage = checkJavaQualifiedName ( value ) ; if ( checkMessage ) { return checkMessage ; } if ( await fse . pathExists ( getNewFilePath ( packageFsPath ! , value ) ) ) { return "Class already exists." ; } return "" ; } , } ) ; if ( ! className ) { return ; } const workspaceEdit = new WorkspaceEdit ( ) ; const fsPath = getNewFilePath ( packageFsPath , className ) ; workspaceEdit . createFile ( Uri . file ( fsPath ) ) ; workspace . applyEdit ( workspaceEdit ) ; } async function newUntiledJavaFile ( ) { await commands . executeCommand ( "workbench.action.files.newUntitledFile" ) ; const textEditor = window . activeTextEditor ; if ( ! textEditor ) { return ; } await languages . setTextDocumentLanguage ( textEditor . document , "java" ) ; const snippets = [ ] ; snippets . push ( `public \${1|class,interface,enum,abstract class,@interface|} \${2:Main} {` ) ; snippets . push ( `\t\${0}` ) ; snippets . push ( "}" ) ; snippets . push ( "" ) ; textEditor . insertSnippet ( new SnippetString ( snippets . join ( "\n" ) ) ) ; } async function inferPackageFsPath ( ) { const javaLanguageSupport = extensions . getExtension ( ExtensionName . JAVA_LANGUAGE_SUPPORT ) ; if ( ! javaLanguageSupport || ! javaLanguageSupport . isActive ) { return "" ; } const extensionApi = javaLanguageSupport . exports ; if ( ! extensionApi ) { return "" ; } if ( extensionApi . serverMode !== "Standard" || extensionApi . status !== "Started" ) { return "" ; } let sourcePaths ; try { const result = await commands . executeCommand < IListCommandResult > ( Commands . EXECUTE_WORKSPACE_COMMAND , Commands . LIST_SOURCEPATHS ) ; if ( result && result . data && result . data . length ) { sourcePaths = result . data . map ( ( entry ) => entry . path ) ; } } catch ( e ) { } if ( ! window . activeTextEditor ) { if ( sourcePaths ?. length === 1 ) { return sourcePaths [ 0 ] ; } return "" ; } const fileUri = window . activeTextEditor . document . uri ; const workspaceFolder = workspace . getWorkspaceFolder ( fileUri ) ; if ( ! workspaceFolder ) { return "" ; } const filePath = window . activeTextEditor . document . uri . fsPath ; if ( sourcePaths ) { for ( const sourcePath of sourcePaths ) { if ( ! path . relative ( sourcePath , filePath ) . startsWith ( ".." ) ) { return path . dirname ( window . activeTextEditor . document . uri . fsPath ) ; } } } return "" ; } function canCreateClass ( node ) { if ( node . nodeData . kind === NodeKind . Project || node . nodeData . kind === NodeKind . PackageRoot || node . nodeData . kind === NodeKind . Package || node . nodeData . kind === NodeKind . PrimaryType ) { return true ; } return false ; } async function getPackageFsPath ( node ) { if ( node . nodeData . kind === NodeKind . Project ) { const childrenNodes = await node . getChildren ( ) as DataNode [ ] ; const packageRoots = childrenNodes . filter ( ( child ) => { return child . nodeData . kind === NodeKind . PackageRoot ; } ) ; if ( packageRoots . length < 1 ) { const packageNode = childrenNodes . find ( ( child ) => { return child . nodeData . kind === NodeKind . Package ; } ) ; if ( ! packageNode && node . uri ) { return Uri . parse ( node . uri ) . fsPath ; } else if ( packageNode ?. uri ) { return getPackageRootPath ( Uri . parse ( packageNode . uri ) . fsPath , packageNode . name ) ; } return "" ; } else if ( packageRoots . length === 1 ) { return Uri . parse ( packageRoots [ 0 ] . uri ) . fsPath ; } else { const options = packageRoots . map ( ( root ) => { return { label : root . name , fsPath : Uri . parse ( root . uri ) . fsPath , } ; } ) ; const choice = await window . showQuickPick ( options , { placeHolder : "Choose a source folder" , ignoreFocusOut : true , } ) ; return choice ?. fsPath ; } } else if ( node . nodeData . kind === NodeKind . PrimaryType ) { return node . uri ? path . dirname ( Uri . parse ( node . uri ) . fsPath ) : "" ; } return node . uri ? Uri . parse ( node . uri ) . fsPath : "" ; } function getNewFilePath ( basePath , className ) { if ( className . endsWith ( ".java" ) ) { className = className . substr ( 0 , className . length - ".java" . length ) ; } return path . join ( basePath , ... className . split ( "." ) ) + ".java" ; } export async function newPackage ( node ? ) { if ( ! node ?. uri || ! canCreatePackage ( node ) ) { return ; } let defaultValue ; let packageRootPath ; const nodeKind = node . nodeData . kind ; if ( nodeKind === NodeKind . Project ) { defaultValue = "" ; packageRootPath = await getPackageFsPath ( node ) || "" ; } else if ( nodeKind === NodeKind . PackageRoot ) { defaultValue = "" ; packageRootPath = Uri . parse ( node . uri ) . fsPath ; } else if ( nodeKind === NodeKind . Package ) { defaultValue = node . nodeData . name + "." ; packageRootPath = getPackageRootPath ( Uri . parse ( node . uri ) . fsPath , node . nodeData . name ) ; } else { return ; } const packageName = await window . showInputBox ( { value : defaultValue , placeHolder : "Input the package name" , valueSelection : [ defaultValue . length , defaultValue . length ] , ignoreFocusOut : true , validateInput : async ( value ) : Promise < string > => { const checkMessage = checkJavaQualifiedName ( value ) ; if ( checkMessage ) { return checkMessage ; } if ( await fse . pathExists ( getNewPackagePath ( packageRootPath , value ) ) ) { return "Package already exists." ; } return "" ; } , } ) ; if ( ! packageName ) { return ; } await fse . ensureDir ( getNewPackagePath ( packageRootPath , packageName ) ) ; } function canCreatePackage ( node ) { if ( node . nodeData . kind === NodeKind . Project || node . nodeData . kind === NodeKind . PackageRoot || node . nodeData . kind === NodeKind . Package ) { return true ; } return false ; } function getPackageRootPath ( packageFsPath , packageName ) { const numberOfSegment = packageName . split ( "." ) . length ; return path . join ( packageFsPath , ... Array ( numberOfSegment ) . fill ( ".." ) ) ; } function getNewPackagePath ( packageRootPath , packageName ) { return path . join ( packageRootPath , ... packageName . split ( "." ) ) ; } interface ISourceRootPickItem extends QuickPickItem { fsPath : string ; } interface IListCommandResult { status : boolean ; message : string ; data ? : ISourcePath [ ] ; } interface ISourcePath { path : string ; displayPath : string ; projectName : string ; projectType : string ; }