diff --git a/platform/editor-ui-api/api-dump.txt b/platform/editor-ui-api/api-dump.txt index 9f9df5fbc64a..ea09af9ef1d7 100644 --- a/platform/editor-ui-api/api-dump.txt +++ b/platform/editor-ui-api/api-dump.txt @@ -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 diff --git a/platform/editor-ui-api/src/com/intellij/ide/structureView/StructureViewBuilder.kt b/platform/editor-ui-api/src/com/intellij/ide/structureView/StructureViewBuilder.kt index e53a6ff91f9e..46cf69a11ced 100644 --- a/platform/editor-ui-api/src/com/intellij/ide/structureView/StructureViewBuilder.kt +++ b/platform/editor-ui-api/src/com/intellij/ide/structureView/StructureViewBuilder.kt @@ -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 diff --git a/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.kt b/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.kt index 1b2291b98bed..9c5784a67ae7 100644 --- a/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.kt +++ b/platform/lang-impl/src/com/intellij/ide/impl/StructureViewWrapperImpl.kt @@ -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 diff --git a/platform/structure-view-impl/api-dump.txt b/platform/structure-view-impl/api-dump.txt index 03a0bf644b4c..530e42644d1d 100644 --- a/platform/structure-view-impl/api-dump.txt +++ b/platform/structure-view-impl/api-dump.txt @@ -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 diff --git a/platform/structure-view-impl/src/com/intellij/ide/structureView/logical/PhysicalAndLogicalStructureViewBuilder.kt b/platform/structure-view-impl/src/com/intellij/ide/structureView/logical/PhysicalAndLogicalStructureViewBuilder.kt index abcec02a3263..2f4ed4faacd8 100644 --- a/platform/structure-view-impl/src/com/intellij/ide/structureView/logical/PhysicalAndLogicalStructureViewBuilder.kt +++ b/platform/structure-view-impl/src/com/intellij/ide/structureView/logical/PhysicalAndLogicalStructureViewBuilder.kt @@ -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(