Skip to content

Commit 42ee758

Browse files
authored
Complete the Implementation of DAP modules explorer. (#139934)
This extends the TreeView to show the module property as a tree item instead of rendering it through the markdown tooltip. ![image](https://github.com/user-attachments/assets/329fabee-9b4a-490e-9450-3f01314674ea)
1 parent 8bbe0d0 commit 42ee758

File tree

4 files changed

+96
-40
lines changed

4 files changed

+96
-40
lines changed

lldb/tools/lldb-dap/JSONUtils.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -416,9 +416,11 @@ llvm::json::Value CreateModule(lldb::SBTarget &target, lldb::SBModule &module,
416416
} else {
417417
object.try_emplace("symbolStatus", "Symbols not found.");
418418
}
419-
std::string loaded_addr = std::to_string(
420-
module.GetObjectFileHeaderAddress().GetLoadAddress(target));
421-
object.try_emplace("addressRange", loaded_addr);
419+
std::string load_address =
420+
llvm::formatv("{0:x}",
421+
module.GetObjectFileHeaderAddress().GetLoadAddress(target))
422+
.str();
423+
object.try_emplace("addressRange", load_address);
422424
std::string version_str;
423425
uint32_t version_nums[3];
424426
uint32_t num_versions =

lldb/tools/lldb-dap/package.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,26 @@
244244
}
245245
}
246246
],
247+
"commands": [
248+
{
249+
"command": "lldb-dap.modules.copyProperty",
250+
"title": "Copy Value"
251+
}
252+
],
253+
"menus": {
254+
"commandPalette": [
255+
{
256+
"command": "lldb-dap.modules.copyProperty",
257+
"when": "false"
258+
}
259+
],
260+
"view/item/context": [
261+
{
262+
"command": "lldb-dap.modules.copyProperty",
263+
"when": "view == lldb-dap.modules && viewItem == property"
264+
}
265+
]
266+
},
247267
"breakpoints": [
248268
{
249269
"language": "ada"

lldb/tools/lldb-dap/src-ts/extension.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ import { LaunchUriHandler } from "./uri-launch-handler";
66
import { LLDBDapConfigurationProvider } from "./debug-configuration-provider";
77
import { LLDBDapServer } from "./lldb-dap-server";
88
import { DebugSessionTracker } from "./debug-session-tracker";
9-
import { ModulesDataProvider } from "./ui/modules-data-provider";
9+
import {
10+
ModulesDataProvider,
11+
ModuleProperty,
12+
} from "./ui/modules-data-provider";
1013

1114
/**
1215
* This class represents the extension and manages its life cycle. Other extensions
@@ -40,6 +43,11 @@ export class LLDBDapExtension extends DisposableContext {
4043
),
4144
vscode.window.registerUriHandler(new LaunchUriHandler()),
4245
);
46+
47+
vscode.commands.registerCommand(
48+
"lldb-dap.modules.copyProperty",
49+
(node: ModuleProperty) => vscode.env.clipboard.writeText(node.value),
50+
);
4351
}
4452
}
4553

lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts

Lines changed: 62 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,60 +2,86 @@ import * as vscode from "vscode";
22
import { DebugProtocol } from "@vscode/debugprotocol";
33
import { DebugSessionTracker } from "../debug-session-tracker";
44

5-
/** A tree data provider for listing loaded modules for the active debug session. */
6-
export class ModulesDataProvider
7-
implements vscode.TreeDataProvider<DebugProtocol.Module>
8-
{
9-
private changeTreeData = new vscode.EventEmitter<void>();
10-
readonly onDidChangeTreeData = this.changeTreeData.event;
5+
export interface ModuleProperty {
6+
key: string;
7+
value: string;
8+
}
119

12-
constructor(private readonly tracker: DebugSessionTracker) {
13-
tracker.onDidChangeModules(() => this.changeTreeData.fire());
14-
vscode.debug.onDidChangeActiveDebugSession(() =>
15-
this.changeTreeData.fire(),
16-
);
10+
/** Type to represent both Module and ModuleProperty since TreeDataProvider
11+
* expects one concrete type */
12+
type TreeData = DebugProtocol.Module | ModuleProperty;
13+
14+
function isModule(type: TreeData): type is DebugProtocol.Module {
15+
return (type as DebugProtocol.Module).id !== undefined;
16+
}
17+
18+
class ModuleItem extends vscode.TreeItem {
19+
constructor(module: DebugProtocol.Module) {
20+
super(module.name, vscode.TreeItemCollapsibleState.Collapsed);
21+
this.description = module.symbolStatus;
1722
}
1823

19-
getTreeItem(module: DebugProtocol.Module): vscode.TreeItem {
20-
let treeItem = new vscode.TreeItem(/*label=*/ module.name);
21-
if (module.path) {
22-
treeItem.description = `${module.id} -- ${module.path}`;
23-
} else {
24-
treeItem.description = `${module.id}`;
25-
}
24+
static getProperties(module: DebugProtocol.Module): ModuleProperty[] {
25+
// does not include the name and symbol status as it is show in the parent.
26+
let children: ModuleProperty[] = [];
27+
children.push({ key: "id:", value: module.id.toString() });
2628

27-
const tooltip = new vscode.MarkdownString();
28-
tooltip.appendMarkdown(`# ${module.name}\n\n`);
29-
tooltip.appendMarkdown(`- **ID**: ${module.id}\n`);
3029
if (module.addressRange) {
31-
tooltip.appendMarkdown(
32-
`- **Load address**: 0x${Number(module.addressRange).toString(16)}\n`,
33-
);
30+
children.push({
31+
key: "load address:",
32+
value: module.addressRange,
33+
});
3434
}
3535
if (module.path) {
36-
tooltip.appendMarkdown(`- **Path**: ${module.path}\n`);
36+
children.push({ key: "path:", value: module.path });
3737
}
3838
if (module.version) {
39-
tooltip.appendMarkdown(`- **Version**: ${module.version}\n`);
40-
}
41-
if (module.symbolStatus) {
42-
tooltip.appendMarkdown(`- **Symbol status**: ${module.symbolStatus}\n`);
39+
children.push({ key: "version:", value: module.version });
4340
}
4441
if (module.symbolFilePath) {
45-
tooltip.appendMarkdown(
46-
`- **Symbol file path**: ${module.symbolFilePath}\n`,
47-
);
42+
children.push({ key: "symbol filepath:", value: module.symbolFilePath });
43+
}
44+
return children;
45+
}
46+
}
47+
48+
/** A tree data provider for listing loaded modules for the active debug session. */
49+
export class ModulesDataProvider implements vscode.TreeDataProvider<TreeData> {
50+
private changeTreeData = new vscode.EventEmitter<void>();
51+
readonly onDidChangeTreeData = this.changeTreeData.event;
52+
53+
constructor(private readonly tracker: DebugSessionTracker) {
54+
tracker.onDidChangeModules(() => this.changeTreeData.fire());
55+
vscode.debug.onDidChangeActiveDebugSession(() =>
56+
this.changeTreeData.fire(),
57+
);
58+
}
59+
60+
getTreeItem(module: TreeData): vscode.TreeItem {
61+
if (isModule(module)) {
62+
return new ModuleItem(module);
4863
}
4964

50-
treeItem.tooltip = tooltip;
51-
return treeItem;
65+
let item = new vscode.TreeItem(module.key);
66+
item.description = module.value;
67+
item.tooltip = `${module.key} ${module.value}`;
68+
item.contextValue = "property";
69+
return item;
5270
}
5371

54-
getChildren(): DebugProtocol.Module[] {
72+
getChildren(element?: TreeData): TreeData[] {
5573
if (!vscode.debug.activeDebugSession) {
5674
return [];
5775
}
5876

59-
return this.tracker.debugSessionModules(vscode.debug.activeDebugSession);
77+
if (!element) {
78+
return this.tracker.debugSessionModules(vscode.debug.activeDebugSession);
79+
}
80+
81+
if (isModule(element)) {
82+
return ModuleItem.getProperties(element);
83+
}
84+
85+
return [];
6086
}
6187
}

0 commit comments

Comments
 (0)