Skip to content

Commit

Permalink
Make checkpoints nameable in UI
Browse files Browse the repository at this point in the history
We don't save the names, since persistent checkpoints rr-debugger/rr#3406
haven't been fully implemented yet. When it gets finished
we can think about having persistent names as well.
  • Loading branch information
theIDinside committed Jan 20, 2024
1 parent f5fa3ce commit b15d4d0
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 55 deletions.
9 changes: 2 additions & 7 deletions modules/gdb-dap/debugSession.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const EventEmitter = require("events");

// eslint-disable-next-line no-unused-vars
const net = require("node:net");
const { toHexString, getAPI, uiSetAllStopComponent } = require("../utils/utils");
const { toHexString, getAPI, uiSetAllStopComponent, ContextKeys } = require("../utils/utils");
const { TerminatedEvent, OutputEvent, InitializedEvent } = require("@vscode/debugadapter");
const { getExtensionPathOf } = require("../utils/sysutils");
const { CustomRequests } = require("../debugSessionCustomRequests");
Expand Down Expand Up @@ -277,18 +277,14 @@ class MidasDAPSession extends DebugAdapter.DebugSession {
}
});

this.on("exit", (evt) => {
this.dispose();
});

this.on("error", (event) => {
this.sendEvent(new DebugAdapter.OutputEvent(event.body, "console", event));
});

}

dispose() {
this.#checkpointsUI.tearDown();
vscode.commands.executeCommand("setContext", ContextKeys.RRSession, false);
this.disposeTerminal();
super.dispose();
}
Expand Down Expand Up @@ -468,7 +464,6 @@ class MidasDAPSession extends DebugAdapter.DebugSession {

// eslint-disable-next-line no-unused-vars
disconnectRequest(response, args, request) {
this.#checkpointsUI.tearDown();
this.gdb.sendRequest(request, args);
}

Expand Down
31 changes: 22 additions & 9 deletions modules/ui/checkpoints/checkpoints.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ class CheckpointsViewProvider {
*/
constructor(extensionContext) {
this.#extensionUri = extensionContext.extensionUri;
this.checkpointIdToNameMap = new Map();

let setCheckpoint = registerCommand("midas.set-checkpoint", () => {
vscode.debug.activeDebugSession.customRequest(CustomRequests.SetCheckpoint);
});
Expand All @@ -33,18 +35,14 @@ class CheckpointsViewProvider {

updateCheckpoints(checkpoints, show = true) {
if (this.#view) {
if (show) this.#view.show?.(true); // `show` is not implemented in 1.49 but is for 1.50 insiders

if (show) this.#view.show?.(true);
for(let cp of checkpoints) {
cp.name = this.checkpointIdToNameMap.get(cp.id) ?? `${cp.where.path}:${cp.where.line}`;
}
this.#view.webview.postMessage({ type: UI_MESSAGES.UpdateCheckpoints, payload: checkpoints });
}
}

addCheckpoint(checkpoint) {
if (this.#view) {
this.#view.show?.(true); // `show` is not implemented in 1.49 but is for 1.50 insiders
this.#view.webview.postMessage({ type: UI_MESSAGES.AddCheckpoint, payload: checkpoint });
}
}
/**
* Gets resource `resource` from the Checkpoints UI module.
* @param {string} resource
Expand All @@ -69,6 +67,9 @@ class CheckpointsViewProvider {
// eslint-disable-next-line no-unused-vars
async resolveWebviewView(webviewView, context, token) {
this.#view = webviewView;
this.#view.onDidDispose(() => {
this.checkpointIdToNameMap.clear();
});
webviewView.webview.options = {
// Allow scripts in the webview
enableScripts: true,
Expand All @@ -77,15 +78,27 @@ class CheckpointsViewProvider {

webviewView.webview.html = this.#createHTMLForWebView(webviewView.webview);

webviewView.webview.onDidReceiveMessage((data) => {
webviewView.webview.onDidReceiveMessage(async (data) => {
switch (data.type) {
case UI_REQUESTS.DeleteCheckpoint: {
this.checkpointIdToNameMap.delete(data.value);
vscode.debug.activeDebugSession.customRequest(CustomRequests.DeleteCheckpoint, data.value);
break;
}
case UI_REQUESTS.RunToCheckpoint:
vscode.debug.activeDebugSession.customRequest(CustomRequests.RestartCheckpoint, data.value);
break;
case UI_REQUESTS.NameCheckpoint:
const { checkpointId, name } = data.value;
this.checkpointIdToNameMap.set(checkpointId, name);
break;
case UI_REQUESTS.GotoSourceLoc:
const { path, line } = data.value;
const doc = await vscode.workspace.openTextDocument(path);
const editor = await vscode.window.showTextDocument(doc, { preview: false });
const position = new vscode.Position(line, 0);
editor.revealRange(new vscode.Range(position, position), vscode.TextEditorRevealType.InCenter);
break;
}
});
}
Expand Down
90 changes: 52 additions & 38 deletions modules/ui/checkpoints/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,60 +6,77 @@ function setupUI(protocol) {
(function () {
const vscode = acquireVsCodeApi();
function create_row(container, cp) {
let name = document.createElement("span");
name.textContent = `${cp.when}`;
name.className = "checkpoints-list-when";
const checkpointEventNumber = document.createElement("span");
checkpointEventNumber.textContent = `${cp.when}`;
checkpointEventNumber.className = "checkpoints-list-when";
container.appendChild(checkpointEventNumber);

container.appendChild(name);
const checkpointName = document.createElement("span");
checkpointName.textContent = cp.name;
checkpointName.className = "file-path";
checkpointName.addEventListener("click", () => {
const sourceLocPath = cp.where.path.split(" at ")[1];

let path = document.createElement("span");
path.textContent = cp.where.path;
path.className = "file-path";
container.appendChild(path);
if(sourceLocPath)
vscode.postMessage({ type: UI_REQUESTS.GotoSourceLoc, value: { path: sourceLocPath, line: cp.where.line }});
});

checkpointName.addEventListener("keydown", (event) => {
if (event.keyCode === 13) {
checkpointName.contentEditable = false;
event.target.blur();
}
});

checkpointName.addEventListener("blur", (event) => {
const payload = { checkpointId: cp.id, name: event.target.textContent };
vscode.postMessage({ type: UI_MESSAGES.NameCheckpoint, value: payload });
});

let action_bar = document.createElement("div");
action_bar.className = "checkpoints-action-bar";
let action_container = document.createElement("ul");
checkpointName.id = `cp-${cp.id}`;

container.appendChild(checkpointName);

const actionBar = document.createElement("div");
actionBar.className = "checkpoints-action-bar";
let actionContainer = document.createElement("ul");

const editButton = document.createElement("li");
editButton.className = "row-button codicon codicon-edit";

editButton.addEventListener("click", () => {
checkpointName.contentEditable = true;
checkpointName.focus();
});

let play_button = document.createElement("li");
play_button.className = "row-button codicon codicon-debug-continue";
const playButton = document.createElement("li");
playButton.className = "row-button codicon codicon-debug-continue";

play_button.addEventListener("click", () => {
playButton.addEventListener("click", () => {
vscode.postMessage({ type: UI_REQUESTS.RunToCheckpoint, value: container.dataset.checkpointId });
});

let remove_button = document.createElement("li");
remove_button.className = "row-button codicon codicon-chrome-close";
const removeButton = document.createElement("li");
removeButton.className = "row-button codicon codicon-chrome-close";

remove_button.addEventListener("click", () => {
removeButton.addEventListener("click", () => {
vscode.postMessage({ type: UI_REQUESTS.DeleteCheckpoint, value: container.dataset.checkpointId });
});

action_container.appendChild(play_button);
action_container.appendChild(remove_button);
action_bar.appendChild(action_container);
container.appendChild(action_bar);

let line = document.createElement("span");
line.textContent = +cp.where.line;
line.className = "checkpoints-count-badge";
container.appendChild(line);
// div.appendChild(container);
// return div;
actionContainer.appendChild(editButton);
actionContainer.appendChild(playButton);
actionContainer.appendChild(removeButton);
actionBar.appendChild(actionContainer);
container.appendChild(actionBar);
}
const oldState = { checkpoints: [] };
/** @type {Array<CheckpointInfo>} */
let checkpoints = oldState.checkpoints;

updateCheckpointsList(checkpoints);

// Handle messages sent from the extension to the webview
window.addEventListener("message", (event) => {
const message = event.data; // The json data that the extension sent
switch (message.type) {
case UI_MESSAGES.ClearCheckpoints: {
checkpoints = [];
updateCheckpointsList(checkpoints);
updateCheckpointsList([]);
break;
}
case UI_MESSAGES.RemovedCheckpoint: {
Expand All @@ -83,20 +100,17 @@ function setupUI(protocol) {
for (const cp of checkpoints) {
const row = document.createElement("div");
row.className = "checkpoints-list-row";
// row.role = "checkbox";
//row.ariaChecked = true;
row.dataIndex = idx;
row.dataLastElement = idx == checkpoints.length - 1;
row.dataset.index = idx;
row.dataset.checkpointId = cp.id;
row.ariaPosInSet = idx + 1;
row.id = `cp-row-${cp.id}`;
create_row(row, cp);
cp_list.appendChild(row);

idx += 1;
}
// Update the saved state
vscode.setState({ checkpoints: checkpoints });
}

function removeCheckpoint(checkpointId) {
Expand Down
3 changes: 2 additions & 1 deletion modules/ui/checkpoints/ui_protocol.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ const UI_MESSAGES = {
ClearCheckpoints: "clear-checkpoint",
RemovedCheckpoint: "removed-checkpoint",
UpdateCheckpoints: "update-checkpoints",
NameCheckpoint: "name-checkpoint"
};

const UI_REQUESTS = { DeleteCheckpoint: "delete-checkpoint", RunToCheckpoint: "run-to-checkpoint" };
const UI_REQUESTS = { DeleteCheckpoint: "delete-checkpoint", RunToCheckpoint: "run-to-checkpoint", NameCheckpoint: "name-checkpoint", GotoSourceLoc: "goto-source-location"};

module.exports.UI_MESSAGES = UI_MESSAGES;
module.exports.UI_REQUESTS = UI_REQUESTS;

0 comments on commit b15d4d0

Please sign in to comment.