From 9efacf56cec68f8cd766c82cd80b5bd1343a01d7 Mon Sep 17 00:00:00 2001 From: InSyncWithFoo Date: Sat, 22 Jun 2024 09:17:34 +0000 Subject: [PATCH] Make all monkeypatches optional --- CHANGELOG.md | 10 ++++---- CHANGELOG_CODE.md | 2 +- build.gradle.kts | 2 +- .../configuration/AllConfigurations.kt | 4 ++++ .../configuration/PathResolvingHint.kt | 1 - .../application/ConfigurationPanel.kt | 24 +++++++++++++++++-- .../application/Configurations.kt | 2 ++ .../project/ConfigurationPanel.kt | 2 -- .../pyrightls/server/CompletionSupport.kt | 18 +++++++++++--- .../pyrightls/server/Listener.kt | 6 ++--- .../pyrightls/server/Settings.kt | 16 +++++++++---- .../resources/messages/pyrightls.properties | 5 ++++ 12 files changed, 71 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e4d17b..e444e3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ For code changes, see [`CHANGELOG_CODE.md`][_-1]. * The list of recognized file extensions can now be configured and includes `py` and `pyi` by default. Previously, only `.py` files are recognized. +* PyCharm has a bug leading to extra quotes being added + when autocompleting `Literal` strings and `TypedDict` keys. + A monkeypatch has been added to mitigate the issues. + It can be disabled using an UI option. * The diagnostic mode is now configurable. Previously, no corresponding value is sent to the language server. * The server can now be asked not to @@ -24,10 +28,8 @@ For code changes, see [`CHANGELOG_CODE.md`][_-1]. ### Changed -* PyCharm has a bug leading to extra quotes being added - when autocompleting `Literal` strings and `TypedDict` keys. - A monkeypatch has been added to mitigate the issues. - This patch might be reverted in the future, when the bug is fixed. +* The "Auto-import" completion item detail monkeypatch + introduced in the previous version can now be disabled. ## [0.5.0] - 2024-05-27 diff --git a/CHANGELOG_CODE.md b/CHANGELOG_CODE.md index 1aaadcd..68c4572 100644 --- a/CHANGELOG_CODE.md +++ b/CHANGELOG_CODE.md @@ -16,7 +16,7 @@ For user-facing changes, see [`CHANGELOG.md`][_-1]. * Project option "Targeted file extensions" is added. (d5c69dbb, 541c5630) * Project option "Diagnostic mode" is added. (553c2ae2) -* Project option "Auto search paths" is added. (HEAD) +* Project option "Auto search paths" is added. (90b572b7) ### Changed diff --git a/build.gradle.kts b/build.gradle.kts index 22fc53a..6497986 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -129,7 +129,7 @@ kover { tasks { runIde { - // From https://app.slack.com/client/T5P9YATH9/C5U8BM1MK + // From https://app.slack.com/client/T5P9YATH9/C5U8BM1MK/1715448677.615749 systemProperty("ide.experimental.ui", "true") systemProperty("projectView.hide.dot.idea", "false") systemProperty("terminal.new.ui", "false") diff --git a/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/AllConfigurations.kt b/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/AllConfigurations.kt index 1ed8fba..fb79e49 100644 --- a/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/AllConfigurations.kt +++ b/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/AllConfigurations.kt @@ -27,6 +27,8 @@ internal infix fun ApplicationConfigurations.mergeWith(other: ProjectConfigurati autocompleteParentheses = this.autocompleteParentheses, diagnosticsSupport = this.diagnosticsSupport, autoRestartServer = this.autoRestartServer, + monkeypatchAutoImportDetails = this.monkeypatchAutoImportDetails, + monkeypatchTrailingQuoteBug = this.monkeypatchTrailingQuoteBug, projectExecutable = other.projectExecutable, autoSuggestExecutable = other.autoSuggestExecutable, @@ -52,6 +54,8 @@ internal data class AllConfigurations( val autocompleteParentheses: Boolean, val diagnosticsSupport: Boolean, val autoRestartServer: Boolean, + val monkeypatchAutoImportDetails: Boolean, + val monkeypatchTrailingQuoteBug: Boolean, val projectExecutable: @SystemDependent String?, val autoSuggestExecutable: Boolean, diff --git a/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/PathResolvingHint.kt b/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/PathResolvingHint.kt index 6a5c177..f186ad4 100644 --- a/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/PathResolvingHint.kt +++ b/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/PathResolvingHint.kt @@ -10,7 +10,6 @@ import kotlin.io.path.isDirectory internal enum class HintIcon { Success, Info, Warning, Error; - // TODO: Re-add icons override fun toString() = "" } diff --git a/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/application/ConfigurationPanel.kt b/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/application/ConfigurationPanel.kt index 830a5bb..9c58a3f 100644 --- a/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/application/ConfigurationPanel.kt +++ b/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/application/ConfigurationPanel.kt @@ -10,6 +10,7 @@ import com.insyncwithfoo.pyrightls.configuration.secondColumnPathInput import com.insyncwithfoo.pyrightls.message import com.intellij.openapi.ui.ComboBox import com.intellij.openapi.ui.TextFieldWithBrowseButton +import com.intellij.openapi.util.text.HtmlChunk import com.intellij.ui.SimpleListCellRenderer import com.intellij.ui.components.JBCheckBox import com.intellij.ui.dsl.builder.Cell @@ -85,10 +86,21 @@ private fun Row.makeAutoRestartServerInput(block: Cell.() -> Unit) = checkBox(message("configurations.autoRestartServer.label")).apply(block) +private fun Row.makeMonkeypatchAutoImportDetailsInput(block: Cell.() -> Unit) = + checkBox(message("configurations.monkeypatchAutoImportDetails.label")).apply(block) + + +private fun Row.makeMonkeypatchTrailingQuoteBugInput(block: Cell.() -> Unit) = run { + val issueLink = HtmlChunk.link("https://youtrack.jetbrains.com/issue/IJPL-155741", " IJPL-155741") + val label = message("configurations.monkeypatchTrailingQuoteBug.label") + val comment = message("configurations.monkeypatchTrailingQuoteBug.comment", issueLink) + + checkBox(label).comment(comment).apply(block) +} + + @Suppress("DialogTitleCapitalization") internal fun configurationPanel(state: Configurations) = panel { - // FIXME: The onInput() callbacks are too deeply nested. - row { makeAlwaysUseGlobalInput { bindSelected(state::alwaysUseGlobal) } } @@ -133,9 +145,17 @@ internal fun configurationPanel(state: Configurations) = panel { row { makeAutoImportCompletionsInput { bindSelected(state::autoImportCompletions) } } + indent { + row { + makeMonkeypatchAutoImportDetailsInput { bindSelected(state::monkeypatchAutoImportDetails) } + } + } row { makeAutocompleteParenthesesInput { bindSelected(state::autocompleteParentheses) } } + row { + makeMonkeypatchTrailingQuoteBugInput { bindSelected(state::monkeypatchTrailingQuoteBug) } + } } row { diff --git a/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/application/Configurations.kt b/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/application/Configurations.kt index 9af5b85..3692471 100644 --- a/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/application/Configurations.kt +++ b/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/application/Configurations.kt @@ -27,4 +27,6 @@ internal class Configurations : BaseState() { var autocompleteParentheses by property(false) var diagnosticsSupport by property(true) var autoRestartServer by property(false) + var monkeypatchAutoImportDetails by property(true) + var monkeypatchTrailingQuoteBug by property(true) } 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 1c944eb..05ab22b 100644 --- a/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/project/ConfigurationPanel.kt +++ b/src/main/kotlin/com/insyncwithfoo/pyrightls/configuration/project/ConfigurationPanel.kt @@ -68,8 +68,6 @@ private fun Row.makeAutoSearchPathsInput(block: Cell.() -> Unit) = internal fun Configurable.configurationPanel(state: Configurations) = panel { - // FIXME: The onInput() callbacks are too deeply nested. - row { makeAutoSuggestExecutableInput { bindSelected(state::autoSuggestExecutable) } } diff --git a/src/main/kotlin/com/insyncwithfoo/pyrightls/server/CompletionSupport.kt b/src/main/kotlin/com/insyncwithfoo/pyrightls/server/CompletionSupport.kt index 08cde1b..3f23389 100644 --- a/src/main/kotlin/com/insyncwithfoo/pyrightls/server/CompletionSupport.kt +++ b/src/main/kotlin/com/insyncwithfoo/pyrightls/server/CompletionSupport.kt @@ -9,6 +9,7 @@ import com.intellij.platform.lsp.api.customization.LspCompletionSupport import org.eclipse.lsp4j.CompletionItem import org.eclipse.lsp4j.CompletionItemKind import org.eclipse.lsp4j.InsertTextFormat +import org.eclipse.lsp4j.TextEdit private const val CARET_POSITION = "\$0" @@ -51,6 +52,11 @@ private val CompletionParameters.followingCharacters: CharSequence get() = editor.document.charsSequence.slice(offset..offset + 2) +private fun CompletionParameters.itemMightTriggerTrailingQuoteBug(item: CompletionItem): Boolean { + return item.isQuoted && followingCharacters.startsWith(item.quoteSequence!!) +} + + private fun CompletionItem.completeWithParentheses() { insertText = "$label($CARET_POSITION)" insertTextFormat = InsertTextFormat.Snippet @@ -64,7 +70,13 @@ private fun CompletionItem.useSourceAsDetailIfPossible() { private fun CompletionItem.removeTrailingQuoteSequence() { - insertText = label.dropLast(quoteSequence!!.length) + val trailingQuoteSequence = quoteSequence!! + + insertText = label.removeSuffix(trailingQuoteSequence) + + (textEdit.get() as? TextEdit)?.apply { + newText = newText.removeSuffix(trailingQuoteSequence) + } } @@ -78,11 +90,11 @@ internal class CompletionSupport(project: Project) : LspCompletionSupport() { item.completeWithParentheses() } - if (item.isAutoImportCompletion) { + if (item.isAutoImportCompletion && configurations.monkeypatchAutoImportDetails) { item.useSourceAsDetailIfPossible() } - if (item.isQuoted && parameters.followingCharacters.startsWith(item.quoteSequence!!)) { + if (parameters.itemMightTriggerTrailingQuoteBug(item) && configurations.monkeypatchTrailingQuoteBug) { item.removeTrailingQuoteSequence() } diff --git a/src/main/kotlin/com/insyncwithfoo/pyrightls/server/Listener.kt b/src/main/kotlin/com/insyncwithfoo/pyrightls/server/Listener.kt index 9780b8a..5b7204e 100644 --- a/src/main/kotlin/com/insyncwithfoo/pyrightls/server/Listener.kt +++ b/src/main/kotlin/com/insyncwithfoo/pyrightls/server/Listener.kt @@ -24,10 +24,10 @@ private val Project.osDependentInterpreterPath: String? private fun Project.createPyrightLSSettingsObject() = Settings().apply { val configurations = pyrightLSConfigurations - python.apply { + python { pythonPath = osDependentInterpreterPath - analysis.apply { + analysis { logLevel = configurations.logLevel.label autoImportCompletions = configurations.autoImportCompletions diagnosticMode = configurations.diagnosticMode.value @@ -35,7 +35,7 @@ private fun Project.createPyrightLSSettingsObject() = Settings().apply { } } - pyright.apply { + pyright { disableTaggedHints = !configurations.taggedHints } } diff --git a/src/main/kotlin/com/insyncwithfoo/pyrightls/server/Settings.kt b/src/main/kotlin/com/insyncwithfoo/pyrightls/server/Settings.kt index 6674b57..4ddd75e 100644 --- a/src/main/kotlin/com/insyncwithfoo/pyrightls/server/Settings.kt +++ b/src/main/kotlin/com/insyncwithfoo/pyrightls/server/Settings.kt @@ -1,23 +1,31 @@ package com.insyncwithfoo.pyrightls.server +private interface Builder + + +internal operator fun T.invoke(block: T.() -> Unit) { + this.apply(block) +} + + internal data class Analysis( var logLevel: String? = null, var autoImportCompletions: Boolean? = null, var diagnosticMode: String? = null, var autoSearchPaths: Boolean = true -) +) : Builder internal data class Python( var pythonPath: String? = null, val analysis: Analysis = Analysis() -) +) : Builder -internal data class Pyright( +internal class Pyright( var disableTaggedHints: Boolean? = null -) +) : Builder internal data class Settings( diff --git a/src/main/resources/messages/pyrightls.properties b/src/main/resources/messages/pyrightls.properties index 919085c..21a2f2b 100644 --- a/src/main/resources/messages/pyrightls.properties +++ b/src/main/resources/messages/pyrightls.properties @@ -29,6 +29,11 @@ configurations.logLevel.warning = Warning configurations.logLevel.information = Information configurations.logLevel.trace = Trace +configurations.monkeypatchAutoImportDetails.label = Display source for auto-import completions + +configurations.monkeypatchTrailingQuoteBug.label = Avoid inserting extraneous trailing quotes +configurations.monkeypatchTrailingQuoteBug.comment = YouTrack issue: {0} + configurations.projectExecutable.label = Project executable: configurations.autoSuggestExecutable.label = Suggest executable on project open