From 9703ddf2a24cd1d4a2f2d441665b5eda94d5e6ef Mon Sep 17 00:00:00 2001 From: Aydar Mukhametzyanov Date: Mon, 14 Jul 2025 16:07:17 +0300 Subject: [PATCH] IJPL-191565 Search Everywhere for RD: fix getting popupInstance (cherry picked from commit 91f3e83e30ae1fe26ceb339066db2f213942522d) GitOrigin-RevId: 8481bc056e2c93673d33c993f44a9c64ed43dcc6 --- .../frontend/src/SeFrontendService.kt | 19 ++- .../commands/SearchEverywhereCommand.java | 118 +++++++++++++----- 2 files changed, 101 insertions(+), 36 deletions(-) diff --git a/platform/searchEverywhere/frontend/src/SeFrontendService.kt b/platform/searchEverywhere/frontend/src/SeFrontendService.kt index 2f126567f34e..5732678d34e8 100644 --- a/platform/searchEverywhere/frontend/src/SeFrontendService.kt +++ b/platform/searchEverywhere/frontend/src/SeFrontendService.kt @@ -33,6 +33,7 @@ import com.intellij.platform.util.coroutines.childScope import com.intellij.platform.util.coroutines.sync.OverflowSemaphore import com.intellij.ui.ScreenUtil import com.intellij.ui.awt.RelativePoint +import com.intellij.util.ui.EDT import com.intellij.util.ui.StartupUiUtil import com.intellij.util.ui.UIUtil import fleet.kernel.DurableRef @@ -43,6 +44,8 @@ import kotlinx.coroutines.channels.BufferOverflow import org.jetbrains.annotations.ApiStatus import java.awt.KeyboardFocusManager import java.awt.Point +import java.util.concurrent.CompletableFuture +import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicBoolean import javax.swing.SwingUtilities @@ -55,7 +58,11 @@ class SeFrontendService(val project: Project?, private val coroutineScope: Corou private val popupSemaphore = OverflowSemaphore(1, overflow = BufferOverflow.DROP_LATEST) @Volatile - private var popupInstance: SePopupInstance? = null + private var popupInstanceFuture: CompletableFuture? = null + private val popupInstance: SePopupInstance? + get() = if (EDT.isCurrentThreadEdt()) popupInstanceFuture?.getNow(null) + else runCatching { popupInstanceFuture?.get(2, TimeUnit.SECONDS) }.getOrNull() + @Volatile var localProvidersHolder: SeProvidersHolder? = null @@ -66,6 +73,9 @@ class SeFrontendService(val project: Project?, private val coroutineScope: Corou val removeSessionRef: AtomicBoolean = AtomicBoolean(true) override fun show(tabId: String, searchText: String?, initEvent: AnActionEvent) { + val popupFuture = CompletableFuture() + popupInstanceFuture = popupFuture + coroutineScope.launch { val popupScope = coroutineScope.childScope("SearchEverywhereFrontendService popup scope") val sessionRef = SeSessionEntity.createRef() @@ -73,12 +83,12 @@ class SeFrontendService(val project: Project?, private val coroutineScope: Corou try { popupSemaphore.withPermit { localProvidersHolder = SeProvidersHolder.initialize(initEvent, project, sessionRef, "Frontend") - val completable = doShowPopup(tabId, searchText, initEvent, popupScope, sessionRef) + val completable = doShowPopup(popupFuture, tabId, searchText, initEvent, popupScope, sessionRef) completable.await() } } finally { - popupInstance = null + popupInstanceFuture = null localProvidersHolder?.let { Disposer.dispose(it) } localProvidersHolder = null @@ -97,6 +107,7 @@ class SeFrontendService(val project: Project?, private val coroutineScope: Corou } private suspend fun doShowPopup( + popupFuture: CompletableFuture, tabId: String, searchText: String?, initEvent: AnActionEvent, @@ -180,7 +191,7 @@ class SeFrontendService(val project: Project?, private val coroutineScope: Corou calcPopupPositionAndShow(popup, contentPane) } - popupInstance = SePopupInstance(popupVm, contentPane, searchStatePublisher) + popupFuture.complete(SePopupInstance(popupVm, contentPane, searchStatePublisher)) val endTime = System.currentTimeMillis() SeLog.log { "Search Everywhere popup opened in ${endTime - startTime} ms" } diff --git a/plugins/performanceTesting/core/src/com/jetbrains/performancePlugin/commands/SearchEverywhereCommand.java b/plugins/performanceTesting/core/src/com/jetbrains/performancePlugin/commands/SearchEverywhereCommand.java index 97e17b64f7b9..ec4789d6c824 100644 --- a/plugins/performanceTesting/core/src/com/jetbrains/performancePlugin/commands/SearchEverywhereCommand.java +++ b/plugins/performanceTesting/core/src/com/jetbrains/performancePlugin/commands/SearchEverywhereCommand.java @@ -91,40 +91,18 @@ public class SearchEverywhereCommand extends AbstractCommand { Ref tabId = computeTabId(tab); int numberOfPermits = getNumberOfPermits(insertText); + var manager = SearchEverywhereManager.getInstance(project); + boolean isNewSe = !(manager instanceof SearchEverywhereManagerImpl); Semaphore typingSemaphore = new Semaphore(numberOfPermits); + TraceKt.use(PerformanceTestSpan.getTracer(warmup).spanBuilder("searchEverywhere"), globalSpan -> { - ApplicationManager.getApplication().invokeAndWait(Context.current().wrap(() -> { - try { - TypingTarget target = findTarget(context); - Component component; - if (!(target instanceof EditorComponentImpl)) { - LOG.info("Editor is not opened, focus owner will be used."); - component = IdeFocusManager.getInstance(project).getFocusOwner(); - } - else { - component = (EditorComponentImpl)target; - } - DataContext dataContext = CustomizedDataContext.withSnapshot( - DataManager.getInstance().getDataContext(component), - sink -> sink.set(CommonDataKeys.PROJECT, context.getProject())); - DataContext wrappedDataContext = wrapDataContextWithActionStartData(dataContext); - IdeEventQueue.getInstance().getPopupManager().closeAllPopups(false); - TraceKt.use(PerformanceTestSpan.getTracer(warmup).spanBuilder("searchEverywhere_dialog_shown"), dialogSpan -> { - var manager = SearchEverywhereManager.getInstance(project); - AnActionEvent event = AnActionEvent.createEvent( - wrappedDataContext, null, ActionPlaces.EDITOR_POPUP, ActionUiKind.POPUP, null); - manager.show(tabId.get(), "", event); - SearchEverywherePopupInstance popupInstance = manager.getCurrentlyShownPopupInstance(); - assert (popupInstance != null); - attachSearchListeners(popupInstance); - return null; - }); - typeOrInsertText(context, insertText, typingSemaphore, warmup); - } - catch (Exception e) { - LOG.error(e); - } - })); + if (isNewSe) { + showPopupInEdtWaitForPopupAndTypeText(manager, project, context, tabId, insertText, typingSemaphore, warmup); + } + else { + showPopupAndTypeTextAllInEDT(manager, project, context, tabId, insertText, typingSemaphore, warmup); + } + try { typingSemaphore.acquire(); SearchEverywherePopupInstance popupInstance = SearchEverywhereManager.getInstance(project).getCurrentlyShownPopupInstance(); @@ -151,6 +129,82 @@ public class SearchEverywhereCommand extends AbstractCommand { return Promises.toPromise(actionCallback); } + private void showPopupAndTypeTextAllInEDT(SearchEverywhereManager manager, Project project, @NotNull PlaybackContext context, Ref tabId, String insertText, Semaphore typingSemaphore, boolean warmup) { + ApplicationManager.getApplication().invokeAndWait(Context.current().wrap(() -> { + try { + DataContext wrappedDataContext = createDataContext(context, project); + IdeEventQueue.getInstance().getPopupManager().closeAllPopups(false); + TraceKt.use(PerformanceTestSpan.getTracer(warmup).spanBuilder("searchEverywhere_dialog_shown"), dialogSpan -> { + showPopup(manager, wrappedDataContext, tabId); + SearchEverywherePopupInstance popupInstance = manager.getCurrentlyShownPopupInstance(); + assert (popupInstance != null); + attachSearchListeners(popupInstance); + return null; + }); + typeOrInsertText(context, insertText, typingSemaphore, warmup); + } + catch (Exception e) { + LOG.error(e); + } + })); + } + + private void showPopupInEdtWaitForPopupAndTypeText(SearchEverywhereManager manager, Project project, @NotNull PlaybackContext context, Ref tabId, String insertText, Semaphore typingSemaphore, boolean warmup) { + ApplicationManager.getApplication().invokeAndWait(Context.current().wrap(() -> { + try { + DataContext wrappedDataContext = createDataContext(context, project); + IdeEventQueue.getInstance().getPopupManager().closeAllPopups(false); + TraceKt.use(PerformanceTestSpan.getTracer(warmup).spanBuilder("searchEverywhere_dialog_shown"), dialogSpan -> { + showPopup(manager, wrappedDataContext, tabId); + return null; + }); + } + catch (Exception e) { + LOG.error(e); + } + })); + + // Get the popup instance outside if EDT + SearchEverywherePopupInstance popupInstance = manager.getCurrentlyShownPopupInstance(); + + ApplicationManager.getApplication().invokeAndWait(Context.current().wrap(() -> { + try { + attachListenersToPopup(popupInstance); + typeOrInsertText(context, insertText, typingSemaphore, warmup); + } + catch (Exception e) { + LOG.error(e); + } + })); + } + + private static DataContext createDataContext(@NotNull PlaybackContext context, @NotNull Project project) { + TypingTarget target = findTarget(context); + Component component; + if (!(target instanceof EditorComponentImpl)) { + LOG.info("Editor is not opened, focus owner will be used."); + component = IdeFocusManager.getInstance(project).getFocusOwner(); + } + else { + component = (EditorComponentImpl)target; + } + DataContext dataContext = CustomizedDataContext.withSnapshot( + DataManager.getInstance().getDataContext(component), + sink -> sink.set(CommonDataKeys.PROJECT, context.getProject())); + return wrapDataContextWithActionStartData(dataContext); + } + + private static void showPopup(SearchEverywhereManager manager, DataContext dataContext, Ref tabId) { + AnActionEvent event = AnActionEvent.createEvent( + dataContext, null, ActionPlaces.EDITOR_POPUP, ActionUiKind.POPUP, null); + manager.show(tabId.get(), "", event); + } + + private void attachListenersToPopup(SearchEverywherePopupInstance popupInstance) { + assert (popupInstance != null); + attachSearchListeners(popupInstance); + } + private static @NotNull Ref computeTabId(String tab) { Ref tabId = new Ref<>(); switch (tab) {