Skip to content

Commit dd8845c

Browse files
Add 'New Java File' menu to file explorer & adjust the existing file explorer menu order (#820)
1 parent 6b8d8ee commit dd8845c

File tree

5 files changed

+117
-20
lines changed

5 files changed

+117
-20
lines changed

.azure-pipelines/nightly.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ extends:
7070
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2
7171
displayName: ESRP CodeSigning
7272
inputs:
73-
ConnectedServiceName: vscjavaci_codesign
73+
ConnectedServiceName: vscjavaci_esrp_codesign
7474
FolderPath: server
7575
Pattern: com.microsoft.jdtls.ext.*.jar
7676
signConfigType: inlineSignParams

.azure-pipelines/rc.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ extends:
6565
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@2
6666
displayName: ESRP CodeSigning
6767
inputs:
68-
ConnectedServiceName: vscjavaci_codesign
68+
ConnectedServiceName: vscjavaci_esrp_codesign
6969
FolderPath: server
7070
Pattern: com.microsoft.jdtls.ext.*.jar
7171
signConfigType: inlineSignParams

package.json

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -547,17 +547,22 @@
547547
{
548548
"command": "java.view.package.revealInProjectExplorer",
549549
"when": "resourceFilename =~ /(.*\\.gradle)|(.*\\.gradle\\.kts)|(pom\\.xml)$/ && java:serverMode == Standard",
550-
"group": "navigation@100"
550+
"group": "1_javaactions"
551551
},
552552
{
553553
"command": "java.view.package.revealInProjectExplorer",
554554
"when": "resourceExtname == .java && java:serverMode == Standard",
555-
"group": "navigation@100"
555+
"group": "1_javaactions"
556556
},
557557
{
558558
"command": "_java.project.create.from.fileexplorer.menu",
559559
"when": "explorerResourceIsFolder",
560-
"group": "navigation@10"
560+
"group": "1_javaactions"
561+
},
562+
{
563+
"submenu": "javaProject.newJavaFile",
564+
"when": "explorerResourceIsFolder",
565+
"group": "1_javaactions"
561566
}
562567
],
563568
"editor/title": [
@@ -791,6 +796,38 @@
791796
"group": "new2@40",
792797
"when": "view == javaProjectExplorer && (viewItem =~ /java:(file|folder|project)/ || viewItem =~ /java:(packageRoot)(?=.*?\\b\\+resource\\b)/)"
793798
}
799+
],
800+
"javaProject.newJavaFile": [
801+
{
802+
"command": "java.view.package.newJavaClass",
803+
"group": "new@10",
804+
"when": "explorerResourceIsFolder"
805+
},
806+
{
807+
"command": "java.view.package.newJavaInterface",
808+
"group": "new@20",
809+
"when": "explorerResourceIsFolder"
810+
},
811+
{
812+
"command": "java.view.package.newJavaEnum",
813+
"group": "new@30",
814+
"when": "explorerResourceIsFolder"
815+
},
816+
{
817+
"command": "java.view.package.newJavaRecord",
818+
"group": "new@40",
819+
"when": "explorerResourceIsFolder"
820+
},
821+
{
822+
"command": "java.view.package.newJavaAnnotation",
823+
"group": "new@50",
824+
"when": "explorerResourceIsFolder"
825+
},
826+
{
827+
"command": "java.view.package.newJavaAbstractClass",
828+
"group": "new@60",
829+
"when": "explorerResourceIsFolder"
830+
}
794831
]
795832
},
796833
"submenus": [
@@ -805,6 +842,10 @@
805842
{
806843
"id": "javaProject.new",
807844
"label": "%contributes.submenus.javaProject.new%"
845+
},
846+
{
847+
"id": "javaProject.newJavaFile",
848+
"label": "%contributes.commands.java.view.menus.file.newJavaClass%"
808849
}
809850
],
810851
"views": {

src/explorerCommands/new.ts

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { NodeKind } from "../java/nodeData";
1212
import { DataNode } from "../views/dataNode";
1313
import { resourceRoots } from "../views/packageRootNode";
1414
import { checkJavaQualifiedName } from "./utility";
15-
import { sendError, setUserError } from "vscode-extension-telemetry-wrapper";
15+
import { sendError, sendInfo, setUserError } from "vscode-extension-telemetry-wrapper";
1616

1717
// tslint:disable no-var-requires
1818
const stringInterpolate = require("fmtr");
@@ -134,7 +134,7 @@ export async function newJavaFile(): Promise<void> {
134134
return newUntitledJavaFile();
135135
}
136136

137-
const includeRecord = !(await isVersionLessThan(Uri.file(packageFsPath).toString(), 16));
137+
const includeRecord = isLanguageServerReady() && !(await isVersionLessThan(Uri.file(packageFsPath).toString(), 16));
138138
const supportedTypes: string[] = JavaType.getDisplayNames(true, includeRecord);
139139
const typeName: string | undefined = await window.showQuickPick(supportedTypes,
140140
{
@@ -148,12 +148,18 @@ export async function newJavaFile(): Promise<void> {
148148
newJavaFile0(packageFsPath, JavaType.fromDisplayName(typeName));
149149
}
150150

151-
// Create a new Java file from the context menu of Java Projects view.
152-
export async function newJavaFileWithSpecificType(javaType: JavaType, node?: DataNode): Promise<void> {
151+
// Create a new Java file from the context menu of Java Projects view or File Explorer.
152+
export async function newJavaFileWithSpecificType(javaType: JavaType, node?: DataNode | Uri): Promise<void> {
153+
sendInfo("", {
154+
"triggernewfilefrom": (node instanceof Uri && node?.fsPath) ? "fileExplorer" : "javaProjectExplorer",
155+
"javatype": javaType.label,
156+
});
153157
let packageFsPath: string | undefined;
154158
if (!node) {
155159
packageFsPath = await inferPackageFsPath();
156-
} else {
160+
} else if (node instanceof Uri && node?.fsPath) { // File Explorer
161+
packageFsPath = node?.fsPath;
162+
} else if (node instanceof DataNode) { // Java Projects view
157163
if (!node?.uri || !canCreateClass(node)) {
158164
return;
159165
}
@@ -292,19 +298,27 @@ async function newUntitledJavaFile(): Promise<void> {
292298
textEditor.insertSnippet(new SnippetString(snippets.join("\n")));
293299
}
294300

295-
async function inferPackageFsPath(): Promise<string> {
301+
function isLanguageServerReady(): boolean {
296302
const javaLanguageSupport: Extension<any> | undefined = extensions.getExtension(ExtensionName.JAVA_LANGUAGE_SUPPORT);
297303
if (!javaLanguageSupport || !javaLanguageSupport.isActive) {
298-
return "";
304+
return false;
299305
}
300306

301307
const extensionApi: any = javaLanguageSupport.exports;
302308
if (!extensionApi) {
303-
return "";
309+
return false;
304310
}
305311

306312
if (extensionApi.serverMode !== "Standard" || extensionApi.status !== "Started") {
307-
return "";
313+
return false;
314+
}
315+
316+
return true;
317+
}
318+
319+
async function inferPackageFsPath(): Promise<string> {
320+
if (!isLanguageServerReady()) {
321+
return getPackageFsPathFromActiveEditor();
308322
}
309323

310324
let sourcePaths: string[] | undefined;
@@ -342,6 +356,25 @@ async function inferPackageFsPath(): Promise<string> {
342356
return "";
343357
}
344358

359+
function getPackageFsPathFromActiveEditor() {
360+
if (!window.activeTextEditor) {
361+
return "";
362+
}
363+
364+
const fileUri: Uri = window.activeTextEditor.document.uri;
365+
const workspaceFolder: WorkspaceFolder | undefined = workspace.getWorkspaceFolder(fileUri);
366+
if (!workspaceFolder) {
367+
return "";
368+
}
369+
370+
const filePath: string = window.activeTextEditor.document.uri.fsPath;
371+
if (filePath.endsWith(".java")) {
372+
return path.dirname(filePath);
373+
}
374+
375+
return "";
376+
}
377+
345378
function canCreateClass(node: DataNode): boolean {
346379
if (node.nodeData.kind === NodeKind.Project ||
347380
node.nodeData.kind === NodeKind.PackageRoot ||
@@ -383,6 +416,10 @@ async function isVersionLessThan(fileUri: string, targetVersion: number): Promis
383416
}
384417

385418
async function resolvePackageName(filePath: string): Promise<string> {
419+
if (!isLanguageServerReady()) {
420+
return guessPackageName(filePath);
421+
}
422+
386423
let sourcePaths: string[] = [];
387424
const result: IListCommandResult =
388425
await commands.executeCommand<IListCommandResult>(Commands.EXECUTE_WORKSPACE_COMMAND, Commands.LIST_SOURCEPATHS);
@@ -404,6 +441,25 @@ async function resolvePackageName(filePath: string): Promise<string> {
404441
return "";
405442
}
406443

444+
function guessPackageName(filePath: string): string {
445+
const packagePath: string = path.dirname(filePath);
446+
const knownSourcePathPrefixes: string[] = [
447+
"src/main/java/",
448+
"src/test/java/",
449+
"src\\main\\java\\",
450+
"src\\test\\java\\",
451+
];
452+
453+
for (const prefix of knownSourcePathPrefixes) {
454+
const index: number = packagePath.lastIndexOf(prefix);
455+
if (index > -1) {
456+
return packagePath.substring(index + prefix.length).replace(/[\\\/]/g, ".");
457+
}
458+
}
459+
460+
return "";
461+
}
462+
407463
function isPrefix(parentPath: string, filePath: string): boolean {
408464
const relative = path.relative(parentPath, filePath);
409465
return !relative || (!relative.startsWith('..') && !path.isAbsolute(relative));

src/views/dependencyExplorer.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,22 +116,22 @@ export class DependencyExplorer implements Disposable {
116116
instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_NEW, async (node: DataNode) => {
117117
newResource(node);
118118
}),
119-
instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_NEW_JAVA_CLASS, async (node?: DataNode) => {
119+
instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_NEW_JAVA_CLASS, async (node?: DataNode | Uri) => {
120120
newJavaFileWithSpecificType(JavaType.CLASS, node);
121121
}),
122-
instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_NEW_JAVA_INTERFACE, async (node?: DataNode) => {
122+
instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_NEW_JAVA_INTERFACE, async (node?: DataNode | Uri) => {
123123
newJavaFileWithSpecificType(JavaType.INTERFACE, node);
124124
}),
125-
instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_NEW_JAVA_ENUM, async (node?: DataNode) => {
125+
instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_NEW_JAVA_ENUM, async (node?: DataNode | Uri) => {
126126
newJavaFileWithSpecificType(JavaType.ENUM, node);
127127
}),
128-
instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_NEW_JAVA_RECORD, async (node?: DataNode) => {
128+
instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_NEW_JAVA_RECORD, async (node?: DataNode | Uri) => {
129129
newJavaFileWithSpecificType(JavaType.RECORD, node);
130130
}),
131-
instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_NEW_JAVA_ANNOTATION, async (node?: DataNode) => {
131+
instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_NEW_JAVA_ANNOTATION, async (node?: DataNode | Uri) => {
132132
newJavaFileWithSpecificType(JavaType.ANNOTATION, node);
133133
}),
134-
instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_NEW_JAVA_ABSTRACT_CLASS, async (node?: DataNode) => {
134+
instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_NEW_JAVA_ABSTRACT_CLASS, async (node?: DataNode | Uri) => {
135135
newJavaFileWithSpecificType(JavaType.ABSTRACT_CLASS, node);
136136
}),
137137
instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_NEW_FILE, async (node: DataNode) => {

0 commit comments

Comments
 (0)