IJPL-191565 Search Everywhere for RD: fix getting popupInstance

(cherry picked from commit 91f3e83e30ae1fe26ceb339066db2f213942522d)

GitOrigin-RevId: 8481bc056e2c93673d33c993f44a9c64ed43dcc6
This commit is contained in:
Aydar Mukhametzyanov
2025-07-14 16:07:17 +03:00
committed by intellij-monorepo-bot
parent dbe65d77f5
commit 9703ddf2a2
2 changed files with 101 additions and 36 deletions

View File

@@ -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<SePopupInstance>? = 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<SePopupInstance>()
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<SePopupInstance>,
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" }

View File

@@ -91,40 +91,18 @@ public class SearchEverywhereCommand extends AbstractCommand {
Ref<String> 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<String> 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<String> 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<String> 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<String> computeTabId(String tab) {
Ref<String> tabId = new Ref<>();
switch (tab) {