diff --git a/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintActionOnSave.kt b/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintActionOnSave.kt index 2245413..bbdff47 100644 --- a/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintActionOnSave.kt +++ b/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintActionOnSave.kt @@ -50,11 +50,15 @@ class KtlintActionOnSave : ActionOnSave() { PsiManager .getInstance(project) .findFile(virtualFile) - ?.let { psiFile -> ktlintFormat(psiFile, "KtlintActionOnSave") } + ?.let { psiFile -> + ktlintFormat(psiFile, ktlintFormatRange = KtlintFileFormatRange, triggeredBy = "KtlintActionOnSave") + } } } else { // Only format files which were modified - psiFiles.forEach { psiFile -> ktlintFormat(psiFile, "KtlintActionOnSave") } + psiFiles.forEach { psiFile -> + ktlintFormat(psiFile, ktlintFormatRange = KtlintFileFormatRange, triggeredBy = "KtlintActionOnSave") + } } } } diff --git a/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintConfigForm.form b/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintConfigForm.form index 782aa86..a4d0af1 100644 --- a/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintConfigForm.form +++ b/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintConfigForm.form @@ -1,6 +1,6 @@
- + @@ -10,7 +10,7 @@ - + @@ -24,7 +24,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -57,7 +57,7 @@ - + @@ -66,7 +66,7 @@ - + @@ -75,13 +75,21 @@ - + + + + + + + + + @@ -100,21 +108,19 @@ - + - - - + @@ -123,17 +129,23 @@ - - + + - + - + - + + + + + + + diff --git a/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintConfigForm.kt b/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintConfigForm.kt index dc96ac3..c939f3e 100644 --- a/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintConfigForm.kt +++ b/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintConfigForm.kt @@ -38,6 +38,7 @@ class KtlintConfigForm( private lateinit var formatLabel: JLabel lateinit var formatOnSave: JCheckBox private set + private lateinit var attachToIntellijFormat: JCheckBox private lateinit var externalJarPaths: TextFieldWithBrowseButton private lateinit var baselinePath: TextFieldWithBrowseButton private lateinit var githubButton: JButton @@ -90,6 +91,7 @@ class KtlintConfigForm( ktlintConfigStorage.ktlintMode = ktlintMode ktlintConfigStorage.ktlintRulesetVersion = ktlintRulesetVersion ktlintConfigStorage.formatOnSave = formatOnSave.isSelected + ktlintConfigStorage.attachToIntellijFormat = attachToIntellijFormat.isSelected ktlintConfigStorage.externalJarPaths = externalJarPaths .text @@ -112,7 +114,7 @@ class KtlintConfigForm( .getInstance(project) .findFile(virtualFile) ?.let { psiFile -> - ktlintFormat(psiFile, triggeredBy = "KtlintActionOnSave") + ktlintFormat(psiFile, ktlintFormatRange = KtlintFileFormatRange, triggeredBy = "KtlintActionOnSave") } } } @@ -126,6 +128,7 @@ class KtlintConfigForm( } rulesetVersion.selectedItem = ktlintConfigStorage.ktlintRulesetVersion.label formatOnSave.isSelected = ktlintConfigStorage.formatOnSave + attachToIntellijFormat.isSelected = ktlintConfigStorage.attachToIntellijFormat baselinePath.text = ktlintConfigStorage.baselinePath.orEmpty() externalJarPaths.text = ktlintConfigStorage.externalJarPaths.joinToString(", ") } @@ -148,12 +151,14 @@ class KtlintConfigForm( Objects.equals(ktlintConfigStorage.ktlintMode, ktlintMode) && Objects.equals(ktlintConfigStorage.ktlintRulesetVersion, ktlintRulesetVersion) && Objects.equals(ktlintConfigStorage.formatOnSave, formatOnSave.isSelected) && + Objects.equals(ktlintConfigStorage.attachToIntellijFormat, attachToIntellijFormat.isSelected) && Objects.equals(ktlintConfigStorage.baselinePath, baselinePath.text) && Objects.equals(ktlintConfigStorage.externalJarPaths, externalJarPaths.text) ) private fun setFormatFieldsVisibility() { - formatLabel.isVisible = distractFreeMode.isSelected + formatLabel.isVisible = distractFreeMode.isSelected || manualMode.isSelected formatOnSave.isVisible = distractFreeMode.isSelected + attachToIntellijFormat.isVisible = manualMode.isSelected } } diff --git a/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintConfigStorage.kt b/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintConfigStorage.kt index f5ce085..c685f38 100644 --- a/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintConfigStorage.kt +++ b/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintConfigStorage.kt @@ -40,6 +40,9 @@ class KtlintConfigStorage : PersistentStateComponent { @Tag var formatOnSave: Boolean = true + @Tag + var attachToIntellijFormat: Boolean = true + @Tag var baselinePath: String? = null diff --git a/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintFormat.kt b/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintFormat.kt index affb259..33a10a0 100644 --- a/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintFormat.kt +++ b/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintFormat.kt @@ -26,25 +26,28 @@ internal fun ktlintLint( psiFile: PsiFile, triggeredBy: String, ) = if (psiFile.virtualFile.isKotlinFile()) { - executeKtlint(LINT, psiFile, triggeredBy, force = true) + executeKtlint(LINT, psiFile, KtlintFileFormatRange, triggeredBy) } else { KtlintResult(NOT_STARTED) } internal fun ktlintFormat( psiFile: PsiFile, + ktlintFormatRange: KtlintFormatRange, triggeredBy: String, forceFormat: Boolean = false, ): KtlintResult { var ktlintResult = KtlintResult(NOT_STARTED) - if (psiFile.virtualFile.isKotlinFile()) { + if (psiFile.virtualFile.isKotlinFile() && + (psiFile.project.config().ktlintMode == DISTRACT_FREE || forceFormat) + ) { val project = psiFile.project val document = psiFile.viewProvider.document PsiDocumentManager .getInstance(project) .doPostponedOperationsAndUnblockDocument(document) WriteCommandAction.runWriteCommandAction(project) { - ktlintResult = executeKtlint(FORMAT, psiFile, triggeredBy, forceFormat) + ktlintResult = executeKtlint(FORMAT, psiFile, ktlintFormatRange, triggeredBy) } FileDocumentManager.getInstance().saveDocument(document) DaemonCodeAnalyzer.getInstance(project).restart(psiFile) @@ -58,13 +61,10 @@ internal fun ktlintFormat( private fun executeKtlint( ktlintExecutionType: KtlintExecutionType, psiFile: PsiFile, + ktlintFormatRange: KtlintFormatRange, triggeredBy: String, - force: Boolean = false, ): KtlintResult { val project = psiFile.project - if (project.config().ktlintMode != DISTRACT_FREE && !force) { - return KtlintResult(NOT_STARTED) - } logger.debug { "Start ktlintFormat on file '${psiFile.virtualFile.name}' triggered by '$triggeredBy'" } @@ -112,14 +112,18 @@ private fun executeKtlint( val errorHandler = { error: LintError -> when { error.isIgnoredInBaseline(baselineErrors) -> Unit - else -> lintErrors.add(error) } } if (ktlintExecutionType == LINT) { ktlintRuleEngine.lint(code) { lintError -> errorHandler(lintError) } } else { - val formattedCode = ktlintRuleEngine.format(code) { lintError, _ -> errorHandler(lintError) } + val formattedCode = + if (ktlintFormatRange == KtlintFileFormatRange) { + ktlintRuleEngine.format(code) { lintError, _ -> errorHandler(lintError) } + } else { + ktlintRuleEngine.format(code, ktlintFormatRange.intRange()) { lintError, _ -> errorHandler(lintError) } + } if (formattedCode != code.content) { psiFile.viewProvider.document.setText(formattedCode) fileChangedByFormat = true diff --git a/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintFormatRange.kt b/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintFormatRange.kt new file mode 100644 index 0000000..3f80a61 --- /dev/null +++ b/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintFormatRange.kt @@ -0,0 +1,16 @@ +package com.nbadal.ktlint + +internal sealed interface KtlintFormatRange { + fun intRange(): IntRange +} + +internal data object KtlintFileFormatRange : KtlintFormatRange { + override fun intRange(): IntRange = IntRange(0, Int.MAX_VALUE) +} + +internal data class KtlintBlockFormatRange( + val startOffset: Int, + val endOffsetInclusive: Int, +) : KtlintFormatRange { + override fun intRange(): IntRange = IntRange(startOffset, endOffsetInclusive) +} diff --git a/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintPostFormatProcessor.kt b/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintPostFormatProcessor.kt index 8ab6c21..18fe7fc 100644 --- a/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintPostFormatProcessor.kt +++ b/plugin/src/main/kotlin/com/nbadal/ktlint/KtlintPostFormatProcessor.kt @@ -17,8 +17,13 @@ class KtlintPostFormatProcessor : PostFormatProcessor { rangeToReformat: TextRange, settings: CodeStyleSettings, ): TextRange { - if (psiFile.project.isEnabled(KtlintFeature.POST_FORMAT_WITH_KTLINT)) { - ktlintFormat(psiFile, "KtlintPostFormatProcessor") + if (psiFile.project.isEnabled(KtlintFeature.POST_FORMAT_WITH_KTLINT) || psiFile.project.config().attachToIntellijFormat) { + ktlintFormat( + psiFile, + ktlintFormatRange = KtlintBlockFormatRange(rangeToReformat.startOffset, rangeToReformat.endOffset + 1), + triggeredBy = "KtlintPostFormatProcessor", + forceFormat = true, + ) } return rangeToReformat } diff --git a/plugin/src/main/kotlin/com/nbadal/ktlint/actions/ForceFormatIntention.kt b/plugin/src/main/kotlin/com/nbadal/ktlint/actions/ForceFormatIntention.kt index de3a504..e55ad7c 100644 --- a/plugin/src/main/kotlin/com/nbadal/ktlint/actions/ForceFormatIntention.kt +++ b/plugin/src/main/kotlin/com/nbadal/ktlint/actions/ForceFormatIntention.kt @@ -7,6 +7,7 @@ import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.psi.PsiFile import com.nbadal.ktlint.KtlintFeature +import com.nbadal.ktlint.KtlintFileFormatRange import com.nbadal.ktlint.isEnabled import com.nbadal.ktlint.ktlintFormat @@ -37,6 +38,6 @@ class ForceFormatIntention : editor: Editor?, psiFile: PsiFile, ) { - ktlintFormat(psiFile, "ForceFormatIntention", forceFormat = true) + ktlintFormat(psiFile, ktlintFormatRange = KtlintFileFormatRange, triggeredBy = "ForceFormatIntention", forceFormat = true) } } diff --git a/plugin/src/main/kotlin/com/nbadal/ktlint/actions/FormatAction.kt b/plugin/src/main/kotlin/com/nbadal/ktlint/actions/FormatAction.kt index 81dc38e..8c9f376 100644 --- a/plugin/src/main/kotlin/com/nbadal/ktlint/actions/FormatAction.kt +++ b/plugin/src/main/kotlin/com/nbadal/ktlint/actions/FormatAction.kt @@ -9,6 +9,7 @@ import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiManager import com.nbadal.ktlint.KtlintFeature.SHOW_MENU_OPTION_FORMAT_WITH_KTLINT +import com.nbadal.ktlint.KtlintFileFormatRange import com.nbadal.ktlint.KtlintMode.DISTRACT_FREE import com.nbadal.ktlint.KtlintNotifier.notifyInformation import com.nbadal.ktlint.KtlintNotifier.notifyWarning @@ -91,7 +92,7 @@ class FormatAction : AnAction() { PsiManager .getInstance(project) .findFile(fileOrDir) - ?.let { ktlintFormat(it, "FormatAction", forceFormat = true) } + ?.let { ktlintFormat(it, ktlintFormatRange = KtlintFileFormatRange, triggeredBy = "FormatAction", forceFormat = true) } // In case an error occurs, a notification has already been sent by ktlintFormat above when (ktlintResult?.status) { KtlintResult.Status.SUCCESS -> { diff --git a/plugin/src/main/kotlin/com/nbadal/ktlint/actions/KtlintRuleSuppressIntention.kt b/plugin/src/main/kotlin/com/nbadal/ktlint/actions/KtlintRuleSuppressIntention.kt index 78d8f7a..ab96b7d 100644 --- a/plugin/src/main/kotlin/com/nbadal/ktlint/actions/KtlintRuleSuppressIntention.kt +++ b/plugin/src/main/kotlin/com/nbadal/ktlint/actions/KtlintRuleSuppressIntention.kt @@ -8,6 +8,7 @@ import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.nbadal.ktlint.KtlintFeature.SHOW_INTENTION_TO_SUPPRESS_VIOLATION +import com.nbadal.ktlint.KtlintFileFormatRange import com.nbadal.ktlint.config import com.nbadal.ktlint.isEnabled import com.nbadal.ktlint.ktlintFormat @@ -67,7 +68,7 @@ class KtlintRuleSuppressIntention( ?.let { updatedCode -> if (updatedCode != code.content) { document.setText(updatedCode) - ktlintFormat(psiFile, "KtlintSuppressIntention") + ktlintFormat(psiFile, ktlintFormatRange = KtlintFileFormatRange, triggeredBy = "KtlintSuppressIntention") } } } diff --git a/plugin/src/main/resources/strings.properties b/plugin/src/main/resources/strings.properties index b7f8d76..858b718 100644 --- a/plugin/src/main/resources/strings.properties +++ b/plugin/src/main/resources/strings.properties @@ -1,3 +1,5 @@ +attachToIntellijFormattingLabel=&attach to Intellij IDEA formatting +attachToIntellijFormattingToolTip=Run Ktlint Formatting after Intellij IDEA formatting baselineLabel=Baseline file: baselineToolTip=The baseline file contains the KtLint violations which have to be ignored. disabledMode=D&isabled