Add ability to postpone script configuration loading
Show notification for scripts with out of date configurations ^KT-35573
This commit is contained in:
+111
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.core.script
|
||||||
|
|
||||||
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
|
import com.intellij.openapi.extensions.ExtensionPointName
|
||||||
|
import com.intellij.openapi.fileEditor.FileEditor
|
||||||
|
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.util.Key
|
||||||
|
import com.intellij.openapi.util.Ref
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.ui.EditorNotificationPanel
|
||||||
|
import com.intellij.ui.HyperlinkLabel
|
||||||
|
import org.jetbrains.annotations.TestOnly
|
||||||
|
import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings
|
||||||
|
import org.jetbrains.kotlin.psi.UserDataProperty
|
||||||
|
|
||||||
|
interface ScriptConfigurationNotificationFactory {
|
||||||
|
fun showNotification(file: VirtualFile, project: Project, onClick: () -> Unit): Boolean
|
||||||
|
fun hideNotification(file: VirtualFile, project: Project): Boolean
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val NOTIFICATION_FACTORY: ExtensionPointName<ScriptConfigurationNotificationFactory> =
|
||||||
|
ExtensionPointName.create("org.jetbrains.kotlin.scripting.idea.notificationFactory")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DefaultScriptConfigurationNotificationFactory : ScriptConfigurationNotificationFactory {
|
||||||
|
override fun showNotification(file: VirtualFile, project: Project, onClick: () -> Unit): Boolean {
|
||||||
|
file.addLoadConfigurationNotificationPanel(project, onClick)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hideNotification(file: VirtualFile, project: Project): Boolean {
|
||||||
|
file.removeLoadConfigurationNotificationPanel(project)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun VirtualFile.removeLoadConfigurationNotificationPanel(project: Project) {
|
||||||
|
withSelectedEditor(project) { manager ->
|
||||||
|
notificationPanel?.let {
|
||||||
|
manager.removeTopComponent(this, it)
|
||||||
|
}
|
||||||
|
notificationPanel = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun VirtualFile.addLoadConfigurationNotificationPanel(
|
||||||
|
project: Project,
|
||||||
|
onClick: () -> Unit
|
||||||
|
) {
|
||||||
|
withSelectedEditor(project) { manager ->
|
||||||
|
val existingPanel = notificationPanel
|
||||||
|
if (existingPanel != null) {
|
||||||
|
notificationPanel?.let {
|
||||||
|
manager.removeTopComponent(this, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val panel = NewLoadConfigurationNotificationPanel(onClick, project)
|
||||||
|
notificationPanel = panel
|
||||||
|
manager.addTopComponent(this, panel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun VirtualFile.withSelectedEditor(project: Project, f: FileEditor.(FileEditorManager) -> Unit) {
|
||||||
|
ApplicationManager.getApplication().invokeLater {
|
||||||
|
if (project.isDisposed) return@invokeLater
|
||||||
|
|
||||||
|
val fileEditorManager = FileEditorManager.getInstance(project)
|
||||||
|
(fileEditorManager.getSelectedEditor(this))?.let {
|
||||||
|
f(it, fileEditorManager)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var FileEditor.notificationPanel: NewLoadConfigurationNotificationPanel?
|
||||||
|
by UserDataProperty<FileEditor, NewLoadConfigurationNotificationPanel>(Key.create("load.script.configuration.panel"))
|
||||||
|
|
||||||
|
private class NewLoadConfigurationNotificationPanel(
|
||||||
|
val onClick: () -> Unit,
|
||||||
|
project: Project
|
||||||
|
) : EditorNotificationPanel() {
|
||||||
|
|
||||||
|
init {
|
||||||
|
setText("Script Configuration might be changed")
|
||||||
|
createComponentActionLabel("Load configuration") {
|
||||||
|
onClick()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
createComponentActionLabel("Enable auto-reload") {
|
||||||
|
onClick()
|
||||||
|
KotlinScriptingSettings.getInstance(project).isAutoReloadEnabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun EditorNotificationPanel.createComponentActionLabel(labelText: String, callback: (HyperlinkLabel) -> Unit) {
|
||||||
|
val label: Ref<HyperlinkLabel> = Ref.create()
|
||||||
|
val action = Runnable {
|
||||||
|
callback(label.get())
|
||||||
|
}
|
||||||
|
label.set(createActionLabel(labelText, action))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
-5
@@ -75,12 +75,14 @@ internal abstract class AbstractScriptConfigurationManager(
|
|||||||
* user can see potential notification and accept new configuration. In other cases this should be `false` since
|
* user can see potential notification and accept new configuration. In other cases this should be `false` since
|
||||||
* loaded configuration will be just leaved in hidden user notification and cannot be used in any way.
|
* loaded configuration will be just leaved in hidden user notification and cannot be used in any way.
|
||||||
* @param forceSync should be used in tests only
|
* @param forceSync should be used in tests only
|
||||||
|
* @param isPostponedLoad is used to postspone loading: show a notification for out of date script and start loading when user request
|
||||||
*/
|
*/
|
||||||
protected abstract fun reloadOutOfDateConfiguration(
|
protected abstract fun reloadOutOfDateConfiguration(
|
||||||
file: KtFile,
|
file: KtFile,
|
||||||
isFirstLoad: Boolean = getAppliedConfiguration(file.originalFile.virtualFile) == null,
|
isFirstLoad: Boolean = getAppliedConfiguration(file.originalFile.virtualFile) == null,
|
||||||
loadEvenWillNotBeApplied: Boolean = false,
|
loadEvenWillNotBeApplied: Boolean = false,
|
||||||
forceSync: Boolean = false
|
forceSync: Boolean = false,
|
||||||
|
isPostponedLoad: Boolean = false
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -149,19 +151,23 @@ internal abstract class AbstractScriptConfigurationManager(
|
|||||||
|
|
||||||
override val updater: ScriptConfigurationUpdater = object : ScriptConfigurationUpdater {
|
override val updater: ScriptConfigurationUpdater = object : ScriptConfigurationUpdater {
|
||||||
override fun ensureUpToDatedConfigurationSuggested(file: KtFile) {
|
override fun ensureUpToDatedConfigurationSuggested(file: KtFile) {
|
||||||
reloadIfOutOfDate(listOf(file), true)
|
reloadIfOutOfDate(listOf(file), loadEvenWillNotBeApplied = true, isPostponedLoad = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun ensureConfigurationUpToDate(files: List<KtFile>): Boolean {
|
override fun ensureConfigurationUpToDate(files: List<KtFile>): Boolean {
|
||||||
return reloadIfOutOfDate(files, false)
|
return reloadIfOutOfDate(files, loadEvenWillNotBeApplied = false, isPostponedLoad = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun postponeConfigurationReload(scope: ScriptConfigurationCacheScope) {
|
override fun postponeConfigurationReload(scope: ScriptConfigurationCacheScope) {
|
||||||
cache.markOutOfDate(scope)
|
cache.markOutOfDate(scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun suggestToUpdateConfigurationIfOutOfDate(file: KtFile) {
|
||||||
|
reloadIfOutOfDate(listOf(file), loadEvenWillNotBeApplied = true, isPostponedLoad = true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun reloadIfOutOfDate(files: List<KtFile>, loadEvenWillNotBeApplied: Boolean): Boolean {
|
private fun reloadIfOutOfDate(files: List<KtFile>, loadEvenWillNotBeApplied: Boolean, isPostponedLoad: Boolean): Boolean {
|
||||||
if (!ScriptDefinitionsManager.getInstance(project).isReady()) return false
|
if (!ScriptDefinitionsManager.getInstance(project).isReady()) return false
|
||||||
|
|
||||||
var upToDate = true
|
var upToDate = true
|
||||||
@@ -175,7 +181,8 @@ internal abstract class AbstractScriptConfigurationManager(
|
|||||||
reloadOutOfDateConfiguration(
|
reloadOutOfDateConfiguration(
|
||||||
file,
|
file,
|
||||||
isFirstLoad = state == null,
|
isFirstLoad = state == null,
|
||||||
loadEvenWillNotBeApplied = loadEvenWillNotBeApplied
|
loadEvenWillNotBeApplied = loadEvenWillNotBeApplied,
|
||||||
|
isPostponedLoad = isPostponedLoad
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,6 +289,7 @@ internal abstract class AbstractScriptConfigurationManager(
|
|||||||
// ScriptRootsCache
|
// ScriptRootsCache
|
||||||
|
|
||||||
private val classpathRootsLock = ReentrantLock()
|
private val classpathRootsLock = ReentrantLock()
|
||||||
|
|
||||||
@Volatile
|
@Volatile
|
||||||
private var _classpathRoots: ScriptClassRootsCache? = null
|
private var _classpathRoots: ScriptClassRootsCache? = null
|
||||||
private val classpathRoots: ScriptClassRootsCache
|
private val classpathRoots: ScriptClassRootsCache
|
||||||
|
|||||||
+44
-15
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.idea.core.script.configuration.utils.DefaultBackgrou
|
|||||||
import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings
|
import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings
|
||||||
import org.jetbrains.kotlin.idea.core.util.EDT
|
import org.jetbrains.kotlin.idea.core.util.EDT
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
|
||||||
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
|
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
|
||||||
import org.jetbrains.kotlin.scripting.resolve.ScriptReportSink
|
import org.jetbrains.kotlin.scripting.resolve.ScriptReportSink
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
@@ -138,6 +139,7 @@ internal class DefaultScriptConfigurationManager(project: Project) :
|
|||||||
* - invalid, in queue. `cache[file]?.upToDate == false && file in backgroundExecutor`.
|
* - invalid, in queue. `cache[file]?.upToDate == false && file in backgroundExecutor`.
|
||||||
* - invalid, loading. `cache[file]?.upToDate == false && file !in backgroundExecutor`.
|
* - invalid, loading. `cache[file]?.upToDate == false && file !in backgroundExecutor`.
|
||||||
* - invalid, waiting for apply. `cache[file]?.upToDate == false && file !in backgroundExecutor` and has notification panel?
|
* - invalid, waiting for apply. `cache[file]?.upToDate == false && file !in backgroundExecutor` and has notification panel?
|
||||||
|
* - invalid, waiting for update. `cache[file]?.upToDate == false` and has notification panel
|
||||||
*
|
*
|
||||||
* Async:
|
* Async:
|
||||||
* - up-to-date: [reloadOutOfDateConfiguration] will not be called.
|
* - up-to-date: [reloadOutOfDateConfiguration] will not be called.
|
||||||
@@ -151,6 +153,8 @@ internal class DefaultScriptConfigurationManager(project: Project) :
|
|||||||
* - `invalid, waiting for apply`:
|
* - `invalid, waiting for apply`:
|
||||||
* Loading will not be queued, since we are marking file as up-to-date with
|
* Loading will not be queued, since we are marking file as up-to-date with
|
||||||
* not yet applied configuration.
|
* not yet applied configuration.
|
||||||
|
* - `invalid, waiting for update`:
|
||||||
|
* Loading wasn't started, only notification is shown
|
||||||
*
|
*
|
||||||
* Sync:
|
* Sync:
|
||||||
* - up-to-date:
|
* - up-to-date:
|
||||||
@@ -163,7 +167,8 @@ internal class DefaultScriptConfigurationManager(project: Project) :
|
|||||||
file: KtFile,
|
file: KtFile,
|
||||||
isFirstLoad: Boolean,
|
isFirstLoad: Boolean,
|
||||||
loadEvenWillNotBeApplied: Boolean,
|
loadEvenWillNotBeApplied: Boolean,
|
||||||
forceSync: Boolean
|
forceSync: Boolean,
|
||||||
|
isPostponedLoad: Boolean
|
||||||
) {
|
) {
|
||||||
val virtualFile = file.originalFile.virtualFile ?: return
|
val virtualFile = file.originalFile.virtualFile ?: return
|
||||||
|
|
||||||
@@ -171,6 +176,8 @@ internal class DefaultScriptConfigurationManager(project: Project) :
|
|||||||
val shouldLoad = isFirstLoad || loadEvenWillNotBeApplied || autoReloadEnabled
|
val shouldLoad = isFirstLoad || loadEvenWillNotBeApplied || autoReloadEnabled
|
||||||
if (!shouldLoad) return
|
if (!shouldLoad) return
|
||||||
|
|
||||||
|
val postponeLoading = isPostponedLoad && !autoReloadEnabled
|
||||||
|
|
||||||
if (!ScriptDefinitionsManager.getInstance(project).isReady()) return
|
if (!ScriptDefinitionsManager.getInstance(project).isReady()) return
|
||||||
val scriptDefinition = file.findScriptDefinition() ?: return
|
val scriptDefinition = file.findScriptDefinition() ?: return
|
||||||
|
|
||||||
@@ -178,28 +185,46 @@ internal class DefaultScriptConfigurationManager(project: Project) :
|
|||||||
|
|
||||||
val syncLoader = sync.firstOrNull { it.loadDependencies(isFirstLoad, file, scriptDefinition, loadingContext) }
|
val syncLoader = sync.firstOrNull { it.loadDependencies(isFirstLoad, file, scriptDefinition, loadingContext) }
|
||||||
if (syncLoader == null) {
|
if (syncLoader == null) {
|
||||||
// run async loader
|
|
||||||
if (forceSync) {
|
if (forceSync) {
|
||||||
async.firstOrNull { it.loadDependencies(isFirstLoad, file, scriptDefinition, loadingContext) }
|
loaders.firstOrNull { it.loadDependencies(isFirstLoad, file, scriptDefinition, loadingContext) }
|
||||||
} else {
|
} else {
|
||||||
backgroundExecutor.ensureScheduled(virtualFile) {
|
if (postponeLoading) {
|
||||||
val cached = getCachedConfigurationState(virtualFile)
|
ScriptConfigurationNotificationFactory.NOTIFICATION_FACTORY.getPoint(project).extensionList.firstOrNull {
|
||||||
|
it.showNotification(virtualFile, project) {
|
||||||
val applied = cached?.applied
|
runAsyncLoaders(file, virtualFile, scriptDefinition, async, postponeLoading)
|
||||||
if (applied != null && applied.inputs.isUpToDate(project, virtualFile)) {
|
}
|
||||||
// in case user reverted to applied configuration
|
|
||||||
suggestOrSaveConfiguration(virtualFile, applied, false)
|
|
||||||
} 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)
|
|
||||||
val actualIsFirstLoad = cached == null
|
|
||||||
async.firstOrNull { it.loadDependencies(actualIsFirstLoad, file, scriptDefinition, loadingContext) }
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
runAsyncLoaders(file, virtualFile, scriptDefinition, async, postponeLoading)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// в нотификации остается старый колбек - нужно перезаписывать колбек
|
||||||
|
private fun runAsyncLoaders(
|
||||||
|
file: KtFile,
|
||||||
|
virtualFile: VirtualFile,
|
||||||
|
scriptDefinition: ScriptDefinition,
|
||||||
|
loaders: List<ScriptConfigurationLoader>,
|
||||||
|
isLoadingPostponed: Boolean
|
||||||
|
) {
|
||||||
|
backgroundExecutor.ensureScheduled(virtualFile) {
|
||||||
|
val cached = getCachedConfigurationState(virtualFile)
|
||||||
|
|
||||||
|
val applied = cached?.applied
|
||||||
|
if (applied != null && applied.inputs.isUpToDate(project, virtualFile)) {
|
||||||
|
// in case user reverted to applied configuration
|
||||||
|
suggestOrSaveConfiguration(virtualFile, applied, isLoadingPostponed)
|
||||||
|
} 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)
|
||||||
|
val actualIsFirstLoad = cached == null
|
||||||
|
loaders.firstOrNull { it.loadDependencies(actualIsFirstLoad, file, scriptDefinition, loadingContext) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun forceReloadConfiguration(file: KtFile, loader: ScriptConfigurationLoader) {
|
override fun forceReloadConfiguration(file: KtFile, loader: ScriptConfigurationLoader) {
|
||||||
val virtualFile = file.originalFile.virtualFile ?: return
|
val virtualFile = file.originalFile.virtualFile ?: return
|
||||||
|
|
||||||
@@ -251,6 +276,10 @@ internal class DefaultScriptConfigurationManager(project: Project) :
|
|||||||
|
|
||||||
setLoadedConfiguration(file, newResult)
|
setLoadedConfiguration(file, newResult)
|
||||||
|
|
||||||
|
ScriptConfigurationNotificationFactory.NOTIFICATION_FACTORY.getPoint(project).extensionList.firstOrNull {
|
||||||
|
it.hideNotification(file, project)
|
||||||
|
}
|
||||||
|
|
||||||
val newConfiguration = newResult.configuration
|
val newConfiguration = newResult.configuration
|
||||||
if (newConfiguration == null) {
|
if (newConfiguration == null) {
|
||||||
saveReports(file, newResult.reports)
|
saveReports(file, newResult.reports)
|
||||||
|
|||||||
+5
@@ -28,4 +28,9 @@ interface ScriptConfigurationUpdater {
|
|||||||
* Invalidate current configuration
|
* Invalidate current configuration
|
||||||
*/
|
*/
|
||||||
fun postponeConfigurationReload(scope: ScriptConfigurationCacheScope)
|
fun postponeConfigurationReload(scope: ScriptConfigurationCacheScope)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Suggest to update script configuration if configuration for [file] is out of date
|
||||||
|
*/
|
||||||
|
fun suggestToUpdateConfigurationIfOutOfDate(file: KtFile)
|
||||||
}
|
}
|
||||||
+3
-1
@@ -78,7 +78,9 @@ class GradleScriptConfigurationLoader(project: Project) : DefaultScriptConfigura
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.loadDependencies(isFirstLoad, ktFile, scriptDefinition, context)
|
val result = getConfigurationThroughScriptingApi(ktFile, vFile, scriptDefinition)
|
||||||
|
context.saveNewConfiguration(vFile, result)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getInputsStamp(virtualFile: VirtualFile, file: KtFile): CachedConfigurationInputs {
|
override fun getInputsStamp(virtualFile: VirtualFile, file: KtFile): CachedConfigurationInputs {
|
||||||
|
|||||||
+2
-2
@@ -22,7 +22,7 @@ open class GradleScriptListener(project: Project) : ScriptChangeListener(project
|
|||||||
// do nothing
|
// do nothing
|
||||||
} else {
|
} else {
|
||||||
val file = getAnalyzableKtFileForScript(vFile) ?: return
|
val file = getAnalyzableKtFileForScript(vFile) ?: return
|
||||||
updater.ensureUpToDatedConfigurationSuggested(file)
|
updater.suggestToUpdateConfigurationIfOutOfDate(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ open class GradleScriptListener(project: Project) : ScriptChangeListener(project
|
|||||||
val file = getAnalyzableKtFileForScript(vFile)
|
val file = getAnalyzableKtFileForScript(vFile)
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
// *.gradle.kts file was changed
|
// *.gradle.kts file was changed
|
||||||
updater.ensureUpToDatedConfigurationSuggested(file)
|
updater.suggestToUpdateConfigurationIfOutOfDate(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,10 @@
|
|||||||
interface="org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptChangeListener"
|
interface="org.jetbrains.kotlin.idea.core.script.configuration.listener.ScriptChangeListener"
|
||||||
area="IDEA_PROJECT"/>
|
area="IDEA_PROJECT"/>
|
||||||
|
|
||||||
|
<extensionPoint qualifiedName="org.jetbrains.kotlin.scripting.idea.notificationFactory"
|
||||||
|
interface="org.jetbrains.kotlin.idea.core.script.ScriptConfigurationNotificationFactory"
|
||||||
|
area="IDEA_PROJECT"/>
|
||||||
|
|
||||||
<extensionPoint qualifiedName="org.jetbrains.kotlin.additionalExtractableAnalyser"
|
<extensionPoint qualifiedName="org.jetbrains.kotlin.additionalExtractableAnalyser"
|
||||||
interface="org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.AdditionalExtractableAnalyser"/>
|
interface="org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.AdditionalExtractableAnalyser"/>
|
||||||
|
|
||||||
@@ -101,6 +105,11 @@
|
|||||||
<scriptDefinitionsProvider id="MainKtsScriptDefinitionSource"
|
<scriptDefinitionsProvider id="MainKtsScriptDefinitionSource"
|
||||||
implementation="org.jetbrains.kotlin.idea.script.MainKtsScriptDefinitionSource"/>
|
implementation="org.jetbrains.kotlin.idea.script.MainKtsScriptDefinitionSource"/>
|
||||||
|
|
||||||
|
<scripting.idea.notificationFactory
|
||||||
|
implementation="org.jetbrains.kotlin.idea.core.script.DefaultScriptConfigurationNotificationFactory"
|
||||||
|
order="last"
|
||||||
|
/>
|
||||||
|
|
||||||
<idePlatformKindResolution implementation="org.jetbrains.kotlin.caches.resolve.JvmPlatformKindResolution"/>
|
<idePlatformKindResolution implementation="org.jetbrains.kotlin.caches.resolve.JvmPlatformKindResolution"/>
|
||||||
<idePlatformKindResolution implementation="org.jetbrains.kotlin.caches.resolve.JsPlatformKindResolution"/>
|
<idePlatformKindResolution implementation="org.jetbrains.kotlin.caches.resolve.JsPlatformKindResolution"/>
|
||||||
<idePlatformKindResolution implementation="org.jetbrains.kotlin.caches.resolve.CommonPlatformKindResolution"/>
|
<idePlatformKindResolution implementation="org.jetbrains.kotlin.caches.resolve.CommonPlatformKindResolution"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user