This was all strictly visual. The only controls I've added for now are continue and step. Let's implement those.
The idea is that once we've hit a breakpoint and are in "debug mode", we can press continue and it will go again until it hits the next user breakpoint. Alternatively, we can press "step" and it will only continue until it attempts to execute the next method or action (at the moment, we don't have action breakpoints set, but I'm going to add them after this episode).
Most debuggers have a "pause" or "interrupt" button, but given that our program is idle most of the time, that doesn't seem worth it.
Most of the code we are going to write is boring, vanilla JavaScript with just a couple of lines of interaction with the debugger that are little different to those we've already seen.
SidePanel Code
Starting with some true boilerplate, we now need to track whether or not we are in "debug" mode so that the buttons are only effective when they should be. We also need to find the buttons in the sidepanel DOM.var debugMode = false;
var continueButton = document.querySelector(".tool-continue");
var stepButton = document.querySelector(".tool-step");
CDP_CONTINUE_STEP:cdp-till/plugin/html/js/sidepanel.js
We need to update the UI every time the debugger becomes active or inactive:function debuggerActive() {
debugMode = true;
breakAt.classList.add("current-break");
continueButton.classList.add("available");
stepButton.classList.add("available");
}
function debuggerInactive() {
debugMode = false;
breakAt.classList.remove("current-break");
continueButton.classList.remove("available");
stepButton.classList.remove("available");
}
CDP_CONTINUE_STEP:cdp-till/plugin/html/js/sidepanel.js
We need handlers for the continue and step buttons:function continueExecution(ev) {
if (!debugMode) {
return;
}
debuggerInactive();
askContinue(false);
}
function stepExecution(ev) {
if (!debugMode) {
return;
}
debuggerInactive();
askContinue(true);
}
CDP_CONTINUE_STEP:cdp-till/plugin/html/js/sidepanel.js
These basically do the same thing, which is to call the askContinue method with a flag indicating whether or not the continuation should be in "step" mode. askContinue turns around and passes the request on to the service worker thread, because that is the context in which we communicate with the debugger.function askContinue(stepMode) {
chrome.runtime.sendMessage({ action: "continue", stepMode: stepMode }).then(resp => {
console.log("response", resp);
});
}
CDP_CONTINUE_STEP:cdp-till/plugin/html/js/sidepanel.js
Having written all the code, we need to wire it up. At the end of the script, we bind the handlers to the buttons' click events:continueButton.addEventListener("click", continueExecution);
stepButton.addEventListener("click", stepExecution);
CDP_CONTINUE_STEP:cdp-till/plugin/html/js/sidepanel.js
And we need to make sure that when we are notified that we have hit a breakpoint, we call the debuggerActive method:case "hitBreakpoint": {
var l = request.line;
breakAt = sourceLines[l].children[1];
debuggerActive();
break;
CDP_CONTINUE_STEP:cdp-till/plugin/html/js/sidepanel.js
(Note that a small refactoring happened here: the toggling of the style currentBreak has been moved into the active/inactive methods (above) and removed from hitBreakpoint here.)Service Worker Code
Meanwhile, over in the service-worker.js file, we need to interact with the debugger. We need to keep track of two things. First, if we are in "step" mode or "run" mode, and then, when we are notified that we have hit a breakpoint, the "source" of that event so that we can respond later.var stepMode = false;
var breakpointSource;
CDP_CONTINUE_STEP:cdp-till/plugin/js/service-worker.js
When the user presses one of the buttons, the notification comes in through the onMessage listener. We already have a case to deal with setting breakpoints, so we just need to add another case for continue, setting stepMode appropriately:case "continue": {
stepMode = request.stepMode;
chrome.debugger.sendCommand(breakpointSource, "Debugger.resume").then(resp => {
console.log("resume response", resp);
});
break;
CDP_CONTINUE_STEP:cdp-till/plugin/js/service-worker.js
And then the final change is to say that we enter debug mode when we hit a classified breakpoint OR when we are in step mode.chrome.debugger.sendCommand(source, "Debugger.evaluateOnCallFrame", { callFrameId: params.callFrames[0].callFrameId, expression: "this.lineNo" }).then(resp => {
var lineNo = resp.result.value;
console.log("line #:", lineNo);
if (stepMode || breakpointLines[lineNo]) {
breakpointSource = source;
chrome.runtime.sendMessage({ action: "hitBreakpoint", line: lineNo });
} else {
CDP_CONTINUE_STEP:cdp-till/plugin/js/service-worker.js
And that's it. We can press the continue and step buttons to see what happens.
No comments:
Post a Comment