[kotlin] KTIJ-35580 rework definition settings model

(cherry picked from commit 7d31457810d87d63ff886bb5f1c0a9dd9fd044fa)

IJ-CR-179206

GitOrigin-RevId: c6257349264b713ca462fe1ebefd88f91b0cb201
This commit is contained in:
Vlad Koshkin
2025-10-21 14:08:15 +00:00
committed by intellij-monorepo-bot
parent 4ffd5876e8
commit 4b7cc5fe6a
2 changed files with 88 additions and 94 deletions
@@ -7,40 +7,34 @@ import com.intellij.ui.BooleanTableCellRenderer
import com.intellij.util.ui.ColumnInfo
import com.intellij.util.ui.ListTableModel
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate
import javax.swing.JTable
data class ScriptDefinitionModel(
val definition: ScriptDefinition,
val id: String,
val name: String,
val pattern: String,
val canBeSwitchedOff: Boolean,
var isEnabled: Boolean,
)
class KotlinScriptDefinitionsModel(definitions: MutableList<ScriptDefinitionModel>) :
ListTableModel<ScriptDefinitionModel>(
arrayOf(
ScriptDefinitionName(),
ScriptDefinitionPattern(),
ScriptDefinitionIsEnabled(),
),
definitions,
0
) {
class ScriptDefinitionTable(definitions: MutableList<ScriptDefinitionModel>) : ListTableModel<ScriptDefinitionModel>(
arrayOf(
ScriptDefinitionName(),
ScriptDefinitionPattern(),
ScriptDefinitionIsEnabled(),
), definitions, 0
) {
private class ScriptDefinitionName : ColumnInfo<ScriptDefinitionModel, String>(
KotlinBundle.message("kotlin.script.definitions.model.name.name")
) {
override fun valueOf(item: ScriptDefinitionModel) = item.definition.name
override fun valueOf(item: ScriptDefinitionModel) = item.name
}
private class ScriptDefinitionPattern : ColumnInfo<ScriptDefinitionModel, String>(
KotlinBundle.message("kotlin.script.definitions.model.name.pattern.extension")
) {
override fun valueOf(item: ScriptDefinitionModel): String =
item.definition.asLegacyOrNull<KotlinScriptDefinitionFromAnnotatedTemplate>()?.scriptFilePattern?.pattern
?: (item.definition as? ScriptDefinition.FromConfigurationsBase)?.fileNamePattern
?: (item.definition as? ScriptDefinition.FromConfigurationsBase)?.filePathPattern
?: ("." + item.definition.fileExtension)
override fun valueOf(item: ScriptDefinitionModel): String = item.pattern
}
private class ScriptDefinitionIsEnabled :
@@ -54,8 +48,6 @@ class KotlinScriptDefinitionsModel(definitions: MutableList<ScriptDefinitionMode
item.isEnabled = value
}
override fun isCellEditable(item: ScriptDefinitionModel): Boolean {
return item.definition.canDefinitionBeSwitchedOff
}
override fun isCellEditable(item: ScriptDefinitionModel): Boolean = item.canBeSwitchedOff
}
}
@@ -21,118 +21,120 @@ import org.jetbrains.kotlin.idea.core.script.k2.settings.ScriptDefinitionPersist
import org.jetbrains.kotlin.idea.core.script.shared.KOTLIN_SCRIPTING_SETTINGS_ID
import org.jetbrains.kotlin.idea.core.script.shared.KotlinBaseScriptingBundle
import org.jetbrains.kotlin.idea.core.script.shared.scriptDefinitionsSourceOfType
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate
import javax.swing.JComponent
import javax.swing.JPanel
import javax.swing.ListSelectionModel
internal class KotlinScriptingSettingsConfigurable(val project: Project, val coroutineScope: CoroutineScope) : SearchableConfigurable {
private var model = calculateModel()
private val definitionsFromClassPathTitle: AtomicProperty<String> = AtomicProperty("")
private fun calculateModel(): KotlinScriptDefinitionsModel {
private var persistedModels = calculateModels()
private var currentModels = persistedModels.deepCopy()
private fun List<ScriptDefinitionModel>.deepCopy(): MutableList<ScriptDefinitionModel> = map { it.copy() }.toMutableList()
override fun isModified(): Boolean = persistedModels != currentModels
private fun calculateModels(): MutableList<ScriptDefinitionModel> {
val settingsProvider = ScriptDefinitionPersistentSettings.getInstance(project)
val definitions = ScriptDefinitionProviderImpl.getInstance(project).definitionsFromSources
return ScriptDefinitionProviderImpl.getInstance(project).definitionsFromSources
.sortedBy { settingsProvider.getScriptDefinitionOrder(it) }
.map {
ScriptDefinitionModel(
it,
settingsProvider.isScriptDefinitionEnabled(it)
id = it.definitionId,
name = it.name,
pattern = it.asLegacyOrNull<KotlinScriptDefinitionFromAnnotatedTemplate>()?.scriptFilePattern?.pattern
?: (it as? ScriptDefinition.FromConfigurationsBase)?.fileNamePattern
?: (it as? ScriptDefinition.FromConfigurationsBase)?.filePathPattern
?: ("." + it.fileExtension),
canBeSwitchedOff = it.canDefinitionBeSwitchedOff,
isEnabled = settingsProvider.isScriptDefinitionEnabled(it)
)
}.toMutableList()
return KotlinScriptDefinitionsModel(definitions)
}
override fun createComponent(): JComponent = panel {
row(message("kotlin.script.definitions.title")) {}
row {
cell(getDefinitionsTable())
.align(Align.FILL)
rowComment(message("text.first.definition.that.matches.script.pattern.extension.applied.starting.from.top"))
}
row {
button(KotlinBaseScriptingBundle.message("button.scan.classpath")) {
coroutineScope.launch {
val definitionsFromClassPath = withBackgroundProgress(
project,
title = KotlinBaseScriptingBundle.message("looking.for.script.definitions.in.classpath")
) {
project.scriptDefinitionsSourceOfType<ScriptTemplatesFromDependenciesDefinitionSource>()?.scanAndLoadDefinitions()
} ?: emptyList()
if (definitionsFromClassPath.isEmpty()) {
definitionsFromClassPathTitle.set(KotlinBaseScriptingBundle.message("label.kotlin.script.no.definitions.found"))
} else {
definitionsFromClassPathTitle.set(
KotlinBaseScriptingBundle.message(
"label.kotlin.script.definitions.found",
definitionsFromClassPath.size
)
)
}
enabled(false)
EditorNotifications.getInstance(project).updateAllNotifications()
override fun reset() {
if (isModified) {
persistedModels.forEach { persisted ->
currentModels.find { it.id == persisted.id }?.let { current ->
current.isEnabled = persisted.isEnabled
}
}
label("").bindText(definitionsFromClassPathTitle)
currentModels.sortBy { current ->
persistedModels.indexOfFirst { it.id == current.id }
}
}
}
private fun getDefinitionsTable(): JPanel {
val table = TableView(model).apply {
override fun createComponent(): JComponent {
val view = TableView(ScriptDefinitionTable(currentModels)).apply {
visibleRowCount = 10
showVerticalLines = false
setSelectionMode(ListSelectionModel.SINGLE_SELECTION)
setEmptyState(message("status.text.no.definitions"))
}
return ToolbarDecorator.createDecorator(table)
val decorator = ToolbarDecorator.createDecorator(view)
.disableAddAction()
.disableRemoveAction()
.createPanel()
return panel {
row(message("kotlin.script.definitions.title")) {}
row {
cell(decorator)
.align(Align.FILL)
rowComment(message("text.first.definition.that.matches.script.pattern.extension.applied.starting.from.top"))
}
row {
button(KotlinBaseScriptingBundle.message("button.scan.classpath")) {
coroutineScope.launch {
val definitionsFromClassPath = withBackgroundProgress(
project,
title = KotlinBaseScriptingBundle.message("looking.for.script.definitions.in.classpath")
) {
project.scriptDefinitionsSourceOfType<ScriptTemplatesFromDependenciesDefinitionSource>()
?.scanAndLoadDefinitions()
} ?: emptyList()
if (definitionsFromClassPath.isEmpty()) {
definitionsFromClassPathTitle.set(KotlinBaseScriptingBundle.message("label.kotlin.script.no.definitions.found"))
} else {
definitionsFromClassPathTitle.set(
KotlinBaseScriptingBundle.message(
"label.kotlin.script.definitions.found",
definitionsFromClassPath.size
)
)
}
enabled(false)
EditorNotifications.getInstance(project).updateAllNotifications()
}
}
label("").bindText(definitionsFromClassPathTitle)
}
}
}
override fun isModified(): Boolean = isScriptDefinitionsChanged()
override fun apply() {
if (isScriptDefinitionsChanged()) {
val settings = model.items.map {
if (isModified) {
val settings = currentModels.map {
ScriptDefinitionSetting(
it.definition.name,
it.definition.definitionId,
it.name,
it.id,
it.isEnabled
)
}
ScriptDefinitionPersistentSettings.getInstance(project).setSettings(settings)
model = calculateModel()
persistedModels = calculateModels()
}
}
private fun isScriptDefinitionsChanged(): Boolean {
val settings = ScriptDefinitionPersistentSettings.getInstance(project).state.settings
if (model.items.size != settings.size) {
return true
}
for (i in 0..<model.items.size) {
val setting = settings[i]
val modelItem = model.items[i]
if (setting.definitionId != modelItem.definition.definitionId
|| setting.name != modelItem.definition.name
|| setting.enabled != modelItem.isEnabled
) {
return true
}
}
return false
}
override fun getDisplayName(): String = message("script.name.kotlin.scripting")
override fun getId(): String = KOTLIN_SCRIPTING_SETTINGS_ID