User: joe Date: 19 Dec 25 20:44 Revision: 8fca69df70547585af51b90ab43d4287818745b0 Summary: Revert some slow operations fixes in new project creator. Closes #2550 TeamCity URL: http://ci.mcdev.io:80/viewModification.html?tab=vcsModificationFiles&modId=10349&personal=false Index: src/main/kotlin/creator/JdkComboBoxWithPreference.kt =================================================================== --- src/main/kotlin/creator/JdkComboBoxWithPreference.kt (revision b7eca0096d0cf6714a392979a5e648d9d88e36bc) +++ src/main/kotlin/creator/JdkComboBoxWithPreference.kt (revision 8fca69df70547585af51b90ab43d4287818745b0) @@ -20,7 +20,6 @@ package com.demonwav.mcdev.creator -import com.demonwav.mcdev.util.invokeLater import com.intellij.ide.util.PropertiesComponent import com.intellij.ide.util.projectWizard.ProjectWizardUtil import com.intellij.ide.util.projectWizard.WizardContext @@ -43,7 +42,6 @@ import com.intellij.ui.dsl.builder.Cell import com.intellij.ui.dsl.builder.Row import javax.swing.JComponent -import org.jetbrains.concurrency.runAsync internal class JdkPreferenceData( var jdk: JavaSdkVersion, @@ -91,17 +89,15 @@ preferenceData.jdk = version reloadModel() - for (jdkVersion in version.ordinal until JavaSdkVersion.entries.size) { - val jdk = JavaSdkVersion.entries[jdkVersion] + for (jdkVersion in version.ordinal until JavaSdkVersion.values().size) { + val jdk = JavaSdkVersion.values()[jdkVersion] val preferredSdkPath = preferenceData.sdkPathByJdk[jdk] if (preferredSdkPath != null) { val sdk = model.sdks.firstOrNull { it.homePath == preferredSdkPath } ?: suggestions.firstOrNull { it.homePath == preferredSdkPath } if (sdk != null) { - runAsync { - setSelectedItem(sdk) + setSelectedItem(sdk) - } return } } @@ -149,7 +145,7 @@ for (preferenceDataStr in preferenceDataStrs) { val parts = preferenceDataStr.split('=', limit = 2) val featureVersion = parts.firstOrNull()?.toIntOrNull() ?: continue - val knownJdkVersions = JavaSdkVersion.entries + val knownJdkVersions = JavaSdkVersion.values() if (featureVersion !in knownJdkVersions.indices) { continue } @@ -180,9 +176,7 @@ } val lastUsedSdk = stateComponent.getValue(selectedJdkProperty) - runAsync { - ProjectWizardUtil.preselectJdkForNewModule(project, lastUsedSdk, comboBox) { true } + ProjectWizardUtil.preselectJdkForNewModule(project, lastUsedSdk, comboBox) { true } - } val windowChild = context.getUserData(AbstractWizard.KEY)!!.contentPanel comboBox.loadSuggestions(windowChild, context.disposable) Index: src/main/kotlin/creator/custom/CreatorTemplateProcessor.kt =================================================================== --- src/main/kotlin/creator/custom/CreatorTemplateProcessor.kt (revision b7eca0096d0cf6714a392979a5e648d9d88e36bc) +++ src/main/kotlin/creator/custom/CreatorTemplateProcessor.kt (revision 8fca69df70547585af51b90ab43d4287818745b0) @@ -34,7 +34,6 @@ import com.intellij.ide.projectView.ProjectView import com.intellij.ide.util.projectWizard.WizardContext import com.intellij.openapi.application.WriteAction -import com.intellij.openapi.concurrency.awaitPromise import com.intellij.openapi.diagnostic.Attachment import com.intellij.openapi.diagnostic.ControlFlowException import com.intellij.openapi.diagnostic.thisLogger @@ -54,15 +53,11 @@ import com.intellij.ui.dsl.builder.panel import com.intellij.util.application import java.nio.file.Path -import java.time.Duration -import java.util.concurrent.TimeUnit import java.util.function.Consumer import kotlin.io.path.createDirectories import kotlin.io.path.writeText import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch -import org.jetbrains.concurrency.await -import org.jetbrains.concurrency.runAsync interface ExternalTemplatePropertyProvider { @@ -273,11 +268,7 @@ destPath.parent.createDirectories() destPath.writeText(processedContent) - val virtualFile = runCatching { - runAsync { - destPath.refreshAndFindVirtualFile() - }.blockingGet(20, TimeUnit.MILLISECONDS) - }.getOrNull() + val virtualFile = destPath.refreshAndFindVirtualFile() if (virtualFile != null) { generatedFiles.add(file to virtualFile) } else { Index: src/main/kotlin/creator/custom/CustomPlatformStep.kt =================================================================== --- src/main/kotlin/creator/custom/CustomPlatformStep.kt (revision b7eca0096d0cf6714a392979a5e648d9d88e36bc) +++ src/main/kotlin/creator/custom/CustomPlatformStep.kt (revision 8fca69df70547585af51b90ab43d4287818745b0) @@ -27,18 +27,12 @@ import com.demonwav.mcdev.creator.custom.providers.TemplateProvider import com.demonwav.mcdev.creator.modalityState import com.demonwav.mcdev.util.getOrLogException -import com.demonwav.mcdev.util.invokeAndWait -import com.demonwav.mcdev.util.runWriteTask -import com.demonwav.mcdev.util.tryWriteSafeContext import com.intellij.ide.wizard.AbstractNewProjectWizardStep import com.intellij.ide.wizard.GitNewProjectWizardData import com.intellij.ide.wizard.NewProjectWizardBaseData import com.intellij.ide.wizard.NewProjectWizardStep import com.intellij.openapi.application.EDT -import com.intellij.openapi.application.ModalityState -import com.intellij.openapi.application.TransactionGuard import com.intellij.openapi.application.asContextElement -import com.intellij.openapi.application.impl.ModalityStateEx import com.intellij.openapi.application.runWriteAction import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.observable.properties.GraphProperty @@ -57,12 +51,10 @@ import com.intellij.util.application import com.intellij.util.ui.AsyncProcessIcon import javax.swing.JLabel -import javax.swing.SwingUtilities import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.cancel import kotlinx.coroutines.launch -import org.jetbrains.kotlin.descriptors.Modality /** * The step to select a custom template repo. @@ -75,7 +67,7 @@ val creatorUiScope = TemplateService.instance.scope("MinecraftDev Creator UI") val templateRepos = MinecraftSettings.instance.creatorTemplateRepos - val templateRepoProperty = propertyGraph.property( + val templateRepoProperty = propertyGraph.property( templateRepos.firstOrNull() ?: MinecraftSettings.TemplateRepo.makeBuiltinRepo() ) var templateRepo by templateRepoProperty @@ -87,19 +79,19 @@ lateinit var availableGroupsSegmentedButton: SegmentedButton lateinit var availableTemplatesSegmentedButton: SegmentedButton - val selectedGroupProperty = propertyGraph.property("") + val selectedGroupProperty = propertyGraph.property("") var selectedGroup by selectedGroupProperty val selectedTemplateProperty = propertyGraph.property(EmptyLoadedTemplate) var selectedTemplate by selectedTemplateProperty - val templateProvidersLoadingProperty = propertyGraph.property(true) + val templateProvidersLoadingProperty = propertyGraph.property(true) val templateProvidersTextProperty = propertyGraph.property("") val templateProvidersText2Property = propertyGraph.property("") lateinit var templateProvidersProcessIcon: Cell - val templateLoadingProperty = propertyGraph.property(false) - val templateLoadingTextProperty = propertyGraph.property("") - val templateLoadingText2Property = propertyGraph.property("") + val templateLoadingProperty = propertyGraph.property(false) + val templateLoadingTextProperty = propertyGraph.property("") + val templateLoadingText2Property = propertyGraph.property("") lateinit var templatePropertiesProcessIcon: Cell lateinit var noTemplatesAvailable: Cell var templateLoadingJob: Job? = null @@ -256,9 +248,11 @@ templateLoadingTextProperty.set(MCDevBundle("creator.step.generic.load_template.message")) templateLoadingProperty.set(true) - tryWriteSafeContext(context.modalityState) { - VirtualFileManager.getInstance().syncRefresh() - } + // For some reason syncRefresh doesn't play nice with writeAction() coroutines so we do it beforehand + application.invokeAndWait( + { runWriteAction { VirtualFileManager.getInstance().syncRefresh() } }, + context.modalityState + ) val dialogCoroutineContext = context.modalityState.asContextElement() val uiContext = dialogCoroutineContext + Dispatchers.EDT Index: src/main/kotlin/creator/custom/providers/BuiltinTemplateProvider.kt =================================================================== --- src/main/kotlin/creator/custom/providers/BuiltinTemplateProvider.kt (revision b7eca0096d0cf6714a392979a5e648d9d88e36bc) +++ src/main/kotlin/creator/custom/providers/BuiltinTemplateProvider.kt (revision 8fca69df70547585af51b90ab43d4287818745b0) @@ -33,8 +33,6 @@ import com.intellij.ui.dsl.builder.bindSelected import com.intellij.ui.dsl.builder.panel import javax.swing.JComponent -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext class BuiltinTemplateProvider : RemoteTemplateProvider() { @@ -61,16 +59,16 @@ override suspend fun loadTemplates( context: WizardContext, repo: MinecraftSettings.TemplateRepo - ): Collection = withContext(Dispatchers.IO) { + ): Collection { val remoteTemplates = doLoadTemplates(context, repo, builtinTemplatesInnerPath) if (remoteTemplates.isNotEmpty()) { - return@withContext remoteTemplates + return remoteTemplates } val repoRoot = builtinTemplatesPath.virtualFile - ?: return@withContext emptyList() + ?: return emptyList() repoRoot.refreshSync(context.modalityState) - TemplateProvider.findTemplates(context.modalityState, repoRoot) + return TemplateProvider.findTemplates(context.modalityState, repoRoot) } override fun setupConfigUi( Index: src/main/kotlin/creator/custom/providers/LocalTemplateProvider.kt =================================================================== --- src/main/kotlin/creator/custom/providers/LocalTemplateProvider.kt (revision b7eca0096d0cf6714a392979a5e648d9d88e36bc) +++ src/main/kotlin/creator/custom/providers/LocalTemplateProvider.kt (revision 8fca69df70547585af51b90ab43d4287818745b0) @@ -39,8 +39,6 @@ import java.nio.file.Path import javax.swing.JComponent import kotlin.io.path.absolute -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext class LocalTemplateProvider : TemplateProvider { @@ -51,13 +49,13 @@ override suspend fun loadTemplates( context: WizardContext, repo: MinecraftSettings.TemplateRepo - ): Collection = withContext(Dispatchers.IO) { + ): Collection { val rootPath = Path.of(repo.data.trim()).absolute() val repoRoot = rootPath.virtualFile - ?: return@withContext emptyList() + ?: return emptyList() val modalityState = context.modalityState repoRoot.refreshSync(modalityState) - TemplateProvider.findTemplates(modalityState, repoRoot) + return TemplateProvider.findTemplates(modalityState, repoRoot) } override fun setupConfigUi( Index: src/main/kotlin/creator/custom/providers/RemoteTemplateProvider.kt =================================================================== --- src/main/kotlin/creator/custom/providers/RemoteTemplateProvider.kt (revision b7eca0096d0cf6714a392979a5e648d9d88e36bc) +++ src/main/kotlin/creator/custom/providers/RemoteTemplateProvider.kt (revision 8fca69df70547585af51b90ab43d4287818745b0) @@ -67,8 +67,6 @@ import kotlin.io.path.absolutePathString import kotlin.io.path.exists import kotlin.io.path.writeBytes -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext open class RemoteTemplateProvider : TemplateProvider { @@ -150,20 +148,18 @@ context: WizardContext, repo: MinecraftSettings.TemplateRepo, rawInnerPath: String - ): List = withContext(Dispatchers.IO) { // don't run on EDT + ): List { val remoteRootPath = RemoteTemplateRepo.getDestinationZip(repo.name) if (!remoteRootPath.exists()) { - return@withContext emptyList() + return emptyList() } val archiveRoot = remoteRootPath.absolutePathString() + JarFileSystem.JAR_SEPARATOR val fs = JarFileSystem.getInstance() - val rootFile = fs.refreshAndFindFileByPath(archiveRoot) - ?: return@withContext emptyList() + ?: return emptyList() val modalityState = context.modalityState - rootFile.refreshSync(modalityState) val innerPath = replaceVariables(rawInnerPath) @@ -174,10 +170,10 @@ } if (repoRoot == null) { - return@withContext emptyList() + return emptyList() } - return@withContext TemplateProvider.findTemplates(modalityState, repoRoot) + return TemplateProvider.findTemplates(modalityState, repoRoot) } private fun replaceVariables(originalRepoUrl: String): String = @@ -271,7 +267,7 @@ index: Int, isSelected: Boolean, cellHasFocus: Boolean - ): Component { + ): Component? { text = value?.displayname?.let(MCDevBundle::invoke) ?: value?.name?.capitalize().toString() return this } Index: src/main/kotlin/creator/custom/providers/TemplateProvider.kt =================================================================== --- src/main/kotlin/creator/custom/providers/TemplateProvider.kt (revision b7eca0096d0cf6714a392979a5e648d9d88e36bc) +++ src/main/kotlin/creator/custom/providers/TemplateProvider.kt (revision 8fca69df70547585af51b90ab43d4287818745b0) @@ -45,11 +45,9 @@ import com.intellij.util.KeyedLazyInstance import com.intellij.util.xmlb.annotations.Attribute import java.util.ResourceBundle -import java.util.concurrent.TimeUnit import javax.swing.JComponent import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import org.jetbrains.concurrency.runAsync +import kotlinx.coroutines.runBlocking /** * Extensions responsible for creating a [TemplateDescriptor] based on whatever data it is provided in its configuration @@ -81,8 +79,9 @@ modalityState: ModalityState, repoRoot: VirtualFile, templates: MutableList = mutableListOf(), - bundle: ResourceBundle? = loadMessagesBundle(modalityState, repoRoot) - ): List = withContext(Dispatchers.IO) { + bundle: ResourceBundle? = null + ): List { + val bundle = bundle ?: loadMessagesBundle(modalityState, repoRoot) val templatesToLoad = mutableListOf() val visitor = object : VirtualFileVisitor() { override fun visitFile(file: VirtualFile): Boolean { @@ -115,10 +114,10 @@ } } - templates + return templates } - fun loadMessagesBundle(modalityState: ModalityState, repoRoot: VirtualFile): ResourceBundle? = try { + suspend fun loadMessagesBundle(modalityState: ModalityState, repoRoot: VirtualFile): ResourceBundle? = try { val locale = DynamicBundle.getLocale() // Simplified bundle resolution, but covers all the most common cases val baseBundle = doLoadMessageBundle( @@ -145,7 +144,7 @@ null } - private fun doLoadMessageBundle( + private suspend fun doLoadMessageBundle( file: VirtualFile?, modalityState: ModalityState, parent: ResourceBundle? @@ -155,9 +154,8 @@ } try { - return runAsync { - file.inputStream.reader().use { TemplateResourceBundle(it, parent) } - }.blockingGet(20, TimeUnit.MILLISECONDS) + return file.refreshSync(modalityState) + ?.inputStream?.reader()?.use { TemplateResourceBundle(it, parent) } } catch (t: Throwable) { if (t is ControlFlowException) { return parent @@ -169,19 +167,15 @@ return parent } - fun createVfsLoadedTemplate( + suspend fun createVfsLoadedTemplate( modalityState: ModalityState, templateRoot: VirtualFile, descriptorFile: VirtualFile, tooltip: String? = null, bundle: ResourceBundle? = null ): VfsLoadedTemplate? { - var descriptor = runCatching { - runAsync { - descriptorFile.refreshSync(modalityState) + descriptorFile.refreshSync(modalityState) - Gson().fromJson(descriptorFile.readText()) - }.blockingGet(100, TimeUnit.MILLISECONDS) - }.getOrNull() ?: return null + var descriptor = Gson().fromJson(descriptorFile.readText()) if (descriptor.version != TemplateDescriptor.FORMAT_VERSION) { thisLogger().warn("Cannot handle template ${descriptorFile.path} of version ${descriptor.version}") return null @@ -200,7 +194,7 @@ descriptor.translateOrNull("platform.${labelKey.lowercase()}.label") ?: descriptor.translate(labelKey) if (descriptor.inherit != null) { - val parent = templateRoot.findFileByRelativePath(descriptor.inherit) + val parent = templateRoot.findFileByRelativePath(descriptor.inherit!!) if (parent != null) { parent.refresh(false, false) val parentDescriptor = Gson().fromJson(parent.readText()) @@ -237,5 +231,5 @@ override fun getKey(): String = name - override fun getImplementationClassName(): String = implementation + override fun getImplementationClassName(): String? = implementation } Index: src/main/kotlin/creator/custom/providers/ZipTemplateProvider.kt =================================================================== --- src/main/kotlin/creator/custom/providers/ZipTemplateProvider.kt (revision b7eca0096d0cf6714a392979a5e648d9d88e36bc) +++ src/main/kotlin/creator/custom/providers/ZipTemplateProvider.kt (revision 8fca69df70547585af51b90ab43d4287818745b0) @@ -38,8 +38,6 @@ import java.nio.file.Path import javax.swing.JComponent import kotlin.io.path.isRegularFile -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext class ZipTemplateProvider : TemplateProvider { @@ -50,14 +48,14 @@ override suspend fun loadTemplates( context: WizardContext, repo: MinecraftSettings.TemplateRepo - ): Collection = withContext(Dispatchers.IO) { + ): Collection { val archiveRoot = repo.data + JarFileSystem.JAR_SEPARATOR val fs = JarFileSystem.getInstance() val rootFile = fs.refreshAndFindFileByPath(archiveRoot) - ?: return@withContext emptyList() + ?: return emptyList() val modalityState = context.modalityState rootFile.refreshSync(modalityState) - TemplateProvider.findTemplates(modalityState, rootFile) + return TemplateProvider.findTemplates(modalityState, rootFile) } override fun setupConfigUi( Index: src/main/kotlin/update/PluginUpdater.kt =================================================================== --- src/main/kotlin/update/PluginUpdater.kt (revision b7eca0096d0cf6714a392979a5e648d9d88e36bc) +++ src/main/kotlin/update/PluginUpdater.kt (revision 8fca69df70547585af51b90ab43d4287818745b0) @@ -58,7 +58,7 @@ .forEachNotNull { updateStatus = updateStatus.mergeWith(checkUpdatesInCustomRepo(it)) } val finalUpdate = updateStatus - invokeLater(ModalityState.any()) { callback(finalUpdate) } + ApplicationManager.getApplication().invokeLater({ callback(finalUpdate) }, ModalityState.any()) } catch (e: Exception) { PluginUpdateStatus.CheckFailed("Minecraft Development plugin update check failed") } Index: src/main/kotlin/util/files.kt =================================================================== --- src/main/kotlin/util/files.kt (revision b7eca0096d0cf6714a392979a5e648d9d88e36bc) +++ src/main/kotlin/util/files.kt (revision 8fca69df70547585af51b90ab43d4287818745b0) @@ -20,20 +20,19 @@ package com.demonwav.mcdev.util +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ModalityState -import com.intellij.openapi.application.TransactionGuard +import com.intellij.openapi.application.writeAction import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.newvfs.RefreshQueue -import com.intellij.util.application import java.io.File import java.io.IOException import java.nio.file.Path import java.util.jar.Attributes import java.util.jar.JarFile import java.util.jar.Manifest -import javax.swing.SwingUtilities val VirtualFile.localFile: File get() = VfsUtilCore.virtualToIoFile(this) @@ -80,10 +79,18 @@ operator fun Manifest.get(attribute: String): String? = mainAttributes.getValue(attribute) operator fun Manifest.get(attribute: Attributes.Name): String? = mainAttributes.getValue(attribute) -fun VirtualFile.refreshSync(modalityState: ModalityState): VirtualFile? { - tryWriteSafeContext(modalityState) { +suspend fun VirtualFile.refreshSync(modalityState: ModalityState): VirtualFile? { + fun refresh() { RefreshQueue.getInstance().refresh(false, this.isDirectory, null, modalityState, this) } + if (ApplicationManager.getApplication().isWriteAccessAllowed) { + refresh() + } else { + writeAction { + refresh() + } + } + return this.parent?.findOrCreateChildData(this, this.name) } Index: src/main/kotlin/util/utils.kt =================================================================== --- src/main/kotlin/util/utils.kt (revision b7eca0096d0cf6714a392979a5e648d9d88e36bc) +++ src/main/kotlin/util/utils.kt (revision 8fca69df70547585af51b90ab43d4287818745b0) @@ -25,7 +25,6 @@ import com.intellij.codeInspection.InspectionProfileEntry import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ModalityState -import com.intellij.openapi.application.TransactionGuard import com.intellij.openapi.application.WriteAction import com.intellij.openapi.application.runReadAction import com.intellij.openapi.command.WriteCommandAction @@ -33,7 +32,6 @@ import com.intellij.openapi.module.Module import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.progress.ProcessCanceledException -import com.intellij.openapi.progress.blockingContext import com.intellij.openapi.project.DumbService import com.intellij.openapi.project.Project import com.intellij.openapi.project.ProjectManager @@ -52,22 +50,20 @@ import java.lang.invoke.MethodHandles import java.util.Locale import java.util.concurrent.CancellationException -import javax.swing.SwingUtilities import kotlin.math.min import kotlin.reflect.KClass -import kotlinx.coroutines.CoroutineScope import org.jetbrains.annotations.NonNls import org.jetbrains.concurrency.Promise import org.jetbrains.concurrency.runAsync -inline fun runWriteTask(modalityState: ModalityState = ModalityState.defaultModalityState(), crossinline func: () -> T): T { - return invokeAndWait(modalityState) { +inline fun runWriteTask(crossinline func: () -> T): T { + return invokeAndWait { ApplicationManager.getApplication().runWriteAction(Computable { func() }) } } -fun runWriteTaskLater(modalityState: ModalityState = ModalityState.defaultModalityState(), func: () -> Unit) { - invokeLater(modalityState) { +fun runWriteTaskLater(func: () -> Unit) { + invokeLater { ApplicationManager.getApplication().runWriteAction(func) } } @@ -93,44 +89,27 @@ dumbService.runWhenSmart(runnable) } -fun invokeAndWait(modalityState: ModalityState = ModalityState.defaultModalityState(), func: () -> T): T { +fun invokeAndWait(func: () -> T): T { val ref = Ref() - ApplicationManager.getApplication().invokeAndWait({ ref.set(func()) }, modalityState) + ApplicationManager.getApplication().invokeAndWait({ ref.set(func()) }, ModalityState.defaultModalityState()) return ref.get() } -fun invokeLater(modalityState: ModalityState = ModalityState.defaultModalityState(), func: () -> Unit) { - ApplicationManager.getApplication().invokeLater(func, modalityState) +fun invokeLater(func: () -> Unit) { + ApplicationManager.getApplication().invokeLater(func, ModalityState.defaultModalityState()) } -fun invokeLater(expired: Condition<*>, modalityState: ModalityState = ModalityState.defaultModalityState(), func: () -> Unit) { - ApplicationManager.getApplication().invokeLater(func, modalityState, expired) +fun invokeLater(expired: Condition<*>, func: () -> Unit) { + ApplicationManager.getApplication().invokeLater(func, ModalityState.defaultModalityState(), expired) } -inline fun runWriteActionAndWait(modalityState: ModalityState = ModalityState.defaultModalityState(), crossinline action: () -> T): T { - return WriteAction.computeAndWait(ThrowableComputable { action() }, modalityState) +fun invokeLaterAny(func: () -> Unit) { + ApplicationManager.getApplication().invokeLater(func, ModalityState.any()) } -// Best effort to get into a context where writing is considered safe, if not possible then `func` will never run. -fun tryWriteSafeContext(modalityState: ModalityState = ModalityState.defaultModalityState(), func: () -> Unit) { - val guard = TransactionGuard.getInstance() - val state = if (guard.isWriteSafeModality(modalityState)) { - modalityState - } else { - ModalityState.nonModal() +inline fun runWriteActionAndWait(crossinline action: () -> T): T { + return WriteAction.computeAndWait(ThrowableComputable { action() }) - } +} - if (SwingUtilities.isEventDispatchThread()) { - if (guard.isWritingAllowed) { - func() - } - } else { - invokeAndWait(state) { - if (guard.isWritingAllowed) { - func() - } - } - } -} inline fun PsiFile.runWriteAction(crossinline func: () -> T) = applyWriteAction { func() }