IJPL-157219 SE - use IdeNavigationService, fire fileOpened for remote dev

GitOrigin-RevId: b027948a20e7872e5d16de5e534357836eaab1e3
This commit is contained in:
Vladimir Krivosheev
2024-06-27 18:38:38 +02:00
committed by intellij-monorepo-bot
parent aa6061cd40
commit 39afeda85c
7 changed files with 126 additions and 40 deletions

View File

@@ -3,7 +3,7 @@
package com.intellij.ide.actions.searcheverywhere
import com.intellij.codeInsight.navigation.activateFileWithPsiElement
import com.intellij.codeWithMe.ClientId
import com.intellij.ide.actions.GotoActionBase
import com.intellij.ide.actions.OpenInRightSplitAction.Companion.openInRightSplit
import com.intellij.ide.actions.QualifiedNameProviderUtil
@@ -24,6 +24,7 @@ import com.intellij.openapi.actionSystem.impl.SimpleDataContext
import com.intellij.openapi.application.*
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.components.serviceAsync
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.fileEditor.OpenFileDescriptor
import com.intellij.openapi.progress.ProgressIndicator
@@ -33,6 +34,8 @@ import com.intellij.openapi.project.DumbService.Companion.isDumbAware
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Key
import com.intellij.openapi.util.text.StringUtil
import com.intellij.platform.backend.navigation.NavigationRequests
import com.intellij.platform.ide.navigation.NavigationService
import com.intellij.platform.util.coroutines.childScope
import com.intellij.pom.Navigatable
import com.intellij.psi.PsiElement
@@ -371,7 +374,7 @@ abstract class AbstractGotoSEContributor protected constructor(event: AnActionEv
return true
}
myProject.service<SearchEverywhereContributorCoroutineScopeHolder>().coroutineScope.launch {
myProject.service<SearchEverywhereContributorCoroutineScopeHolder>().coroutineScope.launch(ClientId.coroutineContext()) {
val command = readAction {
val psiElement = preparePsi(selected, searchText)
val extNavigatable = createExtendedNavigatable(psi = psiElement, searchText = searchText, modifiers = modifiers)
@@ -379,16 +382,28 @@ abstract class AbstractGotoSEContributor protected constructor(event: AnActionEv
@Suppress("DEPRECATION")
if ((modifiers and InputEvent.SHIFT_MASK) != 0 && file != null) {
Runnable { openInRightSplit(project = myProject, file = file, element = extNavigatable, requestFocus = true) }
suspend {
withContext(Dispatchers.EDT + ModalityState.nonModal().asContextElement()) {
openInRightSplit(project = myProject, file = file, element = extNavigatable, requestFocus = true)
}
}
}
else {
Runnable { doNavigate(psiElement, extNavigatable) }
suspend {
if (extNavigatable == null) {
val navigationRequests = serviceAsync<NavigationRequests>()
readAction { navigationRequests.sourceNavigationRequest(myProject, file!!, -1, null) }?.let {
myProject.serviceAsync<NavigationService>().navigate(it)
}
}
else {
myProject.serviceAsync<NavigationService>().navigate(extNavigatable)
}
}
}
}
withContext(Dispatchers.EDT + ModalityState.nonModal().asContextElement()) {
command.run()
}
command()
}
}
else {
@@ -475,15 +490,6 @@ private fun getSelectedScopes(project: Project): MutableMap<String, String?> {
return map
}
private fun doNavigate(psiElement: PsiElement, extNavigatable: Navigatable?) {
if (extNavigatable != null && extNavigatable.canNavigate()) {
extNavigatable.navigate(true)
}
else {
activateFileWithPsiElement(element = psiElement, searchForOpen = true)
}
}
private fun getLineAndColumnRegexpGroup(text: String, groupNumber: Int): Int {
val matcher = ourPatternToDetectLinesAndColumns.matcher(text)
if (matcher.matches()) {

View File

@@ -1,6 +1,7 @@
// 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.ide.actions.searcheverywhere
import com.intellij.codeWithMe.ClientId
import com.intellij.featureStatistics.FeatureUsageTracker
import com.intellij.ide.IdeBundle
import com.intellij.ide.actions.OpenInRightSplitAction.Companion.openInRightSplit
@@ -16,6 +17,7 @@ import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.readAction
import com.intellij.openapi.components.service
import com.intellij.openapi.components.serviceAsync
import com.intellij.openapi.diagnostic.Logger
@@ -23,6 +25,8 @@ import com.intellij.openapi.fileEditor.OpenFileDescriptor
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.io.FileUtilRt
import com.intellij.platform.backend.navigation.NavigationRequests
import com.intellij.platform.ide.navigation.NavigationService
import com.intellij.psi.PsiDirectory
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiFileSystemItem
@@ -115,20 +119,30 @@ open class FileSearchEverywhereContributor(event: AnActionEvent) : AbstractGotoS
}
val lineAndColumn = getLineAndColumn(searchText)
val descriptor = OpenFileDescriptor(myProject, file, lineAndColumn.first, lineAndColumn.second)
if (descriptor.canNavigate()) {
myProject.service<SearchEverywhereContributorCoroutineScopeHolder>().coroutineScope.launch {
withContext(Dispatchers.EDT) {
@Suppress("DEPRECATION")
if ((modifiers and InputEvent.SHIFT_MASK) != 0) {
openInRightSplit(project = myProject, file = file, element = descriptor, requestFocus = true)
}
else {
descriptor.navigate(true)
if (file.isValid) {
if (lineAndColumn.first == -1 && lineAndColumn.second == -1) {
myProject.service<SearchEverywhereContributorCoroutineScopeHolder>().coroutineScope.launch(ClientId.coroutineContext()) {
val navigationRequests = serviceAsync<NavigationRequests>()
readAction { navigationRequests.sourceNavigationRequest(myProject, file, -1, null) }?.let {
myProject.serviceAsync<NavigationService>().navigate(it)
}
}
if (lineAndColumn.first > 0) {
serviceAsync<FeatureUsageTracker>().triggerFeatureUsed("navigation.goto.file.line")
}
else {
val descriptor = OpenFileDescriptor(myProject, file, lineAndColumn.first, lineAndColumn.second)
myProject.service<SearchEverywhereContributorCoroutineScopeHolder>().coroutineScope.launch(ClientId.coroutineContext()) {
@Suppress("DEPRECATION")
if ((modifiers and InputEvent.SHIFT_MASK) != 0) {
withContext(Dispatchers.EDT) {
openInRightSplit(project = myProject, file = file, element = descriptor, requestFocus = true)
}
}
else {
myProject.serviceAsync<NavigationService>().navigate(descriptor)
}
if (lineAndColumn.first > 0) {
serviceAsync<FeatureUsageTracker>().triggerFeatureUsed("navigation.goto.file.line")
}
}
}
return true

View File

@@ -27,5 +27,5 @@ interface NavigationService {
suspend fun navigate(navigatables: List<Navigatable>, options: NavigationOptions): Boolean
@Internal // compatibility function
suspend fun navigate(navigatable: Navigatable, options: NavigationOptions): Boolean
suspend fun navigate(navigatable: Navigatable, options: NavigationOptions = NavigationOptions.defaultOptions()): Boolean
}

View File

@@ -76,7 +76,10 @@ data class EditorCompositeModel internal constructor(
// workaround for remote dev, where we cannot yet implement correctly
@Internal
class PrecomputedFlow(@JvmField val model: EditorCompositeModel) : Flow<EditorCompositeModel> {
class PrecomputedFlow(
@JvmField internal val model: EditorCompositeModel,
@JvmField internal val fireFileOpened: Boolean,
) : Flow<EditorCompositeModel> {
override suspend fun collect(collector: FlowCollector<EditorCompositeModel>) {
error("Must not be called")
}
@@ -135,7 +138,12 @@ open class EditorComposite internal constructor(
EDT.assertIsEdt()
if (model is PrecomputedFlow) {
blockingHandleModel(model.model)
if (model.fireFileOpened) {
blockingHandleModel(model.model)
}
else {
blockingHandleModel2(model.model)
}
}
else {
if (ApplicationManager.getApplication().isHeadlessEnvironment) {
@@ -277,18 +285,67 @@ open class EditorComposite internal constructor(
}
}
val states = oldBadForRemoteDevGetStates(fileEditorWithProviders = fileEditorWithProviders, state = model.state)
applyFileEditorsInEdt(fileEditorWithProviders = fileEditorWithProviders, selectedFileEditorProvider = null, states = states)
}
private fun oldBadForRemoteDevGetStates(
fileEditorWithProviders: List<FileEditorWithProvider>,
state: FileEntry?,
): List<FileEditorState?> {
val states = fileEditorWithProviders.map { (_, provider) ->
if (model.state == null) {
if (state == null) {
// We have to try to get state from the history only in case of the editor is not opened.
// Otherwise, history entry might have a state out of sync with the current editor state.
EditorHistoryManager.getInstance(project).getState(file, provider)
}
else {
model.state.providers.get(provider.editorTypeId)?.let { provider.readState(it, project, file) }
state.providers.get(provider.editorTypeId)?.let { provider.readState(it, project, file) }
}
}
return states
}
// for remote dev - we don't care about performance for now
@RequiresEdt
private fun blockingHandleModel2(model: EditorCompositeModel) {
val fileEditorWithProviders = model.fileEditorAndProviderList
for (editorWithProvider in fileEditorWithProviders) {
val editor = editorWithProvider.fileEditor
FileEditor.FILE_KEY.set(editor, file)
if (!clientId.isLocal) {
assignClientId(editor, clientId)
}
}
// TODO comment this and log a warning or log something
if (fileEditorWithProviders.isEmpty()) {
compositePanel.removeAll()
_selectedEditorWithProvider.value = null
return
}
val messageBus = project.messageBus
val deferredPublishers = messageBus.syncAndPreloadPublisher(FileOpenedSyncListener.TOPIC) to
messageBus.syncAndPreloadPublisher(FileEditorManagerListener.FILE_EDITOR_MANAGER)
val beforePublisher = project.messageBus.syncAndPreloadPublisher(FileEditorManagerListener.Before.FILE_EDITOR_MANAGER)
val fileEditorManager = FileEditorManager.getInstance(project)
beforePublisher!!.beforeFileOpened(fileEditorManager, file)
val states = oldBadForRemoteDevGetStates(fileEditorWithProviders = fileEditorWithProviders, state = model.state)
applyFileEditorsInEdt(fileEditorWithProviders = fileEditorWithProviders, selectedFileEditorProvider = null, states = states)
val (goodPublisher, deprecatedPublisher) = deferredPublishers
goodPublisher.fileOpenedSync(fileEditorManager, file, fileEditorWithProviders)
@Suppress("DEPRECATION")
deprecatedPublisher.fileOpenedSync(fileEditorManager, file, fileEditorWithProviders)
val publisher = project.messageBus.syncAndPreloadPublisher(FileEditorManagerListener.FILE_EDITOR_MANAGER)
publisher.fileOpened(fileEditorManager, file)
}
@RequiresEdt
@@ -930,7 +987,8 @@ internal fun focusEditorOnComposite(
splitters: EditorsSplitters,
toFront: Boolean = true,
): Boolean {
val currentSelectedComposite = splitters.currentCompositeFlow.value
val currentWindow = splitters.currentWindow
val currentSelectedComposite = currentWindow?.selectedComposite
// while the editor was loading, the user switched to another editor - don't steal focus
if (currentSelectedComposite === composite) {
val preferredFocusedComponent = composite.preferredFocusedComponent
@@ -939,10 +997,14 @@ internal fun focusEditorOnComposite(
return false
}
else {
preferredFocusedComponent.requestFocusInWindow()
if (toFront) {
IdeFocusManager.getGlobalInstance().toFront(splitters)
IdeFocusManager.getGlobalInstance().toFront(preferredFocusedComponent)
preferredFocusedComponent.requestFocus()
}
else {
preferredFocusedComponent.requestFocusInWindow()
}
return true
}
}

View File

@@ -150,9 +150,12 @@ internal class EditorCompositeModelManager(
fun blockingFileEditorWithProviderFlow(
editorsWithProviders: List<FileEditorWithProvider>,
): PrecomputedFlow {
): Flow<EditorCompositeModel> {
postProcessFileEditorWithProviderList(editorsWithProviders)
return PrecomputedFlow(EditorCompositeModel(fileEditorAndProviderList = editorsWithProviders, state = null))
return PrecomputedFlow(
model = EditorCompositeModel(fileEditorAndProviderList = editorsWithProviders, state = null),
fireFileOpened = true,
)
}
private fun postProcessFileEditorWithProviderList(editorsWithProviders: List<FileEditorWithProvider>) {

View File

@@ -3,6 +3,7 @@
package com.intellij.openapi.fileEditor.impl
import com.intellij.codeWithMe.ClientId
import com.intellij.featureStatistics.fusCollectors.FileEditorCollector
import com.intellij.featureStatistics.fusCollectors.FileEditorCollector.EmptyStateCause
import com.intellij.icons.AllIcons
@@ -396,7 +397,7 @@ class EditorWindow internal constructor(
owner.setCurrentWindow(window = this@EditorWindow)
}
composite.coroutineScope.launch(Dispatchers.EDT) {
composite.coroutineScope.launch(Dispatchers.EDT + ClientId.coroutineContext() + ModalityState.any().asContextElement()) {
if (!isHeadless) {
owner.setCurrentWindow(window = this@EditorWindow)
}

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// 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.openapi.wm.impl;
import com.intellij.concurrency.ContextAwareRunnable;