fix: prevent UI freeze when showing save dialogs

- Created safeDialogs utility with non-blocking wrappers for showSaveDialog and showOpenDialog
- Updated all save/open dialog calls to use the safe wrappers
- Uses setImmediate to defer dialog calls to next event loop iteration
- Prevents VSCode UI from freezing on macOS with certain configurations

Fixes #6870
This commit is contained in:
Roo Code 2025-08-09 13:38:15 +00:00
parent ad0e33e2d9
commit c101ed9507
5 changed files with 60 additions and 10 deletions

View file

@ -5,6 +5,7 @@ import fs from "fs/promises"
import * as vscode from "vscode"
import { z, ZodError } from "zod"
import { showSaveDialogSafe, showOpenDialogSafe } from "../../utils/safeDialogs"
import { globalSettingsSchema } from "@roo-code/types"
import { TelemetryService } from "@roo-code/telemetry"
@ -109,7 +110,7 @@ export async function importSettingsFromPath(
* @returns Promise resolving to import result
*/
export const importSettings = async ({ providerSettingsManager, contextProxy, customModesManager }: ImportOptions) => {
const uris = await vscode.window.showOpenDialog({
const uris = await showOpenDialogSafe({
filters: { JSON: ["json"] },
canSelectMany: false,
})
@ -143,7 +144,7 @@ export const importSettingsFromFile = async (
}
export const exportSettings = async ({ providerSettingsManager, contextProxy }: ExportOptions) => {
const uri = await vscode.window.showSaveDialog({
const uri = await showSaveDialogSafe({
filters: { JSON: ["json"] },
defaultUri: vscode.Uri.file(path.join(os.homedir(), "Documents", "roo-code-settings.json")),
})

View file

@ -5,6 +5,7 @@ import * as fs from "fs/promises"
import pWaitFor from "p-wait-for"
import * as vscode from "vscode"
import * as yaml from "yaml"
import { showSaveDialogSafe, showOpenDialogSafe } from "../../utils/safeDialogs"
import {
type Language,
@ -1791,8 +1792,8 @@ export const webviewMessageHandler = async (
}
}
// Show save dialog
const saveUri = await vscode.window.showSaveDialog({
// Show save dialog using safe wrapper to prevent UI freezing
const saveUri = await showSaveDialogSafe({
defaultUri,
filters: {
"YAML files": ["yaml", "yml"],
@ -1866,8 +1867,8 @@ export const webviewMessageHandler = async (
}
}
// Show file picker to select YAML file
const fileUri = await vscode.window.showOpenDialog({
// Show file picker to select YAML file using safe wrapper to prevent UI freezing
const fileUri = await showOpenDialogSafe({
canSelectFiles: true,
canSelectFolders: false,
canSelectMany: false,

View file

@ -2,6 +2,7 @@ import { Anthropic } from "@anthropic-ai/sdk"
import os from "os"
import * as path from "path"
import * as vscode from "vscode"
import { showSaveDialogSafe } from "../../utils/safeDialogs"
export async function downloadTask(dateTs: number, conversationHistory: Anthropic.MessageParam[]) {
// File name
@ -28,8 +29,8 @@ export async function downloadTask(dateTs: number, conversationHistory: Anthropi
})
.join("---\n\n")
// Prompt user for save location
const saveUri = await vscode.window.showSaveDialog({
// Prompt user for save location using safe wrapper to prevent UI freezing
const saveUri = await showSaveDialogSafe({
filters: { Markdown: ["md"] },
defaultUri: vscode.Uri.file(path.join(os.homedir(), "Downloads", fileName)),
})

View file

@ -3,6 +3,7 @@ import * as os from "os"
import * as vscode from "vscode"
import { getWorkspacePath } from "../../utils/path"
import { t } from "../../i18n"
import { showSaveDialogSafe } from "../../utils/safeDialogs"
export async function openImage(dataUri: string, options?: { values?: { action?: string } }) {
const matches = dataUri.match(/^data:image\/([a-zA-Z]+);base64,(.+)$/)
@ -67,8 +68,8 @@ export async function saveImage(dataUri: string) {
const defaultFileName = `mermaid_diagram_${Date.now()}.${format}`
const defaultUri = vscode.Uri.file(path.join(defaultPath, defaultFileName))
// Show save dialog
const saveUri = await vscode.window.showSaveDialog({
// Show save dialog using safe wrapper to prevent UI freezing
const saveUri = await showSaveDialogSafe({
filters: {
Images: [format],
"All Files": ["*"],

46
src/utils/safeDialogs.ts Normal file
View file

@ -0,0 +1,46 @@
import * as vscode from "vscode"
/**
* Wraps vscode.window.showSaveDialog in a non-blocking way to prevent UI freezing
* This addresses the issue where the save dialog can cause the entire VSCode UI to freeze
* on certain systems (particularly macOS with specific configurations).
*
* @param options - The save dialog options
* @returns Promise that resolves to the selected URI or undefined if cancelled
*/
export async function showSaveDialogSafe(options: vscode.SaveDialogOptions): Promise<vscode.Uri | undefined> {
// Use setImmediate to defer the dialog call to the next iteration of the event loop
// This prevents the UI thread from being blocked
return new Promise<vscode.Uri | undefined>((resolve) => {
setImmediate(async () => {
try {
const result = await vscode.window.showSaveDialog(options)
resolve(result)
} catch (error) {
console.error("Error showing save dialog:", error)
resolve(undefined)
}
})
})
}
/**
* Wraps vscode.window.showOpenDialog in a non-blocking way to prevent UI freezing
*
* @param options - The open dialog options
* @returns Promise that resolves to the selected URIs or undefined if cancelled
*/
export async function showOpenDialogSafe(options: vscode.OpenDialogOptions): Promise<vscode.Uri[] | undefined> {
// Use setImmediate to defer the dialog call to the next iteration of the event loop
return new Promise<vscode.Uri[] | undefined>((resolve) => {
setImmediate(async () => {
try {
const result = await vscode.window.showOpenDialog(options)
resolve(result)
} catch (error) {
console.error("Error showing open dialog:", error)
resolve(undefined)
}
})
})
}