From 292ee9fc8ee11de3fd00ae2bd612d0a5c838bce8 Mon Sep 17 00:00:00 2001 From: Sheng Chen Date: Tue, 9 Mar 2021 17:13:38 +0800 Subject: [PATCH] fix: Create new packages or classes does not work via hotkeys (#467) --- src/explorerCommands/delete.ts | 4 +- src/explorerCommands/new.ts | 33 ++++++++++++++-- src/explorerCommands/rename.ts | 4 +- src/explorerCommands/utility.ts | 12 +++++- src/views/dependencyDataProvider.ts | 21 +++++----- src/views/dependencyExplorer.ts | 60 ++++++++++++++++++++++++----- 6 files changed, 104 insertions(+), 30 deletions(-) diff --git a/src/explorerCommands/delete.ts b/src/explorerCommands/delete.ts index 036c8c96..3a6d626b 100644 --- a/src/explorerCommands/delete.ts +++ b/src/explorerCommands/delete.ts @@ -7,8 +7,8 @@ import { isMutable } from "./utility"; const confirmMessage = "Move to Recycle Bin"; -export async function deleteFiles(node: DataNode): Promise { - if (!isMutable(node) || !node.uri) { +export async function deleteFiles(node?: DataNode): Promise { + if (!node?.uri || !isMutable(node)) { return; } diff --git a/src/explorerCommands/new.ts b/src/explorerCommands/new.ts index c387e3ef..7d15b9c1 100644 --- a/src/explorerCommands/new.ts +++ b/src/explorerCommands/new.ts @@ -8,7 +8,11 @@ import { NodeKind } from "../java/nodeData"; import { DataNode } from "../views/dataNode"; import { checkJavaQualifiedName } from "./utility"; -export async function newJavaClass(node: DataNode): Promise { +export async function newJavaClass(node?: DataNode): Promise { + if (!node?.uri || !canCreateClass(node)) { + return; + } + const packageFsPath: string = await getPackageFsPath(node); if (!packageFsPath) { return; @@ -43,6 +47,17 @@ export async function newJavaClass(node: DataNode): Promise { workspace.applyEdit(workspaceEdit); } +function canCreateClass(node: DataNode): boolean { + 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: DataNode): Promise { if (node.nodeData.kind === NodeKind.Project) { const childrenNodes: DataNode[] = await node.getChildren() as DataNode[]; @@ -77,6 +92,8 @@ async function getPackageFsPath(node: DataNode): Promise { ); return choice ? 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 : ""; @@ -89,8 +106,8 @@ function getNewFilePath(basePath: string, className: string): string { return path.join(basePath, ...className.split(".")) + ".java"; } -export async function newPackage(node: DataNode): Promise { - if (!node.uri) { +export async function newPackage(node?: DataNode): Promise { + if (!node?.uri || !canCreatePackage(node)) { return; } @@ -136,6 +153,16 @@ export async function newPackage(node: DataNode): Promise { await fse.ensureDir(getNewPackagePath(packageRootPath, packageName)); } +function canCreatePackage(node: DataNode): boolean { + if (node.nodeData.kind === NodeKind.Project || + node.nodeData.kind === NodeKind.PackageRoot || + node.nodeData.kind === NodeKind.Package) { + return true; + } + + return false; +} + function getPackageRootPath(packageFsPath: string, packageName: string): string { const numberOfSegment: number = packageName.split(".").length; return path.join(packageFsPath, ...Array(numberOfSegment).fill("..")); diff --git a/src/explorerCommands/rename.ts b/src/explorerCommands/rename.ts index d5433042..5d4af1b3 100644 --- a/src/explorerCommands/rename.ts +++ b/src/explorerCommands/rename.ts @@ -8,8 +8,8 @@ import { NodeKind } from "../java/nodeData"; import { DataNode } from "../views/dataNode"; import { checkJavaQualifiedName, isMutable } from "./utility"; -export async function renameFile(node: DataNode): Promise { - if (!isMutable(node) || !node.uri) { +export async function renameFile(node?: DataNode): Promise { + if (!node?.uri || !isMutable(node)) { return; } diff --git a/src/explorerCommands/utility.ts b/src/explorerCommands/utility.ts index ec8f4d54..22e26968 100644 --- a/src/explorerCommands/utility.ts +++ b/src/explorerCommands/utility.ts @@ -35,7 +35,15 @@ export function checkJavaQualifiedName(value: string): string { return ""; } -export function getCmdNode(selectedNode: ExplorerNode, node?: DataNode): DataNode { +export function getCmdNode(selectedNodes: ExplorerNode[], node?: DataNode): DataNode | undefined { // if command not invoked by context menu, use selected node in explorer - return node ? node : selectedNode as DataNode; + if (node) { + return node; + } + + if (selectedNodes.length > 0) { + return selectedNodes[0] as DataNode; + } + + return undefined; } diff --git a/src/views/dependencyDataProvider.ts b/src/views/dependencyDataProvider.ts index e28f39c2..aebc3c27 100644 --- a/src/views/dependencyDataProvider.ts +++ b/src/views/dependencyDataProvider.ts @@ -10,7 +10,6 @@ import { instrumentOperation, instrumentOperationAsVsCodeCommand } from "vscode- import { contextManager } from "../../extension.bundle"; import { Commands } from "../commands"; import { Context } from "../constants"; -import { newJavaClass, newPackage } from "../explorerCommands/new"; import { executeExportJarTask } from "../exportJarSteps/ExportJarTaskProvider"; import { Jdtls } from "../java/jdtls"; import { INodeData, NodeKind } from "../java/nodeData"; @@ -41,8 +40,6 @@ export class DependencyDataProvider implements TreeDataProvider { context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_EXPORT_JAR, async (node: INodeData) => { executeExportJarTask(node); })); - context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_NEW_JAVA_CLASS, (node: DataNode) => newJavaClass(node))); - context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_NEW_JAVA_PACKAGE, (node: DataNode) => newPackage(node))); context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_OUTLINE, (uri, range) => window.showTextDocument(Uri.parse(uri), { selection: range }))); context.subscriptions.push(instrumentOperationAsVsCodeCommand(Commands.JAVA_PROJECT_BUILD_WORKSPACE, () => @@ -128,15 +125,7 @@ export class DependencyDataProvider implements TreeDataProvider { return project?.revealPaths(paths); } - private doRefresh(element?: ExplorerNode): void { - if (!element) { - this._rootItems = undefined; - } - explorerNodeCache.removeNodeChildren(element); - this._onDidChangeTreeData.fire(element); - } - - private async getRootProjects(): Promise { + public async getRootProjects(): Promise { const rootElements = await this.getRootNodes(); if (rootElements[0] instanceof ProjectNode) { return rootElements; @@ -152,6 +141,14 @@ export class DependencyDataProvider implements TreeDataProvider { } } + private doRefresh(element?: ExplorerNode): void { + if (!element) { + this._rootItems = undefined; + } + explorerNodeCache.removeNodeChildren(element); + this._onDidChangeTreeData.fire(element); + } + private async getRootNodes(): Promise { try { await this._lock.acquire(); diff --git a/src/views/dependencyExplorer.ts b/src/views/dependencyExplorer.ts index 0c160dfc..1adc5107 100644 --- a/src/views/dependencyExplorer.ts +++ b/src/views/dependencyExplorer.ts @@ -4,12 +4,13 @@ import * as fse from "fs-extra"; import * as _ from "lodash"; import * as path from "path"; -import { commands, Disposable, ExtensionContext, TextEditor, TreeView, +import { commands, Disposable, ExtensionContext, QuickPickItem, TextEditor, TreeView, TreeViewExpansionEvent, TreeViewSelectionChangeEvent, TreeViewVisibilityChangeEvent, Uri, window } from "vscode"; import { instrumentOperationAsVsCodeCommand, sendInfo } from "vscode-extension-telemetry-wrapper"; import { Commands } from "../commands"; import { Build } from "../constants"; import { deleteFiles } from "../explorerCommands/delete"; +import { newJavaClass, newPackage } from "../explorerCommands/new"; import { renameFile } from "../explorerCommands/rename"; import { getCmdNode } from "../explorerCommands/utility"; import { Jdtls } from "../java/jdtls"; @@ -96,29 +97,43 @@ export class DependencyExplorer implements Disposable { // register keybinding commands context.subscriptions.push( + instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_NEW_JAVA_CLASS, async (node?: DataNode) => { + let cmdNode = getCmdNode(this._dependencyViewer.selection, node); + if (!cmdNode) { + cmdNode = await this.promptForProjectNode(); + } + newJavaClass(cmdNode); + }), + instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_NEW_JAVA_PACKAGE, async (node?: DataNode) => { + let cmdNode = getCmdNode(this._dependencyViewer.selection, node); + if (!cmdNode) { + cmdNode = await this.promptForProjectNode(); + } + newPackage(cmdNode); + }), instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_REVEAL_FILE_OS, (node?: DataNode) => { - const cmdNode = getCmdNode(this._dependencyViewer.selection[0], node); - if (cmdNode.uri) { + const cmdNode = getCmdNode(this._dependencyViewer.selection, node); + if (cmdNode?.uri) { commands.executeCommand("revealFileInOS", Uri.parse(cmdNode.uri)); } }), instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_COPY_FILE_PATH, (node?: DataNode) => { - const cmdNode = getCmdNode(this._dependencyViewer.selection[0], node); - if (cmdNode.uri) { + const cmdNode = getCmdNode(this._dependencyViewer.selection, node); + if (cmdNode?.uri) { commands.executeCommand("copyFilePath", Uri.parse(cmdNode.uri)); } }), instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_COPY_RELATIVE_FILE_PATH, (node?: DataNode) => { - const cmdNode = getCmdNode(this._dependencyViewer.selection[0], node); - if (cmdNode.uri) { + const cmdNode = getCmdNode(this._dependencyViewer.selection, node); + if (cmdNode?.uri) { commands.executeCommand("copyRelativeFilePath", Uri.parse(cmdNode.uri)); } }), instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_RENAME_FILE, (node?: DataNode) => { - renameFile(getCmdNode(this._dependencyViewer.selection[0], node)); + renameFile(getCmdNode(this._dependencyViewer.selection, node)); }), instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_MOVE_FILE_TO_TRASH, (node?: DataNode) => { - deleteFiles(getCmdNode(this._dependencyViewer.selection[0], node)); + deleteFiles(getCmdNode(this._dependencyViewer.selection, node)); }), ); } @@ -162,4 +177,31 @@ export class DependencyExplorer implements Disposable { public get dataProvider(): DependencyDataProvider { return this._dataProvider; } + + private async promptForProjectNode(): Promise { + const projects = await this._dataProvider.getRootProjects(); + if (projects.length === 0) { + window.showInformationMessage("There is no Java projects in current workspace."); + return undefined; + } else if (projects.length === 1) { + return projects[0] as DataNode; + } else { + const options: IProjectPickItem[] = projects.map((p: DataNode) => { + return { + label: p.name, + node: p, + }; + }); + const choice: IProjectPickItem | undefined = await window.showQuickPick(options, { + placeHolder: "Choose a project", + ignoreFocusOut: true, + }); + + return choice?.node as DataNode; + } + } +} + +interface IProjectPickItem extends QuickPickItem { + node: ExplorerNode; }