diff --git a/.vscodeignore b/.vscodeignore index 8c941a45..538d224d 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -7,7 +7,7 @@ src/** tsconfig.json gulpfile.js .gitignore -images/** +images/docs/** testprojects/** TestPlan.md .github/** diff --git a/README.md b/README.md index a5889aca..57d4b507 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,10 @@ Please also check the documentation of [Language Support for Java by Red Hat](ht - `java.debug.settings.showQualifiedNames`: show fully qualified class names in "Variables" viewlet, defaults to `false`. - `java.debug.settings.showLogicalStructure`: show the logical structure for the Collection and Map classes in "Variables" viewlet, defaults to `true`. - `java.debug.settings.maxStringLength`: the maximum length of string displayed in "Variables" or "Debug Console" viewlet, the string longer than this length will be trimmed, defaults to `0` which means no trim is performed. -- `java.debug.settings.enableHotCodeReplace`: enable hot code replace for Java code. Make sure the auto build is not disabled for [VSCode Java](https://github.com/redhat-developer/vscode-java). See the [wiki page](https://github.com/Microsoft/vscode-java-debug/wiki/Hot-Code-Replace) for more information about usages and limitations. +- `java.debug.settings.hotCodeReplace`: Reload the changed Java classes during debugging, defaults to `manual`. Make sure `java.autobuild.enabled` is not disabled for [VSCode Java](https://github.com/redhat-developer/vscode-java). See the [wiki page](https://github.com/Microsoft/vscode-java-debug/wiki/Hot-Code-Replace) for more information about usages and limitations. + - manual - Click the toolbar to apply the changes. + - auto - Automatically apply the changes after compilation. + - never - Never apply the changes. - `java.debug.settings.enableRunDebugCodeLens`: enable the code lens provider for the run and debug buttons over main entry points, defaults to `true`. - `java.debug.settings.forceBuildBeforeLaunch`: force building the workspace before launching java program, defaults to `true`. diff --git a/TestPlan.md b/TestPlan.md index 40823019..02c40354 100644 --- a/TestPlan.md +++ b/TestPlan.md @@ -299,20 +299,33 @@ anonymous 1. Open project `19.java9-app` in vscode. 2. Follow gif to verify step filters feature. -![stepfilter](images/33868694-673f14b0-df3f-11e7-9983-b3cff5842020.gif) +![stepfilter](images/docs/33868694-673f14b0-df3f-11e7-9983-b3cff5842020.gif) The new gif: -![stepfilters](images/34507770-69597114-f074-11e7-8f32-027ad1d7a4fd.gif) +![stepfilters](images/docs/34507770-69597114-f074-11e7-8f32-027ad1d7a4fd.gif) ## Hot Code Replace - +- Manually trigger hot code replace 1. Open project `24.hotCodeReplace` in vscode. -2. Set breakpoints: NameProvider.java line 12; Person.java line 13 +2. Set breakpoints: NameProvider.java line 12; Person.java line 13. 3. Press `F5` to start debug. -4. The program stopped at the Person.java line 13 -5. Change the value of the line "old" to "new" -5. Save the document to trigger HCR. Check the breakpoint will stop at line 12 -6. Click F10 to step over, check the value of `res` on the debug view of local variable which should be `new` +4. The program stopped at the Person.java line 13. +5. Change the value of the line "old" to "new", and save the document. +6. Click the "Hot Code Replace" icon in the debug toolbar to trigger HCR. Check the breakpoint will stop at line 12 . +7. Click F10 to step over, check the value of `res` on the debug view of local variable which should be `new`. + +- Automatically trigger hot code replace +1. Repeat step 1 ~ 4 above. +2. Change `java.debug.settings.hotCodeReplace` to `auto`. +3. Change the value of the line "old" to "new", and save the document. +4. HCR will be automatically triggered. Check the breakpoint will stop at line 12 . +5. Click F10 to step over, check the value of `res` on the debug view of local variable which should be `new`. + +- Disable hot code replace +1. Repeat step 1 ~ 4 above. +2. Change `java.debug.settings.hotCodeReplace` to `never`. +3. Change the value of the line "old" to "new", and save the document. +4. Click F10 to step over, check the value of `res` on the debug view of local variable which should be `old`. ## Conditional Breakpoints @@ -342,7 +355,7 @@ public class App 2. set conditional breakpoint on line 13 with condition `i ==1000`, F5 and wait the breakpoint to be hit -![java-conditional-bp-demo](images/37269785-0ffef8e6-2607-11e8-955f-93548ad5a0ad.gif) +![java-conditional-bp-demo](images/docs/37269785-0ffef8e6-2607-11e8-955f-93548ad5a0ad.gif) 3. verify i equals 1000 in variable window. 4. F5 and wait for program to exit. @@ -406,7 +419,7 @@ Exception in thread "main" java.lang.IllegalStateException 2. Launch java debugger and continue your program. 3. When the logpoint code branch is hit, it just log the message to the console and doesn't stop your program. -![logpoint](images/41949312-77627a40-79f3-11e8-9fd2-def4fa06e28d.gif) +![logpoint](images/docs/41949312-77627a40-79f3-11e8-9fd2-def4fa06e28d.gif) ## Start without debugging @@ -472,7 +485,7 @@ Exception in thread "main" java.lang.IllegalStateException ``` 4. Press F5 to verify the variables should be like this: - ![args](images/args.PNG) + ![args](images/docs/args.PNG) ## Classpath shortener for long classpath project 1. Open `longclasspath` project in VS Code. diff --git a/Troubleshooting.md b/Troubleshooting.md index c8966585..f566c3e8 100644 --- a/Troubleshooting.md +++ b/Troubleshooting.md @@ -45,7 +45,7 @@ This error indicates you are doing `Hot Code Replace`. The `Hot Code Replace` fe ### Try: 1. Restart your application to apply the new changes. Or ignore the message, and continue to debug. -2. You can disable the hot code replace feature by changing the user setting `"java.debug.settings.enableHotCodeReplace": false`. +2. You can disable the hot code replace feature by changing the user setting `"java.debug.settings.hotCodeReplace": "never"`. ## Please specify the host name and the port of the remote debuggee in the launch.json. ### Reason: diff --git a/images/commands/hot_code_replace.svg b/images/commands/hot_code_replace.svg new file mode 100644 index 00000000..3e070476 --- /dev/null +++ b/images/commands/hot_code_replace.svg @@ -0,0 +1,13 @@ + + + + +lightning +Created with Sketch. + + + + diff --git a/images/33868694-673f14b0-df3f-11e7-9983-b3cff5842020.gif b/images/docs/33868694-673f14b0-df3f-11e7-9983-b3cff5842020.gif similarity index 100% rename from images/33868694-673f14b0-df3f-11e7-9983-b3cff5842020.gif rename to images/docs/33868694-673f14b0-df3f-11e7-9983-b3cff5842020.gif diff --git a/images/34507770-69597114-f074-11e7-8f32-027ad1d7a4fd.gif b/images/docs/34507770-69597114-f074-11e7-8f32-027ad1d7a4fd.gif similarity index 100% rename from images/34507770-69597114-f074-11e7-8f32-027ad1d7a4fd.gif rename to images/docs/34507770-69597114-f074-11e7-8f32-027ad1d7a4fd.gif diff --git a/images/37269785-0ffef8e6-2607-11e8-955f-93548ad5a0ad.gif b/images/docs/37269785-0ffef8e6-2607-11e8-955f-93548ad5a0ad.gif similarity index 100% rename from images/37269785-0ffef8e6-2607-11e8-955f-93548ad5a0ad.gif rename to images/docs/37269785-0ffef8e6-2607-11e8-955f-93548ad5a0ad.gif diff --git a/images/41949312-77627a40-79f3-11e8-9fd2-def4fa06e28d.gif b/images/docs/41949312-77627a40-79f3-11e8-9fd2-def4fa06e28d.gif similarity index 100% rename from images/41949312-77627a40-79f3-11e8-9fd2-def4fa06e28d.gif rename to images/docs/41949312-77627a40-79f3-11e8-9fd2-def4fa06e28d.gif diff --git a/images/args.PNG b/images/docs/args.PNG similarity index 100% rename from images/args.PNG rename to images/docs/args.PNG diff --git a/package.json b/package.json index a4bd30a3..16a040e4 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "debugger" ], "engines": { - "vscode": "^1.22.0" + "vscode": "^1.32.0" }, "license": "SEE LICENSE IN LICENSE.txt", "repository": { @@ -41,7 +41,31 @@ "javaExtensions": [ "./server/com.microsoft.java.debug.plugin-0.18.0.jar" ], - "commands": [], + "commands": [ + { + "command": "java.debug.hotCodeReplace", + "title": "Hot Code Replace", + "icon": { + "dark": "images/commands/hot_code_replace.svg", + "light": "images/commands/hot_code_replace.svg" + } + } + ], + "menus": { + "debug/toolBar": [ + { + "command": "java.debug.hotCodeReplace", + "group": "navigation@100", + "when": "inDebugMode && debugType == java && javaHotReload == 'manual'" + } + ], + "commandPalette": [ + { + "command": "java.debug.hotCodeReplace", + "when": "false" + } + ] + }, "debuggers": [ { "type": "java", @@ -409,10 +433,15 @@ "description": "%java.debugger.configuration.maxStringLength.description%", "default": 0 }, - "java.debug.settings.enableHotCodeReplace": { - "type": "boolean", - "description": "%java.debugger.configuration.enableHotCodeReplace.description%", - "default": true + "java.debug.settings.hotCodeReplace": { + "type": "string", + "default": "manual", + "description": "%java.debugger.configuration.hotCodeReplace.description%", + "enum": [ + "auto", + "manual", + "never" + ] }, "java.debug.settings.enableRunDebugCodeLens": { "type": "boolean", diff --git a/package.nls.it.json b/package.nls.it.json index 03c66a1f..e7654964 100644 --- a/package.nls.it.json +++ b/package.nls.it.json @@ -5,6 +5,5 @@ "java.debugger.configuration.showStaticVariables.description": "Mostra variabili statiche nella scheda \"variabili\".", "java.debugger.configuration.showQualifiedNames.description": "Mostra nome completo delle classi nella scheda \"variabili\".", "java.debugger.configuration.maxStringLength.description": "Lunghezza massima delle stringhe visualizzate nella scheda \"Variabili\" o \"Console di Debug\", stringhe più lunghe di questo numero verranno tagliate, se 0 nessun taglio viene eseguito.", - "java.debugger.configuration.enableHotCodeReplace.description": "Attiva sostituzione hotcode per codice Java.", "java.debugger.configuration.enableRunDebugCodeLens.description": "Abilitare i provider di lenti di codice run e debug sui metodi principali." } diff --git a/package.nls.json b/package.nls.json index edadc88d..342eade2 100644 --- a/package.nls.json +++ b/package.nls.json @@ -41,7 +41,7 @@ "java.debugger.configuration.showQualifiedNames.description": "Show fully qualified class names in \"Variables\" viewlet.", "java.debugger.configuration.showLogicalStructure.description": "Show the logical structure for the Collection and Map classes in \"Variables\" viewlet.", "java.debugger.configuration.maxStringLength.description": "The maximum length of strings displayed in \"Variables\" or \"Debug Console\" viewlet, strings longer than this length will be trimmed, if 0 no trim is performed.", - "java.debugger.configuration.enableHotCodeReplace.description": "Enable hot code replace for Java code.", + "java.debugger.configuration.hotCodeReplace.description": "Reload the changed Java classes during debugging. Make sure 'java.autobuild.enabled' is not disabled.", "java.debugger.configuration.enableRunDebugCodeLens.description": "Enable the run and debug code lens providers over main methods.", "java.debugger.configuration.forceBuildBeforeLaunch": "Force building the workspace before launching java program." } diff --git a/package.nls.zh.json b/package.nls.zh.json index 1f51555f..cc5538a2 100644 --- a/package.nls.zh.json +++ b/package.nls.zh.json @@ -41,7 +41,7 @@ "java.debugger.configuration.showQualifiedNames.description": "在“变量”视图中显示类的全名。", "java.debugger.configuration.showLogicalStructure.description": "在“变量”视图中显示Collection和Map类的逻辑结构。", "java.debugger.configuration.maxStringLength.description": "设定“变量”或“调试控制台”视图中显示的字符串最大长度,长度超过部分将被剪掉。如果值为0,则不执行修剪。", - "java.debugger.configuration.enableHotCodeReplace.description": "为Java代码启用热代码替换。", + "java.debugger.configuration.hotCodeReplace.description": "在调试期间重新加载已更改的Java类。确保未禁用'java.autobuild.enabled'。", "java.debugger.configuration.enableRunDebugCodeLens.description": "在main方法上启用CodeLens标记。", "java.debugger.configuration.forceBuildBeforeLaunch": "在启动java程序之前强制编译整个工作空间。" } \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index a997ea48..2f14591a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -import * as path from "path"; import * as vscode from "vscode"; import { dispose as disposeTelemetryWrapper, initializeFromJsonFile, instrumentOperation } from "vscode-extension-telemetry-wrapper"; import * as commands from "./commands"; @@ -49,6 +48,29 @@ function initializeExtension(operationId: string, context: vscode.ExtensionConte context.subscriptions.push(instrumentAndRegisterCommand("JavaDebug.SpecifyProgramArgs", async () => { return specifyProgramArguments(context); })); + context.subscriptions.push(instrumentAndRegisterCommand("java.debug.hotCodeReplace", async (args: any) => { + const autobuildConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("java.autobuild"); + if (!autobuildConfig.enabled) { + const ans = await vscode.window.showWarningMessage( + "The hot code replace feature requires you to enable the autobuild flag, do you want to enable it?", + "Yes", "No"); + if (ans === "Yes") { + await autobuildConfig.update("enabled", true); + } else { + return; + } + } + + const debugSession: vscode.DebugSession = vscode.debug.activeDebugSession; + if (!debugSession) { + return; + } + + return vscode.window.withProgress({ location: vscode.ProgressLocation.Window }, async (progress) => { + progress.report({ message: "Applying code changes..." }); + return await debugSession.customRequest("redefineClasses"); + }); + })); initializeHotCodeReplace(context); context.subscriptions.push(vscode.debug.onDidReceiveDebugSessionCustomEvent((customEvent) => { const t = customEvent.session ? customEvent.session.type : undefined; diff --git a/src/hotCodeReplace.ts b/src/hotCodeReplace.ts index a49fbfe0..2e7d0589 100644 --- a/src/hotCodeReplace.ts +++ b/src/hotCodeReplace.ts @@ -4,7 +4,7 @@ import * as vscode from "vscode"; import * as anchor from "./anchor"; -import { HCR_EVENT, JAVA_LANGID } from "./constants"; +import { JAVA_LANGID } from "./constants"; import * as utility from "./utility"; const suppressedReasons: Set = new Set(); @@ -24,6 +24,12 @@ enum HcrChangeType { } export function initializeHotCodeReplace(context: vscode.ExtensionContext) { + vscode.commands.executeCommand("setContext", "javaHotReload", getHotReloadFlag()); + vscode.workspace.onDidChangeConfiguration((event) => { + if (event.affectsConfiguration("java.debug.settings.hotCodeReplace")) { + vscode.commands.executeCommand("setContext", "javaHotReload", getHotReloadFlag()); + } + }); context.subscriptions.push(vscode.debug.onDidTerminateDebugSession((session) => { const t = session ? session.type : undefined; if (t === JAVA_LANGID) { @@ -34,10 +40,12 @@ export function initializeHotCodeReplace(context: vscode.ExtensionContext) { export function handleHotCodeReplaceCustomEvent(hcrEvent) { if (hcrEvent.body.changeType === HcrChangeType.BUILD_COMPLETE) { - return vscode.window.withProgress({ location: vscode.ProgressLocation.Window }, (progress) => { - progress.report({ message: "Applying code changes..." }); - return hcrEvent.session.customRequest("redefineClasses"); - }); + if (getHotReloadFlag() === "auto") { + return vscode.window.withProgress({ location: vscode.ProgressLocation.Window }, (progress) => { + progress.report({ message: "Applying code changes..." }); + return hcrEvent.session.customRequest("redefineClasses"); + }); + } } if (hcrEvent.body.changeType === HcrChangeType.ERROR || hcrEvent.body.changeType === HcrChangeType.WARNING) { @@ -55,3 +63,7 @@ export function handleHotCodeReplaceCustomEvent(hcrEvent) { } } } + +function getHotReloadFlag(): string { + return vscode.workspace.getConfiguration("java.debug.settings").get("hotCodeReplace") || "manual"; +}