<p style="font-size:small;">Content-Length: 38689 | <a href="http://clevelandohioweatherforecast.com//pFad.php?u=" style="font-size:small;">pFad</a> | <a href="https://github.com/microsoft/vscode-java-debug/raw/refs/heads/main/src/configurationProvider.ts" style="font-size:small;">https://github.com/microsoft/vscode-java-debug/raw/refs/heads/main/src/configurationProvider.ts</a></p>h: 38677 // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. import * as fs from "fs"; import * as _ from "lodash"; import * as os from "os"; import * as path from "path"; import * as vscode from "vscode"; import * as dotenv from 'dotenv'; import { instrumentOperation, sendError, sendInfo, setUserError } from "vscode-extension-telemetry-wrapper"; import * as anchor from "./anchor"; import { buildWorkspace } from "./build"; import { populateStepFilters, substituteFilterVariables } from "./classFilter"; import * as commands from "./commands"; import { ClasspathVariable } from "./constants"; import { Type } from "./javaLogger"; import * as lsPlugin from "./languageServerPlugin"; import { addMoreHelpfulVMArgs, getJavaVersion, getShortenApproachForCLI, validateRuntimeCompatibility } from "./launchCommand"; import { mainClassPicker } from "./mainClassPicker"; import { resolveJavaProcess } from "./processPicker"; import { IProgressReporter } from "./progressAPI"; import { progressProvider } from "./progressImpl"; import * as utility from "./utility"; const platformNameMappings: { [key: string]: string } = { win32: "windows", linux: "linux", darwin: "osx", }; const platformName = platformNameMappings[process.platform]; export let lastUsedLaunchConfig: vscode.DebugConfiguration | undefined; export class JavaDebugConfigurationProvider implements vscode.DebugConfigurationProvider { private isUserSettingsDirty: boolean = true; constructor() { const packageJson: {[key: string]: any} = require("../package.json"); const debugConfigNames = Object.keys(packageJson?.contributes?.configuration?.properties || {}); vscode.workspace.onDidChangeConfiguration((event) => { if (event.affectsConfiguration("java.debug")) { for (const key of debugConfigNames) { if (event.affectsConfiguration(key)) { sendInfo("", { operationName: "changeJavaDebugSettings", configName: key, }); } } if (vscode.debug.activeDebugSession) { this.isUserSettingsDirty = false; return updateDebugSettings(event); } else { this.isUserSettingsDirty = true; } } return undefined; }); } // Returns an initial debug configurations based on contextual information. public provideDebugConfigurations(folder: vscode.WorkspaceFolder | undefined, token?: vscode.CancellationToken): vscode.ProviderResult<vscode.DebugConfiguration[]> { const provideDebugConfigurationsHandler = instrumentOperation("provideDebugConfigurations", (_operationId: string) => { return <Thenable<vscode.DebugConfiguration[]>>this.provideDebugConfigurationsAsync(folder, token); }); return provideDebugConfigurationsHandler(); } // Try to add all missing attributes to the debug configuration being launched. public resolveDebugConfiguration(_folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration, _token?: vscode.CancellationToken): vscode.ProviderResult<vscode.DebugConfiguration> { // If no debug configuration is provided, then generate one in memory. if (this.isEmptyConfig(config)) { config.type = "java"; config.name = "Java Debug"; config.request = "launch"; config.__origen = "internal"; } return config; } // Try to add all missing attributes to the debug configuration being launched. public resolveDebugConfigurationWithSubstitutedVariables( folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration, token?: vscode.CancellationToken): vscode.ProviderResult<vscode.DebugConfiguration> { const resolveDebugConfigurationHandler = instrumentOperation("resolveDebugConfiguration", (_operationId: string) => { try { // See https://github.com/microsoft/vscode-java-debug/issues/778 // Merge the platform specific properties to the global config to simplify the subsequent resolving logic. this.mergePlatformProperties(config, folder); return this.resolveAndValidateDebugConfiguration(folder, config, token); } catch (ex) { utility.showErrorMessage({ type: Type.EXCEPTION, message: String((ex && ex.message) || ex), }); return undefined; } }); return resolveDebugConfigurationHandler(); } private provideDebugConfigurationsAsync(folder: vscode.WorkspaceFolder | undefined, token?: vscode.CancellationToken) { return new Promise(async (resolve, _reject) => { const progressReporter = progressProvider.createProgressReporter("Create launch.json", vscode.ProgressLocation.Window); progressReporter.observe(token); const defaultLaunchConfig = { type: "java", name: "Current File", request: "launch", // tslint:disable-next-line mainClass: "${file}", }; try { const isOnStandardMode = await utility.waitForStandardMode(progressReporter); if (!isOnStandardMode) { resolve([defaultLaunchConfig]); return; } if (progressReporter.isCancelled()) { resolve([defaultLaunchConfig]); return; } progressReporter.report("Generating Java configuration..."); const mainClasses = await lsPlugin.resolveMainClass(folder ? folder.uri : undefined); const cache = {}; const launchConfigs = mainClasses.map((item) => { return { ...defaultLaunchConfig, name: this.constructLaunchConfigName(item.mainClass, cache), mainClass: item.mainClass, projectName: item.projectName, }; }); if (progressReporter.isCancelled()) { resolve([defaultLaunchConfig]); return; } resolve([defaultLaunchConfig, ...launchConfigs]); } catch (ex) { if (ex instanceof utility.JavaExtensionNotEnabledError) { utility.guideToInstallJavaExtension(); } else { // tslint:disable-next-line console.error(ex); } resolve([defaultLaunchConfig]); } finally { progressReporter.done(); } }); } private mergePlatformProperties(config: vscode.DebugConfiguration, _folder?: vscode.WorkspaceFolder) { if (config && platformName && config[platformName]) { try { for (const key of Object.keys(config[platformName])) { config[key] = config[platformName][key]; } config[platformName] = undefined; } catch { // do nothing } } } private constructLaunchConfigName(mainClass: string, cache: { [key: string]: any }) { const name = `${mainClass.substr(mainClass.lastIndexOf(".") + 1)}`; if (cache[name] === undefined) { cache[name] = 0; return name; } else { cache[name] += 1; return `${name}(${cache[name]})`; } } private mergeEnvFile(config: vscode.DebugConfiguration) { const baseEnv = config.env || {}; let result = baseEnv; if (config.envFile) { try { if (typeof config.envFile === 'string') { result = { ...result, ...readEnvFile(config.envFile) }; } if (Array.isArray(config.envFile)) { config.envFile.forEach((f) => { result = { ...result, ...readEnvFile(f) }; }); } } catch (e) { throw new utility.UserError({ message: "Cannot load environment file.", type: Type.USAGEERROR, }); } } config.env = result; } private async resolveAndValidateDebugConfiguration(folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration, token?: vscode.CancellationToken) { let configCopy: vscode.DebugConfiguration | undefined; const isConfigFromInternal = config.__origen === "internal" /** in-memory configuration from debugger */ || config.__configurationTarget /** configuration from launch.json */; if (config.request === "launch" && isConfigFromInternal) { configCopy = _.cloneDeep(config); delete configCopy.__progressId; delete configCopy.noDebug; } let progressReporter = progressProvider.getProgressReporter(config.__progressId); if (!progressReporter && config.__progressId) { return undefined; } else if (!progressReporter) { progressReporter = progressProvider.createProgressReporter(utility.launchJobName(config.name, config.noDebug)); } progressReporter.observe(token); if (progressReporter.isCancelled()) { return undefined; } try { const isOnStandardMode = await utility.waitForStandardMode(progressReporter); if (!isOnStandardMode || progressReporter.isCancelled()) { return undefined; } if (this.isUserSettingsDirty) { this.isUserSettingsDirty = false; await updateDebugSettings(); } // If no debug configuration is provided, then generate one in memory. if (this.isEmptyConfig(config)) { config.type = "java"; config.name = "Java Debug"; config.request = "launch"; } if (config.request === "launch") { const mainClassOption = await this.resolveAndValidateMainClass(folder && folder.uri, config, progressReporter); if (!mainClassOption || !mainClassOption.mainClass) { // Exit silently if the user cancels the prompt fix by ESC. // Exit the debug session. return undefined; } config.mainClass = mainClassOption.mainClass; config.projectName = mainClassOption.projectName; if (config.__workspaceFolder && config.__workspaceFolder !== folder) { folder = config.__workspaceFolder; } // Update the job name if the main class is changed during the resolving of configuration provider. if (configCopy && configCopy.mainClass !== config.mainClass) { config.name = config.mainClass.substr(config.mainClass.lastIndexOf(".") + 1); progressReporter.setJobName(utility.launchJobName(config.name, config.noDebug)); } if (progressReporter.isCancelled()) { return undefined; } if (needsBuildWorkspace()) { progressReporter.report("Compiling..."); const proceed = await buildWorkspace({ mainClass: mainClassOption.mainClass, projectName: mainClassOption.projectName, isFullBuild: false, }, progressReporter); if (!proceed) { return undefined; } } if (progressReporter.isCancelled()) { return undefined; } progressReporter.report("Resolving launch configuration..."); this.mergeEnvFile(config); // If the user doesn't specify 'vmArgs' in launch.json, use the global setting to get the default vmArgs. if (config.vmArgs === undefined) { const debugSettings: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("java.debug.settings"); config.vmArgs = debugSettings.vmArgs; } // If the user doesn't specify 'console' in launch.json, use the global setting to get the launch console. if (!config.console) { const debugSettings: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("java.debug.settings"); config.console = debugSettings.console; } // If the console is integratedTerminal, don't auto switch the focus to DEBUG CONSOLE. if (config.console === "integratedTerminal" && !config.internalConsoleOptions) { config.internalConsoleOptions = "neverOpen"; } if (progressReporter.isCancelled()) { return undefined; } if (_.isEmpty(config.classPaths) && _.isEmpty(config.modulePaths)) { const result = <any[]>(await lsPlugin.resolveClasspath(config.mainClass, config.projectName)); config.modulePaths = result[0]; 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)) { throw new utility.UserError({ message: "Cannot resolve the modulepaths/classpaths automatically, please specify the value in the launch.json.", type: Type.USAGEERROR, }); } if (_.isEmpty(config.javaExec)) { config.javaExec = await lsPlugin.resolveJavaExecutable(config.mainClass, config.projectName); } else { if (!fs.existsSync(config.javaExec)) { throw new utility.UserError({ message: "Java executable file path cannot be accessed, please specify a valid path in the launch.json.", type: Type.USAGEERROR, }); } } // Add the default launch options to the config. config.cwd = config.cwd || _.get(folder, "uri.fsPath"); if (Array.isArray(config.args)) { config.args = this.concatArgs(config.args); } if (Array.isArray(config.vmArgs)) { config.vmArgs = this.concatArgs(config.vmArgs); } if (progressReporter.isCancelled()) { return undefined; } // Populate the class filters to the debug configuration. await populateStepFilters(config); const targetJavaVersion: number = await getJavaVersion(config.javaExec); // Auto add '--enable-preview' vmArgs if the java project enables COMPILER_PB_ENABLE_PREVIEW_FEATURES flag. if (await lsPlugin.detectPreviewFlag(config.mainClass, config.projectName)) { config.vmArgs = (config.vmArgs || "") + " --enable-preview"; validateRuntimeCompatibility(targetJavaVersion); } // Add more helpful vmArgs. await addMoreHelpfulVMArgs(config, targetJavaVersion); if (!config.shortenCommandLine || config.shortenCommandLine === "auto") { config.shortenCommandLine = await getShortenApproachForCLI(config, targetJavaVersion); } // VS Code internal console uses UTF-8 to display output by default. if (config.console === "internalConsole" && !config.encoding) { config.encoding = "UTF-8"; } } else if (config.request === "attach") { if (config.hostName && config.port && Number.isInteger(Number(config.port))) { config.port = Number(config.port); config.processId = undefined; // Continue if the hostName and port are configured. } else if (config.processId !== undefined) { // tslint:disable-next-line if (config.processId === "${command:PickJavaProcess}") { return undefined; } const pid: number = Number(config.processId); if (Number.isNaN(pid)) { vscode.window.showErrorMessage(`The processId config '${config.processId}' is not a valid process id.`); return undefined; } const javaProcess = await resolveJavaProcess(pid); if (!javaProcess) { vscode.window.showErrorMessage(`Attach to process: pid '${config.processId}' is not a debuggable Java process. ` + `Please make sure the process has turned on debug mode using vmArgs like ` + `'-agentlib:jdwp=transport=dt_socket,server=y,address=5005.'`); return undefined; } config.processId = undefined; config.hostName = javaProcess.hostName; config.port = javaProcess.debugPort; } else { throw new utility.UserError({ message: "Please specify the hostName/port directly, or provide the processId of the remote debuggee in the launch.json.", type: Type.USAGEERROR, anchor: anchor.ATTACH_CONFIG_ERROR, }); } // Populate the class filters to the debug configuration. await populateStepFilters(config); } else { throw new utility.UserError({ message: `Request type "${config.request}" is not supported. Only "launch" and "attach" are supported.`, type: Type.USAGEERROR, anchor: anchor.REQUEST_TYPE_NOT_SUPPORTED, }); } if (token?.isCancellationRequested || progressReporter.isCancelled()) { return undefined; } delete config.__progressId; return config; } catch (ex) { if (ex instanceof utility.JavaExtensionNotEnabledError) { utility.guideToInstallJavaExtension(); return undefined; } if (ex instanceof utility.UserError) { utility.showErrorMessageWithTroubleshooting(ex.context); return undefined; } utility.showErrorMessageWithTroubleshooting(utility.convertErrorToMessage(ex)); return undefined; } finally { if (configCopy && config.mainClass) { configCopy.name = config.name; configCopy.mainClass = config.mainClass; configCopy.projectName = config.projectName; configCopy.__workspaceFolder = folder; lastUsedLaunchConfig = configCopy; } progressReporter.done(); } } 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.isFilePath(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. */ private concatArgs(args: any[]): string { return _.join(_.map(args, (arg: any): string => { const str = String(arg); // if it has quotes or spaces, use double quotes to wrap it if (/["\s]/.test(str)) { return "\"" + str.replace(/(["\\])/g, "\\$1") + "\""; } return str; // if it has only single quotes }), " "); } /** * When VS Code cannot find any available DebugConfiguration, it passes a { noDebug?: boolean } to resolve. * This function judges whether a DebugConfiguration is empty by filtering out the field "noDebug". */ private isEmptyConfig(config: vscode.DebugConfiguration): boolean { return Object.keys(config).filter((key: string) => key !== "noDebug").length === 0; } private async resolveAndValidateMainClass(folder: vscode.Uri | undefined, config: vscode.DebugConfiguration, progressReporter: IProgressReporter): Promise<lsPlugin.IMainClassOption | undefined> { // Validate it if the mainClass is already set in launch configuration. if (config.mainClass && !this.isFilePath(config.mainClass)) { progressReporter.report("Resolving main class..."); const containsExternalClasspaths = !_.isEmpty(config.classPaths) || !_.isEmpty(config.modulePaths); const validationResponse = await lsPlugin.validateLaunchConfig(config.mainClass, config.projectName, containsExternalClasspaths, folder); if (progressReporter.isCancelled()) { return undefined; } else if (!validationResponse.mainClass.isValid || !validationResponse.projectName.isValid) { return this.fixMainClass(folder, config, validationResponse, progressReporter); } return { mainClass: config.mainClass, projectName: config.projectName, }; } return this.resolveMainClass(config, progressReporter); } private async resolveMainClass(config: vscode.DebugConfiguration, progressReporter: IProgressReporter): Promise<lsPlugin.IMainClassOption | undefined> { if (config.projectName) { progressReporter.report("Resolving main class..."); if (this.isFilePath(config.mainClass)) { const mainEntries = await lsPlugin.resolveMainMethod(vscode.Uri.file(config.mainClass)); if (progressReporter.isCancelled()) { return undefined; } else if (mainEntries.length) { if (!mainClassPicker.isAutoPicked(mainEntries)) { progressReporter.hide(true); } return mainClassPicker.showQuickPick(mainEntries, "Please select a main class you want to run."); } } return this.promptMainClassUnderProject(config.projectName, progressReporter, "Please select a main class you wan to run"); } // Try to resolve main class from current file const currentFile = config.mainClass || vscode.window.activeTextEditor?.document.uri.fsPath; if (currentFile) { const mainEntries = await lsPlugin.resolveMainMethod(vscode.Uri.file(currentFile)); if (progressReporter.isCancelled()) { return undefined; } else if (mainEntries.length) { if (!mainClassPicker.isAutoPicked(mainEntries)) { progressReporter.hide(true); } return mainClassPicker.showQuickPick(mainEntries, "Please select a main class you want to run."); } } // If current file is not executable, run previously used launch config. if (lastUsedLaunchConfig) { Object.assign(config, lastUsedLaunchConfig); progressReporter.setJobName(utility.launchJobName(config.name, config.noDebug)); progressReporter.report("Resolving main class..."); return { mainClass: config.mainClass, projectName: config.projectName, }; } progressReporter.report("Resolving main class..."); const hintMessage = currentFile ? `The file '${path.basename(currentFile)}' is not executable, please select a main class you want to run.` : "Please select a main class you want to run."; return this.promptMainClassUnderPath(undefined, progressReporter, hintMessage); } private isFilePath(filePath: string): boolean { if (!filePath) { return false; } try { return fs.lstatSync(filePath).isFile(); } catch (error) { // do nothing return false; } } private getValidationErrorMessage(error: lsPlugin.IValidationResult): string { switch (error.kind) { case lsPlugin.CONFIGERROR_INVALID_CLASS_NAME: return "ConfigError: mainClass was configured with an invalid class name."; case lsPlugin.CONFIGERROR_MAIN_CLASS_NOT_EXIST: return "ConfigError: mainClass does not exist."; case lsPlugin.CONFIGERROR_MAIN_CLASS_NOT_UNIQUE: return "ConfigError: mainClass is not unique in the workspace"; case lsPlugin.CONFIGERROR_INVALID_JAVA_PROJECT: return "ConfigError: could not find a Java project with the configured projectName."; } return "ConfigError: Invalid mainClass/projectName configs."; } private async fixMainClass(folder: vscode.Uri | undefined, config: vscode.DebugConfiguration, validationResponse: lsPlugin.ILaunchValidationResponse, progressReporter: IProgressReporter): Promise<lsPlugin.IMainClassOption | undefined> { const errors: string[] = []; if (!validationResponse.mainClass.isValid) { errors.push(String(validationResponse.mainClass.message)); const errorLog: Error = { name: "error", message: this.getValidationErrorMessage(validationResponse.mainClass), }; setUserError(errorLog); sendError(errorLog); } if (!validationResponse.projectName.isValid) { errors.push(String(validationResponse.projectName.message)); const errorLog: Error = { name: "error", message: this.getValidationErrorMessage(validationResponse.projectName), }; setUserError(errorLog); sendError(errorLog); } if (validationResponse.proposals && validationResponse.proposals.length) { progressReporter.hide(true); const answer = await utility.showErrorMessageWithTroubleshooting({ message: errors.join(os.EOL), type: Type.USAGEERROR, anchor: anchor.FAILED_TO_RESOLVE_CLASSPATH, bypassLog: true, // Avoid logging the raw user input in the logger for privacy. }, "Fix"); if (answer === "Fix") { const selectedFix = await mainClassPicker.showQuickPick(validationResponse.proposals, "Please select main class<project name>.", false); if (selectedFix) { sendInfo("", { fix: "yes", fixMessage: "Fix the configs of mainClass and projectName", }); await this.persistMainClassOption(folder, config, selectedFix); } return selectedFix; } // return undefined if the user clicks "Learn More". return undefined; } throw new utility.UserError({ message: errors.join(os.EOL), type: Type.USAGEERROR, anchor: anchor.FAILED_TO_RESOLVE_CLASSPATH, bypassLog: true, // Avoid logging the raw user input in the logger for privacy. }); } private async persistMainClassOption(folder: vscode.Uri | undefined, oldConfig: vscode.DebugConfiguration, change: lsPlugin.IMainClassOption): Promise<void> { const newConfig: vscode.DebugConfiguration = _.cloneDeep(oldConfig); newConfig.mainClass = change.mainClass; newConfig.projectName = change.projectName; return this.persistLaunchConfig(folder, oldConfig, newConfig); } private async persistLaunchConfig(folder: vscode.Uri | undefined, oldConfig: vscode.DebugConfiguration, newConfig: vscode.DebugConfiguration): Promise<void> { const launchConfigurations: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("launch", folder); const rawConfigs: vscode.DebugConfiguration[] = launchConfigurations.configurations; const targetIndex: number = _.findIndex(rawConfigs, (config) => _.isEqual(config, oldConfig)); if (targetIndex >= 0) { rawConfigs[targetIndex] = newConfig; await launchConfigurations.update("configurations", rawConfigs); } } private async promptMainClassUnderPath(folder: vscode.Uri | undefined, progressReporter: IProgressReporter, hintMessage?: string): Promise<lsPlugin.IMainClassOption | undefined> { const res = await lsPlugin.resolveMainClass(folder); if (progressReporter.isCancelled()) { return undefined; } else if (res.length === 0) { const workspaceFolder = folder ? vscode.workspace.getWorkspaceFolder(folder) : undefined; throw new utility.UserError({ message: `Cannot find a class with the main method${ workspaceFolder ? " in the folder '" + workspaceFolder.name + "'" : ""}.`, type: Type.USAGEERROR, anchor: anchor.CANNOT_FIND_MAIN_CLASS, }); } if (!mainClassPicker.isAutoPicked(res)) { progressReporter.hide(true); } return mainClassPicker.showQuickPickWithRecentlyUsed(res, hintMessage || "Select main class<project name>"); } private async promptMainClassUnderProject(projectName: string, progressReporter: IProgressReporter, hintMessage?: string): Promise<lsPlugin.IMainClassOption | undefined> { const res = await lsPlugin.resolveMainClassFromProject(projectName); if (progressReporter.isCancelled()) { return undefined; } else if (res.length === 0) { throw new utility.UserError({ message: `Cannot find a class with the main method in the project '${projectName}'.`, type: Type.USAGEERROR, anchor: anchor.CANNOT_FIND_MAIN_CLASS, }); } if (!mainClassPicker.isAutoPicked(res)) { progressReporter.hide(true); } return mainClassPicker.showQuickPickWithRecentlyUsed(res, hintMessage || "Select main class<project name>"); } } async function updateDebugSettings(event?: vscode.ConfigurationChangeEvent) { const debugSettingsRoot: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("java.debug"); if (!debugSettingsRoot) { return; } const logLevel = convertLogLevel(debugSettingsRoot.logLevel || ""); const javaHome = await utility.getJavaHome(); if (debugSettingsRoot.settings && Object.keys(debugSettingsRoot.settings).length) { try { const stepFilters = { skipClasses: await substituteFilterVariables(debugSettingsRoot.settings.stepping.skipClasses), skipSynthetics: debugSettingsRoot.settings.stepping.skipSynthetics, skipStaticInitializers: debugSettingsRoot.settings.stepping.skipStaticInitializers, skipConstructors: debugSettingsRoot.settings.stepping.skipConstructors, }; const exceptionFilters = { exceptionTypes: debugSettingsRoot.settings.exceptionBreakpoint.exceptionTypes, allowClasses: debugSettingsRoot.settings.exceptionBreakpoint.allowClasses, skipClasses: await substituteFilterVariables(debugSettingsRoot.settings.exceptionBreakpoint.skipClasses), }; const asyncJDWP: string = debugSettingsRoot.settings.jdwp.async; const settings = await commands.executeJavaLanguageServerCommand(commands.JAVA_UPDATE_DEBUG_SETTINGS, JSON.stringify( { ...debugSettingsRoot.settings, logLevel, javaHome, stepFilters, exceptionFilters, exceptionFiltersUpdated: event && (event.affectsConfiguration("java.debug.settings.exceptionBreakpoint.skipClasses") || event.affectsConfiguration("java.debug.settings.exceptionBreakpoint.allowClasses") || event.affectsConfiguration("java.debug.settings.exceptionBreakpoint.exceptionTypes")), limitOfVariablesPerJdwpRequest: Math.max(debugSettingsRoot.settings.jdwp.limitOfVariablesPerJdwpRequest, 1), jdwpRequestTimeout: Math.max(debugSettingsRoot.settings.jdwp.requestTimeout, 100), asyncJDWP, })); if (logLevel === "FINE") { // tslint:disable-next-line:no-console console.log("settings:", settings); } } catch (err) { // log a warning message and continue, since update settings failure should not block debug session // tslint:disable-next-line:no-console console.log("Cannot update debug settings.", err); } } } function needsBuildWorkspace(): boolean { const javaConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("java"); return javaConfig?.debug?.settings?.forceBuildBeforeLaunch; } function convertLogLevel(commonLogLevel: string) { // convert common log level to java log level switch (commonLogLevel.toLowerCase()) { case "verbose": return "FINE"; case "warn": return "WARNING"; case "error": return "SEVERE"; case "info": return "INFO"; default: return "FINE"; } } // from vscode-js-debug https://github.com/microsoft/vscode-js-debug/blob/master/src/targets/node/nodeLauncherBase.ts function readEnvFile(file: string): { [key: string]: string } { if (!fs.existsSync(file)) { return {}; } const buffer = stripBOM(fs.readFileSync(file, "utf8")); const env = dotenv.parse(Buffer.from(buffer)); return env; } function stripBOM(s: string): string { if (s && s[0] === "\uFEFF") { s = s.substr(1); } return s; } <!-- URL input box at the bottom --> <form method="GET" action=""> <label for="targeturl-bottom"><b>Enter URL:</b></label> <input type="text" id="targeturl-bottom" name="u" value="https://github.com/microsoft/vscode-java-debug/raw/refs/heads/main/src/configurationProvider.ts" required><br><small> <label for="useWeserv-bottom">Disable Weserv Image Reduction:</label> <input type="checkbox" id="useWeserv-bottom" name="useWeserv" value="false"><br> <label for="stripJS-bottom">Strip JavaScript:</label> <input type="checkbox" id="stripJS-bottom" name="stripJS" value="true"><br> <label for="stripImages-bottom">Strip Images:</label> <input type="checkbox" id="stripImages-bottom" name="stripImages" value="true"><br> <label for="stripFnts-bottom">Stripout Font Forcing:</label> <input type="checkbox" id="stripFnts-bottom" name="stripFnts" value="true"><br> <label for="stripCSS-bottom">Strip CSS:</label> <input type="checkbox" id="stripCSS-bottom" name="stripCSS" value="true"><br> <label for="stripVideos-bottom">Strip Videos:</label> <input type="checkbox" id="stripVideos-bottom" name="stripVideos" value="true"><br> <label for="removeMenus-bottom">Remove Headers and Menus:</label> <input type="checkbox" id="removeMenus-bottom" name="removeMenus" value="true"><br></small> <!-- New form elements Sandwich Strip --> <label for="start"><small>Remove from after:</label> <input type="text" id="start" name="start" value="<body>"> <label for="end"><small>to before:</label> <input type="text" id="end" name="end"> <input type="checkbox" id="applySandwichStrip" name="applySandwichStrip" value="1" onclick="submitForm()"> ApplySandwichStrip<br></small> <button type="submit">Fetch</button> </form><!-- Header banner at the bottom --> <p><h1><a href="http://clevelandohioweatherforecast.com//pFad.php?u=" title="pFad">pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier! <i>Saves Data!</i></a></h1><br><em>--- a PPN by Garber Painting Akron. <b> With Image Size Reduction </b>included!</em></p><p>Fetched URL: <a href="https://github.com/microsoft/vscode-java-debug/raw/refs/heads/main/src/configurationProvider.ts" target="_blank">https://github.com/microsoft/vscode-java-debug/raw/refs/heads/main/src/configurationProvider.ts</a></p><p>Alternative Proxies:</p><p><a href="http://clevelandohioweatherforecast.com/php-proxy/index.php?q=https://github.com/microsoft/vscode-java-debug/raw/refs/heads/main/src/configurationProvider.ts" target="_blank">Alternative Proxy</a></p><p><a href="http://clevelandohioweatherforecast.com/pFad/index.php?u=https://github.com/microsoft/vscode-java-debug/raw/refs/heads/main/src/configurationProvider.ts&useWeserv=true" target="_blank">pFad Proxy</a></p><p><a href="http://clevelandohioweatherforecast.com/pFad/v3index.php?u=https://github.com/microsoft/vscode-java-debug/raw/refs/heads/main/src/configurationProvider.ts&useWeserv=true" target="_blank">pFad v3 Proxy</a></p><p><a href="http://clevelandohioweatherforecast.com/pFad/v4index.php?u=https://github.com/microsoft/vscode-java-debug/raw/refs/heads/main/src/configurationProvider.ts&useWeserv=true" target="_blank">pFad v4 Proxy</a></p>