From 930c8a19ecf01576e13c6f7286a7d968b35793ee Mon Sep 17 00:00:00 2001 From: Richard Giliam Date: Fri, 19 Apr 2024 12:36:29 -0700 Subject: [PATCH 1/2] Support IntelliJ 2024.1, and update release to v2.6.0 --- .github/workflows/build.yml | 2 +- .github/workflows/pr.yml | 2 +- build.gradle.kts | 15 +++- .../intellij/formatting/ASTNodeUtils.kt | 18 +++++ .../IonCodeStyleSettingsProvider.kt | 33 +++++++++ .../formatting/IonFormattingModelBuilder.kt | 34 ++++++++++ .../formatting/blocks/IonSExpressionBlock.kt | 68 +++++++++++++++++++ .../intellij/psi/PsiElementExtensions.kt | 11 +++ 8 files changed, 179 insertions(+), 4 deletions(-) create mode 100644 src/IC-241/kotlin/com/amazon/ion/plugin/intellij/formatting/ASTNodeUtils.kt create mode 100644 src/IC-241/kotlin/com/amazon/ion/plugin/intellij/formatting/IonCodeStyleSettingsProvider.kt create mode 100644 src/IC-241/kotlin/com/amazon/ion/plugin/intellij/formatting/IonFormattingModelBuilder.kt create mode 100644 src/IC-241/kotlin/com/amazon/ion/plugin/intellij/formatting/blocks/IonSExpressionBlock.kt create mode 100644 src/IC-241/kotlin/com/amazon/ion/plugin/intellij/psi/PsiElementExtensions.kt diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2281b8f..8be7196 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,7 +36,7 @@ jobs: strategy: fail-fast: false matrix: - product: [ "IC-2022.2", "IC-2023.1", "IC-2023.2", "IC-2023.3"] + product: [ "IC-2022.2", "IC-2023.1", "IC-2023.2", "IC-2023.3", "IC-2024.1"] max-parallel: 5 env: PRODUCT_NAME: ${{ matrix.product }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 7ea1f2c..7922b4d 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -34,7 +34,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - product: [ "IC-2022.2", "IC-2023.1", "IC-2023.2", "IC-2023.3" ] + product: [ "IC-2022.2", "IC-2023.1", "IC-2023.2", "IC-2023.3", "IC-2024.1" ] max-parallel: 5 env: PRODUCT_NAME: ${{ matrix.product }} diff --git a/build.gradle.kts b/build.gradle.kts index 7da4c59..343d644 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -63,10 +63,21 @@ val plugins = listOf( apiVersion = "1.6" ), dependencies = listOf("java", "Kotlin") + ), + PluginDescriptor( + since = "241", + until = "241.*", + sdkVersion = "IC-2024.1", + platformType = PlatformType.IdeaCommunity, + sourceFolder = "IC-241", + kotlin = KotlinOptions( + apiVersion = "1.6" + ), + dependencies = listOf("java", "Kotlin") ) ) -val defaultProductName = "IC-2023.3" +val defaultProductName = "IC-2024.1" val productName = System.getenv("PRODUCT_NAME") ?: defaultProductName val maybeGithubRunNumber = System.getenv("GITHUB_RUN_NUMBER")?.toInt() val descriptor = plugins.first { it.sdkVersion == productName } @@ -77,7 +88,7 @@ val pluginGroup: String by project // `pluginName_` variable ends with `_` because of the collision with Kotlin magic getter in the `intellij` closure. // Read more about the issue: https://github.com/JetBrains/intellij-platform-plugin-template/issues/29 val pluginName_: String by project -val pluginVersion: String = pluginVersion(major = "2", minor = "5", patch = "0") +val pluginVersion: String = pluginVersion(major = "2", minor = "6", patch = "0") val pluginDescriptionFile: String by project val pluginChangeNotesFile: String by project diff --git a/src/IC-241/kotlin/com/amazon/ion/plugin/intellij/formatting/ASTNodeUtils.kt b/src/IC-241/kotlin/com/amazon/ion/plugin/intellij/formatting/ASTNodeUtils.kt new file mode 100644 index 0000000..3531811 --- /dev/null +++ b/src/IC-241/kotlin/com/amazon/ion/plugin/intellij/formatting/ASTNodeUtils.kt @@ -0,0 +1,18 @@ +package com.amazon.ion.plugin.intellij.formatting + +import com.amazon.ion.plugin.intellij.utils.filterWhitespace +import com.intellij.lang.ASTNode +import org.jetbrains.kotlin.idea.base.psi.getLineNumber +import org.jetbrains.kotlin.psi.psiUtil.siblings + +/** + * Determine if a node is on the same line as another node. + */ +fun ASTNode.sameLineAs(another: ASTNode) = + another.psi.getLineNumber(start = true) == this.psi.getLineNumber(start = true) + +/** + * Return the previous sibling of a node if it exists. + */ +fun ASTNode.previousSibling(): ASTNode? = + siblings(forward = false).filterWhitespace().firstOrNull() diff --git a/src/IC-241/kotlin/com/amazon/ion/plugin/intellij/formatting/IonCodeStyleSettingsProvider.kt b/src/IC-241/kotlin/com/amazon/ion/plugin/intellij/formatting/IonCodeStyleSettingsProvider.kt new file mode 100644 index 0000000..eb52d10 --- /dev/null +++ b/src/IC-241/kotlin/com/amazon/ion/plugin/intellij/formatting/IonCodeStyleSettingsProvider.kt @@ -0,0 +1,33 @@ +package com.amazon.ion.plugin.intellij.formatting + +import com.amazon.ion.plugin.intellij.IonLanguage +import com.intellij.application.options.CodeStyleAbstractConfigurable +import com.intellij.application.options.CodeStyleAbstractPanel +import com.intellij.application.options.TabbedLanguageCodeStylePanel +import com.intellij.openapi.options.Configurable +import com.intellij.psi.codeStyle.CodeStyleSettings +import com.intellij.psi.codeStyle.CodeStyleSettingsProvider + +private const val CODE_STYLE_SETTINGS_DISPLAY_NAME = "Ion" + +class IonCodeStyleSettingsProvider : CodeStyleSettingsProvider() { + override fun getConfigurableDisplayName(): String = CODE_STYLE_SETTINGS_DISPLAY_NAME + + override fun createSettingsPage(settings: CodeStyleSettings, modelSettings: CodeStyleSettings): Configurable = + CodeStyleConfigurableConfiguration(settings, modelSettings) +} + +private class CodeStyleConfigurableConfiguration(settings: CodeStyleSettings, modelSettings: CodeStyleSettings) + : CodeStyleAbstractConfigurable(settings, modelSettings, CODE_STYLE_SETTINGS_DISPLAY_NAME) { + + override fun createPanel(settings: CodeStyleSettings): CodeStyleAbstractPanel = IonCodeStyleMainPanel(currentSettings, settings) + override fun getHelpTopic(): String? = null +} + +private class IonCodeStyleMainPanel(currentSettings: CodeStyleSettings, settings: CodeStyleSettings) + : TabbedLanguageCodeStylePanel(IonLanguage.INSTANCE, currentSettings, settings) { + + override fun initTabs(settings: CodeStyleSettings?) { + addIndentOptionsTab(settings) + } +} diff --git a/src/IC-241/kotlin/com/amazon/ion/plugin/intellij/formatting/IonFormattingModelBuilder.kt b/src/IC-241/kotlin/com/amazon/ion/plugin/intellij/formatting/IonFormattingModelBuilder.kt new file mode 100644 index 0000000..51a531b --- /dev/null +++ b/src/IC-241/kotlin/com/amazon/ion/plugin/intellij/formatting/IonFormattingModelBuilder.kt @@ -0,0 +1,34 @@ +package com.amazon.ion.plugin.intellij.formatting + +import com.amazon.ion.plugin.intellij.formatting.blocks.IonBlockOptions +import com.amazon.ion.plugin.intellij.formatting.blocks.RootIonBlock +import com.intellij.formatting.FormattingContext +import com.intellij.formatting.FormattingModel +import com.intellij.formatting.FormattingModelBuilder +import com.intellij.formatting.FormattingModelProvider + +/** + * Creates the block model for an Ion file. + * + * The block model will determine how elements are spaced, indented and aligned. + */ +class IonFormattingModelBuilder : FormattingModelBuilder { + override fun createModel(formattingContext: FormattingContext): FormattingModel { + val element = formattingContext.psiElement + val settings = formattingContext.codeStyleSettings + + val rootBlock = RootIonBlock( + node = element.node, + options = IonBlockOptions( + spaceBuilder = IonCodeBlockSpacingProvider(settings), + codeStyle = settings + ) + ) + + + return FormattingModelProvider.createFormattingModelForPsiFile( + element.containingFile, + rootBlock, settings + ) + } +} diff --git a/src/IC-241/kotlin/com/amazon/ion/plugin/intellij/formatting/blocks/IonSExpressionBlock.kt b/src/IC-241/kotlin/com/amazon/ion/plugin/intellij/formatting/blocks/IonSExpressionBlock.kt new file mode 100644 index 0000000..12d64d3 --- /dev/null +++ b/src/IC-241/kotlin/com/amazon/ion/plugin/intellij/formatting/blocks/IonSExpressionBlock.kt @@ -0,0 +1,68 @@ +package com.amazon.ion.plugin.intellij.formatting.blocks + +import com.amazon.ion.plugin.intellij.formatting.previousSibling +import com.amazon.ion.plugin.intellij.formatting.sameLineAs +import com.amazon.ion.plugin.intellij.psi.IonTypes +import com.amazon.ion.plugin.intellij.psi.isOneLiner +import com.amazon.ion.plugin.intellij.utils.elementIsA +import com.intellij.lang.ASTNode +import com.intellij.openapi.diagnostic.debug +import com.intellij.openapi.diagnostic.logger +import com.intellij.psi.tree.IElementType +import org.jetbrains.kotlin.idea.base.psi.getLineNumber + +private val logger = logger() + +class IonSExpressionBlock( + node: ASTNode, + formatting: IonBlockFormattingOptions, + options: IonBlockOptions +) : AbstractIonBlock(node, formatting = formatting, options = options) { + + override val childIndentedTypes: Set = setOf( + IonTypes.VALUE, + IonTypes.COMMENT + ) + + override val childContainerTypes: Set = setOf( + IonTypes.SEXPRESSION_ELEMENTS + ) + + override val containerWrapperTypes: Set = setOf( + IonTypes.LPAREN, + IonTypes.RPAREN + ) + + override fun buildChildBlockFormatting(child: ASTNode): IonBlockFormattingOptions = + buildSpecialCaseChildBlockFormatting(child) ?: + super.buildChildBlockFormatting(child) + + private fun buildSpecialCaseChildBlockFormatting(child: ASTNode): IonBlockFormattingOptions? { + + // Lazy evaluate the previous sibling if needed. + val previous by lazy { child.previousSibling() } + + /** + * Check if we are the first comment within the expression, there is a special comment + * case where we don't want to apply the child alignment to the comment. For example: + * + * (join // special case comment which is inline with operator + * // child comments are inline with inner values + * anotherValue + * ) + */ + if (child elementIsA IonTypes.COMMENT && previous?.elementType == IonTypes.SEXPRESSION_OPERATOR) { + + logger.debug { "Formatting [${child.psi.getLineNumber()}] - Special case inline expression comment line" } + + val comment = child.psi + val expressionOperator = previous!! + + if (comment.isOneLiner() && child.sameLineAs(expressionOperator)) { + return IonBlockFormatting.sameAlignment(this) + } + } + + return null + } +} diff --git a/src/IC-241/kotlin/com/amazon/ion/plugin/intellij/psi/PsiElementExtensions.kt b/src/IC-241/kotlin/com/amazon/ion/plugin/intellij/psi/PsiElementExtensions.kt new file mode 100644 index 0000000..5c36ea7 --- /dev/null +++ b/src/IC-241/kotlin/com/amazon/ion/plugin/intellij/psi/PsiElementExtensions.kt @@ -0,0 +1,11 @@ +package com.amazon.ion.plugin.intellij.psi + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.idea.base.psi.getLineCount + +/** + * True if the element is all in a single line. + * + * Exists for Backwards Compatibility: <= IC-2020.2 + */ +fun PsiElement.isOneLiner() = getLineCount() == 1 From 0884d55acfec2418de34e18526107ca09493e596 Mon Sep 17 00:00:00 2001 From: Richard Giliam Date: Fri, 19 Apr 2024 13:10:57 -0700 Subject: [PATCH 2/2] Add IC-2024.1 to release.yml product list --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ba3ca56..ea5f08f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: release: strategy: matrix: - product: [ "IC-2022.2", "IC-2023.1", "IC-2023.2", "IC-2023.3" ] + product: [ "IC-2022.2", "IC-2023.1", "IC-2023.2", "IC-2023.3", "IC-2024.1" ] max-parallel: 1 env: PRODUCT_NAME: ${{ matrix.product }}