extract SchemeLoader

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.
This commit is contained in:
Vladimir Krivosheev
2018-10-25 12:08:51 +02:00
parent 212120c7bd
commit 3fe96a0da0
7 changed files with 237 additions and 182 deletions
@@ -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)
}
}
}
}
@@ -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<SchemeLoader<Any, Any>>)
}
internal class SchemeFileTracker(private val schemeManager: SchemeManagerImpl<Any, Any>, private val project: Project?) : BulkFileListener {
@@ -33,14 +33,14 @@ internal class SchemeFileTracker(private val schemeManager: SchemeManagerImpl<An
private val projectManager by lazy { (ProjectManager.getInstance() as StoreAwareProjectManager) }
private class RemoveAllSchemes : SchemeChangeEvent {
override fun SchemeFileTracker.execute() {
override fun SchemeFileTracker.execute(schemaLoader: Lazy<SchemeLoader<Any, Any>>) {
schemeManager.cachedVirtualDirectory = null
schemeManager.removeExternalizableSchemes()
}
}
private data class RemoveScheme(private val fileName: String) : SchemeChangeEvent {
override fun SchemeFileTracker.execute() {
override fun SchemeFileTracker.execute(schemaLoader: Lazy<SchemeLoader<Any, Any>>) {
val scheme = findExternalizableSchemeByFileName(fileName)
if (scheme != null) {
schemeManager.removeScheme(scheme)
@@ -50,39 +50,50 @@ internal class SchemeFileTracker(private val schemeManager: SchemeManagerImpl<An
}
private data class AddScheme(private val file: VirtualFile) : SchemeChangeEvent {
override fun SchemeFileTracker.execute() {
override fun SchemeFileTracker.execute(schemaLoader: Lazy<SchemeLoader<Any, Any>>) {
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<SchemeLoader<Any, Any>>) {
}
}
private fun readSchemeFromFile(file: VirtualFile, schemes: MutableList<Any>): Any? {
private fun readSchemeFromFile(file: VirtualFile, schemeLoader: SchemeLoader<Any, Any>): 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<SchemeChangeEvent>) {
internal fun reload(events: Collection<SchemeChangeEvent>, schemaLoaderRef: Ref<SchemeLoader<Any, Any>>) {
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<An
processor.onSchemeDeleted(it)
}
val newScheme = readSchemeFromFile(file, schemeManager.schemes)?.let {
processor.initScheme(it)
processor.onSchemeAdded(it)
it
}
val newScheme = readSchemeFromFile(file, lazySchemaLoader.value)
fun isNewActiveScheme(): Boolean {
if (newActiveScheme != null) {
return false
@@ -143,7 +149,9 @@ internal class SchemeFileTracker(private val schemeManager: SchemeManagerImpl<An
fun registerChange(schemeEvent: SchemeChangeEvent) {
if (project == null) {
// test mode
reload(listOf(schemeEvent))
useSchemeLoader {
reload(listOf(schemeEvent), it)
}
}
else {
projectManager.registerChangedScheme(schemeEvent, this, project)
@@ -221,23 +229,15 @@ internal class SchemeFileTracker(private val schemeManager: SchemeManagerImpl<An
return false
}
private fun schemeCreatedExternally(file: VirtualFile) {
val newSchemes = SmartList<Any>()
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<Any, Any>) {
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
}
}
}
@@ -18,10 +18,12 @@ abstract class SchemeManagerBase<T : Any, in MUTABLE_SCHEME : T>(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) {
@@ -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<T : Any, MUTABLE_SCHEME : T>(val fileSpec: String,
}
}
private fun getFileExtension(fileName: CharSequence, allowAny: Boolean): String {
internal fun createSchemeLoader(isDuringLoad: Boolean = false): SchemeLoader<T, MUTABLE_SCHEME> {
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<T : Any, MUTABLE_SCHEME : T>(val fileSpec: String,
}
try {
val filesToDelete = THashSet<String>()
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<T : Any, MUTABLE_SCHEME : T>(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<T : Any, MUTABLE_SCHEME : T>(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<T>, filesToDelete: MutableSet<String>? = 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<String, String?> {
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<T : Any, MUTABLE_SCHEME : T>(val fileSpec: String,
return result
}
override fun setSchemes(newSchemes: List<T>, newCurrentScheme: T?, removeCondition: Condition<T>?): Unit = schemeListManager.setSchemes(newSchemes, newCurrentScheme, removeCondition)
override fun setSchemes(newSchemes: List<T>, newCurrentScheme: T?, removeCondition: Condition<T>?) = schemeListManager.setSchemes(newSchemes, newCurrentScheme, removeCondition)
internal fun retainExternalInfo() {
if (schemeToInfo.isEmpty()) {
@@ -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<T : Any, MUTABLE_SCHEME : T>(private val schemeManager: SchemeManagerImpl<T, MUTABLE_SCHEME>,
private val oldSchemes: ConcurrentList<T>,
private val preScheduledFilesToDelete: MutableSet<String>,
private val isDuringLoad: Boolean) {
private val filesToDelete = THashSet<String>()
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<T> {
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<String, String?> {
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<SchemeLoader<Any, Any>>) -> Unit) {
val schemeLoaderRef = Ref<SchemeLoader<Any, Any>>()
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()
@@ -199,12 +199,7 @@ public class TemplateSettings implements PersistentStateComponent<TemplateSettin
@Override
public void reloaded(@NotNull SchemeManager<TemplateGroup> schemeManager, @NotNull Collection<? extends TemplateGroup> 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<TemplateSettin
return templateSetElement;
}
@Override
public void initScheme(@NotNull final TemplateGroup scheme) {
for (TemplateImpl template : scheme.getElements()) {
addTemplateImpl(template);
}
}
@Override
public void onSchemeAdded(@NotNull final TemplateGroup scheme) {
for (TemplateImpl template : scheme.getElements()) {
@@ -271,12 +259,15 @@ public class TemplateSettings implements PersistentStateComponent<TemplateSettin
}
});
for (TemplateGroup group : mySchemeManager.loadSchemes()) {
doLoadTemplates(mySchemeManager.loadSchemes());
}
private void doLoadTemplates(@NotNull Collection<? extends TemplateGroup> groups) {
for (TemplateGroup group : groups) {
for (TemplateImpl template : group.getElements()) {
addTemplateImpl(template);
}
}
loadDefaultLiveTemplates();
}
@@ -63,9 +63,6 @@ abstract class SchemeProcessor<SCHEME, in MUTABLE_SCHEME: SCHEME> {
*/
abstract fun writeScheme(scheme: MUTABLE_SCHEME): Parent?
open fun initScheme(scheme: MUTABLE_SCHEME) {
}
/**
* Called on external scheme add or change file events.
*/