Scripting setting: auto reloading of script dependencies is now per definition

This commit is contained in:
Natalia Selezneva
2020-05-28 18:26:30 +03:00
parent 8726d3dc4e
commit fd07d5f301
21 changed files with 323 additions and 134 deletions
@@ -17,6 +17,7 @@ import com.intellij.ui.HyperlinkLabel
import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings
import org.jetbrains.kotlin.idea.core.util.KotlinIdeaCoreBundle
import org.jetbrains.kotlin.psi.UserDataProperty
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
object LoadScriptConfigurationNotificationFactory {
fun showNotification(file: VirtualFile, project: Project, onClick: () -> Unit): Boolean {
@@ -50,7 +51,7 @@ object LoadScriptConfigurationNotificationFactory {
return@withSelectedEditor
}
val panel = NewLoadConfigurationNotificationPanel(onClick, project)
val panel = NewLoadConfigurationNotificationPanel(onClick, project, this@addLoadConfigurationNotificationPanel)
notificationPanel = panel
manager.addTopComponent(this, panel)
}
@@ -72,7 +73,8 @@ object LoadScriptConfigurationNotificationFactory {
private class NewLoadConfigurationNotificationPanel(
var onClick: () -> Unit,
project: Project
project: Project,
file: VirtualFile
) : EditorNotificationPanel() {
init {
@@ -83,7 +85,9 @@ object LoadScriptConfigurationNotificationFactory {
createComponentActionLabel(KotlinIdeaCoreBundle.message("notification.action.text.enable.auto.reload")) {
onClick()
KotlinScriptingSettings.getInstance(project).isAutoReloadEnabled = true
val scriptDefinition = file.findScriptDefinition(project) ?: return@createComponentActionLabel
KotlinScriptingSettings.getInstance(project).setAutoReloadConfigurations(scriptDefinition, true)
}
}
@@ -171,6 +171,11 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit
}
fun reorderScriptDefinitions() = lock.write {
definitions?.forEach {
it.order = KotlinScriptingSettings.getInstance(project).getScriptDefinitionOrder(it)
}
definitions = definitions?.sortedBy { it.order }
updateDefinitions()
}
@@ -197,10 +202,6 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit
private fun updateDefinitions() {
assert(lock.isWriteLocked) { "updateDefinitions should only be called under the write lock" }
definitions = definitions?.sortedBy {
KotlinScriptingSettings.getInstance(project).getScriptDefinitionOrder(it)
}
val fileTypeManager = FileTypeManager.getInstance()
val newExtensions = getKnownFilenameExtensions().filter {
@@ -18,6 +18,7 @@ import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings
import org.jetbrains.kotlin.idea.core.util.KotlinIdeaCoreBundle
import org.jetbrains.kotlin.psi.UserDataProperty
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper
fun VirtualFile.removeScriptDependenciesNotificationPanel(project: Project) {
@@ -45,7 +46,7 @@ fun VirtualFile.addScriptDependenciesNotificationPanel(
}
}
val panel = NewScriptDependenciesNotificationPanel(onClick, compilationConfigurationResult, project)
val panel = NewScriptDependenciesNotificationPanel(onClick, compilationConfigurationResult, project, this@addScriptDependenciesNotificationPanel)
notificationPanel = panel
manager.addTopComponent(this, panel)
}
@@ -81,7 +82,8 @@ private var FileEditor.notificationPanel: NewScriptDependenciesNotificationPanel
private class NewScriptDependenciesNotificationPanel(
val onClick: () -> Unit,
val compilationConfigurationResult: ScriptCompilationConfigurationWrapper,
project: Project
project: Project,
file: VirtualFile
) : EditorNotificationPanel() {
init {
@@ -92,7 +94,9 @@ private class NewScriptDependenciesNotificationPanel(
createComponentActionLabel(KotlinIdeaCoreBundle.message("notification.action.text.enable.auto.reload")) {
onClick()
KotlinScriptingSettings.getInstance(project).isAutoReloadEnabled = true
val scriptDefinition = file.findScriptDefinition(project) ?: return@createComponentActionLabel
KotlinScriptingSettings.getInstance(project).setAutoReloadConfigurations(scriptDefinition, true)
}
}
@@ -174,7 +174,7 @@ class DefaultScriptingSupport(manager: CompositeScriptConfigurationManager) : De
if (forceSync) {
loaders.firstOrNull { it.loadDependencies(isFirstLoad, file, scriptDefinition, loadingContext) }
} else {
val autoReloadEnabled = KotlinScriptingSettings.getInstance(project).isAutoReloadEnabled
val autoReloadEnabled = KotlinScriptingSettings.getInstance(project).autoReloadConfigurations(scriptDefinition)
val postponeLoading = isPostponedLoad && !autoReloadEnabled
if (postponeLoading) {
@@ -206,7 +206,8 @@ class DefaultScriptingSupport(manager: CompositeScriptConfigurationManager) : De
val applied = cached?.applied
if (applied != null && applied.inputs.isUpToDate(project, virtualFile)) {
// in case user reverted to applied configuration
suggestOrSaveConfiguration(virtualFile, applied, skipNotification = isLoadingPostponed)
val skipNotification = isLoadingPostponed || KotlinScriptingSettings.getInstance(project).autoReloadConfigurations(scriptDefinition)
suggestOrSaveConfiguration(virtualFile, applied, skipNotification)
} else if (cached == null || !cached.isUpToDate(project, virtualFile)) {
// don't start loading if nothing was changed
// (in case we checking for up-to-date and loading concurrently)
@@ -280,7 +281,6 @@ class DefaultScriptingSupport(manager: CompositeScriptConfigurationManager) : De
} else {
val autoReload = skipNotification
|| oldConfiguration == null
|| KotlinScriptingSettings.getInstance(project).isAutoReloadEnabled
|| ApplicationManager.getApplication().isUnitTestModeWithoutScriptLoadingNotification
if (autoReload) {
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
import org.jetbrains.kotlin.idea.core.script.configuration.cache.CachedConfigurationInputs
import org.jetbrains.kotlin.idea.core.script.configuration.cache.ScriptConfigurationSnapshot
import org.jetbrains.kotlin.idea.core.script.debug
import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
@@ -43,7 +44,11 @@ open class DefaultScriptConfigurationLoader(val project: Project) : ScriptConfig
val result = getConfigurationThroughScriptingApi(ktFile, virtualFile, scriptDefinition)
context.suggestNewConfiguration(virtualFile, result)
if (KotlinScriptingSettings.getInstance(project).autoReloadConfigurations(scriptDefinition)) {
context.saveNewConfiguration(virtualFile, result)
} else {
context.suggestNewConfiguration(virtualFile, result)
}
return true
}
@@ -14,7 +14,7 @@ interface ScriptConfigurationLoadingContext {
/**
* Show notification about new configuration with suggestion to apply it.
* User may disable this notifications, in this case configuration will be saved immediately.
* User may disable this notifications, in this case [saveNewConfiguration] should be called
*
* If configuration is null, then the result will be treated as failed, and
* reports will be displayed immediately.
@@ -10,9 +10,11 @@ import com.intellij.openapi.components.State
import com.intellij.openapi.components.Storage
import com.intellij.openapi.project.Project
import com.intellij.util.addOptionTag
import com.intellij.util.attribute
import com.intellij.util.getAttributeBooleanValue
import org.jdom.Element
import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager
import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings.KotlinScriptDefinitionValue.Companion.DEFAULT
import org.jetbrains.kotlin.idea.util.application.executeOnPooledThread
import org.jetbrains.kotlin.idea.util.application.getServiceSafe
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
@@ -20,8 +22,7 @@ import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
name = "KotlinScriptingSettings",
storages = [Storage("kotlinScripting.xml")]
)
class KotlinScriptingSettings : PersistentStateComponent<Element> {
var isAutoReloadEnabled = false
class KotlinScriptingSettings(private val project: Project) : PersistentStateComponent<Element> {
/**
* true if notification about multiple script definition applicable for one script file is suppressed
@@ -33,13 +34,6 @@ class KotlinScriptingSettings : PersistentStateComponent<Element> {
override fun getState(): Element {
val definitionsRootElement = Element("KotlinScriptingSettings")
if (isAutoReloadEnabled) {
definitionsRootElement.addOptionTag(
KotlinScriptingSettings::isAutoReloadEnabled.name,
isAutoReloadEnabled.toString()
)
}
if (suppressDefinitionsCheck) {
definitionsRootElement.addOptionTag(
KotlinScriptingSettings::suppressDefinitionsCheck.name,
@@ -59,9 +53,6 @@ class KotlinScriptingSettings : PersistentStateComponent<Element> {
}
override fun loadState(state: Element) {
state.getOptionTag(KotlinScriptingSettings::isAutoReloadEnabled.name)?.let {
isAutoReloadEnabled = it
}
state.getOptionTag(KotlinScriptingSettings::suppressDefinitionsCheck.name)?.let {
suppressDefinitionsCheck = it
}
@@ -70,29 +61,63 @@ class KotlinScriptingSettings : PersistentStateComponent<Element> {
for (scriptDefinitionElement in scriptDefinitionsList) {
scriptDefinitions[scriptDefinitionElement.toKey()] = scriptDefinitionElement.toValue()
}
if (scriptDefinitionsList.isNotEmpty()) {
executeOnPooledThread {
ScriptDefinitionsManager.getInstance(project).reorderScriptDefinitions()
}
}
}
fun setOrder(scriptDefinition: ScriptDefinition, order: Int) {
scriptDefinitions[scriptDefinition.toKey()] = scriptDefinitions[scriptDefinition.toKey()]?.copy(order = order) ?:
KotlinScriptDefinitionValue(order)
scriptDefinitions[scriptDefinition.toKey()] =
scriptDefinitions[scriptDefinition.toKey()]?.copy(order = order) ?: KotlinScriptDefinitionValue(order)
}
fun setEnabled(scriptDefinition: ScriptDefinition, isEnabled: Boolean) {
scriptDefinitions[scriptDefinition.toKey()] = scriptDefinitions[scriptDefinition.toKey()]?.copy(isEnabled = isEnabled) ?:
KotlinScriptDefinitionValue(scriptDefinitions.size, isEnabled)
scriptDefinitions[scriptDefinition.toKey()] =
scriptDefinitions[scriptDefinition.toKey()]?.copy(isEnabled = isEnabled) ?: KotlinScriptDefinitionValue(
scriptDefinition.order,
isEnabled = isEnabled
)
}
fun setAutoReloadConfigurations(scriptDefinition: ScriptDefinition, autoReloadScriptDependencies: Boolean) {
scriptDefinitions[scriptDefinition.toKey()] =
scriptDefinitions[scriptDefinition.toKey()]?.copy(autoReloadConfigurations = autoReloadScriptDependencies)
?: KotlinScriptDefinitionValue(
scriptDefinition.order,
autoReloadConfigurations = autoReloadScriptDependencies
)
}
fun getScriptDefinitionOrder(scriptDefinition: ScriptDefinition): Int {
return scriptDefinitions[scriptDefinition.toKey()]?.order ?: Integer.MAX_VALUE
return scriptDefinitions[scriptDefinition.toKey()]?.order ?: DEFAULT.order
}
fun isScriptDefinitionEnabled(scriptDefinition: ScriptDefinition): Boolean {
return scriptDefinitions[scriptDefinition.toKey()]?.isEnabled ?: true
return scriptDefinitions[scriptDefinition.toKey()]?.isEnabled ?: DEFAULT.isEnabled
}
private data class KotlinScriptDefinitionKey(val definitionName: String, val className: String)
private data class KotlinScriptDefinitionValue(val order: Int, val isEnabled: Boolean = true)
fun autoReloadConfigurations(scriptDefinition: ScriptDefinition): Boolean {
return scriptDefinitions[scriptDefinition.toKey()]?.autoReloadConfigurations ?: DEFAULT.autoReloadConfigurations
}
private data class KotlinScriptDefinitionKey(
val definitionName: String,
val className: String
)
private data class KotlinScriptDefinitionValue(
val order: Int,
val isEnabled: Boolean = true,
val autoReloadConfigurations: Boolean = false
) {
companion object {
val DEFAULT = KotlinScriptDefinitionValue(Integer.MAX_VALUE)
}
}
private fun Element.toKey() = KotlinScriptDefinitionKey(
getAttributeValue(KotlinScriptDefinitionKey::definitionName.name),
@@ -104,8 +129,8 @@ class KotlinScriptingSettings : PersistentStateComponent<Element> {
private fun Element.addScriptDefinitionContentElement(definition: KotlinScriptDefinitionKey, settings: KotlinScriptDefinitionValue) {
addElement(SCRIPT_DEFINITION_TAG).apply {
attribute(KotlinScriptDefinitionKey::className.name, definition.className)
attribute(KotlinScriptDefinitionKey::definitionName.name, definition.definitionName)
setAttribute(KotlinScriptDefinitionKey::className.name, definition.className)
setAttribute(KotlinScriptDefinitionKey::definitionName.name, definition.definitionName)
addElement(KotlinScriptDefinitionValue::order.name).apply {
text = settings.order.toString()
@@ -116,6 +141,11 @@ class KotlinScriptingSettings : PersistentStateComponent<Element> {
text = settings.isEnabled.toString()
}
}
if (settings.autoReloadConfigurations) {
addElement(KotlinScriptDefinitionValue::autoReloadConfigurations.name).apply {
text = settings.autoReloadConfigurations.toString()
}
}
}
}
@@ -126,10 +156,14 @@ class KotlinScriptingSettings : PersistentStateComponent<Element> {
}
private fun Element.toValue(): KotlinScriptDefinitionValue {
val order = getChildText(KotlinScriptDefinitionValue::order.name)?.toInt() ?: Integer.MAX_VALUE
val isEnabled = getChildText(KotlinScriptDefinitionValue::isEnabled.name)?.toBoolean() ?: true
val order = getChildText(KotlinScriptDefinitionValue::order.name)?.toInt()
?: DEFAULT.order
val isEnabled = getChildText(KotlinScriptDefinitionValue::isEnabled.name)?.toBoolean()
?: DEFAULT.isEnabled
val autoReloadScriptDependencies = getChildText(KotlinScriptDefinitionValue::autoReloadConfigurations.name)?.toBoolean()
?: DEFAULT.autoReloadConfigurations
return KotlinScriptDefinitionValue(order, isEnabled)
return KotlinScriptDefinitionValue(order, isEnabled, autoReloadScriptDependencies)
}
private fun Element.getOptionTag(name: String) =