Skip to content

Commit f2dfc46

Browse files
authored
feat - Suppport create package from file explorer (#845)
1 parent 0904e07 commit f2dfc46

File tree

5 files changed

+132
-54
lines changed

5 files changed

+132
-54
lines changed

package.json

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,11 @@
257257
"title": "%contributes.commands.java.view.package.newPackage%",
258258
"category": "Java"
259259
},
260+
{
261+
"command": "java.view.fileExplorer.newPackage",
262+
"title": "%contributes.commands.java.view.fileExplorer.newPackage%",
263+
"category": "Java"
264+
},
260265
{
261266
"command": "java.view.package.newFile",
262267
"title": "%contributes.commands.java.view.package.newFile%",
@@ -502,6 +507,10 @@
502507
"command": "java.view.package.deleteFilePermanently",
503508
"when": "false"
504509
},
510+
{
511+
"command": "java.view.fileExplorer.newPackage",
512+
"when": "false"
513+
},
505514
{
506515
"command": "java.project.build.workspace",
507516
"when": "false"
@@ -545,24 +554,29 @@
545554
],
546555
"explorer/context": [
547556
{
548-
"command": "java.view.package.revealInProjectExplorer",
549-
"when": "resourceFilename =~ /(.*\\.gradle)|(.*\\.gradle\\.kts)|(pom\\.xml)$/ && java:serverMode == Standard",
550-
"group": "1_javaactions"
557+
"submenu": "javaProject.newJavaFile",
558+
"when": "explorerResourceIsFolder",
559+
"group": "1_javaactions@10"
551560
},
552561
{
553-
"command": "java.view.package.revealInProjectExplorer",
554-
"when": "resourceExtname == .java && java:serverMode == Standard",
555-
"group": "1_javaactions"
562+
"command": "java.view.fileExplorer.newPackage",
563+
"when": "explorerResourceIsFolder",
564+
"group": "1_javaactions@20"
556565
},
557566
{
558567
"command": "_java.project.create.from.fileexplorer.menu",
559568
"when": "explorerResourceIsFolder",
560-
"group": "1_javaactions"
569+
"group": "1_javaactions@30"
561570
},
562571
{
563-
"submenu": "javaProject.newJavaFile",
564-
"when": "explorerResourceIsFolder",
565-
"group": "1_javaactions"
572+
"command": "java.view.package.revealInProjectExplorer",
573+
"when": "resourceFilename =~ /(.*\\.gradle)|(.*\\.gradle\\.kts)|(pom\\.xml)$/ && java:serverMode == Standard",
574+
"group": "1_javaactions@40"
575+
},
576+
{
577+
"command": "java.view.package.revealInProjectExplorer",
578+
"when": "resourceExtname == .java && java:serverMode == Standard",
579+
"group": "1_javaactions@40"
566580
}
567581
],
568582
"editor/title": [

package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"contributes.commands.java.view.package.renameFile": "Rename",
3636
"contributes.commands.java.view.package.moveFileToTrash": "Delete",
3737
"contributes.commands.java.view.package.deleteFilePermanently": "Delete Permanently",
38+
"contributes.commands.java.view.fileExplorer.newPackage": "New Java Package...",
3839
"contributes.submenus.javaProject.new": "New",
3940
"contributes.commands.java.view.menus.file.newJavaClass": "New Java File",
4041
"configuration.java.dependency.showMembers": "Show the members in the explorer",

src/commands.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ export namespace Commands {
5454

5555
export const VIEW_PACKAGE_NEW_JAVA_PACKAGE = "java.view.package.newPackage";
5656

57+
export const VIEW_EXPLORER_NEW_PACKAGE = "java.view.fileExplorer.newPackage";
58+
5759
export const VIEW_PACKAGE_RENAME_FILE = "java.view.package.renameFile";
5860

5961
export const VIEW_PACKAGE_MOVE_FILE_TO_TRASH = "java.view.package.moveFileToTrash";

src/explorerCommands/new.ts

Lines changed: 102 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -321,15 +321,7 @@ async function inferPackageFsPath(): Promise<string> {
321321
return getPackageFsPathFromActiveEditor();
322322
}
323323

324-
let sourcePaths: string[] | undefined;
325-
try {
326-
const result = await commands.executeCommand<IListCommandResult>(Commands.EXECUTE_WORKSPACE_COMMAND, Commands.LIST_SOURCEPATHS);
327-
if (result && result.data && result.data.length) {
328-
sourcePaths = result.data.map((entry) => entry.path);
329-
}
330-
} catch (e) {
331-
// do nothing
332-
}
324+
let sourcePaths: string[] | undefined = (await getSourceRoots())?.data?.map((sourcePath) => sourcePath.path);
333325

334326
if (!window.activeTextEditor) {
335327
if (sourcePaths?.length === 1) {
@@ -420,14 +412,10 @@ async function resolvePackageName(filePath: string): Promise<string> {
420412
return guessPackageName(filePath);
421413
}
422414

423-
let sourcePaths: string[] = [];
424-
const result: IListCommandResult =
425-
await commands.executeCommand<IListCommandResult>(Commands.EXECUTE_WORKSPACE_COMMAND, Commands.LIST_SOURCEPATHS);
426-
if (result && result.data && result.data.length) {
427-
sourcePaths = result.data.map((sourcePath) => sourcePath.path).sort((a, b) => b.length - a.length);
428-
}
415+
let sourcePaths: string[] = (await getSourceRoots())?.data?.map(
416+
(sourcePath) => sourcePath.path).sort((a, b) => b.length - a.length) ?? [];
429417

430-
if (!sourcePaths || !sourcePaths.length) {
418+
if (!sourcePaths?.length) {
431419
return "";
432420
}
433421

@@ -513,40 +501,30 @@ function getNewFilePath(basePath: string, className: string): string {
513501
return path.join(basePath, ...className.split(".")) + ".java";
514502
}
515503

516-
export async function newPackage(node?: DataNode): Promise<void> {
517-
if (!node?.uri || !canCreatePackage(node)) {
504+
export async function newPackage(node: DataNode | Uri | undefined): Promise<void> {
505+
if (!node) {
518506
return;
519507
}
520508

521-
let defaultValue: string;
522-
let packageRootPath: string;
523-
const nodeKind = node.nodeData.kind;
524-
if (nodeKind === NodeKind.Project) {
525-
defaultValue = "";
526-
packageRootPath = await getPackageFsPath(node) || "";
527-
} else if (nodeKind === NodeKind.PackageRoot) {
528-
defaultValue = "";
529-
packageRootPath = Uri.parse(node.uri).fsPath;
530-
} else if (nodeKind === NodeKind.Package) {
531-
defaultValue = node.nodeData.name + ".";
532-
packageRootPath = getPackageRootPath(Uri.parse(node.uri).fsPath, node.nodeData.name);
533-
} else if (nodeKind === NodeKind.PrimaryType) {
534-
const primaryTypeNode = <PrimaryTypeNode> node;
535-
packageRootPath = primaryTypeNode.getPackageRootPath();
536-
if (packageRootPath === "") {
537-
window.showErrorMessage("Failed to get the package root path.");
538-
return;
539-
}
540-
const packagePath = await getPackageFsPath(node);
541-
if (!packagePath) {
542-
window.showErrorMessage("Failed to get the package path.");
543-
return;
544-
}
545-
defaultValue = path.relative(packageRootPath, packagePath).replace(/[\\\/]/g, ".") + ".";
546-
} else {
509+
const isUri = node instanceof Uri;
510+
if (!isUri && (!node.uri || !canCreatePackage(node))) {
511+
return;
512+
}
513+
514+
sendInfo("", {
515+
"triggernewpackagefrom": isUri ? "fileExplorer" : "javaProjectExplorer",
516+
});
517+
518+
let {defaultValue, packageRootPath} = (isUri ? await getPackageInformationFromUri(node)
519+
: await getPackageInformationFromNode(node)) || {};
520+
if (defaultValue === undefined || packageRootPath === undefined) {
547521
return;
548522
}
549523

524+
if (defaultValue.length > 0 && !defaultValue.endsWith(".")) {
525+
defaultValue += ".";
526+
}
527+
550528
const packageName: string | undefined = await window.showInputBox({
551529
value: defaultValue,
552530
placeHolder: "Input the package name",
@@ -573,6 +551,74 @@ export async function newPackage(node?: DataNode): Promise<void> {
573551
await fse.ensureDir(getNewPackagePath(packageRootPath, packageName));
574552
}
575553

554+
async function getPackageInformationFromUri(uri: Uri): Promise<Record<string, string> | undefined> {
555+
const defaultValue = {
556+
defaultValue: "",
557+
packageRootPath: uri.fsPath,
558+
};
559+
if (!isLanguageServerReady()) {
560+
return defaultValue;
561+
}
562+
563+
let sourcePaths: string[] = (await getSourceRoots())?.data?.map(
564+
(sourcePath) => sourcePath.path).sort((a, b) => b.length - a.length) ?? [];
565+
566+
if (!sourcePaths?.length) {
567+
return defaultValue;
568+
}
569+
570+
for (const sourcePath of sourcePaths) {
571+
if (isPrefix(sourcePath, uri.fsPath)) {
572+
const relative = path.relative(sourcePath, uri.fsPath);
573+
return {
574+
defaultValue: relative.replace(/[/\\]/g, "."),
575+
packageRootPath: sourcePath,
576+
};
577+
}
578+
}
579+
580+
return defaultValue;
581+
}
582+
583+
584+
async function getPackageInformationFromNode(node: DataNode): Promise<Record<string, string> | undefined> {
585+
const nodeKind = node.nodeData.kind;
586+
if (nodeKind === NodeKind.Project) {
587+
return {
588+
packageRootPath: await getPackageFsPath(node) || "",
589+
defaultValue: "",
590+
}
591+
} else if (nodeKind === NodeKind.PackageRoot) {
592+
return {
593+
packageRootPath: Uri.parse(node.uri!).fsPath,
594+
defaultValue: "",
595+
}
596+
} else if (nodeKind === NodeKind.Package) {
597+
return {
598+
packageRootPath: getPackageRootPath(Uri.parse(node.uri!).fsPath, node.nodeData.name),
599+
defaultValue: node.nodeData.name + ".",
600+
}
601+
} else if (nodeKind === NodeKind.PrimaryType) {
602+
const primaryTypeNode = <PrimaryTypeNode> node;
603+
const packageRootPath = primaryTypeNode.getPackageRootPath();
604+
if (packageRootPath === "") {
605+
window.showErrorMessage("Failed to get the package root path.");
606+
return undefined;
607+
}
608+
const packagePath = await getPackageFsPath(node);
609+
if (!packagePath) {
610+
window.showErrorMessage("Failed to get the package path.");
611+
return undefined;
612+
}
613+
return {
614+
packageRootPath: packageRootPath,
615+
defaultValue: path.relative(packageRootPath, packagePath).replace(/[/\\]/g, "."),
616+
}
617+
}
618+
619+
return undefined;
620+
}
621+
576622
/**
577623
* Check if the create package command is available for the given node.
578624
* Currently the check logic is the same as the create class command.
@@ -708,3 +754,15 @@ function getBasePath(node: DataNode): string | undefined {
708754
return undefined;
709755
}
710756
}
757+
758+
async function getSourceRoots(): Promise<IListCommandResult | undefined>{
759+
try {
760+
const result = await commands.executeCommand<IListCommandResult>(Commands.EXECUTE_WORKSPACE_COMMAND, Commands.LIST_SOURCEPATHS);
761+
if (result?.data?.length) {
762+
return result;
763+
}
764+
} catch (e) {
765+
// ignore;
766+
}
767+
return undefined;
768+
}

src/views/dependencyExplorer.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ export class DependencyExplorer implements Disposable {
147147
}
148148
newPackage(cmdNode);
149149
}),
150+
instrumentOperationAsVsCodeCommand(Commands.VIEW_EXPLORER_NEW_PACKAGE, (node: Uri) => {
151+
newPackage(node);
152+
}),
150153
instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_REVEAL_FILE_OS, (node?: DataNode) => {
151154
const cmdNode = getCmdNode(this._dependencyViewer.selection, node);
152155
if (cmdNode?.uri) {

0 commit comments

Comments
 (0)