33
44import * as fse from "fs-extra" ;
55import * as path from "path" ;
6- import { QuickPickItem , Uri , window , workspace , WorkspaceEdit } from "vscode" ;
6+ import { commands , languages , QuickPickItem , SnippetString , TextEditor , Uri , window , workspace , WorkspaceEdit , WorkspaceFolder } from "vscode" ;
7+ import { Commands } from "../../extension.bundle" ;
78import { NodeKind } from "../java/nodeData" ;
89import { DataNode } from "../views/dataNode" ;
910import { checkJavaQualifiedName } from "./utility" ;
1011
1112export async function newJavaClass ( node ?: DataNode ) : Promise < void > {
12- if ( ! node ?. uri || ! canCreateClass ( node ) ) {
13- return ;
13+ let packageFsPath : string | undefined ;
14+ if ( ! node ) {
15+ packageFsPath = await inferPackageFsPath ( ) ;
16+ } else {
17+ if ( ! node ?. uri || ! canCreateClass ( node ) ) {
18+ return ;
19+ }
20+
21+ packageFsPath = await getPackageFsPath ( node ) ;
1422 }
1523
16- const packageFsPath : string = await getPackageFsPath ( node ) ;
17- if ( ! packageFsPath ) {
24+ if ( packageFsPath === undefined ) {
25+ // User canceled
1826 return ;
27+ } else if ( packageFsPath . length === 0 ) {
28+ return newUntiledJavaFile ( ) ;
1929 }
2030
2131 const className : string | undefined = await window . showInputBox ( {
@@ -27,7 +37,7 @@ export async function newJavaClass(node?: DataNode): Promise<void> {
2737 return checkMessage ;
2838 }
2939
30- if ( await fse . pathExists ( getNewFilePath ( packageFsPath , value ) ) ) {
40+ if ( await fse . pathExists ( getNewFilePath ( packageFsPath ! , value ) ) ) {
3141 return "Class already exists." ;
3242 }
3343
@@ -47,6 +57,57 @@ export async function newJavaClass(node?: DataNode): Promise<void> {
4757 workspace . applyEdit ( workspaceEdit ) ;
4858}
4959
60+ async function newUntiledJavaFile ( ) : Promise < void > {
61+ await commands . executeCommand ( "workbench.action.files.newUntitledFile" ) ;
62+ const textEditor : TextEditor | undefined = window . activeTextEditor ;
63+ if ( ! textEditor ) {
64+ return ;
65+ }
66+ await languages . setTextDocumentLanguage ( textEditor . document , "java" ) ;
67+ const snippets : string [ ] = [ ] ;
68+ snippets . push ( `public \${1|class,interface,enum,abstract class,@interface|} \${2:Main} {` ) ;
69+ snippets . push ( `\t\${0}` ) ;
70+ snippets . push ( "}" ) ;
71+ snippets . push ( "" ) ;
72+ textEditor . insertSnippet ( new SnippetString ( snippets . join ( "\n" ) ) ) ;
73+ }
74+
75+ async function inferPackageFsPath ( ) : Promise < string > {
76+ let sourcePaths : string [ ] | undefined ;
77+ try {
78+ const result = await commands . executeCommand < IListCommandResult > ( Commands . EXECUTE_WORKSPACE_COMMAND , Commands . LIST_SOURCEPATHS ) ;
79+ if ( result && result . data && result . data . length ) {
80+ sourcePaths = result . data . map ( ( entry ) => entry . path ) ;
81+ }
82+ } catch ( e ) {
83+ // do nothing
84+ }
85+
86+ if ( ! window . activeTextEditor ) {
87+ if ( sourcePaths ?. length === 1 ) {
88+ return sourcePaths [ 0 ] ;
89+ }
90+ return "" ;
91+ }
92+
93+ const fileUri : Uri = window . activeTextEditor . document . uri ;
94+ const workspaceFolder : WorkspaceFolder | undefined = workspace . getWorkspaceFolder ( fileUri ) ;
95+ if ( ! workspaceFolder ) {
96+ return "" ;
97+ }
98+
99+ const filePath : string = window . activeTextEditor . document . uri . fsPath ;
100+ if ( sourcePaths ) {
101+ for ( const sourcePath of sourcePaths ) {
102+ if ( ! path . relative ( sourcePath , filePath ) . startsWith ( ".." ) ) {
103+ return path . dirname ( window . activeTextEditor . document . uri . fsPath ) ;
104+ }
105+ }
106+ }
107+
108+ return "" ;
109+ }
110+
50111function canCreateClass ( node : DataNode ) : boolean {
51112 if ( node . nodeData . kind === NodeKind . Project ||
52113 node . nodeData . kind === NodeKind . PackageRoot ||
@@ -58,7 +119,7 @@ function canCreateClass(node: DataNode): boolean {
58119 return false ;
59120}
60121
61- async function getPackageFsPath ( node : DataNode ) : Promise < string > {
122+ async function getPackageFsPath ( node : DataNode ) : Promise < string | undefined > {
62123 if ( node . nodeData . kind === NodeKind . Project ) {
63124 const childrenNodes : DataNode [ ] = await node . getChildren ( ) as DataNode [ ] ;
64125 const packageRoots : any [ ] = childrenNodes . filter ( ( child ) => {
@@ -90,7 +151,7 @@ async function getPackageFsPath(node: DataNode): Promise<string> {
90151 ignoreFocusOut : true ,
91152 } ,
92153 ) ;
93- return choice ? choice . fsPath : "" ;
154+ return choice ? .fsPath ;
94155 }
95156 } else if ( node . nodeData . kind === NodeKind . PrimaryType ) {
96157 return node . uri ? path . dirname ( Uri . parse ( node . uri ) . fsPath ) : "" ;
@@ -116,7 +177,7 @@ export async function newPackage(node?: DataNode): Promise<void> {
116177 const nodeKind = node . nodeData . kind ;
117178 if ( nodeKind === NodeKind . Project ) {
118179 defaultValue = "" ;
119- packageRootPath = await getPackageFsPath ( node ) ;
180+ packageRootPath = await getPackageFsPath ( node ) || "" ;
120181 } else if ( nodeKind === NodeKind . PackageRoot ) {
121182 defaultValue = "" ;
122183 packageRootPath = Uri . parse ( node . uri ) . fsPath ;
@@ -175,3 +236,16 @@ function getNewPackagePath(packageRootPath: string, packageName: string): string
175236interface ISourceRootPickItem extends QuickPickItem {
176237 fsPath : string ;
177238}
239+
240+ interface IListCommandResult {
241+ status : boolean ;
242+ message : string ;
243+ data ?: ISourcePath [ ] ;
244+ }
245+
246+ interface ISourcePath {
247+ path : string ;
248+ displayPath : string ;
249+ projectName : string ;
250+ projectType : string ;
251+ }
0 commit comments