diff --git a/vscode/package.json b/vscode/package.json index a24f75428..833851444 100644 --- a/vscode/package.json +++ b/vscode/package.json @@ -56,6 +56,14 @@ "group": "9_cutcopypaste" } ], + "editor/title": [ + { + "command": "rubyLsp.profileFile", + "when": "editorTextFocus && resourceLangId == ruby", + "group": "navigation", + "icon": "$(record)" + } + ], "view/title": [ { "command": "rubyLsp.fileOperation", @@ -155,6 +163,12 @@ "command": "rubyLsp.collectRubyLspInfo", "title": "Collect Ruby LSP Information for Issue Reporting", "category": "Ruby LSP" + }, + { + "command": "rubyLsp.profileFile", + "title": "Profile file", + "category": "Ruby LSP", + "icon": "$(record)" } ], "configuration": { diff --git a/vscode/src/common.ts b/vscode/src/common.ts index 3f688fd9e..fc76f6a74 100644 --- a/vscode/src/common.ts +++ b/vscode/src/common.ts @@ -28,6 +28,7 @@ export enum Command { NewMinitestFile = "rubyLsp.newMinitestFile", CollectRubyLspInfo = "rubyLsp.collectRubyLspInfo", StartServerInDebugMode = "rubyLsp.startServerInDebugMode", + ProfileFile = "rubyLsp.profileFile", } export interface RubyInterface { diff --git a/vscode/src/profileTaskProvider.ts b/vscode/src/profileTaskProvider.ts index 806b8abbe..6c74fd9b9 100644 --- a/vscode/src/profileTaskProvider.ts +++ b/vscode/src/profileTaskProvider.ts @@ -1,7 +1,47 @@ +import path from "path"; + import * as vscode from "vscode"; import { Workspace } from "./workspace"; +class ProfileView { + private readonly panel: vscode.WebviewPanel; + + constructor(fileName: string, profile: any) { + this.panel = vscode.window.createWebviewPanel( + ProfileTaskProvider.TaskType, + `Profile results ${fileName}`, + vscode.ViewColumn.One, + {}, + ); + + this.generateHtml(fileName, profile); + this.panel.onDidDispose(() => { + this.panel.dispose(); + }); + } + + reveal() { + this.panel.reveal(); + } + + private generateHtml(file: string, profile: any) { + this.panel.webview.html = ` + + + + + + Profile results ${file} + + +

Results

+ ${profile.toString()} + + `; + } +} + class ProfileTaskTerminal implements vscode.Pseudoterminal { readonly writeEmitter = new vscode.EventEmitter(); onDidWrite: vscode.Event = this.writeEmitter.event; @@ -40,23 +80,21 @@ class ProfileTaskTerminal implements vscode.Pseudoterminal { try { const profile = await vscode.workspace.fs.readFile(profileUri); this.writeEmitter.fire( - "Successfully profiled. Generating visualization...", + "Successfully profiled. Generating visualization...\r\n", ); + + const profileView = new ProfileView(path.basename(currentFile), profile); + this.closeEmitter.fire(0); + profileView.reveal(); } catch (error) { this.writeEmitter.fire( `An error occurred while profiling (press any key to close):\r\n ${stderr}\r\n`, ); + this.closeEmitter.fire(1); } - - this.closeEmitter.fire(0); } close(): void {} - - // Close the task pseudo terminal if the user presses any keys - handleInput(_data: string): void { - this.closeEmitter.fire(0); - } } export class ProfileTaskProvider implements vscode.TaskProvider { diff --git a/vscode/src/rubyLsp.ts b/vscode/src/rubyLsp.ts index 6d70ad120..864112986 100644 --- a/vscode/src/rubyLsp.ts +++ b/vscode/src/rubyLsp.ts @@ -605,6 +605,20 @@ export class RubyLsp { await workspace?.start(true); }, ), + vscode.commands.registerCommand(Command.ProfileFile, async () => { + const tasks = await vscode.tasks.fetchTasks({ + type: ProfileTaskProvider.TaskType, + }); + + if (tasks.length === 0) { + await vscode.window.showErrorMessage( + "No profile tasks found. Has it been declared in the .vscode/tasks.json file?", + ); + return; + } + + await vscode.tasks.executeTask(tasks[0]); + }), ); }