From 4822fa5066bf0986990fecaae2e6c4258a65df9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl?= Date: Sat, 3 Aug 2024 23:25:41 +0200 Subject: [PATCH] Enabling proper code generation for comments (Comment with Line/Block Comment) (#3582) * feat: enabling proper code generation for comments (toggleable, Comment with Line/Block Comment) * Add the correct ERL and elixir arguments for starting IEx depending on the version of elixir sdk * Bundle latest OtpErlang.jar from JInterface v1.14 for OTP v26 * Infer OTP_RELEASE & ERLANG_SDK_HOME if no environment variable is set (#3600) * Add compatibility for 2024.1 IDEs (#3569) * Update gradlewrapper to v7.6.4 ./gradlew wrapper --gradle-version=7.6.4 To fix gradle issue: https://github.com/gradle/gradle/issues/27156 * Remove use of `FileUtil.FILE_HASHING_STRATEGY` from Intellij FileUtil, it was removed in 2024.1. (Note, this is only used in the jps-build test suite). This also removes references to Trove THashSet, and no longer stores File directly in sets or collections. See https://github.com/JetBrains/intellij-community/commit/560e8fc36b7b889b0cd20b079560c374e86aa5c0 * Add support for 2024.1 IDEs (and runs tests correctly against 2024.1) * Update usages group wording for 2024.1 * Fix more sdk configuration commits in application RW thread, fixes compatibility with IDEs v2024.1 * Fix whitespace in tests due to 2024.1 change I believe 2024.1 changed how the Usages work. In 2023.x: ```kotlin val usages = myFixture.testFindUsagesUsingAction("module_attribute_usage.ex", "kernel.ex") .map { it as UsageInfo2UsageAdapter } ``` In the debugger shows: ``` 0 = {ReadWriteAccessUsageInfo2UsageAdapter@19239} "4|def usage, |do|: |@|module_attribute" 1 = {ReadWriteAccessUsageInfo2UsageAdapter@19240} "2|@|module_attribute| |1" ``` For 2024.1, this shows: ``` 0 = {ReadWriteAccessUsageInfo2UsageAdapter@19421} "2| |@module_attribute| 1" 1 = {ReadWriteAccessUsageInfo2UsageAdapter@19422} "4| def usage, do: |@module_attribute" ``` I believe it not shows the whitespace for the file, where previously it didn't. * pin versions * use BasePlatformTestCase to stop warning * add do block match test * set 241.0 as the version, to fix certain intellij warnings * fix key * revert tests * use thread --------- Co-authored-by: Josh Taylor * Add 18.0.0 changelog, fix version (#3602) * support only the newest version. * remove tests for now, kind of pointless --------- Co-authored-by: Ashley Sommer Co-authored-by: Josh Taylor --- .../formatter/settings/CodeGenerationPanel.kt | 91 +++++++++++++++++++ .../settings/ElixirCodeStyleMainPanel.kt | 3 +- .../LanguageCodeStyleSettingsProvider.kt | 10 +- src/org/elixir_lang/sdk/elixir/Type.kt | 28 +++--- 4 files changed, 116 insertions(+), 16 deletions(-) create mode 100644 src/org/elixir_lang/formatter/settings/CodeGenerationPanel.kt diff --git a/src/org/elixir_lang/formatter/settings/CodeGenerationPanel.kt b/src/org/elixir_lang/formatter/settings/CodeGenerationPanel.kt new file mode 100644 index 000000000..27d2591bf --- /dev/null +++ b/src/org/elixir_lang/formatter/settings/CodeGenerationPanel.kt @@ -0,0 +1,91 @@ +package org.elixir_lang.formatter.settings + +import com.intellij.application.options.CodeStyleAbstractPanel +import com.intellij.application.options.codeStyle.CommenterForm +import com.intellij.lang.Language +import com.intellij.openapi.editor.colors.EditorColorsScheme +import com.intellij.openapi.editor.highlighter.EditorHighlighter +import com.intellij.openapi.fileTypes.FileType +import com.intellij.openapi.fileTypes.FileTypeEditorHighlighterProviders +import com.intellij.openapi.util.NlsContexts.TabTitle +import com.intellij.psi.codeStyle.CodeStyleSettings +import com.intellij.psi.codeStyle.CodeStyleSettingsCustomizable.CommenterOption +import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider +import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider.SettingsType +import com.intellij.ui.IdeBorderFactory +import com.intellij.ui.components.JBScrollPane +import com.intellij.util.ui.JBInsets +import org.elixir_lang.ElixirFileType +import org.elixir_lang.ElixirLanguage +import javax.swing.BoxLayout +import javax.swing.JComponent +import javax.swing.JPanel + +class CodeGenerationPanel(settings: CodeStyleSettings) : CodeStyleAbstractPanel(settings) { + + private val panel: JPanel + private val myCommenterForm: CommenterForm = CommenterForm(ElixirLanguage) + private var myPanel: JComponent? = null + + init { + panel = JPanel().apply { + layout = BoxLayout(this, BoxLayout.Y_AXIS) + border = IdeBorderFactory.createEmptyBorder(JBInsets(0, 10, 10, 10)) + add(myCommenterForm.commenterPanel) + } + } + + override fun getFileType(): FileType = ElixirFileType.INSTANCE + + override fun getTabTitle(): @TabTitle String = "Code Generation" + + override fun getDefaultLanguage(): Language = ElixirLanguage + + override fun getRightMargin(): Int = 47 + + override fun getPreviewText(): String = LanguageCodeStyleSettingsProvider.forLanguage(ElixirLanguage)!! + .getCodeSample(SettingsType.LANGUAGE_SPECIFIC)!! + + override fun apply(settings: CodeStyleSettings) { + if (isModified(settings)) myCommenterForm.apply(settings) + } + + override fun isModified(settings: CodeStyleSettings): Boolean { + return myCommenterForm.isModified(settings) + } + + fun getPanelInner(): JComponent { + return panel + } + + override fun resetImpl(settings: CodeStyleSettings) { + myCommenterForm.reset(settings) + } + + override fun getPanel(): JComponent? { + if (myPanel == null) { + val contentPanel = getPanelInner() + myPanel = JBScrollPane(contentPanel) + } + return myPanel!! + } + + override fun createHighlighter(colors: EditorColorsScheme): EditorHighlighter { + val fileType: FileType = getFileType() + return FileTypeEditorHighlighterProviders.INSTANCE.forFileType(fileType) + .getEditorHighlighter(null, fileType, null, colors) + } + + companion object { + fun getSupportedCommenterStandardOptionNames(): MutableList { + val supportedCommenterStandardOptionNames = mutableListOf().apply { + add(CommenterOption.LINE_COMMENT_AT_FIRST_COLUMN.name) + add(CommenterOption.LINE_COMMENT_ADD_SPACE.name) + add(CommenterOption.LINE_COMMENT_ADD_SPACE_ON_REFORMAT.name) + add(CommenterOption.BLOCK_COMMENT_AT_FIRST_COLUMN.name) + add(CommenterOption.BLOCK_COMMENT_ADD_SPACE.name) + } + return supportedCommenterStandardOptionNames + } + } +} \ No newline at end of file diff --git a/src/org/elixir_lang/formatter/settings/ElixirCodeStyleMainPanel.kt b/src/org/elixir_lang/formatter/settings/ElixirCodeStyleMainPanel.kt index a1750ae62..9d96f2d95 100644 --- a/src/org/elixir_lang/formatter/settings/ElixirCodeStyleMainPanel.kt +++ b/src/org/elixir_lang/formatter/settings/ElixirCodeStyleMainPanel.kt @@ -7,11 +7,12 @@ import org.elixir_lang.ElixirLanguage class ElixirCodeStyleMainPanel(currentSettings: CodeStyleSettings?, baseSettings: CodeStyleSettings) : TabbedLanguageCodeStylePanel(ElixirLanguage, currentSettings, baseSettings) { - override fun initTabs(settings: CodeStyleSettings?) { + override fun initTabs(settings: CodeStyleSettings) { addTab(MixFormatPanel(settings)) addIndentOptionsTab(settings) addSpacesTab(settings) addWrappingAndBracesTab(settings) + addTab(CodeGenerationPanel(settings)) // DO NOT have Blank Lines tab } } diff --git a/src/org/elixir_lang/formatter/settings/LanguageCodeStyleSettingsProvider.kt b/src/org/elixir_lang/formatter/settings/LanguageCodeStyleSettingsProvider.kt index fedbe928e..9f6e40cc7 100644 --- a/src/org/elixir_lang/formatter/settings/LanguageCodeStyleSettingsProvider.kt +++ b/src/org/elixir_lang/formatter/settings/LanguageCodeStyleSettingsProvider.kt @@ -5,8 +5,10 @@ import com.intellij.application.options.CodeStyleAbstractPanel import com.intellij.application.options.IndentOptionsEditor import com.intellij.application.options.SmartIndentOptionsEditor import com.intellij.lang.Language +import com.intellij.openapi.util.BuildNumber import com.intellij.psi.codeStyle.* import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider +import com.intellij.psi.codeStyle.CodeStyleSettingsCustomizable.* import org.elixir_lang.ElixirLanguage import org.elixir_lang.code_style.CodeStyleSettings @@ -27,12 +29,16 @@ class LanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvider() { SettingsType.SPACING_SETTINGS -> customizeSpaceSettings(consumer) SettingsType.WRAPPING_AND_BRACES_SETTINGS -> customizeWrappingAndBracesSettings(consumer) SettingsType.LANGUAGE_SPECIFIC -> customizeLanguageSpecific(consumer) + SettingsType.COMMENTER_SETTINGS -> customizeCodeGenerationSettings(consumer) SettingsType.BLANK_LINES_SETTINGS, - SettingsType.INDENT_SETTINGS, - SettingsType.COMMENTER_SETTINGS -> Unit + SettingsType.INDENT_SETTINGS -> Unit } } + private fun customizeCodeGenerationSettings(consumer: CodeStyleSettingsCustomizable) { + consumer.showStandardOptions(*CodeGenerationPanel.getSupportedCommenterStandardOptionNames().toTypedArray()) + } + private fun customizeSpaceSettings(consumer: CodeStyleSettingsCustomizable) { consumer.showStandardOptions( // SPACE_BEFORE_PARENTHESES group /* SPACE_BEFORE_METHOD_PARENTHESES - Disabled because space between function name and call arguments diff --git a/src/org/elixir_lang/sdk/elixir/Type.kt b/src/org/elixir_lang/sdk/elixir/Type.kt index 8f1404245..b60b6b309 100644 --- a/src/org/elixir_lang/sdk/elixir/Type.kt +++ b/src/org/elixir_lang/sdk/elixir/Type.kt @@ -531,21 +531,23 @@ ELIXIR_SDK_HOME return if (!project.isDisposed) { /* ModuleUtilCore.findModuleForPsiElement can fail with NullPointerException if the ProjectFileIndex.SERVICE.getInstance(Project) returns {@code null}, so check that the - ProjectFileIndex is available first */ + ProjectFileIndex is available first + */ if (ProjectFileIndex.SERVICE.getInstance(project) != null) { - val module = try { - ReadAction.compute { - ModuleUtilCore.findModuleForPsiElement(psiElement) + ApplicationManager.getApplication().executeOnPooledThread(Callable { + ReadAction.compute { + try { + val module = ModuleUtilCore.findModuleForPsiElement(psiElement) + if (module != null) { + mostSpecificSdk(module) + } else { + mostSpecificSdk(project) + } + } catch (_: AlreadyDisposedException) { + null + } } - } catch (_: AlreadyDisposedException) { - null - } - - if (module != null) { - mostSpecificSdk(module) - } else { - mostSpecificSdk(project) - } + }).get() } else { mostSpecificSdk(project) }