[platform UI] IJPL-188269 Search Everywhere: 'Open in Right Split' and 'Assign Shortcut' links are not available in the footer

- Fixes:
- Don't hide extendedInfoContainer when the left text is empty
- Implement `isExtendedInfoEnabled` in tabs and `SeExtendedInfoProvider` in providers to hide the extended info only for specific tabs
- Call `updateExtendedInfoContainer` in tab flow

GitOrigin-RevId: 7d8e2124f253763b7056c07428936b73495cd47b
This commit is contained in:
Tatiana Elfimova
2025-10-14 21:57:42 +00:00
committed by intellij-monorepo-bot
parent 58e975cc05
commit d5f48672a8
25 changed files with 116 additions and 14 deletions
@@ -259,6 +259,18 @@ class SeBackendService(val project: Project, private val coroutineScope: Corouti
}
}
suspend fun isExtendedInfoEnabled(
session: SeSession,
dataContextId: DataContextId,
providerIds: List<SeProviderId>,
isAllTab: Boolean,
): Boolean {
return providerIds.any { providerId ->
val provider = getProvidersHolder(session, dataContextId)?.get(providerId, isAllTab)
provider?.isExtendedInfoEnabled() ?: false
}
}
companion object {
@JvmStatic
fun getInstance(project: Project): SeBackendService = project.service<SeBackendService>()
@@ -149,4 +149,9 @@ class SeRemoteApiImpl : SeRemoteApi {
val project = projectId.findProjectOrNull() ?: return false
return SeBackendService.getInstance(project).isPreviewEnabled(session, dataContextId, providerIds, isAllTab)
}
override suspend fun isExtendedInfoEnabled(projectId: ProjectId, session: SeSession, dataContextId: DataContextId, providerIds: List<SeProviderId>, isAllTab: Boolean): Boolean {
val project = projectId.findProjectOrNull() ?: return false
return SeBackendService.getInstance(project).isExtendedInfoEnabled(session, dataContextId, providerIds, isAllTab)
}
}
@@ -18,7 +18,8 @@ import org.jetbrains.annotations.Nls
class SeClassesProvider(private val contributorWrapper: SeAsyncContributorWrapper<Any>) : SeWrappedLegacyContributorItemsProvider(),
SeSearchScopesProvider,
SeTypeVisibilityStateProvider,
SeItemsPreviewProvider {
SeItemsPreviewProvider,
SeExtendedInfoProvider {
override val id: String get() = SeProviderIdUtils.CLASSES_ID
override val displayName: @Nls String
get() = contributorWrapper.contributor.fullGroupName
@@ -18,7 +18,8 @@ import org.jetbrains.annotations.Nls
class SeFilesProvider(private val contributorWrapper: SeAsyncContributorWrapper<Any>) : SeWrappedLegacyContributorItemsProvider(),
SeSearchScopesProvider,
SeTypeVisibilityStateProvider,
SeItemsPreviewProvider{
SeItemsPreviewProvider,
SeExtendedInfoProvider {
override val id: String get() = SeProviderIdUtils.FILES_ID
override val displayName: @Nls String
get() = contributorWrapper.contributor.fullGroupName
@@ -5,6 +5,7 @@ import com.intellij.ide.actions.searcheverywhere.SearchEverywhereContributor
import com.intellij.ide.util.gotoByName.FileTypeRef
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Disposer
import com.intellij.platform.searchEverywhere.SeExtendedInfoProvider
import com.intellij.platform.searchEverywhere.*
import com.intellij.platform.searchEverywhere.backend.providers.target.SeTargetsProviderDelegate
import com.intellij.platform.searchEverywhere.providers.SeAsyncContributorWrapper
@@ -13,7 +14,9 @@ import org.jetbrains.annotations.ApiStatus.Internal
import org.jetbrains.annotations.Nls
@Internal
class SeRecentFilesProvider(private val contributorWrapper: SeAsyncContributorWrapper<Any>) : SeWrappedLegacyContributorItemsProvider(), SeItemsPreviewProvider {
class SeRecentFilesProvider(private val contributorWrapper: SeAsyncContributorWrapper<Any>) : SeWrappedLegacyContributorItemsProvider(),
SeItemsPreviewProvider,
SeExtendedInfoProvider {
override val id: String get() = SeProviderIdUtils.RECENT_FILES_ID
override val displayName: @Nls String
get() = contributorWrapper.contributor.fullGroupName
@@ -18,7 +18,8 @@ import org.jetbrains.annotations.Nls
class SeSymbolsProvider(private val contributorWrapper: SeAsyncContributorWrapper<Any>) : SeWrappedLegacyContributorItemsProvider(),
SeSearchScopesProvider,
SeTypeVisibilityStateProvider,
SeItemsPreviewProvider{
SeItemsPreviewProvider,
SeExtendedInfoProvider {
override val id: String get() = SeProviderIdUtils.SYMBOLS_ID
override val displayName: @Nls String
get() = contributorWrapper.contributor.fullGroupName
@@ -45,7 +45,8 @@ class SeTextSearchItem(
@ApiStatus.Internal
class SeTextItemsProvider(project: Project, private val contributorWrapper: SeAsyncContributorWrapper<Any>) : SeWrappedLegacyContributorItemsProvider(),
SeSearchScopesProvider,
SeItemsPreviewProvider{
SeItemsPreviewProvider,
SeExtendedInfoProvider {
override val id: String get() = SeProviderIdUtils.TEXT_ID
override val displayName: @Nls String
get() = contributor.fullGroupName
@@ -97,6 +97,12 @@ class SeFrontendItemDataProvidersFacade(private val projectId: ProjectId,
)
}
suspend fun isExtendedInfoEnabled(): Boolean {
return SeRemoteApi.getInstance().isExtendedInfoEnabled(
projectId, providerIds = providerIds, session = session, dataContextId = dataContextId, isAllTab = isAllTab
)
}
companion object {
private const val DEFAULT_CHUNK_SIZE: Int = 50
}
@@ -47,4 +47,6 @@ interface SeTab : Disposable {
suspend fun isPreviewEnabled(): Boolean
suspend fun getPreviewInfo(itemData: SeItemData): SePreviewInfo?
suspend fun isExtendedInfoEnabled(): Boolean
}
@@ -39,7 +39,7 @@ class SeActionItem(
}
@Internal
class SeActionsAdaptedProvider(private val contributorWrapper: SeAsyncContributorWrapper<MatchedValue>) : SeWrappedLegacyContributorItemsProvider() {
class SeActionsAdaptedProvider(private val contributorWrapper: SeAsyncContributorWrapper<MatchedValue>) : SeWrappedLegacyContributorItemsProvider(), SeExtendedInfoProvider {
override val id: String get() = SeProviderIdUtils.ACTIONS_ID
override val displayName: @Nls String
get() = contributor.fullGroupName
@@ -163,6 +163,10 @@ class SeTabDelegate(
return providers.getValue().isPreviewEnabled()
}
suspend fun isExtendedInfoEnabled(): Boolean {
return providers.getValue().isExtendedInfoEnabled()
}
override fun dispose() {}
private class Providers(
@@ -266,6 +270,10 @@ class SeTabDelegate(
suspend fun isPreviewEnabled(): Boolean {
return localProviders.values.any { it.isPreviewEnabled() } || frontendProvidersFacade?.isPreviewEnabled() == true
}
suspend fun isExtendedInfoEnabled(): Boolean {
return localProviders.values.any { it.isExtendedInfoEnabled() } || frontendProvidersFacade?.isExtendedInfoEnabled() == true
}
}
// Workaround for: IJPL-188383 Search Everywhere, All tab: 'Top Hit' filter is duplicated
@@ -63,6 +63,10 @@ class SeActionsTab(private val delegate: SeTabDelegate) : SeTab {
return delegate.getPreviewInfo(itemData, false)
}
override suspend fun isExtendedInfoEnabled(): Boolean {
return delegate.isExtendedInfoEnabled()
}
override fun dispose() {
Disposer.dispose(delegate)
}
@@ -67,6 +67,10 @@ class SeAllTab(private val delegate: SeTabDelegate) : SeTab {
return delegate.getUpdatedPresentation(item)
}
override suspend fun isExtendedInfoEnabled(): Boolean {
return delegate.isExtendedInfoEnabled()
}
override suspend fun performExtendedAction(item: SeItemData): Boolean {
return delegate.performExtendedAction(item)
}
@@ -65,6 +65,10 @@ class SeClassesTab(private val delegate: SeTabDelegate) : SeTab {
return delegate.getPreviewInfo(itemData, false)
}
override suspend fun isExtendedInfoEnabled(): Boolean {
return delegate.isExtendedInfoEnabled()
}
override fun dispose() {
Disposer.dispose(delegate)
}
@@ -66,6 +66,10 @@ class SeFilesTab(private val delegate: SeTabDelegate) : SeTab {
return delegate.getPreviewInfo(itemData, false)
}
override suspend fun isExtendedInfoEnabled(): Boolean {
return delegate.isExtendedInfoEnabled()
}
override fun dispose() {
Disposer.dispose(delegate)
}
@@ -45,6 +45,10 @@ class SeTabMock(
return delegate.isPreviewEnabled()
}
override suspend fun isExtendedInfoEnabled(): Boolean {
return delegate.isExtendedInfoEnabled()
}
override fun dispose() {
Disposer.dispose(delegate)
}
@@ -65,6 +65,10 @@ class SeSymbolsTab(private val delegate: SeTabDelegate) : SeTab {
return delegate.getPreviewInfo(itemData, false)
}
override suspend fun isExtendedInfoEnabled(): Boolean {
return delegate.isExtendedInfoEnabled()
}
override fun dispose() {
Disposer.dispose(delegate)
}
@@ -68,6 +68,10 @@ class SeTextTab(private val delegate: SeTabDelegate, registerShortcut: (AnAction
return delegate.getPreviewInfo(itemData, false)
}
override suspend fun isExtendedInfoEnabled(): Boolean {
return delegate.isExtendedInfoEnabled()
}
override fun dispose() {
Disposer.dispose(filterEditorDisposable)
Disposer.dispose(delegate)
@@ -152,8 +152,6 @@ class SePopupContentPane(
resultList.setFocusable(false)
updateExtendedInfoContainer()
RowsGridBuilder(this)
.row().cell(headerPane, horizontalAlign = HorizontalAlign.FILL, resizableColumn = true)
.row().cell(textField, horizontalAlign = HorizontalAlign.FILL, resizableColumn = true)
@@ -300,6 +298,9 @@ class SePopupContentPane(
}
}
}
withContext(Dispatchers.EDT) {
updateExtendedInfoContainer()
}
}
}
@@ -581,14 +582,12 @@ class SePopupContentPane(
vmState.value?.let { vm ->
vm.selectNextTab()
logTabSwitchedEvent(e)
updateExtendedInfoContainer()
}
}
val prevTabAction: (AnActionEvent) -> Unit = { e ->
vmState.value?.let { vm ->
vm.selectPreviousTab()
logTabSwitchedEvent(e)
updateExtendedInfoContainer()
}
}
@@ -751,11 +750,10 @@ class SePopupContentPane(
.show(relativePoint)
}
private fun createExtendedInfoComponent(): ExtendedInfoComponent? {
if (isExtendedInfoEnabled()) {
private suspend fun createExtendedInfoComponent(): ExtendedInfoComponent? {
if (isExtendedInfoEnabled() && vm.isExtendedInfoEnabledInTab()) {
val leftText = fun(element: Any): String? {
val leftText = (element as? SeResultListItemRow)?.item?.presentation?.extendedInfo?.text
extendedInfoContainer.isVisible = !leftText.isNullOrEmpty()
return leftText
}
@@ -788,7 +786,7 @@ class SePopupContentPane(
return null
}
private fun updateExtendedInfoContainer() {
private suspend fun updateExtendedInfoContainer() {
extendedInfoContainer.removeAll()
extendedInfoComponent = createExtendedInfoComponent()
extendedInfoComponent?.let { extendedInfoContainer.add(it.component) }
@@ -250,6 +250,10 @@ class SePopupVm(
return previewFetcher?.fetchPreview(usages)
}
suspend fun isExtendedInfoEnabledInTab(): Boolean {
return currentTab.isExtendedInfoEnabled()
}
private val popupVm = this
inner class ShowInFindToolWindowAction : DumbAwareAction(IdeBundle.messagePointer("show.in.find.window.button.name"),
@@ -239,6 +239,10 @@ class SeTabVm(
}
suspend fun getPreviewInfo(itemData: SeItemData): SePreviewInfo? = tab.getPreviewInfo(itemData)
suspend fun isExtendedInfoEnabled() : Boolean {
return tab.isExtendedInfoEnabled()
}
}
private const val ESSENTIALS_THROTTLE_DELAY: Long = 100
@@ -0,0 +1,7 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.platform.searchEverywhere
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
interface SeExtendedInfoProvider
@@ -131,6 +131,12 @@ interface SeRemoteApi : RemoteApi<Unit> {
isAllTab: Boolean,
): Boolean
suspend fun isExtendedInfoEnabled(projectId: ProjectId,
session: SeSession,
dataContextId: DataContextId,
providerIds: List<SeProviderId>,
isAllTab: Boolean): Boolean
companion object {
@JvmStatic
suspend fun getInstance(): SeRemoteApi {
@@ -3,6 +3,7 @@ package com.intellij.platform.searchEverywhere.providers
import com.intellij.ide.actions.searcheverywhere.SearchEverywhereContributor
import com.intellij.ide.actions.searcheverywhere.SearchEverywherePreviewProvider
import com.intellij.ide.actions.searcheverywhere.SearchEverywhereExtendedInfoProvider
import com.intellij.openapi.application.EDT
import com.intellij.openapi.util.Disposer
import com.intellij.platform.searchEverywhere.*
@@ -55,6 +56,10 @@ class SeAdaptedItemsProvider(contributor: SearchEverywhereContributor<Any>) : Se
return contributorWrapper.contributor is SearchEverywherePreviewProvider
}
fun isExtendedInfoProvider(): Boolean {
return contributorWrapper.contributor is SearchEverywhereExtendedInfoProvider
}
override fun dispose() {
Disposer.dispose(contributorWrapper)
}
@@ -1,6 +1,7 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.platform.searchEverywhere.providers
import com.intellij.ide.actions.searcheverywhere.SearchEverywhereExtendedInfoProvider
import com.intellij.ide.actions.searcheverywhere.statistics.SearchEverywhereUsageTriggerCollector
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.EDT
@@ -118,6 +119,15 @@ class SeLocalItemDataProvider(
return provider is SeItemsPreviewProvider
}
fun isExtendedInfoEnabled(): Boolean {
if (provider is SeTopHitItemsProvider) {
return provider.contributor is SearchEverywhereExtendedInfoProvider
} else if (provider is SeAdaptedItemsProvider) {
return provider.isExtendedInfoProvider()
}
return provider is SeExtendedInfoProvider
}
override fun dispose() {
SeLog.log(SeLog.LIFE_CYCLE, "$logLabel provider ${id.value} disposed")
Disposer.dispose(provider)