Просмотр исходного кода

Windows and Intellij IDEA 2024.3 fix

paviko 2 месяцев назад
Родитель
Сommit
b6e7be5c1a

+ 11 - 1
hosts/jetbrains-plugin/src/main/kotlin/paviko/opencode/ui/ChatToolWindowFactory.kt

@@ -8,6 +8,7 @@ import com.intellij.openapi.wm.ToolWindow
 import com.intellij.openapi.wm.ToolWindowFactory
 import com.intellij.ui.jcef.JBCefApp
 import com.intellij.ui.jcef.JBCefBrowser
+import com.intellij.ui.jcef.JBCefClient
 import com.intellij.util.ui.JBUI
 import paviko.opencode.backendprocess.BackendLauncher
 import paviko.opencode.settings.OpenCodeSettings
@@ -107,7 +108,16 @@ class ChatToolWindowFactory : ToolWindowFactory, DumbAware {
 
                                 SwingUtilities.invokeLater {
                                     try {
-                                        val browser = JBCefBrowser(appUrl)
+                                        // Create client with JS_QUERY_POOL_SIZE for Windows IDEA 2024.3 compatibility
+                                        // This allows JBCefJSQuery.create() to work after browser creation
+                                        val client = JBCefApp.getInstance().createClient()
+                                        try {
+                                            client.setProperty(JBCefClient.Properties.JS_QUERY_POOL_SIZE, 1)
+                                        } catch (_: Throwable) {}
+                                        val browser = JBCefBrowser.createBuilder()
+                                            .setClient(client)
+                                            .setUrl(appUrl)
+                                            .build()
 
                                         // Store browser reference for path insertion (context actions)
                                         // PathInserter.setBrowser(browser) - Removed, now stateless

+ 28 - 42
hosts/jetbrains-plugin/src/main/kotlin/paviko/opencode/ui/IdeBridge.kt

@@ -13,9 +13,9 @@ import com.intellij.openapi.vfs.LocalFileSystem
 import com.intellij.ui.jcef.JBCefBrowser
 import com.intellij.ui.jcef.JBCefJSQuery
 import org.cef.browser.CefBrowser
+import org.cef.browser.CefFrame
 import org.cef.handler.CefLoadHandlerAdapter
 import javax.swing.SwingUtilities
-import java.util.concurrent.atomic.AtomicBoolean
 
 object IdeBridge {
     private val logger = Logger.getInstance(IdeBridge::class.java)
@@ -32,50 +32,13 @@ object IdeBridge {
     private val states = java.util.concurrent.ConcurrentHashMap<Project, ProjectState>()
 
     fun install(browser: JBCefBrowser, project: Project) {
-        // Create placeholder state without query - will be set up on page load
-        val state = ProjectState(browser, null)
-        states[project] = state
-        
-        val installed = AtomicBoolean(false)
-        
-        // Use load handler to ensure browser is fully ready before creating JBCefJSQuery
-        // This fixes race condition on cold IDE start in IDEA 2024.3
-        val loadHandler = object : CefLoadHandlerAdapter() {
-            override fun onLoadingStateChange(
-                cefBrowser: CefBrowser?,
-                isLoading: Boolean,
-                canGoBack: Boolean,
-                canGoForward: Boolean
-            ) {
-                // Install once when loading starts (browser is ready)
-                if (isLoading && installed.compareAndSet(false, true)) {
-                    SwingUtilities.invokeLater {
-                        doInstall(browser, project)
-                    }
-                }
-            }
-        }
-        
-        browser.jbCefClient.addLoadHandler(loadHandler, browser.cefBrowser)
-        
-        // Also try immediate install in case page already loading
-        SwingUtilities.invokeLater {
-            if (installed.compareAndSet(false, true)) {
-                doInstall(browser, project)
-            }
-        }
-    }
-    
-    private fun doInstall(browser: JBCefBrowser, project: Project) {
+        // Create JBCefJSQuery immediately (requires JS_QUERY_POOL_SIZE set on client)
         val q = try { JBCefJSQuery.create(browser) } catch (t: Throwable) { 
             logger.warn("Failed to create JBCefJSQuery", t)
             null 
         }
         
-        // Update state with query
-        val oldState = states[project]
-        val state = ProjectState(browser, q, oldState?.outbox ?: mutableListOf())
-        state.ready = oldState?.ready ?: false
+        val state = ProjectState(browser, q)
         states[project] = state
         
         if (q != null) {
@@ -90,8 +53,27 @@ object IdeBridge {
                 }
             } catch (_: Throwable) {}
         }
+        
+        val sendInvoke = try { q?.inject("String(json)") } catch (_: Throwable) { null } ?: "void 0"
+        
+        // Use onLoadEnd to inject JS after page loads - handles race condition on Windows IDEA 2024.3
+        // Re-injects on every page load since JS context resets on navigation
+        val loadHandler = object : CefLoadHandlerAdapter() {
+            override fun onLoadEnd(cefBrowser: CefBrowser?, frame: CefFrame?, httpStatusCode: Int) {
+                // Only inject in main frame
+                if (frame?.isMain == true) {
+                    SwingUtilities.invokeLater {
+                        injectBridgeJs(browser, project, sendInvoke)
+                    }
+                }
+            }
+        }
+        
+        browser.jbCefClient.addLoadHandler(loadHandler, browser.cefBrowser)
+    }
+    
+    private fun injectBridgeJs(browser: JBCefBrowser, project: Project, sendInvoke: String) {
         try {
-            val sendInvoke = try { q?.inject("String(json)") } catch (_: Throwable) { null } ?: "void 0"
             val js = (
                 "(function(){" +
                 "if(!window.ideBridge){" +
@@ -104,7 +86,11 @@ object IdeBridge {
                 "})();"
             )
             browser.cefBrowser.executeJavaScript(js, browser.cefBrowser.url, 0)
-            SwingUtilities.invokeLater { flushOutbox(project) }
+            val state = states[project]
+            if (state != null) {
+                state.ready = true
+                flushOutbox(project)
+            }
         } catch (t: Throwable) {
             logger.warn("Failed to inject ideBridge", t)
         }