refactor: eliminate code duplication between openClineInNewTab and openClineInThisTab

- Extract common initialization logic to initializeClineTabProvider()
- Extract common panel setup to setupClinePanel()
- Both functions now share ~95% of their code through these helpers
- Reduces maintenance burden and ensures consistency
This commit is contained in:
daniel-lxs 2025-08-15 13:45:30 -05:00
parent 2fef294c22
commit b31aac188b
No known key found for this signature in database
GPG key ID: 21C74479048B3AA6

View file

@ -224,13 +224,14 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt
},
})
export const openClineInNewTab = async ({ context, outputChannel }: Omit<RegisterCommandOptions, "provider">) => {
// (This example uses webviewProvider activation event which is necessary to
// deserialize cached webview, but since we use retainContextWhenHidden, we
// don't need to use that event).
// https://github.com/microsoft/vscode-extension-samples/blob/main/webview-sample/src/extension.ts
/**
* Common initialization for Roo Code tab panels
*/
async function initializeClineTabProvider(
context: vscode.ExtensionContext,
outputChannel: vscode.OutputChannel,
): Promise<ClineProvider> {
const contextProxy = await ContextProxy.getInstance(context)
const codeIndexManager = CodeIndexManager.getInstance(context)
// Get the existing MDM service instance to ensure consistent policy enforcement
let mdmService: MdmService | undefined
@ -241,7 +242,57 @@ export const openClineInNewTab = async ({ context, outputChannel }: Omit<Registe
mdmService = undefined
}
const tabProvider = new ClineProvider(context, outputChannel, "editor", contextProxy, mdmService)
return new ClineProvider(context, outputChannel, "editor", contextProxy, mdmService)
}
/**
* Common panel setup for Roo Code webview panels
*/
function setupClinePanel(
panel: vscode.WebviewPanel,
context: vscode.ExtensionContext,
tabProvider: ClineProvider,
): void {
// Save as tab type panel
setPanel(panel, "tab")
// Set the icon
panel.iconPath = {
light: vscode.Uri.joinPath(context.extensionUri, "assets", "icons", "panel_light.png"),
dark: vscode.Uri.joinPath(context.extensionUri, "assets", "icons", "panel_dark.png"),
}
// Resolve the webview
tabProvider.resolveWebviewView(panel)
// Add listener for visibility changes to notify webview
panel.onDidChangeViewState(
(e) => {
const webviewPanel = e.webviewPanel
if (webviewPanel.visible) {
webviewPanel.webview.postMessage({ type: "action", action: "didBecomeVisible" })
}
},
null,
context.subscriptions,
)
// Handle panel closing events
panel.onDidDispose(
() => {
setPanel(undefined, "tab")
},
null,
context.subscriptions,
)
}
export const openClineInNewTab = async ({ context, outputChannel }: Omit<RegisterCommandOptions, "provider">) => {
// (This example uses webviewProvider activation event which is necessary to
// deserialize cached webview, but since we use retainContextWhenHidden, we
// don't need to use that event).
// https://github.com/microsoft/vscode-extension-samples/blob/main/webview-sample/src/extension.ts
const tabProvider = await initializeClineTabProvider(context, outputChannel)
const lastCol = Math.max(...vscode.window.visibleTextEditors.map((editor) => editor.viewColumn || 0))
// Check if there are any visible text editors, otherwise open a new group
@ -260,38 +311,7 @@ export const openClineInNewTab = async ({ context, outputChannel }: Omit<Registe
localResourceRoots: [context.extensionUri],
})
// Save as tab type panel.
setPanel(newPanel, "tab")
// TODO: Use better svg icon with light and dark variants (see
// https://stackoverflow.com/questions/58365687/vscode-extension-iconpath).
newPanel.iconPath = {
light: vscode.Uri.joinPath(context.extensionUri, "assets", "icons", "panel_light.png"),
dark: vscode.Uri.joinPath(context.extensionUri, "assets", "icons", "panel_dark.png"),
}
await tabProvider.resolveWebviewView(newPanel)
// Add listener for visibility changes to notify webview
newPanel.onDidChangeViewState(
(e) => {
const panel = e.webviewPanel
if (panel.visible) {
panel.webview.postMessage({ type: "action", action: "didBecomeVisible" }) // Use the same message type as in SettingsView.tsx
}
},
null, // First null is for `thisArgs`
context.subscriptions, // Register listener for disposal
)
// Handle panel closing events.
newPanel.onDidDispose(
() => {
setPanel(undefined, "tab")
},
null,
context.subscriptions, // Also register dispose listener
)
await setupClinePanel(newPanel, context, tabProvider)
// Lock the editor group so clicking on files doesn't open them over the panel.
await delay(100)
@ -300,20 +320,11 @@ export const openClineInNewTab = async ({ context, outputChannel }: Omit<Registe
return tabProvider
}
/**
* Opens Roo Code in the current active tab, replacing its content
*/
export const openClineInThisTab = async ({ context, outputChannel }: Omit<RegisterCommandOptions, "provider">) => {
const contextProxy = await ContextProxy.getInstance(context)
const codeIndexManager = CodeIndexManager.getInstance(context)
// Get the existing MDM service instance to ensure consistent policy enforcement
let mdmService: MdmService | undefined
try {
mdmService = MdmService.getInstance()
} catch (error) {
// MDM service not initialized, which is fine - extension can work without it
mdmService = undefined
}
const tabProvider = new ClineProvider(context, outputChannel, "editor", contextProxy, mdmService)
const tabProvider = await initializeClineTabProvider(context, outputChannel)
// Get the active text editor's view column, or use the first column if no editor is active
const activeColumn = vscode.window.activeTextEditor?.viewColumn || vscode.ViewColumn.One
@ -330,37 +341,7 @@ export const openClineInThisTab = async ({ context, outputChannel }: Omit<Regist
},
)
// Save as tab type panel
setPanel(newPanel, "tab")
// Set the icon
newPanel.iconPath = {
light: vscode.Uri.joinPath(context.extensionUri, "assets", "icons", "panel_light.png"),
dark: vscode.Uri.joinPath(context.extensionUri, "assets", "icons", "panel_dark.png"),
}
await tabProvider.resolveWebviewView(newPanel)
// Add listener for visibility changes to notify webview
newPanel.onDidChangeViewState(
(e) => {
const panel = e.webviewPanel
if (panel.visible) {
panel.webview.postMessage({ type: "action", action: "didBecomeVisible" })
}
},
null,
context.subscriptions,
)
// Handle panel closing events
newPanel.onDidDispose(
() => {
setPanel(undefined, "tab")
},
null,
context.subscriptions,
)
await setupClinePanel(newPanel, context, tabProvider)
return tabProvider
}