Add debug/toolbar button to reload changed classes (#586)

* Add debug/toolbar button to reload changed classes

Signed-off-by: Jinbo Wang <jinbwan@microsoft.com>

* Make tslint happy

Signed-off-by: Jinbo Wang <jinbwan@microsoft.com>

* Show a warning when autobuild is disabled

Signed-off-by: Jinbo Wang <jinbwan@microsoft.com>

* Address review comments

Signed-off-by: Jinbo Wang <jinbwan@microsoft.com>
This commit is contained in:
Jinbo Wang 2019-05-28 10:42:32 +08:00 committed by GitHub
parent 7af2ba9b3c
commit f79664cd8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 120 additions and 29 deletions

View File

@ -7,7 +7,7 @@ src/**
tsconfig.json tsconfig.json
gulpfile.js gulpfile.js
.gitignore .gitignore
images/** images/docs/**
testprojects/** testprojects/**
TestPlan.md TestPlan.md
.github/** .github/**

View File

@ -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.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.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.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.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`. - `java.debug.settings.forceBuildBeforeLaunch`: force building the workspace before launching java program, defaults to `true`.

View File

@ -299,20 +299,33 @@ anonymous
1. Open project `19.java9-app` in vscode. 1. Open project `19.java9-app` in vscode.
2. Follow gif to verify step filters feature. 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: 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 ## Hot Code Replace
- Manually trigger hot code replace
1. Open project `24.hotCodeReplace` in vscode. 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. 3. Press `F5` to start debug.
4. The program stopped at the Person.java line 13 4. The program stopped at the Person.java line 13.
5. Change the value of the line "old" to "new" 5. Change the value of the line "old" to "new", and save the document.
5. Save the document to trigger HCR. Check the breakpoint will stop at line 12 6. Click the "Hot Code Replace" icon in the debug toolbar 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` 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 ## 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 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. 3. verify i equals 1000 in variable window.
4. F5 and wait for program to exit. 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. 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. 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 ## 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: 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 ## Classpath shortener for long classpath project
1. Open `longclasspath` project in VS Code. 1. Open `longclasspath` project in VS Code.

View File

@ -45,7 +45,7 @@ This error indicates you are doing `Hot Code Replace`. The `Hot Code Replace` fe
### Try: ### Try:
1. Restart your application to apply the new changes. Or ignore the message, and continue to debug. 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. ## Please specify the host name and the port of the remote debuggee in the launch.json.
### Reason: ### Reason:

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 32 32" style="enable-background:new 0 0 32 32;" xml:space="preserve">
<style type="text/css">
.st0{fill:#F3A600;}
</style>
<title>lightning</title>
<desc>Created with Sketch.</desc>
<g id="lightning">
<path id="Combined-Shape" class="st0" d="M15,12l9,1l-9,19V20l-9-1l9-19V12z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 568 B

View File

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

Before

Width:  |  Height:  |  Size: 281 KiB

After

Width:  |  Height:  |  Size: 281 KiB

View File

Before

Width:  |  Height:  |  Size: 4.5 MiB

After

Width:  |  Height:  |  Size: 4.5 MiB

View File

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@ -14,7 +14,7 @@
"debugger" "debugger"
], ],
"engines": { "engines": {
"vscode": "^1.22.0" "vscode": "^1.32.0"
}, },
"license": "SEE LICENSE IN LICENSE.txt", "license": "SEE LICENSE IN LICENSE.txt",
"repository": { "repository": {
@ -41,7 +41,31 @@
"javaExtensions": [ "javaExtensions": [
"./server/com.microsoft.java.debug.plugin-0.18.0.jar" "./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": [ "debuggers": [
{ {
"type": "java", "type": "java",
@ -409,10 +433,15 @@
"description": "%java.debugger.configuration.maxStringLength.description%", "description": "%java.debugger.configuration.maxStringLength.description%",
"default": 0 "default": 0
}, },
"java.debug.settings.enableHotCodeReplace": { "java.debug.settings.hotCodeReplace": {
"type": "boolean", "type": "string",
"description": "%java.debugger.configuration.enableHotCodeReplace.description%", "default": "manual",
"default": true "description": "%java.debugger.configuration.hotCodeReplace.description%",
"enum": [
"auto",
"manual",
"never"
]
}, },
"java.debug.settings.enableRunDebugCodeLens": { "java.debug.settings.enableRunDebugCodeLens": {
"type": "boolean", "type": "boolean",

View File

@ -5,6 +5,5 @@
"java.debugger.configuration.showStaticVariables.description": "Mostra variabili statiche nella scheda \"variabili\".", "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.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.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." "java.debugger.configuration.enableRunDebugCodeLens.description": "Abilitare i provider di lenti di codice run e debug sui metodi principali."
} }

View File

@ -41,7 +41,7 @@
"java.debugger.configuration.showQualifiedNames.description": "Show fully qualified class names in \"Variables\" viewlet.", "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.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.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.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." "java.debugger.configuration.forceBuildBeforeLaunch": "Force building the workspace before launching java program."
} }

View File

@ -41,7 +41,7 @@
"java.debugger.configuration.showQualifiedNames.description": "在“变量”视图中显示类的全名。", "java.debugger.configuration.showQualifiedNames.description": "在“变量”视图中显示类的全名。",
"java.debugger.configuration.showLogicalStructure.description": "在“变量”视图中显示Collection和Map类的逻辑结构。", "java.debugger.configuration.showLogicalStructure.description": "在“变量”视图中显示Collection和Map类的逻辑结构。",
"java.debugger.configuration.maxStringLength.description": "设定“变量”或“调试控制台”视图中显示的字符串最大长度长度超过部分将被剪掉。如果值为0则不执行修剪。", "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.enableRunDebugCodeLens.description": "在main方法上启用CodeLens标记。",
"java.debugger.configuration.forceBuildBeforeLaunch": "在启动java程序之前强制编译整个工作空间。" "java.debugger.configuration.forceBuildBeforeLaunch": "在启动java程序之前强制编译整个工作空间。"
} }

View File

@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. // Licensed under the MIT license.
import * as path from "path";
import * as vscode from "vscode"; import * as vscode from "vscode";
import { dispose as disposeTelemetryWrapper, initializeFromJsonFile, instrumentOperation } from "vscode-extension-telemetry-wrapper"; import { dispose as disposeTelemetryWrapper, initializeFromJsonFile, instrumentOperation } from "vscode-extension-telemetry-wrapper";
import * as commands from "./commands"; import * as commands from "./commands";
@ -49,6 +48,29 @@ function initializeExtension(operationId: string, context: vscode.ExtensionConte
context.subscriptions.push(instrumentAndRegisterCommand("JavaDebug.SpecifyProgramArgs", async () => { context.subscriptions.push(instrumentAndRegisterCommand("JavaDebug.SpecifyProgramArgs", async () => {
return specifyProgramArguments(context); 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); initializeHotCodeReplace(context);
context.subscriptions.push(vscode.debug.onDidReceiveDebugSessionCustomEvent((customEvent) => { context.subscriptions.push(vscode.debug.onDidReceiveDebugSessionCustomEvent((customEvent) => {
const t = customEvent.session ? customEvent.session.type : undefined; const t = customEvent.session ? customEvent.session.type : undefined;

View File

@ -4,7 +4,7 @@
import * as vscode from "vscode"; import * as vscode from "vscode";
import * as anchor from "./anchor"; import * as anchor from "./anchor";
import { HCR_EVENT, JAVA_LANGID } from "./constants"; import { JAVA_LANGID } from "./constants";
import * as utility from "./utility"; import * as utility from "./utility";
const suppressedReasons: Set<string> = new Set(); const suppressedReasons: Set<string> = new Set();
@ -24,6 +24,12 @@ enum HcrChangeType {
} }
export function initializeHotCodeReplace(context: vscode.ExtensionContext) { 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) => { context.subscriptions.push(vscode.debug.onDidTerminateDebugSession((session) => {
const t = session ? session.type : undefined; const t = session ? session.type : undefined;
if (t === JAVA_LANGID) { if (t === JAVA_LANGID) {
@ -34,11 +40,13 @@ export function initializeHotCodeReplace(context: vscode.ExtensionContext) {
export function handleHotCodeReplaceCustomEvent(hcrEvent) { export function handleHotCodeReplaceCustomEvent(hcrEvent) {
if (hcrEvent.body.changeType === HcrChangeType.BUILD_COMPLETE) { if (hcrEvent.body.changeType === HcrChangeType.BUILD_COMPLETE) {
if (getHotReloadFlag() === "auto") {
return vscode.window.withProgress({ location: vscode.ProgressLocation.Window }, (progress) => { return vscode.window.withProgress({ location: vscode.ProgressLocation.Window }, (progress) => {
progress.report({ message: "Applying code changes..." }); progress.report({ message: "Applying code changes..." });
return hcrEvent.session.customRequest("redefineClasses"); return hcrEvent.session.customRequest("redefineClasses");
}); });
} }
}
if (hcrEvent.body.changeType === HcrChangeType.ERROR || hcrEvent.body.changeType === HcrChangeType.WARNING) { if (hcrEvent.body.changeType === HcrChangeType.ERROR || hcrEvent.body.changeType === HcrChangeType.WARNING) {
if (!suppressedReasons.has(hcrEvent.body.message)) { if (!suppressedReasons.has(hcrEvent.body.message)) {
@ -55,3 +63,7 @@ export function handleHotCodeReplaceCustomEvent(hcrEvent) {
} }
} }
} }
function getHotReloadFlag(): string {
return vscode.workspace.getConfiguration("java.debug.settings").get("hotCodeReplace") || "manual";
}