Clean up disposables when panel is closed

This commit is contained in:
Saoud Rizwan
2024-07-24 08:15:48 -04:00
parent b19ae3038d
commit 97f740b089

View File

@@ -1,10 +1,9 @@
import { Uri, Webview } from "vscode" import { Uri, Webview } from "vscode"
//import * as weather from "weather-js" //import * as weather from "weather-js"
import * as vscode from "vscode" import * as vscode from "vscode"
import { ClaudeDev } from "../ClaudeDev"
import { ClaudeMessage, ExtensionMessage } from "../shared/ExtensionMessage" import { ClaudeMessage, ExtensionMessage } from "../shared/ExtensionMessage"
import { WebviewMessage } from "../shared/WebviewMessage" import { WebviewMessage } from "../shared/WebviewMessage"
import { ClaudeDev } from "../ClaudeDev"
import { WebviewPanel, WebviewView } from "vscode"
/* /*
https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/default/weather-webview/src/providers/WeatherViewProvider.ts https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/default/weather-webview/src/providers/WeatherViewProvider.ts
@@ -18,16 +17,38 @@ type ExtensionWorkspaceStateKey = "claudeMessages"
export class SidebarProvider implements vscode.WebviewViewProvider { export class SidebarProvider implements vscode.WebviewViewProvider {
public static readonly viewType = "claude-dev.SidebarProvider" public static readonly viewType = "claude-dev.SidebarProvider"
private disposables: vscode.Disposable[] = []
private view?: vscode.WebviewView | vscode.WebviewPanel private view?: vscode.WebviewView | vscode.WebviewPanel
private claudeDev?: ClaudeDev private claudeDev?: ClaudeDev
private claudeMessagesCache: ClaudeMessage[] = [] private claudeMessagesCache: ClaudeMessage[] = []
constructor(private readonly context: vscode.ExtensionContext) {} constructor(private readonly context: vscode.ExtensionContext) {}
/*
VSCode extensions use the disposable pattern to clean up resources when the sidebar/editor tab is closed by the user or system. This applies to event listening, commands, interacting with the UI, etc.
- https://vscode-docs.readthedocs.io/en/stable/extensions/patterns-and-principles/
- https://github.com/microsoft/vscode-extension-samples/blob/main/webview-sample/src/extension.ts
*/
async dispose() {
console.log("Disposing provider...")
await this.clearTask() // clears claudeDev and claudeMesssagesCache
console.log("Cleared task")
if (this.view && "dispose" in this.view) {
this.view.dispose()
console.log("Disposed webview")
}
while (this.disposables.length) {
const x = this.disposables.pop()
if (x) {
x.dispose()
}
}
console.log("Disposed disposables")
}
resolveWebviewView( resolveWebviewView(
webviewView: vscode.WebviewView | vscode.WebviewPanel webviewView: vscode.WebviewView | vscode.WebviewPanel
//context: vscode.WebviewViewResolveContext<unknown>, //context: vscode.WebviewViewResolveContext<unknown>, used to recreate a deallocated webview, but we don't need this since we use retainContextWhenHidden
//token: vscode.CancellationToken //token: vscode.CancellationToken
): void | Thenable<void> { ): void | Thenable<void> {
this.view = webviewView this.view = webviewView
@@ -50,26 +71,50 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
// https://github.com/microsoft/vscode-discussions/discussions/840 // https://github.com/microsoft/vscode-discussions/discussions/840
if ("onDidChangeViewState" in webviewView) { if ("onDidChangeViewState" in webviewView) {
// WebviewView and WebviewPanel have all the same properties except for this visibility listener // WebviewView and WebviewPanel have all the same properties except for this visibility listener
webviewView.onDidChangeViewState(() => { // panel
webviewView.onDidChangeViewState(
() => {
if (this.view?.visible) { if (this.view?.visible) {
this.postMessageToWebview({ type: "action", action: "didBecomeVisible" }) this.postMessageToWebview({ type: "action", action: "didBecomeVisible" })
} }
}) },
null,
this.disposables
)
} else if ("onDidChangeVisibility" in webviewView) { } else if ("onDidChangeVisibility" in webviewView) {
webviewView.onDidChangeVisibility(() => { // sidebar
webviewView.onDidChangeVisibility(
() => {
if (this.view?.visible) { if (this.view?.visible) {
this.postMessageToWebview({ type: "action", action: "didBecomeVisible" }) this.postMessageToWebview({ type: "action", action: "didBecomeVisible" })
} }
}) },
null,
this.disposables
)
} }
// Listen for when the view is disposed
// This happens when the user closes the view or when the view is closed programmatically
webviewView.onDidDispose(
async () => {
await this.dispose()
},
null,
this.disposables
)
// Listen for when color changes // Listen for when color changes
vscode.workspace.onDidChangeConfiguration((e) => { vscode.workspace.onDidChangeConfiguration(
(e) => {
if (e.affectsConfiguration("workbench.colorTheme")) { if (e.affectsConfiguration("workbench.colorTheme")) {
// Sends latest theme name to webview // Sends latest theme name to webview
this.postStateToWebview() this.postStateToWebview()
} }
}) },
null,
this.disposables
)
// if the extension is starting a new session, clear previous task state // if the extension is starting a new session, clear previous task state
this.clearTask() this.clearTask()
@@ -178,10 +223,10 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
* executes code based on the message that is recieved. * executes code based on the message that is recieved.
* *
* @param webview A reference to the extension webview * @param webview A reference to the extension webview
* @param context A reference to the extension context
*/ */
private setWebviewMessageListener(webview: vscode.Webview) { private setWebviewMessageListener(webview: vscode.Webview) {
webview.onDidReceiveMessage(async (message: WebviewMessage) => { webview.onDidReceiveMessage(
async (message: WebviewMessage) => {
switch (message.type) { switch (message.type) {
case "webviewDidLaunch": case "webviewDidLaunch":
await this.updateGlobalState("didOpenOnce", true) await this.updateGlobalState("didOpenOnce", true)
@@ -226,7 +271,10 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
// Add more switch case statements here as more webview message commands // Add more switch case statements here as more webview message commands
// are created within the webview context (i.e. inside media/main.js) // are created within the webview context (i.e. inside media/main.js)
} }
}) },
null,
this.disposables
)
} }
async postStateToWebview() { async postStateToWebview() {