Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 42 additions & 19 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,13 +264,52 @@ async function runJavaFile(uri: vscode.Uri, noDebug: boolean) {
throw ex;
}

const hasMainMethods: boolean = mainMethods.length > 0;
const canRunTests: boolean = await canDelegateToJavaTestRunner(uri);

if (!hasMainMethods && !canRunTests) {
const mainClasses: IMainClassOption[] = await utility.searchMainMethods();
await launchMain(mainClasses, uri, noDebug);
} else if (hasMainMethods && !canRunTests) {
await launchMain(mainMethods, uri, noDebug);
} else if (!hasMainMethods && canRunTests) {
await launchTesting(uri, noDebug);
} else {
const launchMainChoice: string = "main() method";
const launchTestChoice: string = "unit tests";
const choice: string = await vscode.window.showQuickPick(
[launchMainChoice, launchTestChoice],
{ placeHolder: "Please select which kind of task you would like to launch" },
);
if (choice === launchMainChoice) {
await launchMain(mainMethods, uri, noDebug);
} else if (choice === launchTestChoice) {
await launchTesting(uri, noDebug);
}
}
}

async function canDelegateToJavaTestRunner(uri: vscode.Uri): Promise<boolean> {
const fsPath: string = uri.fsPath;
const isTestFile: boolean = /.*[\/\\]src[\/\\]test[\/\\]java[\/\\].*[Tt]ests?\.java/.test(fsPath);
if (!isTestFile) {
return false;
}
return (await vscode.commands.getCommands()).includes("java.test.editor.run");
}

async function launchTesting(uri: vscode.Uri, noDebug: boolean): Promise<void> {
noDebug ? vscode.commands.executeCommand("java.test.editor.run", uri) : vscode.commands.executeCommand("java.test.editor.debug", uri);
}

async function launchMain(mainMethods: IMainClassOption[], uri: vscode.Uri, noDebug: boolean): Promise<void> {
if (!mainMethods || !mainMethods.length) {
vscode.window.showErrorMessage(
"Error: Main method not found in the file, please define the main method as: public static void main(String[] args)");
return;
}

const pick = await mainClassPicker.showQuickPick(mainMethods, "Select the main class to run.", (option) => option.mainClass);
const pick = await mainClassPicker.showQuickPickWithRecentlyUsed(mainMethods, "Select the main class to run.");
if (!pick) {
return;
}
Expand All @@ -287,31 +326,15 @@ async function runJavaProject(node: any, noDebug: boolean) {
throw error;
}

let mainClassesOptions: IMainClassOption[] = [];
try {
mainClassesOptions = await vscode.window.withProgress<IMainClassOption[]>(
{
location: vscode.ProgressLocation.Window,
},
async (p) => {
p.report({
message: "Searching main class...",
});
return resolveMainClass(vscode.Uri.parse(node.uri));
});
} catch (ex) {
vscode.window.showErrorMessage(String((ex && ex.message) || ex));
throw ex;
}

const mainClassesOptions: IMainClassOption[] = await utility.searchMainMethods(vscode.Uri.parse(node.uri));
if (!mainClassesOptions || !mainClassesOptions.length) {
vscode.window.showErrorMessage(`Failed to ${noDebug ? "run" : "debug"} this project '${node._nodeData.displayName || node.name}' `
+ "because it does not contain any main class.");
return;
}

const pick = await mainClassPicker.showQuickPickWithRecentlyUsed(mainClassesOptions,
"Select the main class to run.", (option) => option.mainClass);
"Select the main class to run.");
if (!pick) {
return;
}
Expand Down
8 changes: 6 additions & 2 deletions src/mainClassPicker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { TextEditor, window } from "vscode";
import { IMainClassOption } from "./languageServerPlugin";

const defaultLabelFormatter = (option: IMainClassOption) => {
return option.mainClass + `${option.projectName ? "<" + option.projectName + ">" : ""}`;
return option.mainClass;
};
type Formatter = (option: IMainClassOption) => string;

Expand Down Expand Up @@ -44,7 +44,7 @@ class MainClassPicker {
return {
label: labelFormatter(option),
description: option.filePath ? path.basename(option.filePath) : "",
detail: undefined,
detail: option.projectName ? `Project: ${option.projectName}` : "",
data: option,
};
});
Expand Down Expand Up @@ -109,6 +109,10 @@ class MainClassPicker {
adjustedDetail.push(`$(file-text) active editor (${path.basename(option.filePath)})`);
}

if (option.projectName) {
adjustedDetail.push(`Project: ${option.projectName}`);
}

const detail: string = adjustedDetail.join(", ");

return {
Expand Down
15 changes: 15 additions & 0 deletions src/utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import * as path from "path";
import * as vscode from "vscode";
import { sendError, sendInfo, setUserError } from "vscode-extension-telemetry-wrapper";
import { IMainClassOption, resolveMainClass } from "./languageServerPlugin";
import { logger, Type } from "./logger";

const TROUBLESHOOTING_LINK = "https://github.com/Microsoft/vscode-java-debug/blob/master/Troubleshooting.md";
Expand Down Expand Up @@ -248,3 +249,17 @@ export async function waitForStandardMode(): Promise<boolean> {

return true;
}

export async function searchMainMethods(uri?: vscode.Uri): Promise<IMainClassOption[]> {
try {
return await vscode.window.withProgress<IMainClassOption[]>(
{ location: vscode.ProgressLocation.Window },
async (p) => {
p.report({ message: "Searching main classes..." });
return resolveMainClass(uri);
});
} catch (ex) {
vscode.window.showErrorMessage(String((ex && ex.message) || ex));
throw ex;
}
}