3
3
4
4
import * as fse from "fs-extra" ;
5
5
import * 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" ;
7
8
import { NodeKind } from "../java/nodeData" ;
8
9
import { DataNode } from "../views/dataNode" ;
9
10
import { checkJavaQualifiedName } from "./utility" ;
10
11
11
12
export 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 ) ;
14
22
}
15
23
16
- const packageFsPath : string = await getPackageFsPath ( node ) ;
17
- if ( ! packageFsPath ) {
24
+ if ( packageFsPath === undefined ) {
25
+ // User canceled
18
26
return ;
27
+ } else if ( packageFsPath . length === 0 ) {
28
+ return newUntiledJavaFile ( ) ;
19
29
}
20
30
21
31
const className : string | undefined = await window . showInputBox ( {
@@ -27,7 +37,7 @@ export async function newJavaClass(node?: DataNode): Promise<void> {
27
37
return checkMessage ;
28
38
}
29
39
30
- if ( await fse . pathExists ( getNewFilePath ( packageFsPath , value ) ) ) {
40
+ if ( await fse . pathExists ( getNewFilePath ( packageFsPath ! , value ) ) ) {
31
41
return "Class already exists." ;
32
42
}
33
43
@@ -47,6 +57,57 @@ export async function newJavaClass(node?: DataNode): Promise<void> {
47
57
workspace . applyEdit ( workspaceEdit ) ;
48
58
}
49
59
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
+
50
111
function canCreateClass ( node : DataNode ) : boolean {
51
112
if ( node . nodeData . kind === NodeKind . Project ||
52
113
node . nodeData . kind === NodeKind . PackageRoot ||
@@ -58,7 +119,7 @@ function canCreateClass(node: DataNode): boolean {
58
119
return false ;
59
120
}
60
121
61
- async function getPackageFsPath ( node : DataNode ) : Promise < string > {
122
+ async function getPackageFsPath ( node : DataNode ) : Promise < string | undefined > {
62
123
if ( node . nodeData . kind === NodeKind . Project ) {
63
124
const childrenNodes : DataNode [ ] = await node . getChildren ( ) as DataNode [ ] ;
64
125
const packageRoots : any [ ] = childrenNodes . filter ( ( child ) => {
@@ -90,7 +151,7 @@ async function getPackageFsPath(node: DataNode): Promise<string> {
90
151
ignoreFocusOut : true ,
91
152
} ,
92
153
) ;
93
- return choice ? choice . fsPath : "" ;
154
+ return choice ? .fsPath ;
94
155
}
95
156
} else if ( node . nodeData . kind === NodeKind . PrimaryType ) {
96
157
return node . uri ? path . dirname ( Uri . parse ( node . uri ) . fsPath ) : "" ;
@@ -116,7 +177,7 @@ export async function newPackage(node?: DataNode): Promise<void> {
116
177
const nodeKind = node . nodeData . kind ;
117
178
if ( nodeKind === NodeKind . Project ) {
118
179
defaultValue = "" ;
119
- packageRootPath = await getPackageFsPath ( node ) ;
180
+ packageRootPath = await getPackageFsPath ( node ) || "" ;
120
181
} else if ( nodeKind === NodeKind . PackageRoot ) {
121
182
defaultValue = "" ;
122
183
packageRootPath = Uri . parse ( node . uri ) . fsPath ;
@@ -175,3 +236,16 @@ function getNewPackagePath(packageRootPath: string, packageName: string): string
175
236
interface ISourceRootPickItem extends QuickPickItem {
176
237
fsPath : string ;
177
238
}
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