From 639231bb6c851f3b1da6c9866cc4acc993212a88 Mon Sep 17 00:00:00 2001 From: InSyncWithFoo Date: Thu, 9 May 2024 01:23:00 +0000 Subject: [PATCH] Allow configuring targeted file extensions (#35) --- .../configuration/AllConfigurations.kt | 7 +++++-- .../pyrightls/configuration/UIExtensions.kt | 5 ++++- .../project/ConfigurationPanel.kt | 18 ++++++++++++++++++ .../configuration/project/Configurations.kt | 18 ++++++++++++++++++ .../pyrightls/server/PyrightLSDescriptor.kt | 4 +++- .../resources/messages/pyrightls.properties | 3 +++ .../configuration/ConfigurationFieldsTest.kt | 3 ++- 7 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/AllConfigurations.kt b/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/AllConfigurations.kt index 4dddf5a..2e53d7f 100644 --- a/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/AllConfigurations.kt +++ b/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/AllConfigurations.kt @@ -1,6 +1,7 @@ package com.insyncwithfoo.pyrightls.configuration import com.insyncwithfoo.pyrightls.configuration.application.LogLevel +import com.insyncwithfoo.pyrightls.configuration.project.DelimitedFileExtensions import com.insyncwithfoo.pyrightls.configuration.project.WorkspaceFolders import org.jetbrains.annotations.SystemDependent import com.insyncwithfoo.pyrightls.configuration.application.Configurations as ApplicationConfigurations @@ -26,7 +27,8 @@ internal infix fun ApplicationConfigurations.mergeWith(other: ProjectConfigurati projectExecutable = other.projectExecutable, autoSuggestExecutable = other.autoSuggestExecutable, - workspaceFolders = other.workspaceFolders + workspaceFolders = other.workspaceFolders, + targetedFileExtensions = other.targetedFileExtensions ) @@ -48,7 +50,8 @@ internal data class AllConfigurations( val projectExecutable: @SystemDependent String?, val autoSuggestExecutable: Boolean, - val workspaceFolders: WorkspaceFolders + val workspaceFolders: WorkspaceFolders, + val targetedFileExtensions: DelimitedFileExtensions? ) { val executable: @SystemDependent String? get() = when { diff --git a/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/UIExtensions.kt b/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/UIExtensions.kt index 35a9ca5..9247c42 100644 --- a/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/UIExtensions.kt +++ b/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/UIExtensions.kt @@ -30,7 +30,7 @@ internal fun Cell.ensureComment() = this.apply { } -internal fun Row.secondColumnPathInput() = textFieldWithBrowseButton().apply { +internal fun Cell.asSecondColumnInput() = this.apply { ensureComment() gap(RightGap.SMALL) @@ -39,6 +39,9 @@ internal fun Row.secondColumnPathInput() = textFieldWithBrowseButton().apply { } +internal fun Row.secondColumnPathInput() = textFieldWithBrowseButton().asSecondColumnInput() + + internal fun Cell.bindText(property: KMutableProperty0) = bindText({ property.get().orEmpty() }, property::set) diff --git a/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/project/ConfigurationPanel.kt b/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/project/ConfigurationPanel.kt index 9f273f9..05e8dc4 100644 --- a/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/project/ConfigurationPanel.kt +++ b/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/project/ConfigurationPanel.kt @@ -1,6 +1,7 @@ package com.insyncwithfoo.pyrightls.configuration.project import com.insyncwithfoo.pyrightls.configuration.Hint +import com.insyncwithfoo.pyrightls.configuration.asSecondColumnInput import com.insyncwithfoo.pyrightls.configuration.bindText import com.insyncwithfoo.pyrightls.configuration.displayPathHint import com.insyncwithfoo.pyrightls.configuration.executablePathResolvingHint @@ -14,11 +15,14 @@ import com.intellij.openapi.ui.ComboBox import com.intellij.openapi.ui.TextFieldWithBrowseButton import com.intellij.ui.SimpleListCellRenderer import com.intellij.ui.components.JBCheckBox +import com.intellij.ui.components.fields.ExpandableTextField import com.intellij.ui.dsl.builder.Cell import com.intellij.ui.dsl.builder.Row import com.intellij.ui.dsl.builder.bindItem import com.intellij.ui.dsl.builder.bindSelected +import com.intellij.ui.dsl.builder.bindText import com.intellij.ui.dsl.builder.panel +import com.intellij.ui.dsl.builder.toNonNullableProperty import com.intellij.ui.dsl.builder.toNullableProperty @@ -43,6 +47,14 @@ private fun Row.makeWorkspaceFoldersInput(block: Cell } +private fun Row.makeFileExtensionsInput(block: Cell.() -> Unit) { + val parser = DelimitedFileExtensions::split + val joiner = TargetedFileExtensions::join + + expandableTextField(parser, joiner).asSecondColumnInput().apply(block) +} + + internal fun Configurable.configurationPanel(state: Configurations) = panel { // FIXME: The onInput() callbacks are too deeply nested. @@ -66,6 +78,12 @@ internal fun Configurable.configurationPanel(state: Configurations) = panel { @Suppress("DialogTitleCapitalization") group(message("configurations.group.languageServer")) { + row(message("configurations.targetedFileExtensions.label")) { + makeFileExtensionsInput { + comment(message("configurations.targetedFileExtensions.comment")) + bindText(state::targetedFileExtensions.toNonNullableProperty(defaultValue = "")) + } + } row(message("configurations.workspaceFolders.label")) { makeWorkspaceFoldersInput { bindItem(state::workspaceFolders.toNullableProperty()) } } diff --git a/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/project/Configurations.kt b/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/project/Configurations.kt index 728f44c..67f26e7 100644 --- a/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/project/Configurations.kt +++ b/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/project/Configurations.kt @@ -4,6 +4,23 @@ import com.insyncwithfoo.pyrightls.message import com.intellij.openapi.components.BaseState +internal typealias DelimitedFileExtensions = String +internal typealias TargetedFileExtensions = List + + +internal const val fileExtensionsDelimiter = "|" + + +internal fun DelimitedFileExtensions.split(): MutableList { + return this.split(fileExtensionsDelimiter).mapTo(mutableListOf()) { it.trim().lowercase() } +} + + +internal fun TargetedFileExtensions.join(): String { + return this.joinToString(fileExtensionsDelimiter) { it.trim().lowercase() } +} + + internal enum class WorkspaceFolders(val label: String) { PROJECT_BASE(message("configurations.workspaceFolders.projectBase")), SOURCE_ROOTS(message("configurations.workspaceFolders.sourceRoots")); @@ -14,4 +31,5 @@ internal class Configurations : BaseState() { var projectExecutable by string(null) var autoSuggestExecutable by property(true) var workspaceFolders by enum(WorkspaceFolders.PROJECT_BASE) + var targetedFileExtensions by string("py") } diff --git a/src/main/kotlin/com/insyncwithfoo/pyrightls/server/PyrightLSDescriptor.kt b/src/main/kotlin/com/insyncwithfoo/pyrightls/server/PyrightLSDescriptor.kt index ac754a6..3381501 100644 --- a/src/main/kotlin/com/insyncwithfoo/pyrightls/server/PyrightLSDescriptor.kt +++ b/src/main/kotlin/com/insyncwithfoo/pyrightls/server/PyrightLSDescriptor.kt @@ -1,6 +1,7 @@ package com.insyncwithfoo.pyrightls.server import com.insyncwithfoo.pyrightls.configuration.project.WorkspaceFolders +import com.insyncwithfoo.pyrightls.configuration.project.split import com.insyncwithfoo.pyrightls.message import com.insyncwithfoo.pyrightls.path import com.insyncwithfoo.pyrightls.pyrightLSConfigurations @@ -50,7 +51,8 @@ internal class PyrightLSDescriptor(project: Project, private val executable: Pat LOGGER.info(configurations.toString()) } - override fun isSupportedFile(file: VirtualFile) = file.isSupported + override fun isSupportedFile(file: VirtualFile) = + file.extension in configurations.targetedFileExtensions.orEmpty().split() override fun createCommandLine() = GeneralCommandLine(executable.toString(), "--stdio").apply { diff --git a/src/main/resources/messages/pyrightls.properties b/src/main/resources/messages/pyrightls.properties index 4cb994f..52da17b 100644 --- a/src/main/resources/messages/pyrightls.properties +++ b/src/main/resources/messages/pyrightls.properties @@ -36,6 +36,9 @@ configurations.workspaceFolders.label = Workspace folders: configurations.workspaceFolders.projectBase = Project base directories configurations.workspaceFolders.sourceRoots = Source roots +configurations.targetedFileExtensions.label = Targeted file extensions: +configurations.targetedFileExtensions.comment = List of extensions of files on which the language server should be run. + configurations.hint.fileFound = File found configurations.hint.fileNotExecutable = File is not executable configurations.hint.fileNotFound = No file found at given path diff --git a/src/test/kotlin/com/insyncwithfoo/pyrightls/configuration/ConfigurationFieldsTest.kt b/src/test/kotlin/com/insyncwithfoo/pyrightls/configuration/ConfigurationFieldsTest.kt index b50d5c0..c554a62 100644 --- a/src/test/kotlin/com/insyncwithfoo/pyrightls/configuration/ConfigurationFieldsTest.kt +++ b/src/test/kotlin/com/insyncwithfoo/pyrightls/configuration/ConfigurationFieldsTest.kt @@ -47,13 +47,14 @@ class ConfigurationFieldsTest : TestCase() { fun `test defaults - project`() { val configurations = ProjectConfigurations() - assertEquals(3, projectFields().size) + assertEquals(4, projectFields().size) configurations.run { assertEquals(null, projectExecutable) assertEquals(true, autoSuggestExecutable) assertEquals(WorkspaceFolders.PROJECT_BASE, workspaceFolders) + assertEquals("py", targetedFileExtensions) } }