llvm-project/lldb/tools/lldb-dap/src-ts/ui/symbols-provider.ts
Ely Ronnen 8b64cd8be2
[lldb-dap] Add module symbol table viewer to VS Code extension #140626 (#153836)
- VS Code extension:
- Add module symbol table viewer using
[Tabulator](https://tabulator.info/) for sorting and formatting rows.
  - Add context menu action to the modules tree.
 - lldb-dap
   -  Add `DAPGetModuleSymbolsRequest` to get symbols from a module.
 
Fixes #140626

[Screencast From 2025-08-15
19-12-33.webm](https://github.com/user-attachments/assets/75e2f229-ac82-487c-812e-3ea33a575b70)
2025-08-21 00:31:48 +02:00

128 lines
4.5 KiB
TypeScript

import * as vscode from "vscode";
import { DebugProtocol } from "@vscode/debugprotocol";
import { DebugSessionTracker } from "../debug-session-tracker";
import { DisposableContext } from "../disposable-context";
import { SymbolType } from "..";
import { getSymbolsTableHTMLContent } from "./symbols-webview-html";
import { getDefaultConfigKey } from "../debug-configuration-provider";
export class SymbolsProvider extends DisposableContext {
constructor(
private readonly tracker: DebugSessionTracker,
private readonly extensionContext: vscode.ExtensionContext,
) {
super();
this.pushSubscription(vscode.commands.registerCommand(
"lldb-dap.debug.showSymbols",
() => {
const session = vscode.debug.activeDebugSession;
if (!session) return;
this.SelectModuleAndShowSymbols(session);
},
));
this.pushSubscription(vscode.commands.registerCommand(
"lldb-dap.modules.showSymbols",
(moduleItem: DebugProtocol.Module) => {
const session = vscode.debug.activeDebugSession;
if (!session) return;
this.showSymbolsForModule(session, moduleItem);
},
));
this.tracker.onDidReceiveSessionCapabilities(([ _session, capabilities ]) => {
if (capabilities.supportsModuleSymbolsRequest) {
vscode.commands.executeCommand(
"setContext", "lldb-dap.supportsModuleSymbolsRequest", true);
}
});
this.tracker.onDidExitSession((_session) => {
vscode.commands.executeCommand("setContext", "lldb-dap.supportsModuleSymbolsRequest", false);
});
}
private async SelectModuleAndShowSymbols(session: vscode.DebugSession) {
const modules = this.tracker.debugSessionModules(session);
if (!modules || modules.length === 0) {
return;
}
// Let the user select a module to show symbols for
const selectedModule = await vscode.window.showQuickPick(modules.map(m => new ModuleQuickPickItem(m)), {
placeHolder: "Select a module to show symbols for"
});
if (!selectedModule) {
return;
}
this.showSymbolsForModule(session, selectedModule.module);
}
private async showSymbolsForModule(session: vscode.DebugSession, module: DebugProtocol.Module) {
try {
const symbols = await this.getSymbolsForModule(session, module.id.toString());
this.showSymbolsInNewTab(module.name.toString(), symbols);
} catch (error) {
if (error instanceof Error) {
vscode.window.showErrorMessage("Failed to retrieve symbols: " + error.message);
} else {
vscode.window.showErrorMessage("Failed to retrieve symbols due to an unknown error.");
}
return;
}
}
private async getSymbolsForModule(session: vscode.DebugSession, moduleId: string): Promise<SymbolType[]> {
const symbols_response: { symbols: Array<SymbolType> } = await session.customRequest("__lldb_moduleSymbols", { moduleId, moduleName: '' });
return symbols_response?.symbols || [];
}
private async showSymbolsInNewTab(moduleName: string, symbols: SymbolType[]) {
const panel = vscode.window.createWebviewPanel(
"lldb-dap.symbols",
`Symbols for ${moduleName}`,
vscode.ViewColumn.Active,
{
enableScripts: true,
localResourceRoots: [
this.getExtensionResourcePath()
]
}
);
let tabulatorJsFilename = "tabulator_simple.min.css";
if (vscode.window.activeColorTheme.kind === vscode.ColorThemeKind.Dark || vscode.window.activeColorTheme.kind === vscode.ColorThemeKind.HighContrast) {
tabulatorJsFilename = "tabulator_midnight.min.css";
}
const tabulatorCssPath = panel.webview.asWebviewUri(vscode.Uri.joinPath(this.getExtensionResourcePath(), tabulatorJsFilename));
const tabulatorJsPath = panel.webview.asWebviewUri(vscode.Uri.joinPath(this.getExtensionResourcePath(), "tabulator.min.js"));
const symbolsTableScriptPath = panel.webview.asWebviewUri(vscode.Uri.joinPath(this.getExtensionResourcePath(), "symbols-table-view.js"));
panel.webview.html = getSymbolsTableHTMLContent(tabulatorJsPath, tabulatorCssPath, symbolsTableScriptPath);
panel.webview.postMessage({ command: "updateSymbols", symbols: symbols });
}
private getExtensionResourcePath(): vscode.Uri {
return vscode.Uri.joinPath(this.extensionContext.extensionUri, "out", "webview");
}
}
class ModuleQuickPickItem implements vscode.QuickPickItem {
constructor(public readonly module: DebugProtocol.Module) {}
get label(): string {
return this.module.name;
}
get description(): string {
return this.module.id.toString();
}
}