diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt index e91a8300673..d62a2fd5720 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt @@ -37,6 +37,7 @@ import com.intellij.util.containers.SLRUMap import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.caches.project.SdkInfo import org.jetbrains.kotlin.idea.caches.project.getScriptRelatedModuleInfo +import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings import org.jetbrains.kotlin.script.* import org.jetbrains.kotlin.scripting.compiler.plugin.KotlinScriptDefinitionAdapterFromNewAPI import org.jetbrains.kotlin.utils.PathUtil @@ -89,6 +90,8 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit definitionsByContributor[contributor] = contributor.safeGetDefinitions() + definitions = definitionsByContributor.values.flattenTo(mutableListOf()) + updateDefinitions() } @@ -121,15 +124,13 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit definitionsByContributor[contributor] = definitions } + definitions = definitionsByContributor.values.flattenTo(mutableListOf()) + updateDefinitions() } - fun saveNewDefinitions(newDefinitions: List) = lock.write { - definitions = newDefinitions - - clearCache() - ServiceManager.getService(project, ScriptDependenciesCache::class.java).clear() - EditorNotifications.getInstance(project).updateAllNotifications() + fun reorderScriptDefinitions() = lock.write { + updateDefinitions() } fun getAllDefinitions() = currentDefinitions.toList() @@ -141,8 +142,8 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit private fun updateDefinitions() { assert(lock.isWriteLocked) { "updateDefinitions should only be called under the write lock" } - definitions = definitionsByContributor.values.flattenTo(mutableListOf()).sortedBy { - definitions?.indexOf(it) ?: 1000 + definitions = definitions?.sortedBy { + KotlinScriptingSettings.getInstance(project).getScriptDefinitionOrder(it) } val fileTypeManager = FileTypeManager.getInstance() diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/settings/KotlinScriptingSettings.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/settings/KotlinScriptingSettings.kt index 189ae41d17f..a862f74e6ba 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/settings/KotlinScriptingSettings.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/settings/KotlinScriptingSettings.kt @@ -10,13 +10,18 @@ import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.components.State import com.intellij.openapi.components.Storage import com.intellij.openapi.project.Project -import com.intellij.util.xmlb.XmlSerializerUtil +import com.intellij.util.addOptionTag +import com.intellij.util.attribute +import com.intellij.util.element +import com.intellij.util.getAttributeBooleanValue +import org.jdom.Element +import org.jetbrains.kotlin.script.KotlinScriptDefinition @State( name = "KotlinScriptingSettings", storages = [Storage("kotlinScripting.xml")] ) -class KotlinScriptingSettings : PersistentStateComponent { +class KotlinScriptingSettings : PersistentStateComponent { var isAutoReloadEnabled = false /** @@ -24,16 +29,89 @@ class KotlinScriptingSettings : PersistentStateComponent() + + override fun getState(): Element { + val definitionsRootElement = Element("KotlinScriptingSettings") + + if (isAutoReloadEnabled) { + definitionsRootElement.addOptionTag( + KotlinScriptingSettings::isAutoReloadEnabled.name, + isAutoReloadEnabled.toString() + ) + } + + if (suppressDefinitionsCheck) { + definitionsRootElement.addOptionTag( + KotlinScriptingSettings::suppressDefinitionsCheck.name, + suppressDefinitionsCheck.toString() + ) + } + + if (scriptDefinitions.isEmpty()) { + return definitionsRootElement + } + + for (scriptDefinition in scriptDefinitions) { + definitionsRootElement.addScriptDefinitionContentElement(scriptDefinition.key, scriptDefinition.value) + } + + return definitionsRootElement } - override fun getState(): KotlinScriptingSettings { - return this + override fun loadState(state: Element) { + isAutoReloadEnabled = + state.getAttributeBooleanValue(KotlinScriptingSettings::isAutoReloadEnabled.name) + suppressDefinitionsCheck = + state.getAttributeBooleanValue(KotlinScriptingSettings::suppressDefinitionsCheck.name) + + val scriptDefinitionsList = state.getChildren(SCRIPT_DEFINITION_TAG) + for (scriptDefinitionElement in scriptDefinitionsList) { + scriptDefinitions[scriptDefinitionElement.toKey()] = scriptDefinitionElement.getOrderTag() + } + } + + fun saveScriptDefinitionsOrder(newScriptDefinitions: List) { + for ((index, scriptDefinition) in newScriptDefinitions.withIndex()) { + scriptDefinitions[scriptDefinition.toKey()] = index + } + } + + fun getScriptDefinitionOrder(scriptDefinition: KotlinScriptDefinition): Int { + return scriptDefinitions[scriptDefinition.toKey()] ?: Integer.MAX_VALUE + } + + private data class KotlinScriptDefinitionKey(val definitionName: String, val className: String) + + private fun Element.toKey() = KotlinScriptDefinitionKey( + getAttributeValue(KotlinScriptDefinitionKey::definitionName.name), + getAttributeValue(KotlinScriptDefinitionKey::className.name) + ) + + private fun KotlinScriptDefinition.toKey() = + KotlinScriptDefinitionKey(this.name, this::class.qualifiedName ?: "unknown") + + private fun Element.addScriptDefinitionContentElement(definition: KotlinScriptDefinitionKey, order: Int) { + element(SCRIPT_DEFINITION_TAG).apply { + attribute(KotlinScriptDefinitionKey::className.name, definition.className) + attribute(KotlinScriptDefinitionKey::definitionName.name, definition.definitionName) + + element(SCRIPT_DEFINITION_ORDER_TAG).apply { + text = order.toString() + } + } + } + + private fun Element.getOrderTag(): Int { + return getChildText(SCRIPT_DEFINITION_ORDER_TAG)?.toInt() ?: Integer.MAX_VALUE } companion object { fun getInstance(project: Project): KotlinScriptingSettings = ServiceManager.getService(project, KotlinScriptingSettings::class.java) + + private const val SCRIPT_DEFINITION_TAG = "scriptDefinition" + private const val SCRIPT_DEFINITION_ORDER_TAG = "order" + } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/script/configuration/KotlinScriptingSettingsConfigurable.java b/idea/src/org/jetbrains/kotlin/idea/script/configuration/KotlinScriptingSettingsConfigurable.java index 5c41191cb83..753fe83141d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/script/configuration/KotlinScriptingSettingsConfigurable.java +++ b/idea/src/org/jetbrains/kotlin/idea/script/configuration/KotlinScriptingSettingsConfigurable.java @@ -54,15 +54,17 @@ public class KotlinScriptingSettingsConfigurable implements SearchableConfigurab @Override public boolean isModified() { return isModified(scriptDependenciesAutoReload, settings.isAutoReloadEnabled()) - || !model.getItems().equals(manager.getAllDefinitions()); + || isScriptDefinitionsChanged(); } @Override public void apply() { settings.setAutoReloadEnabled(scriptDependenciesAutoReload.isSelected()); - - manager.saveNewDefinitions(Collections.unmodifiableList(model.getItems())); + if (isScriptDefinitionsChanged()) { + settings.saveScriptDefinitionsOrder(Collections.unmodifiableList(model.getItems())); + manager.reorderScriptDefinitions(); + } } @Override @@ -72,6 +74,11 @@ public class KotlinScriptingSettingsConfigurable implements SearchableConfigurab model.setItems(Lists.newArrayList(manager.getAllDefinitions())); } + private boolean isScriptDefinitionsChanged() { + return !model.getItems().equals(manager.getAllDefinitions()); + } + + @Override @Nls public String getDisplayName() {