IJPL-166086 Implement PhysicalAndLogicalStructureViewBuilder.createStructureViewSuspend

To avoid executing slow ops in getLogicalStructureBuilder()
on the EDT, split the implementation into the BGT and EDT parts.
The old function remains the same, but the new suspend
one executes the slow part in a regular readAction,
and the UI part on the EDT under the WIL.


(cherry picked from commit f772898db79b87079d03ee404ea8152359ec79e9)

IJ-CR-149552

GitOrigin-RevId: ef76166383c63919ffab3d7b14e30b8a5ee61a0d
This commit is contained in:
Sergei Tachenov
2024-11-04 17:23:35 +02:00
committed by intellij-monorepo-bot
parent 66782f337c
commit 41677ecfc8
5 changed files with 51 additions and 9 deletions

View File

@@ -137,6 +137,8 @@ com.intellij.ide.structureView.StructureView
com.intellij.ide.structureView.StructureViewBuilder
- sf:PROVIDER:com.intellij.ide.structureView.StructureViewBuilderProvider
- a:createStructureView(com.intellij.openapi.fileEditor.FileEditor,com.intellij.openapi.project.Project):com.intellij.ide.structureView.StructureView
- createStructureViewSuspend(com.intellij.openapi.fileEditor.FileEditor,com.intellij.openapi.project.Project,kotlin.coroutines.Continuation):java.lang.Object
- bs:createStructureViewSuspend$suspendImpl(com.intellij.ide.structureView.StructureViewBuilder,com.intellij.openapi.fileEditor.FileEditor,com.intellij.openapi.project.Project,kotlin.coroutines.Continuation):java.lang.Object
- s:getProvider():com.intellij.ide.structureView.StructureViewBuilderProvider
com.intellij.ide.structureView.StructureViewBuilderProvider
- a:getStructureViewBuilder(com.intellij.openapi.fileTypes.FileType,com.intellij.openapi.vfs.VirtualFile,com.intellij.openapi.project.Project):com.intellij.ide.structureView.StructureViewBuilder

View File

@@ -1,12 +1,16 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.structureView
import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.writeIntentReadAction
import com.intellij.openapi.extensions.ExtensionPointName
import com.intellij.openapi.extensions.ExtensionPointName.Companion.create
import com.intellij.openapi.extensions.KeyedFactoryEPBean
import com.intellij.openapi.fileEditor.FileEditor
import com.intellij.openapi.fileTypes.FileTypeExtensionFactory
import com.intellij.openapi.project.Project
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.jetbrains.annotations.ApiStatus
/**
@@ -32,6 +36,22 @@ interface StructureViewBuilder {
*/
fun createStructureView(fileEditor: FileEditor?, project: Project): StructureView
/**
* Returns the structure view implementation for the specified file
*
* A coroutine-friendly version of [createStructureView].
* The default implementation just invokes [createStructureView]
* under the write intent lock on the EDT.
* Implementations may choose to override it if they have slow ops that need to be performed on a BGT.
*/
suspend fun createStructureViewSuspend(fileEditor: FileEditor?, project: Project): StructureView {
return withContext(Dispatchers.EDT) {
writeIntentReadAction {
createStructureView(fileEditor, project)
}
}
}
@ApiStatus.Internal
companion object {
@ApiStatus.Internal

View File

@@ -416,9 +416,9 @@ class StructureViewWrapperImpl(
val structureViewBuilder = if (editor != null && editor.isValid)
readAction { editor.structureViewBuilder } else createStructureViewBuilder(file)
if (structureViewBuilder != null) {
val structureView = structureViewBuilder.createStructureViewSuspend(editor, project)
withContext(Dispatchers.EDT) {
writeIntentReadAction {
val structureView = structureViewBuilder.createStructureView(editor, project)
myStructureView = structureView
myFileEditor = editor

View File

@@ -73,6 +73,7 @@ f:com.intellij.ide.structureView.logical.PhysicalAndLogicalStructureViewBuilder
- f:createPhysicalStructureView(com.intellij.openapi.fileEditor.FileEditor,com.intellij.openapi.project.Project):com.intellij.ide.structureView.StructureView
- createStructureView(com.intellij.openapi.fileEditor.FileEditor,com.intellij.openapi.project.Project):com.intellij.ide.structureView.StructureView
- createStructureViewModel(com.intellij.openapi.editor.Editor):com.intellij.ide.structureView.StructureViewModel
- createStructureViewSuspend(com.intellij.openapi.fileEditor.FileEditor,com.intellij.openapi.project.Project,kotlin.coroutines.Continuation):java.lang.Object
com.intellij.ide.structureView.logical.PropertyElementProvider
- com.intellij.ide.structureView.logical.LogicalStructureElementsProvider
- a:getPropertyName():java.lang.String

View File

@@ -1,26 +1,45 @@
// 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.structureView.logical
import com.intellij.ide.structureView.StructureView
import com.intellij.ide.structureView.StructureViewBundle
import com.intellij.ide.structureView.StructureViewModel
import com.intellij.ide.structureView.TreeBasedStructureViewBuilder
import com.intellij.ide.structureView.*
import com.intellij.ide.structureView.impl.StructureViewComposite
import com.intellij.ide.structureView.logical.impl.LogicalStructureViewService.Companion.getInstance
import com.intellij.openapi.application.EDT
import com.intellij.openapi.application.readAction
import com.intellij.openapi.application.writeIntentReadAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.fileEditor.FileEditor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
class PhysicalAndLogicalStructureViewBuilder(
private val physicalBuilder: TreeBasedStructureViewBuilder,
psiFile: PsiFile,
private val psiFile: PsiFile,
): TreeBasedStructureViewBuilder() {
// Builders are created on a BGT, but createStructureView() is called on the EDT.
// Therefore, all slow ops must be in the constructor, and all UI creation must be in that method.
private val logicalBuilder = getInstance(psiFile.project).getLogicalStructureBuilder(psiFile)
override fun createStructureView(fileEditor: FileEditor?, project: Project): StructureView {
val logicalBuilder = getInstance(psiFile.project).getLogicalStructureBuilder(psiFile)
return createStructureView(logicalBuilder, fileEditor, project)
}
override suspend fun createStructureViewSuspend(fileEditor: FileEditor?, project: Project): StructureView {
val logicalBuilder = readAction {
getInstance(psiFile.project).getLogicalStructureBuilder(psiFile)
}
return withContext(Dispatchers.EDT) {
writeIntentReadAction {
createStructureView(logicalBuilder, fileEditor, project)
}
}
}
private fun createStructureView(
logicalBuilder: StructureViewBuilder?,
fileEditor: FileEditor?,
project: Project,
): StructureView {
if (logicalBuilder == null) return createPhysicalStructureView(fileEditor, project)
return StructureViewComposite(