Skip to content

Commit f25fdfe

Browse files
authored
feat: Support new file contribution (#533)
1 parent 3bc57b4 commit f25fdfe

File tree

5 files changed

+108
-31
lines changed

5 files changed

+108
-31
lines changed

package-lock.json

Lines changed: 11 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"explorer"
1313
],
1414
"engines": {
15-
"vscode": "^1.53.0"
15+
"vscode": "^1.59.0"
1616
},
1717
"repository": {
1818
"type": "git",
@@ -31,6 +31,7 @@
3131
"onCommand:java.project.create",
3232
"onCommand:java.view.package.exportJar",
3333
"onCommand:java.view.package.revealInProjectExplorer",
34+
"onCommand:java.view.package.newJavaClass",
3435
"onView:javaProjectExplorer"
3536
],
3637
"license": "MIT",
@@ -257,6 +258,11 @@
257258
}
258259
],
259260
"menus": {
261+
"file/newFile": [
262+
{
263+
"command": "java.view.package.newJavaClass"
264+
}
265+
],
260266
"commandPalette": [
261267
{
262268
"command": "java.view.package.exportJar",
@@ -310,10 +316,6 @@
310316
"command": "java.project.refreshLibraries",
311317
"when": "false"
312318
},
313-
{
314-
"command": "java.view.package.newJavaClass",
315-
"when": "false"
316-
},
317319
{
318320
"command": "java.view.package.newPackage",
319321
"when": "false"
@@ -595,7 +597,7 @@
595597
"@types/mocha": "^8.2.1",
596598
"@types/node": "^8.10.66",
597599
"@types/semver": "^7.3.8",
598-
"@types/vscode": "1.53.0",
600+
"@types/vscode": "1.59.0",
599601
"copy-webpack-plugin": "^6.4.1",
600602
"glob": "^7.1.6",
601603
"gulp": "^4.0.2",

src/commands.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ export namespace Commands {
9494
export const WORKBENCH_ACTION_FILES_OPENFOLDER = "workbench.action.files.openFolder";
9595

9696
export const WORKBENCH_ACTION_FILES_OPENFILEFOLDER = "workbench.action.files.openFileFolder";
97+
98+
/**
99+
* Commands from JLS
100+
*/
101+
export const LIST_SOURCEPATHS = "java.project.listSourcePaths";
97102
}
98103

99104
export function executeJavaLanguageServerCommand(...rest: any[]) {

src/explorerCommands/new.ts

Lines changed: 83 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,29 @@
33

44
import * as fse from "fs-extra";
55
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";
78
import { NodeKind } from "../java/nodeData";
89
import { DataNode } from "../views/dataNode";
910
import { checkJavaQualifiedName } from "./utility";
1011

1112
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);
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+
50111
function 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
175236
interface 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+
}

src/views/dependencyExplorer.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,7 @@ export class DependencyExplorer implements Disposable {
9797
// register keybinding commands
9898
context.subscriptions.push(
9999
instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_NEW_JAVA_CLASS, async (node?: DataNode) => {
100-
let cmdNode = getCmdNode(this._dependencyViewer.selection, node);
101-
if (!cmdNode) {
102-
cmdNode = await this.promptForProjectNode();
103-
}
104-
newJavaClass(cmdNode);
100+
newJavaClass(node);
105101
}),
106102
instrumentOperationAsVsCodeCommand(Commands.VIEW_PACKAGE_NEW_JAVA_PACKAGE, async (node?: DataNode) => {
107103
let cmdNode = getCmdNode(this._dependencyViewer.selection, node);

0 commit comments

Comments
 (0)