From 34e20741b093a51742daa71c2856ba87e01c5541 Mon Sep 17 00:00:00 2001 From: Aydar Mukhametzyanov Date: Wed, 21 May 2025 21:50:07 +0200 Subject: [PATCH] IJPL-158622 Search Everywhere for RD: fix popup presentation on Welcome screen GitOrigin-RevId: 215e1959968259ab7a68e8f5f948cf20658ddc7a --- platform/searchEverywhere/frontend/src/SeFrontendService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/searchEverywhere/frontend/src/SeFrontendService.kt b/platform/searchEverywhere/frontend/src/SeFrontendService.kt index 0912fb4ab64c..a9a54a97529b 100644 --- a/platform/searchEverywhere/frontend/src/SeFrontendService.kt +++ b/platform/searchEverywhere/frontend/src/SeFrontendService.kt @@ -1 +1 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.platform.searchEverywhere.frontend import com.intellij.ide.actions.SearchEverywhereManagerFactory import com.intellij.ide.actions.searcheverywhere.SearchEverywhereManager import com.intellij.ide.actions.searcheverywhere.SearchEverywherePopupInstance import com.intellij.ide.actions.searcheverywhere.SearchEverywhereUI import com.intellij.ide.actions.searcheverywhere.SearchHistoryList import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.application.EDT import com.intellij.openapi.components.Service import com.intellij.openapi.components.service import com.intellij.openapi.project.Project import com.intellij.openapi.ui.popup.JBPopup import com.intellij.openapi.ui.popup.JBPopupFactory import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.registry.Registry import com.intellij.platform.searchEverywhere.SeSessionEntity import com.intellij.platform.searchEverywhere.frontend.ui.SePopupContentPane import com.intellij.platform.searchEverywhere.frontend.vm.SePopupVm import com.intellij.platform.searchEverywhere.providers.SeLog import com.intellij.platform.util.coroutines.childScope import com.intellij.platform.util.coroutines.sync.OverflowSemaphore import com.intellij.util.ui.StartupUiUtil import fleet.kernel.DurableRef import fleet.kernel.change import fleet.kernel.shared import kotlinx.coroutines.* import kotlinx.coroutines.channels.BufferOverflow import org.jetbrains.annotations.ApiStatus @ApiStatus.Internal @Service(Service.Level.PROJECT, Service.Level.APP) class SeFrontendService(val project: Project?, private val coroutineScope: CoroutineScope) : SearchEverywhereManager { @Suppress("unused") constructor(coroutineScope: CoroutineScope) : this(null, coroutineScope) private val popupSemaphore = OverflowSemaphore(1, overflow = BufferOverflow.DROP_LATEST) @Volatile private var popupInstance: SePopupInstance? = null private val historyList = SearchHistoryList(true) override fun show(tabId: String, searchText: String?, initEvent: AnActionEvent) { coroutineScope.launch { val popupScope = coroutineScope.childScope("SearchEverywhereFrontendService popup scope") val sessionRef = SeSessionEntity.createRef() try { popupSemaphore.withPermit { val completable = doShowPopup(tabId, searchText, initEvent, popupScope, sessionRef) completable.await() } } finally { popupInstance = null withContext(NonCancellable) { popupScope.cancel() change { shared { sessionRef.derefOrNull()?.delete() } } } } } } private suspend fun doShowPopup( tabId: String, searchText: String?, initEvent: AnActionEvent, popupScope: CoroutineScope, sessionRef: DurableRef, ): CompletableDeferred { val startTime = System.currentTimeMillis() val tabs = SeTabFactory.EP_NAME.extensionList.mapNotNull { it.getTab(project, sessionRef, initEvent) } if (tabs.isEmpty()) { throw IllegalStateException("No tabs available") } var popup: JBPopup? = null val popupVm = SePopupVm(popupScope, project, sessionRef, tabs, searchText, tabId, historyList) { popup?.cancel() popup = null } popupVm.showTab(tabId) val completable = CompletableDeferred() withContext(Dispatchers.EDT) { val contentPane = SePopupContentPane(project, popupVm) popup = createPopup(contentPane, popupVm, project) { completable.complete(Unit) } if (project == null) popup?.showInFocusCenter() else popup?.showCenteredInCurrentWindow(project) popupInstance = SePopupInstance(popupVm, contentPane) val endTime = System.currentTimeMillis() SeLog.log { "Search Everywhere popup opened in ${endTime - startTime} ms" } } return completable } private fun createPopup(panel: SePopupContentPane, popupVm: SePopupVm, project: Project?, onCancel: () -> Unit): JBPopup { val popup = JBPopupFactory.getInstance().createComponentPopupBuilder(panel, panel.preferableFocusedComponent) .setProject(project) .setModalContext(false) .setNormalWindowLevel(StartupUiUtil.isWaylandToolkit()) .setCancelOnClickOutside(true) .setRequestFocus(true) .setCancelKeyEnabled(false) .setResizable(true) .setMovable(true) .setDimensionServiceKey(project, POPUP_LOCATION_SETTINGS_KEY, true) .setLocateWithinScreenBounds(false) .setCancelCallback { popupVm.saveSearchText() onCancel() true } .createPopup() Disposer.register(popup, panel) return popup } override fun isShown(): Boolean = popupInstance != null @Deprecated("Deprecated in the interface") override fun getCurrentlyShownUI(): SearchEverywhereUI { throw UnsupportedOperationException("The method is deprecated. Please use getCurrentlyShownPopupInstance() instead.") } override fun getCurrentlyShownPopupInstance(): SearchEverywherePopupInstance? = popupInstance override fun getSelectedTabID(): String = popupInstance?.getSelectedTabID() ?: "" override fun setSelectedTabID(tabID: String) { popupInstance?.setSelectedTabID(tabID) } override fun toggleEverywhereFilter() { popupInstance?.toggleEverywhereFilter() } override fun isEverywhere(): Boolean = popupInstance?.isEverywhere() ?: false companion object { @JvmStatic fun getInstance(project: Project?): SeFrontendService = project?.getService(SeFrontendService::class.java) ?: service() @JvmStatic val isEnabled: Boolean get() = Registry.`is`("search.everywhere.new.enabled", false) private const val POPUP_LOCATION_SETTINGS_KEY: String = "search.everywhere.popup" } } @ApiStatus.Internal class RemDevFriendlySearchEverywhereManager : SearchEverywhereManagerFactory { override fun isAvailable(): Boolean = SeFrontendService.isEnabled override fun getManager(project: Project?): SearchEverywhereManager = SeFrontendService.getInstance(project) } \ No newline at end of file +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.platform.searchEverywhere.frontend import com.intellij.ide.actions.SearchEverywhereManagerFactory import com.intellij.ide.actions.searcheverywhere.SearchEverywhereManager import com.intellij.ide.actions.searcheverywhere.SearchEverywherePopupInstance import com.intellij.ide.actions.searcheverywhere.SearchEverywhereUI import com.intellij.ide.actions.searcheverywhere.SearchHistoryList import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.application.EDT import com.intellij.openapi.components.Service import com.intellij.openapi.components.service import com.intellij.openapi.project.Project import com.intellij.openapi.ui.popup.JBPopup import com.intellij.openapi.ui.popup.JBPopupFactory import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.registry.Registry import com.intellij.platform.searchEverywhere.SeSessionEntity import com.intellij.platform.searchEverywhere.frontend.ui.SePopupContentPane import com.intellij.platform.searchEverywhere.frontend.vm.SePopupVm import com.intellij.platform.searchEverywhere.providers.SeLog import com.intellij.platform.util.coroutines.childScope import com.intellij.platform.util.coroutines.sync.OverflowSemaphore import com.intellij.util.ui.StartupUiUtil import fleet.kernel.DurableRef import fleet.kernel.change import fleet.kernel.shared import kotlinx.coroutines.* import kotlinx.coroutines.channels.BufferOverflow import org.jetbrains.annotations.ApiStatus import java.awt.KeyboardFocusManager @ApiStatus.Internal @Service(Service.Level.PROJECT, Service.Level.APP) class SeFrontendService(val project: Project?, private val coroutineScope: CoroutineScope) : SearchEverywhereManager { @Suppress("unused") constructor(coroutineScope: CoroutineScope) : this(null, coroutineScope) private val popupSemaphore = OverflowSemaphore(1, overflow = BufferOverflow.DROP_LATEST) @Volatile private var popupInstance: SePopupInstance? = null private val historyList = SearchHistoryList(true) override fun show(tabId: String, searchText: String?, initEvent: AnActionEvent) { coroutineScope.launch { val popupScope = coroutineScope.childScope("SearchEverywhereFrontendService popup scope") val sessionRef = SeSessionEntity.createRef() try { popupSemaphore.withPermit { val completable = doShowPopup(tabId, searchText, initEvent, popupScope, sessionRef) completable.await() } } finally { popupInstance = null withContext(NonCancellable) { popupScope.cancel() change { shared { sessionRef.derefOrNull()?.delete() } } } } } } private suspend fun doShowPopup( tabId: String, searchText: String?, initEvent: AnActionEvent, popupScope: CoroutineScope, sessionRef: DurableRef, ): CompletableDeferred { val startTime = System.currentTimeMillis() val tabs = SeTabFactory.EP_NAME.extensionList.mapNotNull { it.getTab(project, sessionRef, initEvent) } if (tabs.isEmpty()) { throw IllegalStateException("No tabs available") } var popup: JBPopup? = null val popupVm = SePopupVm(popupScope, project, sessionRef, tabs, searchText, tabId, historyList) { popup?.cancel() popup = null } popupVm.showTab(tabId) val completable = CompletableDeferred() withContext(Dispatchers.EDT) { val contentPane = SePopupContentPane(project, popupVm) popup = createPopup(contentPane, popupVm, project) { completable.complete(Unit) } if (project == null) popup?.showInCenterOf(KeyboardFocusManager.getCurrentKeyboardFocusManager().focusedWindow) else popup?.showCenteredInCurrentWindow(project) popupInstance = SePopupInstance(popupVm, contentPane) val endTime = System.currentTimeMillis() SeLog.log { "Search Everywhere popup opened in ${endTime - startTime} ms" } } return completable } private fun createPopup(panel: SePopupContentPane, popupVm: SePopupVm, project: Project?, onCancel: () -> Unit): JBPopup { val popup = JBPopupFactory.getInstance().createComponentPopupBuilder(panel, panel.preferableFocusedComponent) .setProject(project) .setModalContext(false) .setNormalWindowLevel(StartupUiUtil.isWaylandToolkit()) .setCancelOnClickOutside(true) .setRequestFocus(true) .setCancelKeyEnabled(false) .setResizable(true) .setMovable(true) .setDimensionServiceKey(project, POPUP_LOCATION_SETTINGS_KEY, true) .setLocateWithinScreenBounds(false) .setCancelCallback { popupVm.saveSearchText() onCancel() true } .createPopup() Disposer.register(popup, panel) return popup } override fun isShown(): Boolean = popupInstance != null @Deprecated("Deprecated in the interface") override fun getCurrentlyShownUI(): SearchEverywhereUI { throw UnsupportedOperationException("The method is deprecated. Please use getCurrentlyShownPopupInstance() instead.") } override fun getCurrentlyShownPopupInstance(): SearchEverywherePopupInstance? = popupInstance override fun getSelectedTabID(): String = popupInstance?.getSelectedTabID() ?: "" override fun setSelectedTabID(tabID: String) { popupInstance?.setSelectedTabID(tabID) } override fun toggleEverywhereFilter() { popupInstance?.toggleEverywhereFilter() } override fun isEverywhere(): Boolean = popupInstance?.isEverywhere() ?: false companion object { @JvmStatic fun getInstance(project: Project?): SeFrontendService = project?.getService(SeFrontendService::class.java) ?: service() @JvmStatic val isEnabled: Boolean get() = Registry.`is`("search.everywhere.new.enabled", false) private const val POPUP_LOCATION_SETTINGS_KEY: String = "search.everywhere.popup" } } @ApiStatus.Internal class RemDevFriendlySearchEverywhereManager : SearchEverywhereManagerFactory { override fun isAvailable(): Boolean = SeFrontendService.isEnabled override fun getManager(project: Project?): SearchEverywhereManager = SeFrontendService.getInstance(project) } \ No newline at end of file