From 3fe96a0da0ea391506b1f7d3231bf38f50ff0ca1 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Thu, 25 Oct 2018 11:17:42 +0200 Subject: [PATCH] extract SchemeLoader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. initScheme removed because the only usage in our code was incorrect — TemplateSettings in any case calls the same code after load: for (TemplateGroup group : groups) { for (TemplateImpl template : group.getElements()) { addTemplateImpl(template); } } initScheme is overriden in QAPlug, but it is dummy override in scheme processor, so, decided to break it (doesn't lead to runtime exception) 2. Still, schemeManager.schemeToInfo is modified directly (alongside other issues that are the reasons why this refactoring is made), but it will be addressed in separate commit to reduce complexity of this one 3. Potential issues with direct modification of filesToDelete is fixed. --- .../src/StoreAwareProjectManager.kt | 9 +- .../src/schemeManager/SchemeFileTracker.kt | 70 ++++---- .../src/schemeManager/SchemeManagerBase.kt | 4 +- .../src/schemeManager/SchemeManagerImpl.kt | 149 +++------------- .../src/schemeManager/schemeLoader.kt | 163 ++++++++++++++++++ .../template/impl/TemplateSettings.java | 21 +-- .../com/intellij/openapi/options/scheme.kt | 3 - 7 files changed, 237 insertions(+), 182 deletions(-) diff --git a/platform/configuration-store-impl/src/StoreAwareProjectManager.kt b/platform/configuration-store-impl/src/StoreAwareProjectManager.kt index 97b57a072e68..4b4ada1b84b7 100644 --- a/platform/configuration-store-impl/src/StoreAwareProjectManager.kt +++ b/platform/configuration-store-impl/src/StoreAwareProjectManager.kt @@ -3,6 +3,7 @@ package com.intellij.configurationStore import com.intellij.configurationStore.schemeManager.SchemeChangeEvent import com.intellij.configurationStore.schemeManager.SchemeFileTracker +import com.intellij.configurationStore.schemeManager.useSchemeLoader import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationNamesInfo import com.intellij.openapi.application.ModalityState @@ -71,9 +72,11 @@ class StoreAwareProjectManager(virtualFileManager: VirtualFileManager, progressM runBatchUpdate(project.messageBus) { // reload schemes first because project file can refer to scheme (e.g. inspection profile) if (changedSchemes != null) { - for ((tracker, files) in changedSchemes.entrySet()) { - LOG.runAndLogException { - tracker.reload(files) + useSchemeLoader { schemeLoaderRef -> + for ((tracker, files) in changedSchemes.entrySet()) { + LOG.runAndLogException { + tracker.reload(files, schemeLoaderRef) + } } } } diff --git a/platform/configuration-store-impl/src/schemeManager/SchemeFileTracker.kt b/platform/configuration-store-impl/src/schemeManager/SchemeFileTracker.kt index aa2851a6e7bf..2e01d55ab052 100644 --- a/platform/configuration-store-impl/src/schemeManager/SchemeFileTracker.kt +++ b/platform/configuration-store-impl/src/schemeManager/SchemeFileTracker.kt @@ -7,6 +7,7 @@ import com.intellij.configurationStore.SchemeContentChangedHandler import com.intellij.configurationStore.StoreAwareProjectManager import com.intellij.openapi.project.Project import com.intellij.openapi.project.ProjectManager +import com.intellij.openapi.util.Ref import com.intellij.openapi.util.io.FileUtilRt import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.newvfs.BulkFileListener @@ -14,12 +15,11 @@ import com.intellij.openapi.vfs.newvfs.events.VFileContentChangeEvent import com.intellij.openapi.vfs.newvfs.events.VFileCreateEvent import com.intellij.openapi.vfs.newvfs.events.VFileDeleteEvent import com.intellij.openapi.vfs.newvfs.events.VFileEvent -import com.intellij.util.SmartList import com.intellij.util.io.systemIndependentPath import java.util.function.Function internal interface SchemeChangeEvent { - fun SchemeFileTracker.execute() + fun SchemeFileTracker.execute(schemaLoader: Lazy>) } internal class SchemeFileTracker(private val schemeManager: SchemeManagerImpl, private val project: Project?) : BulkFileListener { @@ -33,14 +33,14 @@ internal class SchemeFileTracker(private val schemeManager: SchemeManagerImpl>) { schemeManager.cachedVirtualDirectory = null schemeManager.removeExternalizableSchemes() } } private data class RemoveScheme(private val fileName: String) : SchemeChangeEvent { - override fun SchemeFileTracker.execute() { + override fun SchemeFileTracker.execute(schemaLoader: Lazy>) { val scheme = findExternalizableSchemeByFileName(fileName) if (scheme != null) { schemeManager.removeScheme(scheme) @@ -50,39 +50,50 @@ internal class SchemeFileTracker(private val schemeManager: SchemeManagerImpl>) { if (file.isValid) { - schemeCreatedExternally(file) + schemeCreatedExternally(file, schemaLoader.value) } } } private data class UpdateScheme(val file: VirtualFile) : SchemeChangeEvent { - override fun SchemeFileTracker.execute() { + override fun SchemeFileTracker.execute(schemaLoader: Lazy>) { } } - private fun readSchemeFromFile(file: VirtualFile, schemes: MutableList): Any? { + private fun readSchemeFromFile(file: VirtualFile, schemeLoader: SchemeLoader): Any? { val fileName = file.name if (file.isDirectory || !schemeManager.canRead(fileName)) { return null } catchAndLog(fileName) { - return file.inputStream.use { schemeManager.loadScheme(fileName, it, schemes) } + return file.inputStream.use { + schemeLoader.loadScheme(fileName, it) + } } return null } - internal fun reload(events: Collection) { + internal fun reload(events: Collection, schemaLoaderRef: Ref>) { val oldActiveScheme = schemeManager.activeScheme var newActiveScheme: Any? = null + val lazySchemaLoader = lazy { + var result = schemaLoaderRef.get() + if (result == null) { + result = schemeManager.createSchemeLoader() + schemaLoaderRef.set(result) + } + result + } + val processor = schemeManager.processor for (event in events) { event.apply { - execute() + execute(lazySchemaLoader) } if (event !is UpdateScheme) { @@ -106,12 +117,7 @@ internal class SchemeFileTracker(private val schemeManager: SchemeManagerImpl() - val readScheme = readSchemeFromFile(file, newSchemes) - if (readScheme != null) { - val readSchemeKey = schemeManager.processor.getSchemeKey(readScheme) - val existingScheme = schemeManager.findSchemeByName(readSchemeKey) - @Suppress("SuspiciousEqualsCombination") - if (existingScheme != null && schemeManager.schemeListManager.readOnlyExternalizableSchemes.get( - schemeManager.processor.getSchemeKey(existingScheme)) !== existingScheme) { - LOG.warn("Ignore incorrect VFS create scheme event: schema ${readSchemeKey} is already exists") - return - } - - schemeManager.schemes.addAll(newSchemes) - - schemeManager.processor.initScheme(readScheme) - schemeManager.processor.onSchemeAdded(readScheme) + private fun schemeCreatedExternally(file: VirtualFile, schemeLoader: SchemeLoader) { + val readScheme = readSchemeFromFile(file, schemeLoader) ?: return + val readSchemeKey = schemeManager.processor.getSchemeKey(readScheme) + val existingScheme = schemeManager.findSchemeByName(readSchemeKey) + @Suppress("SuspiciousEqualsCombination") + if (existingScheme != null && schemeManager.schemeListManager.readOnlyExternalizableSchemes.get( + schemeManager.processor.getSchemeKey(existingScheme)) !== existingScheme) { + LOG.warn("Ignore incorrect VFS create scheme event: schema ${readSchemeKey} is already exists") + return } } } \ No newline at end of file diff --git a/platform/configuration-store-impl/src/schemeManager/SchemeManagerBase.kt b/platform/configuration-store-impl/src/schemeManager/SchemeManagerBase.kt index f57e56d6ff9e..2e3f9f5de47a 100644 --- a/platform/configuration-store-impl/src/schemeManager/SchemeManagerBase.kt +++ b/platform/configuration-store-impl/src/schemeManager/SchemeManagerBase.kt @@ -18,10 +18,12 @@ abstract class SchemeManagerBase(internal val pr get() = activeScheme?.let { processor.getSchemeKey(it) } ?: currentPendingSchemeName set(schemeName) = setCurrentSchemeName(schemeName, true) - internal fun processPendingCurrentSchemeName(newScheme: T) { + internal fun processPendingCurrentSchemeName(newScheme: T): Boolean { if (processor.getSchemeKey(newScheme) == currentPendingSchemeName) { setCurrent(newScheme, false) + return true } + return false } override fun setCurrent(scheme: T?, notify: Boolean) { diff --git a/platform/configuration-store-impl/src/schemeManager/SchemeManagerImpl.kt b/platform/configuration-store-impl/src/schemeManager/SchemeManagerImpl.kt index f560ee98ae2d..12fc53b043ad 100644 --- a/platform/configuration-store-impl/src/schemeManager/SchemeManagerImpl.kt +++ b/platform/configuration-store-impl/src/schemeManager/SchemeManagerImpl.kt @@ -11,7 +11,6 @@ import com.intellij.openapi.components.impl.stores.FileStorageCoreUtil import com.intellij.openapi.components.impl.stores.FileStorageCoreUtil.DEFAULT_EXT import com.intellij.openapi.diagnostic.runAndLogException import com.intellij.openapi.extensions.AbstractExtensionPointBean -import com.intellij.openapi.options.NonLazySchemeProcessor import com.intellij.openapi.options.SchemeProcessor import com.intellij.openapi.options.SchemeState import com.intellij.openapi.progress.ProcessCanceledException @@ -32,10 +31,8 @@ import com.intellij.util.text.UniqueNameGenerator import gnu.trove.THashSet import org.jdom.Document import org.jdom.Element -import org.xmlpull.v1.XmlPullParser import java.io.File import java.io.IOException -import java.io.InputStream import java.nio.file.Path import java.util.* import java.util.concurrent.atomic.AtomicBoolean @@ -157,11 +154,21 @@ class SchemeManagerImpl(val fileSpec: String, } } - private fun getFileExtension(fileName: CharSequence, allowAny: Boolean): String { + internal fun createSchemeLoader(isDuringLoad: Boolean = false): SchemeLoader { + val filesToDelete = THashSet(filesToDelete) + // caller must call SchemeLoader.apply to bring back scheduled for delete files + this.filesToDelete.removeAll(filesToDelete) + // SchemeLoader can use retain list to bring back previously scheduled for delete file, + // but what if someone will call save() during load and file will be deleted, although should be loaded by a new load session + // (because modified on disk) + return SchemeLoader(this, schemes, filesToDelete, isDuringLoad) + } + + internal fun getFileExtension(fileName: CharSequence, isAllowAny: Boolean): String { return when { StringUtilRt.endsWithIgnoreCase(fileName, schemeExtension) -> schemeExtension StringUtilRt.endsWithIgnoreCase(fileName, DEFAULT_EXT) -> DEFAULT_EXT - allowAny -> PathUtil.getFileExtension(fileName.toString())!! + isAllowAny -> PathUtil.getFileExtension(fileName.toString())!! else -> throw IllegalStateException("Scheme file extension $fileName is unknown, must be filtered out") } } @@ -172,13 +179,12 @@ class SchemeManagerImpl(val fileSpec: String, } try { - val filesToDelete = THashSet() - val oldSchemes = schemes - val schemes = oldSchemes.toMutableList() - val newSchemesOffset = schemes.size + // isDuringLoad is true even if loadSchemes called not first time, but on reload, + // because scheme processor should use cumulative event `reloaded` to update runtime state/caches + val schemeLoader = createSchemeLoader(isDuringLoad = true) if (provider != null && provider.processChildren(fileSpec, roamingType, { canRead(it) }) { name, input, readOnly -> catchAndLog(name) { - val scheme = loadScheme(name, input, schemes, filesToDelete) + val scheme = schemeLoader.loadScheme(name, input) if (readOnly && scheme != null) { schemeListManager.readOnlyExternalizableSchemes.put(processor.getSchemeKey(scheme), scheme) } @@ -194,26 +200,22 @@ class SchemeManagerImpl(val fileSpec: String, } catchAndLog(file.fileName.toString()) { filename -> - file.inputStream().use { loadScheme(filename, it, schemes, filesToDelete) } + file.inputStream().use { schemeLoader.loadScheme(filename, it) } } } } } - this.filesToDelete.addAll(filesToDelete) - schemeListManager.replaceSchemeList(oldSchemes, schemes) - - @Suppress("UNCHECKED_CAST") - for (i in newSchemesOffset until schemes.size) { - val scheme = schemes.get(i) as MUTABLE_SCHEME - processor.initScheme(scheme) - @Suppress("UNCHECKED_CAST") - processPendingCurrentSchemeName(scheme) + val newSchemes = schemeLoader.apply() + for (newScheme in newSchemes) { + if (processPendingCurrentSchemeName(newScheme)) { + break + } } fileChangeSubscriber?.invoke(this) - return schemes.subList(newSchemesOffset, schemes.size) + return newSchemes } finally { isLoadingSchemes.set(false) @@ -250,109 +252,6 @@ class SchemeManagerImpl(val fileSpec: String, retainExternalInfo() } - private fun isOverwriteOnLoad(existingScheme: T): Boolean { - val info = schemeToInfo.get(existingScheme) - // scheme from file with old extension, so, we must ignore it - return info != null && schemeExtension != info.fileExtension - } - - internal fun loadScheme(fileName: String, input: InputStream, schemes: MutableList, filesToDelete: MutableSet? = null): MUTABLE_SCHEME? { - val extension = getFileExtension(fileName, false) - if (filesToDelete != null && filesToDelete.contains(fileName)) { - LOG.warn("Scheme file \"$fileName\" is not loaded because marked to delete") - return null - } - - val fileNameWithoutExtension = fileName.substring(0, fileName.length - extension.length) - fun checkExisting(schemeName: String): Boolean { - if (filesToDelete == null) { - return true - } - - schemes.firstOrNull { processor.getSchemeKey(it) == schemeName}?.let { existingScheme -> - if (schemeListManager.readOnlyExternalizableSchemes.get(processor.getSchemeKey(existingScheme)) === existingScheme) { - // so, bundled scheme is shadowed - schemeListManager.removeFirstScheme(schemes, scheduleDelete = false) { it === existingScheme } - return true - } - else if (processor.isExternalizable(existingScheme) && isOverwriteOnLoad(existingScheme)) { - schemeListManager.removeFirstScheme(schemes) { it === existingScheme } - } - else { - if (schemeExtension != extension && schemeToInfo.get(existingScheme)?.fileNameWithoutExtension == fileNameWithoutExtension) { - // 1.oldExt is loading after 1.newExt - we should delete 1.oldExt - filesToDelete.add(fileName) - } - else { - // We don't load scheme with duplicated name - if we generate unique name for it, it will be saved then with new name. - // It is not what all can expect. Such situation in most cases indicates error on previous level, so, we just warn about it. - LOG.warn("Scheme file \"$fileName\" is not loaded because defines duplicated name \"$schemeName\"") - } - return false - } - } - - return true - } - - fun createInfo(schemeName: String, element: Element?): ExternalInfo { - val info = ExternalInfo(fileNameWithoutExtension, extension) - element?.let { - info.digest = it.digest() - } - info.schemeKey = schemeName - return info - } - - val duringLoad = filesToDelete != null - var scheme: MUTABLE_SCHEME? = null - if (processor is LazySchemeProcessor) { - val bytes = input.readBytes() - lazyPreloadScheme(bytes, isOldSchemeNaming) { name, parser -> - val attributeProvider = Function { - if (parser.eventType == XmlPullParser.START_TAG) { - parser.getAttributeValue(null, it) - } - else { - null - } - } - val schemeName = name - ?: processor.getSchemeKey(attributeProvider, fileNameWithoutExtension) - ?: throw nameIsMissed(bytes) - if (!checkExisting(schemeName)) { - return null - } - - val externalInfo = createInfo(schemeName, null) - scheme = processor.createScheme(SchemeDataHolderImpl(processor, bytes, externalInfo), schemeName, attributeProvider) - schemeToInfo.put(scheme, externalInfo) - this.filesToDelete.remove(fileName) - } - } - else { - val element = loadElement(input) - scheme = (processor as NonLazySchemeProcessor).readScheme(element, duringLoad) ?: return null - val schemeKey = processor.getSchemeKey(scheme!!) - if (!checkExisting(schemeKey)) { - return null - } - - schemeToInfo.put(scheme, createInfo(schemeKey, element)) - this.filesToDelete.remove(fileName) - } - - if (schemes === this.schemes) { - @Suppress("UNCHECKED_CAST") - addScheme(scheme as T, true) - } - else { - @Suppress("UNCHECKED_CAST") - schemes.add(scheme as T) - } - return scheme - } - internal fun getFileName(scheme: T) = schemeToInfo.get(scheme)?.fileNameWithoutExtension fun canRead(name: CharSequence): Boolean = (updateExtension && name.endsWith(DEFAULT_EXT, true) || name.endsWith(schemeExtension, ignoreCase = true)) && (processor !is LazySchemeProcessor || processor.isSchemeFile(name)) @@ -631,7 +530,7 @@ class SchemeManagerImpl(val fileSpec: String, return result } - override fun setSchemes(newSchemes: List, newCurrentScheme: T?, removeCondition: Condition?): Unit = schemeListManager.setSchemes(newSchemes, newCurrentScheme, removeCondition) + override fun setSchemes(newSchemes: List, newCurrentScheme: T?, removeCondition: Condition?) = schemeListManager.setSchemes(newSchemes, newCurrentScheme, removeCondition) internal fun retainExternalInfo() { if (schemeToInfo.isEmpty()) { diff --git a/platform/configuration-store-impl/src/schemeManager/schemeLoader.kt b/platform/configuration-store-impl/src/schemeManager/schemeLoader.kt index 3af08ce60799..c4075271f650 100644 --- a/platform/configuration-store-impl/src/schemeManager/schemeLoader.kt +++ b/platform/configuration-store-impl/src/schemeManager/schemeLoader.kt @@ -1,16 +1,179 @@ +// Copyright 2000-2018 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.configurationStore.schemeManager +import com.intellij.configurationStore.LOG +import com.intellij.configurationStore.LazySchemeProcessor +import com.intellij.configurationStore.digest import com.intellij.openapi.application.runUndoTransparentWriteAction +import com.intellij.openapi.options.NonLazySchemeProcessor import com.intellij.openapi.project.ProjectBundle +import com.intellij.openapi.util.JDOMUtil +import com.intellij.openapi.util.Ref import com.intellij.openapi.vfs.VfsUtil import com.intellij.openapi.vfs.VirtualFile +import com.intellij.util.containers.ConcurrentList import com.intellij.util.io.createDirectories import com.intellij.util.io.systemIndependentPath +import gnu.trove.THashSet +import org.jdom.Element import org.xmlpull.mxp1.MXParser import org.xmlpull.v1.XmlPullParser import java.io.IOException +import java.io.InputStream import java.nio.file.Path import java.util.* +import java.util.concurrent.atomic.AtomicBoolean +import java.util.function.Function + +internal class SchemeLoader(private val schemeManager: SchemeManagerImpl, + private val oldSchemes: ConcurrentList, + private val preScheduledFilesToDelete: MutableSet, + private val isDuringLoad: Boolean) { + private val filesToDelete = THashSet() + + private val schemes = oldSchemes.toMutableList() + private val newSchemesOffset = schemes.size + + private val isApplied = AtomicBoolean() + + private fun isFromFileWithOldExtension(existingScheme: T): Boolean { + val info = schemeManager.schemeToInfo.get(existingScheme) + // scheme from file with old extension, so, we must ignore it + return info != null && schemeManager.schemeExtension != info.fileExtension + } + + private fun isFromFileWithNewExtension(existingScheme: T, fileNameWithoutExtension: String): Boolean { + return schemeManager.schemeToInfo.get(existingScheme)?.fileNameWithoutExtension == fileNameWithoutExtension + } + + /** + * Returns list of new schemes. + */ + fun apply(): List { + LOG.assertTrue(isApplied.compareAndSet(false, true)) + + schemeManager.filesToDelete.addAll(filesToDelete) + schemeManager.filesToDelete.addAll(preScheduledFilesToDelete) + + val result = schemes.subList(newSchemesOffset, schemes.size) + schemeManager.schemeListManager.replaceSchemeList(oldSchemes, schemes) + if (!isDuringLoad) { + for (newScheme in result) { + @Suppress("UNCHECKED_CAST") + schemeManager.processor.onSchemeAdded(newScheme as MUTABLE_SCHEME) + } + } + return result + } + + fun loadScheme(fileName: String, input: InputStream): MUTABLE_SCHEME? { + val extension = schemeManager.getFileExtension(fileName, isAllowAny = false) + if (isFileScheduledForDeleteInThisLoadSession(fileName)) { + LOG.warn("Scheme file \"$fileName\" is not loaded because marked to delete") + return null + } + + val processor = schemeManager.processor + val schemeListManager = schemeManager.schemeListManager + + val fileNameWithoutExtension = fileName.substring(0, fileName.length - extension.length) + + fun checkExisting(schemeName: String): Boolean { + schemes.firstOrNull { processor.getSchemeKey(it) == schemeName}?.let { existingScheme -> + if (schemeListManager.readOnlyExternalizableSchemes.get(processor.getSchemeKey(existingScheme)) === existingScheme) { + // so, bundled scheme is shadowed + schemeListManager.removeFirstScheme(schemes, scheduleDelete = false) { it === existingScheme } + return true + } + else if (processor.isExternalizable(existingScheme) && isFromFileWithOldExtension(existingScheme)) { + schemeListManager.removeFirstScheme(schemes) { it === existingScheme } + } + else { + if (schemeManager.schemeExtension != extension && isFromFileWithNewExtension(existingScheme, fileNameWithoutExtension)) { + // 1.oldExt is loading after 1.newExt - we should delete 1.oldExt + filesToDelete.add(fileName) + } + else { + // We don't load scheme with duplicated name - if we generate unique name for it, it will be saved then with new name. + // It is not what all can expect. Such situation in most cases indicates error on previous level, so, we just warn about it. + LOG.warn("Scheme file \"$fileName\" is not loaded because defines duplicated name \"$schemeName\"") + } + return false + } + } + + return true + } + + fun createInfo(schemeName: String, element: Element?): ExternalInfo { + val info = ExternalInfo(fileNameWithoutExtension, extension) + element?.let { + info.digest = it.digest() + } + info.schemeKey = schemeName + return info + } + + var scheme: MUTABLE_SCHEME? = null + if (processor is LazySchemeProcessor) { + val bytes = input.readBytes() + lazyPreloadScheme(bytes, schemeManager.isOldSchemeNaming) { name, parser -> + val attributeProvider = Function { + if (parser.eventType == XmlPullParser.START_TAG) { + parser.getAttributeValue(null, it) + } + else { + null + } + } + val schemeName = name + ?: processor.getSchemeKey(attributeProvider, fileNameWithoutExtension) + ?: throw nameIsMissed(bytes) + if (!checkExisting(schemeName)) { + return null + } + + val externalInfo = createInfo(schemeName, null) + scheme = processor.createScheme(SchemeDataHolderImpl(processor, bytes, externalInfo), schemeName, attributeProvider) + schemeManager.schemeToInfo.put(scheme, externalInfo) + retainProbablyScheduledForDeleteFile(fileName) + } + } + else { + val element = JDOMUtil.load(input.bufferedReader()) + scheme = (processor as NonLazySchemeProcessor).readScheme(element, isDuringLoad) ?: return null + val schemeKey = processor.getSchemeKey(scheme!!) + if (!checkExisting(schemeKey)) { + return null + } + + schemeManager.schemeToInfo.put(scheme, createInfo(schemeKey, element)) + retainProbablyScheduledForDeleteFile(fileName) + } + + schemes.add(scheme) + return scheme + } + + private fun isFileScheduledForDeleteInThisLoadSession(fileName: String): Boolean { + return filesToDelete.contains(fileName) + } + + private fun retainProbablyScheduledForDeleteFile(fileName: String) { + filesToDelete.remove(fileName) + preScheduledFilesToDelete.remove(fileName) + } +} + +internal inline fun useSchemeLoader(executor: (Ref>) -> Unit) { + val schemeLoaderRef = Ref>() + executor(schemeLoaderRef) + val schemeLoader = schemeLoaderRef.get() + if (schemeLoader != null) { + schemeLoaderRef.set(null) + schemeLoader.apply() + } +} internal inline fun lazyPreloadScheme(bytes: ByteArray, isOldSchemeNaming: Boolean, consumer: (name: String?, parser: XmlPullParser) -> Unit) { val parser = MXParser() diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java index dfef29b4b562..d446ad0a5005 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java @@ -199,12 +199,7 @@ public class TemplateSettings implements PersistentStateComponent schemeManager, @NotNull Collection groups) { - for (TemplateGroup group : groups) { - for (TemplateImpl template : group.getElements()) { - addTemplateImpl(template); - } - } - loadDefaultLiveTemplates(); + doLoadTemplates(groups); } @NotNull @@ -249,13 +244,6 @@ public class TemplateSettings implements PersistentStateComponent groups) { + for (TemplateGroup group : groups) { for (TemplateImpl template : group.getElements()) { addTemplateImpl(template); } } - loadDefaultLiveTemplates(); } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/options/scheme.kt b/platform/projectModel-impl/src/com/intellij/openapi/options/scheme.kt index 0c3bbaf28550..29f112617152 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/options/scheme.kt +++ b/platform/projectModel-impl/src/com/intellij/openapi/options/scheme.kt @@ -63,9 +63,6 @@ abstract class SchemeProcessor { */ abstract fun writeScheme(scheme: MUTABLE_SCHEME): Parent? - open fun initScheme(scheme: MUTABLE_SCHEME) { - } - /** * Called on external scheme add or change file events. */