Support customizing the classpaths and modulepaths (#1005)
* Support customizing the classpaths and modulepaths
This commit is contained in:
parent
5f8f68895d
commit
5fc5db2543
36
package.json
36
package.json
|
@ -397,7 +397,23 @@
|
||||||
"modulePaths": {
|
"modulePaths": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"enum": [
|
||||||
|
"$Auto",
|
||||||
|
"$Runtime",
|
||||||
|
"$Test",
|
||||||
|
"!<path>"
|
||||||
|
],
|
||||||
|
"enumDescriptions": [
|
||||||
|
"%java.debugger.launch.modulePaths.auto%",
|
||||||
|
"%java.debugger.launch.modulePaths.runtime%",
|
||||||
|
"%java.debugger.launch.modulePaths.test%",
|
||||||
|
"%java.debugger.launch.modulePaths.exclude%"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"string"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"description": "%java.debugger.launch.modulePaths.description%",
|
"description": "%java.debugger.launch.modulePaths.description%",
|
||||||
"default": []
|
"default": []
|
||||||
|
@ -405,7 +421,23 @@
|
||||||
"classPaths": {
|
"classPaths": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"enum": [
|
||||||
|
"$Auto",
|
||||||
|
"$Runtime",
|
||||||
|
"$Test",
|
||||||
|
"!<path>"
|
||||||
|
],
|
||||||
|
"enumDescriptions": [
|
||||||
|
"%java.debugger.launch.classPaths.auto%",
|
||||||
|
"%java.debugger.launch.classPaths.runtime%",
|
||||||
|
"%java.debugger.launch.classPaths.test%",
|
||||||
|
"%java.debugger.launch.classPaths.exclude%"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"string"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"description": "%java.debugger.launch.classPaths.description%",
|
"description": "%java.debugger.launch.classPaths.description%",
|
||||||
"default": []
|
"default": []
|
||||||
|
|
|
@ -4,7 +4,15 @@
|
||||||
"java.debugger.launch.args.description": "The command line arguments passed to the program.",
|
"java.debugger.launch.args.description": "The command line arguments passed to the program.",
|
||||||
"java.debugger.launch.vmArgs.description": "The extra options and system properties for the JVM (e.g. -Xms<size> -Xmx<size> -D<name>=<value>).",
|
"java.debugger.launch.vmArgs.description": "The extra options and system properties for the JVM (e.g. -Xms<size> -Xmx<size> -D<name>=<value>).",
|
||||||
"java.debugger.launch.modulePaths.description": "The modulepaths for launching the JVM. If not specified, the debugger will automatically resolve from current project.",
|
"java.debugger.launch.modulePaths.description": "The modulepaths for launching the JVM. If not specified, the debugger will automatically resolve from current project.",
|
||||||
|
"java.debugger.launch.modulePaths.auto": "Automatically resolve the module paths of current project.",
|
||||||
|
"java.debugger.launch.modulePaths.runtime": "The module paths within 'runtime' scope of current project.",
|
||||||
|
"java.debugger.launch.modulePaths.test": "The module paths within 'test' scope of current project.",
|
||||||
|
"java.debugger.launch.modulePaths.exclude": "The path after '!' will be excluded from the modulePaths.",
|
||||||
"java.debugger.launch.classPaths.description": "The classpaths for launching the JVM. If not specified, the debugger will automatically resolve from current project.",
|
"java.debugger.launch.classPaths.description": "The classpaths for launching the JVM. If not specified, the debugger will automatically resolve from current project.",
|
||||||
|
"java.debugger.launch.classPaths.auto": "Automatically resolve the classpaths of current project.",
|
||||||
|
"java.debugger.launch.classPaths.runtime": "The classpaths within 'runtime' scope of current project.",
|
||||||
|
"java.debugger.launch.classPaths.test": "The classpaths within 'test' scope of current project.",
|
||||||
|
"java.debugger.launch.classPaths.exclude": "The path after '!' will be excluded from the classpaths.",
|
||||||
"java.debugger.launch.sourcePaths.description": "The extra source directories of the program. The debugger looks for source code from project settings by default. This option allows the debugger to look for source code in extra directories.",
|
"java.debugger.launch.sourcePaths.description": "The extra source directories of the program. The debugger looks for source code from project settings by default. This option allows the debugger to look for source code in extra directories.",
|
||||||
"java.debugger.launch.encoding.description": "The file.encoding setting for the JVM. If not specified, 'UTF-8' will be used. Possible values can be found in https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html.",
|
"java.debugger.launch.encoding.description": "The file.encoding setting for the JVM. If not specified, 'UTF-8' will be used. Possible values can be found in https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html.",
|
||||||
"java.debugger.launch.cwd.description": "The working directory of the program. Defaults to the current workspace root.",
|
"java.debugger.launch.cwd.description": "The working directory of the program. Defaults to the current workspace root.",
|
||||||
|
|
|
@ -4,7 +4,15 @@
|
||||||
"java.debugger.launch.args.description": "启动应用程序的命令行参数。",
|
"java.debugger.launch.args.description": "启动应用程序的命令行参数。",
|
||||||
"java.debugger.launch.vmArgs.description": "用于启动JVM的额外选项和系统属性(例如-Xms <size> -Xmx <size> -D <name> = <value>)。",
|
"java.debugger.launch.vmArgs.description": "用于启动JVM的额外选项和系统属性(例如-Xms <size> -Xmx <size> -D <name> = <value>)。",
|
||||||
"java.debugger.launch.modulePaths.description": "用于启动JVM的模块路径。如果未指定,调试器将自动从当前工程中解析。",
|
"java.debugger.launch.modulePaths.description": "用于启动JVM的模块路径。如果未指定,调试器将自动从当前工程中解析。",
|
||||||
|
"java.debugger.launch.modulePaths.auto": "自动从当前工程中解析模块路径。",
|
||||||
|
"java.debugger.launch.modulePaths.runtime": "当前工程中属于 runtime 作用域的模块路径。",
|
||||||
|
"java.debugger.launch.modulePaths.test": "当前工程中属于 test 作用域的模块路径。",
|
||||||
|
"java.debugger.launch.modulePaths.exclude": "'!' 之后的路径将会从模块路径中去除。",
|
||||||
"java.debugger.launch.classPaths.description": "用于启动JVM的类路径。如果未指定,调试器将自动从当前工程中解析。",
|
"java.debugger.launch.classPaths.description": "用于启动JVM的类路径。如果未指定,调试器将自动从当前工程中解析。",
|
||||||
|
"java.debugger.launch.classPaths.auto": "自动从当前工程中解析类路径。",
|
||||||
|
"java.debugger.launch.classPaths.runtime": "当前工程中属于 runtime 作用域的类路径。",
|
||||||
|
"java.debugger.launch.classPaths.test": "当前工程中属于 test 作用域的类路径。",
|
||||||
|
"java.debugger.launch.classPaths.exclude": "'!' 之后的路径将会从类路径中去除。",
|
||||||
"java.debugger.launch.sourcePaths.description": "应用程序的额外源代码目录。调试器默认从工程配置中查找源代码。此选项允许调试器在额外目录中查找源代码。",
|
"java.debugger.launch.sourcePaths.description": "应用程序的额外源代码目录。调试器默认从工程配置中查找源代码。此选项允许调试器在额外目录中查找源代码。",
|
||||||
"java.debugger.launch.encoding.description": "JVM的file.encoding设置。如果未指定,将使用“UTF-8”。可以在http://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html中找到可能的值。",
|
"java.debugger.launch.encoding.description": "JVM的file.encoding设置。如果未指定,将使用“UTF-8”。可以在http://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html中找到可能的值。",
|
||||||
"java.debugger.launch.cwd.description": "应用程序的工作目录。默认为当前工作空间根目录。",
|
"java.debugger.launch.cwd.description": "应用程序的工作目录。默认为当前工作空间根目录。",
|
||||||
|
|
|
@ -11,6 +11,7 @@ import * as anchor from "./anchor";
|
||||||
import { buildWorkspace } from "./build";
|
import { buildWorkspace } from "./build";
|
||||||
import { populateStepFilters, substituteFilterVariables } from "./classFilter";
|
import { populateStepFilters, substituteFilterVariables } from "./classFilter";
|
||||||
import * as commands from "./commands";
|
import * as commands from "./commands";
|
||||||
|
import { ClasspathVariable } from "./constants";
|
||||||
import { Type } from "./javaLogger";
|
import { Type } from "./javaLogger";
|
||||||
import * as lsPlugin from "./languageServerPlugin";
|
import * as lsPlugin from "./languageServerPlugin";
|
||||||
import { addMoreHelpfulVMArgs, getJavaVersion, getShortenApproachForCLI, validateRuntimeCompatibility } from "./launchCommand";
|
import { addMoreHelpfulVMArgs, getJavaVersion, getShortenApproachForCLI, validateRuntimeCompatibility } from "./launchCommand";
|
||||||
|
@ -263,10 +264,16 @@ export class JavaDebugConfigurationProvider implements vscode.DebugConfiguration
|
||||||
if (progressReporter.isCancelled()) {
|
if (progressReporter.isCancelled()) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_.isEmpty(config.classPaths) && _.isEmpty(config.modulePaths)) {
|
if (_.isEmpty(config.classPaths) && _.isEmpty(config.modulePaths)) {
|
||||||
const result = <any[]>(await lsPlugin.resolveClasspath(config.mainClass, config.projectName));
|
const result = <any[]>(await lsPlugin.resolveClasspath(config.mainClass, config.projectName));
|
||||||
config.modulePaths = result[0];
|
config.modulePaths = result[0];
|
||||||
config.classPaths = result[1];
|
config.classPaths = result[1];
|
||||||
|
} else {
|
||||||
|
config.modulePaths = await this.resolvePath(folder, config.modulePaths, config.mainClass,
|
||||||
|
config.projectName, true /*isModulePath*/);
|
||||||
|
config.classPaths = await this.resolvePath(folder, config.classPaths, config.mainClass,
|
||||||
|
config.projectName, false /*isModulePath*/);
|
||||||
}
|
}
|
||||||
if (_.isEmpty(config.classPaths) && _.isEmpty(config.modulePaths)) {
|
if (_.isEmpty(config.classPaths) && _.isEmpty(config.modulePaths)) {
|
||||||
throw new utility.UserError({
|
throw new utility.UserError({
|
||||||
|
@ -381,6 +388,88 @@ export class JavaDebugConfigurationProvider implements vscode.DebugConfiguration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async resolvePath(folder: vscode.WorkspaceFolder | undefined, pathArray: string[], mainClass: string,
|
||||||
|
projectName: string, isModulePath: boolean): Promise<string[]> {
|
||||||
|
if (_.isEmpty(pathArray)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const pathVariables: string[] = [ClasspathVariable.Auto, ClasspathVariable.Runtime, ClasspathVariable.Test];
|
||||||
|
const containedVariables: string[] = pathArray.filter((cp: string) => pathVariables.includes(cp));
|
||||||
|
if (_.isEmpty(containedVariables)) {
|
||||||
|
return this.filterExcluded(folder, pathArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
const scope: string | undefined = this.mergeScope(containedVariables);
|
||||||
|
const response: any[] = <any[]> await lsPlugin.resolveClasspath(mainClass, projectName, scope);
|
||||||
|
const resolvedPaths: string[] = isModulePath ? response?.[0] : response?.[1];
|
||||||
|
if (!resolvedPaths) {
|
||||||
|
// tslint:disable-next-line:no-console
|
||||||
|
console.log("The Java Language Server failed to resolve the classpaths/modulepaths");
|
||||||
|
}
|
||||||
|
const paths: string[] = [];
|
||||||
|
let replaced: boolean = false;
|
||||||
|
for (const p of pathArray) {
|
||||||
|
if (pathVariables.includes(p)) {
|
||||||
|
if (!replaced) {
|
||||||
|
paths.push(...resolvedPaths);
|
||||||
|
replaced = true;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
paths.push(p);
|
||||||
|
}
|
||||||
|
return this.filterExcluded(folder, paths);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async filterExcluded(folder: vscode.WorkspaceFolder | undefined, paths: string[]): Promise<string[]> {
|
||||||
|
const result: string[] = [];
|
||||||
|
const excludes: Map<string, boolean> = new Map<string, boolean>();
|
||||||
|
for (const p of paths) {
|
||||||
|
if (p.startsWith("!")) {
|
||||||
|
let exclude = p.substr(1);
|
||||||
|
if (!path.isAbsolute(exclude)) {
|
||||||
|
exclude = path.join(folder?.uri.fsPath || "", exclude);
|
||||||
|
}
|
||||||
|
// use Uri to normalize the fs path
|
||||||
|
excludes.set(vscode.Uri.file(exclude).fsPath, this.isFile(exclude));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push(vscode.Uri.file(p).fsPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.filter((r) => {
|
||||||
|
for (const [excludedPath, isFile] of excludes.entries()) {
|
||||||
|
if (isFile && r === excludedPath) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isFile && r.startsWith(excludedPath)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private mergeScope(scopes: string[]): string | undefined {
|
||||||
|
if (scopes.includes(ClasspathVariable.Test)) {
|
||||||
|
return "test";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scopes.includes(ClasspathVariable.Auto)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scopes.includes(ClasspathVariable.Runtime)) {
|
||||||
|
return "runtime";
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts an array of arguments to a string as the args and vmArgs.
|
* Converts an array of arguments to a string as the args and vmArgs.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,3 +4,9 @@
|
||||||
export const JAVA_LANGID: string = "java";
|
export const JAVA_LANGID: string = "java";
|
||||||
export const HCR_EVENT = "hotcodereplace";
|
export const HCR_EVENT = "hotcodereplace";
|
||||||
export const USER_NOTIFICATION_EVENT = "usernotification";
|
export const USER_NOTIFICATION_EVENT = "usernotification";
|
||||||
|
|
||||||
|
export enum ClasspathVariable {
|
||||||
|
Auto = "$Auto",
|
||||||
|
Runtime = "$Runtime",
|
||||||
|
Test = "$Test",
|
||||||
|
}
|
||||||
|
|
|
@ -46,8 +46,8 @@ export function startDebugSession() {
|
||||||
return commands.executeJavaLanguageServerCommand(commands.JAVA_START_DEBUGSESSION);
|
return commands.executeJavaLanguageServerCommand(commands.JAVA_START_DEBUGSESSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveClasspath(mainClass: string, projectName: string) {
|
export function resolveClasspath(mainClass: string, projectName: string, scope?: string) {
|
||||||
return commands.executeJavaLanguageServerCommand(commands.JAVA_RESOLVE_CLASSPATH, mainClass, projectName);
|
return commands.executeJavaLanguageServerCommand(commands.JAVA_RESOLVE_CLASSPATH, mainClass, projectName, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveMainClass(workspaceUri?: vscode.Uri): Promise<IMainClassOption[]> {
|
export function resolveMainClass(workspaceUri?: vscode.Uri): Promise<IMainClassOption[]> {
|
||||||
|
|
Loading…
Reference in New Issue