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. */