From a4931c004b20fcb71ba5aa29df2a7c199c8cada0 Mon Sep 17 00:00:00 2001 From: Qian Date: Thu, 13 Nov 2025 13:39:55 +0800 Subject: [PATCH 1/4] fix bug: set the property JS_QUERY_POOL_SIZE to use JBCefJSQuery after the browser has been created --- .../continueintellijextension/browser/ContinueBrowser.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/browser/ContinueBrowser.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/browser/ContinueBrowser.kt index 836ad0cb1e7..8a2c4c1b3d5 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/browser/ContinueBrowser.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/browser/ContinueBrowser.kt @@ -21,12 +21,14 @@ class ContinueBrowser( ): Disposable { private val log = Logger.getInstance(ContinueBrowser::class.java.simpleName) - private val browser: JBCefBrowser = JBCefBrowser.createBuilder().setOffScreenRendering(true).build() + private val myJBCefClient: JBCefClient = JBCefApp.getInstance().createClient().apply { + setProperty(JBCefClient.Properties.JS_QUERY_POOL_SIZE, 200) + } + private val browser: JBCefBrowser = JBCefBrowser.createBuilder().setOffScreenRendering(true).setClient(myJBCefClient).build() private val myJSQueryOpenInBrowser = JBCefJSQuery.create(browser as JBCefBrowserBase) init { CefApp.getInstance().registerSchemeHandlerFactory("http", "continue", CustomSchemeHandlerFactory()) - browser.jbCefClient.setProperty(JBCefClient.Properties.JS_QUERY_POOL_SIZE, 200) myJSQueryOpenInBrowser.addHandler { msg: String? -> val json = gsonService.gson.fromJson(msg, BrowserMessage::class.java) val messageType = json.messageType @@ -107,6 +109,7 @@ class ContinueBrowser( override fun dispose() { Disposer.dispose(myJSQueryOpenInBrowser) Disposer.dispose(browser) + Disposer.dispose(myJBCefClient) } // todo: remove and use types.Message From f97c969303b52f4db106f64eb2ed73f05b9fc1d8 Mon Sep 17 00:00:00 2001 From: Qian Date: Thu, 13 Nov 2025 13:41:58 +0800 Subject: [PATCH 2/4] feat: add JCEF reload action --- .../actions/ContinuePluginActions.kt | 28 +++++++++++++ .../browser/ContinueBrowserService.kt | 42 +++++++++++++++---- .../src/main/resources/META-INF/plugin.xml | 9 ++++ 3 files changed, 72 insertions(+), 7 deletions(-) diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/actions/ContinuePluginActions.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/actions/ContinuePluginActions.kt index d28d8258a28..6dcabd60041 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/actions/ContinuePluginActions.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/actions/ContinuePluginActions.kt @@ -2,6 +2,7 @@ package com.github.continuedev.continueintellijextension.actions import com.github.continuedev.continueintellijextension.HighlightedCodePayload import com.github.continuedev.continueintellijextension.RangeInFileWithContents +import com.github.continuedev.continueintellijextension.browser.ContinueBrowserService import com.github.continuedev.continueintellijextension.browser.ContinueBrowserService.Companion.getBrowser import com.github.continuedev.continueintellijextension.editor.DiffStreamService import com.github.continuedev.continueintellijextension.editor.EditorUtils @@ -12,6 +13,7 @@ import com.intellij.openapi.actionSystem.PlatformDataKeys import com.intellij.openapi.components.service import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.project.Project +import com.intellij.openapi.wm.ToolWindowManager import java.io.File class RestartContinueProcess : AnAction() { @@ -89,6 +91,32 @@ class OpenConfigAction : ContinueToolbarAction() { } } +class ReloadBrowserAction: ContinueToolbarAction() { + override fun toolbarActionPerformed(project: Project) { + val toolWindow = ToolWindowManager.getInstance(project).getToolWindow("Continue") + ?: return + val contentManager = toolWindow.contentManager + val browserService = project.service() + browserService.reload() + + val newBrowser = project.getBrowser() ?: return + val newBrowserComponent = newBrowser.getComponent() + + contentManager.removeAllContents(true) + val newContent = contentManager.factory.createContent( + newBrowserComponent, + null, + false + ) + + contentManager.addContent(newContent) + + contentManager.setSelectedContent(newContent) + + toolWindow.activate(null) + } +} + class OpenLogsAction : AnAction() { override fun actionPerformed(e: AnActionEvent) { val project = e.project ?: return diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/browser/ContinueBrowserService.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/browser/ContinueBrowserService.kt index 155d9ffe882..5282aead9cf 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/browser/ContinueBrowserService.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/browser/ContinueBrowserService.kt @@ -8,16 +8,44 @@ import com.intellij.openapi.util.Disposer import com.intellij.ui.jcef.JBCefApp @Service(Service.Level.PROJECT) -class ContinueBrowserService(project: Project): Disposable { +class ContinueBrowserService(val project: Project): Disposable { - private val browser: ContinueBrowser? = - if (JBCefApp.isSupported()) - ContinueBrowser(project) - else null + private var browser: ContinueBrowser? = null + + init { + load() + } override fun dispose() { - if (browser != null) - Disposer.dispose(browser) + browser?.let { Disposer.dispose(it) } + browser = null + } + + private fun load(): ContinueBrowser? { + if (browser != null) { + return browser + } + if (!JBCefApp.isSupported()) { + return null + } + val newBrowser = ContinueBrowser(project) + Disposer.register(this, newBrowser) + + this.browser = newBrowser + return this.browser + } + + /** + * Reloads the browser by disposing the current one and creating a new one. + * This method is intended for use when browser is frozen (unresponsive). + */ + fun reload() { + browser?.let { + Disposer.dispose(it) + } + browser = null + + load() } companion object { diff --git a/extensions/intellij/src/main/resources/META-INF/plugin.xml b/extensions/intellij/src/main/resources/META-INF/plugin.xml index 7481b8abafc..3b04166d4a2 100644 --- a/extensions/intellij/src/main/resources/META-INF/plugin.xml +++ b/extensions/intellij/src/main/resources/META-INF/plugin.xml @@ -155,6 +155,14 @@ + + + + + Date: Tue, 18 Nov 2025 13:51:40 +0800 Subject: [PATCH 3/4] fix: update reload action --- .../actions/ContinuePluginActions.kt | 42 +++++++++++-------- .../browser/ContinueBrowserService.kt | 14 +++++-- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/actions/ContinuePluginActions.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/actions/ContinuePluginActions.kt index 6dcabd60041..cd802c079d0 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/actions/ContinuePluginActions.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/actions/ContinuePluginActions.kt @@ -10,6 +10,7 @@ import com.github.continuedev.continueintellijextension.services.ContinuePluginS import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.PlatformDataKeys +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.service import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.project.Project @@ -95,25 +96,32 @@ class ReloadBrowserAction: ContinueToolbarAction() { override fun toolbarActionPerformed(project: Project) { val toolWindow = ToolWindowManager.getInstance(project).getToolWindow("Continue") ?: return - val contentManager = toolWindow.contentManager val browserService = project.service() - browserService.reload() - val newBrowser = project.getBrowser() ?: return - val newBrowserComponent = newBrowser.getComponent() - - contentManager.removeAllContents(true) - val newContent = contentManager.factory.createContent( - newBrowserComponent, - null, - false - ) - - contentManager.addContent(newContent) - - contentManager.setSelectedContent(newContent) - - toolWindow.activate(null) + // Perform the reload and UI update on the Event Dispatch Thread + ApplicationManager.getApplication().invokeLater { + // Reload the browser service to get a new browser instance + browserService.reload() + + val newBrowser = project.getBrowser() ?: return@invokeLater + val newBrowserComponent = newBrowser.getComponent() + + val contentManager = toolWindow.contentManager + contentManager.removeAllContents(true) + + val newContent = contentManager.factory.createContent( + newBrowserComponent, + null, + false + ) + contentManager.addContent(newContent) + contentManager.setSelectedContent(newContent, true) // Request focus + + toolWindow.activate({ + // After activation, ensure the browser's input field gets focus + newBrowser.focusOnInput() + }, true) + } } } diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/browser/ContinueBrowserService.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/browser/ContinueBrowserService.kt index 5282aead9cf..12736614038 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/browser/ContinueBrowserService.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/browser/ContinueBrowserService.kt @@ -1,6 +1,7 @@ package com.github.continuedev.continueintellijextension.browser import com.intellij.openapi.Disposable +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.Service import com.intellij.openapi.components.service import com.intellij.openapi.project.Project @@ -40,11 +41,18 @@ class ContinueBrowserService(val project: Project): Disposable { * This method is intended for use when browser is frozen (unresponsive). */ fun reload() { - browser?.let { - Disposer.dispose(it) - } + // Store the old browser instance to be disposed later + val oldBrowser = browser browser = null + // Dispose the old browser after the new one is loaded and UI is updated. + // This avoids race conditions. We can do this on a background thread. + oldBrowser?.let { + ApplicationManager.getApplication().invokeLater { + Disposer.dispose(it) + } + } + load() } From 8bfc78de7d75e46341a93af4cf9f7092cff117d0 Mon Sep 17 00:00:00 2001 From: Qian Date: Wed, 19 Nov 2025 21:09:23 +0800 Subject: [PATCH 4/4] Revert "fix bug: set the property JS_QUERY_POOL_SIZE to use JBCefJSQuery after the browser has been created" This reverts commit e998ae83b261a171b03e0473cf2b8aaeac481ed7. --- .../continueintellijextension/browser/ContinueBrowser.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/browser/ContinueBrowser.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/browser/ContinueBrowser.kt index 8a2c4c1b3d5..836ad0cb1e7 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/browser/ContinueBrowser.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/browser/ContinueBrowser.kt @@ -21,14 +21,12 @@ class ContinueBrowser( ): Disposable { private val log = Logger.getInstance(ContinueBrowser::class.java.simpleName) - private val myJBCefClient: JBCefClient = JBCefApp.getInstance().createClient().apply { - setProperty(JBCefClient.Properties.JS_QUERY_POOL_SIZE, 200) - } - private val browser: JBCefBrowser = JBCefBrowser.createBuilder().setOffScreenRendering(true).setClient(myJBCefClient).build() + private val browser: JBCefBrowser = JBCefBrowser.createBuilder().setOffScreenRendering(true).build() private val myJSQueryOpenInBrowser = JBCefJSQuery.create(browser as JBCefBrowserBase) init { CefApp.getInstance().registerSchemeHandlerFactory("http", "continue", CustomSchemeHandlerFactory()) + browser.jbCefClient.setProperty(JBCefClient.Properties.JS_QUERY_POOL_SIZE, 200) myJSQueryOpenInBrowser.addHandler { msg: String? -> val json = gsonService.gson.fromJson(msg, BrowserMessage::class.java) val messageType = json.messageType @@ -109,7 +107,6 @@ class ContinueBrowser( override fun dispose() { Disposer.dispose(myJSQueryOpenInBrowser) Disposer.dispose(browser) - Disposer.dispose(myJBCefClient) } // todo: remove and use types.Message