diff --git a/.idea/icon.svg b/.idea/icon.svg new file mode 100644 index 0000000..ac688d8 --- /dev/null +++ b/.idea/icon.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/CHANGELOG.md b/CHANGELOG.md index 07d55e0..7c96c2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,16 +2,12 @@ # idea-clang-format Changelog -[Unreleased] - -## [1.0.0] - 2024-11-02 +## [Unreleased] ### Added +- Initial scaffold created from [IntelliJ Platform Plugin Template](https://github.com/JetBrains/intellij-platform-plugin-template) - Language support for `.clang-format` files - Detect indentation style and column limit from `.clang-format` file - Format code using `clang-format` binary - Settings page to configure `clang-format` binary path - Format on save option - -[Unreleased]: https://github.com/aarcangeli/idea-clang-format/compare/v1.0.0...HEAD -[1.0.0]: https://github.com/aarcangeli/idea-clang-format/commits/v1.0.0 diff --git a/README.md b/README.md index 1806734..603baa4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Clang-Format Tools for JetBrains IDEs -[![Build](https://github.com/aarcangeli/idea-clang-format/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/aarcangeli/idea-clang-format/actions/workflows/build.yml) +[![Build](https://github.com/aarcangeli/idea-clang-format/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/aarcangeli/idea-clang-format/actions/workflows/build.yml?query=branch%3Amain) [![Version](https://img.shields.io/jetbrains/plugin/v/20785-clang-format-tools.svg)](https://plugins.jetbrains.com/plugin/20785-clang-format-tools) [![Downloads](https://img.shields.io/jetbrains/plugin/d/20785-clang-format-tools.svg)](https://plugins.jetbrains.com/plugin/20785-clang-format-tools) [![Rating](https://img.shields.io/jetbrains/plugin/r/rating/20785-clang-format-tools)](https://plugins.jetbrains.com/plugin/20785-clang-format-tools) diff --git a/gradle.properties b/gradle.properties index a5c7b92..cab46a8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ pluginGroup = com.github.aarcangeli.idea-clang-format pluginName = idea-clang-format pluginRepositoryUrl = https://github.com/aarcangeli/idea-clang-format # SemVer format -> https://semver.org -pluginVersion = 0.0.2-beta +pluginVersion = 1.0.0 # Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html pluginSinceBuild = 233 diff --git a/src/main/kotlin/com/github/aarcangeli/ideaclangformat/ClangFormatConfig.kt b/src/main/kotlin/com/github/aarcangeli/ideaclangformat/ClangFormatConfig.kt index b393b6b..64a8a64 100644 --- a/src/main/kotlin/com/github/aarcangeli/ideaclangformat/ClangFormatConfig.kt +++ b/src/main/kotlin/com/github/aarcangeli/ideaclangformat/ClangFormatConfig.kt @@ -1,6 +1,9 @@ package com.github.aarcangeli.ideaclangformat -import com.intellij.openapi.components.* +import com.intellij.openapi.components.BaseState +import com.intellij.openapi.components.SimplePersistentStateComponent +import com.intellij.openapi.components.State +import com.intellij.openapi.components.Storage /** * Application-wide configuration for the ClangFormat plugin. diff --git a/src/main/kotlin/com/github/aarcangeli/ideaclangformat/MyBundle.kt b/src/main/kotlin/com/github/aarcangeli/ideaclangformat/MyBundle.kt index 77d5a20..99aaac4 100644 --- a/src/main/kotlin/com/github/aarcangeli/ideaclangformat/MyBundle.kt +++ b/src/main/kotlin/com/github/aarcangeli/ideaclangformat/MyBundle.kt @@ -9,12 +9,12 @@ private const val BUNDLE = "messages.ClangFormatBundle" object MyBundle : DynamicBundle(BUNDLE) { - @JvmStatic - fun message(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any) = - getMessage(key, *params) + @JvmStatic + fun message(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any) = + getMessage(key, *params) - @Suppress("unused") - @JvmStatic - fun messagePointer(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any) = - getLazyMessage(key, *params) + @Suppress("unused") + @JvmStatic + fun messagePointer(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any) = + getLazyMessage(key, *params) } diff --git a/src/main/kotlin/com/github/aarcangeli/ideaclangformat/actions/ReformatCodeWithClangAction.kt b/src/main/kotlin/com/github/aarcangeli/ideaclangformat/actions/ReformatCodeWithClangAction.kt index 7a84287..16b7ad2 100644 --- a/src/main/kotlin/com/github/aarcangeli/ideaclangformat/actions/ReformatCodeWithClangAction.kt +++ b/src/main/kotlin/com/github/aarcangeli/ideaclangformat/actions/ReformatCodeWithClangAction.kt @@ -1,5 +1,6 @@ package com.github.aarcangeli.ideaclangformat.actions +import com.github.aarcangeli.ideaclangformat.experimental.ClangFormatExternalFormatProcessor import com.github.aarcangeli.ideaclangformat.services.ClangFormatService import com.intellij.codeInsight.actions.ReformatCodeAction import com.intellij.openapi.actionSystem.* @@ -48,7 +49,7 @@ class ReformatCodeWithClangAction(private val baseAction: AnAction) : AnAction() return getVirtualFileFor(project, editor.document) != null } - fun getVirtualFileFor(project: Project, document: Document): VirtualFile? { + private fun getVirtualFileFor(project: Project, document: Document): VirtualFile? { val psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document) if (psiFile != null && service().mayBeFormatted(psiFile, true)) { return psiFile.originalFile.virtualFile diff --git a/src/main/kotlin/com/github/aarcangeli/ideaclangformat/exceptions/exceptions.kt b/src/main/kotlin/com/github/aarcangeli/ideaclangformat/exceptions/exceptions.kt index 566edef..7db1180 100644 --- a/src/main/kotlin/com/github/aarcangeli/ideaclangformat/exceptions/exceptions.kt +++ b/src/main/kotlin/com/github/aarcangeli/ideaclangformat/exceptions/exceptions.kt @@ -26,7 +26,7 @@ class ClangValidationError(@JvmField val description: @Nls String, private val f /** * Thrown on any exit code different from 0. */ -class ClangExitCode(val exitCode: Int) : ClangFormatError("Clang-format exited with code $exitCode") +class ClangExitCode(exitCode: Int) : ClangFormatError("Clang-format exited with code $exitCode") /** * Thrown when no ".clang-format" files support the file language. diff --git a/src/main/kotlin/com/github/aarcangeli/ideaclangformat/experimental/ClangFormatExternalFormatProcessor.kt b/src/main/kotlin/com/github/aarcangeli/ideaclangformat/experimental/ClangFormatExternalFormatProcessor.kt index 8ff84bf..89ec6bb 100644 --- a/src/main/kotlin/com/github/aarcangeli/ideaclangformat/experimental/ClangFormatExternalFormatProcessor.kt +++ b/src/main/kotlin/com/github/aarcangeli/ideaclangformat/experimental/ClangFormatExternalFormatProcessor.kt @@ -13,16 +13,16 @@ class ClangFormatExternalFormatProcessor : ExternalFormatProcessor { } override fun format( - source: PsiFile, - range: TextRange, - canChangeWhiteSpacesOnly: Boolean, - keepLineBreaks: Boolean, - enableBulkUpdate: Boolean, - cursorOffset: Int + source: PsiFile, + range: TextRange, + canChangeWhiteSpacesOnly: Boolean, + keepLineBreaks: Boolean, + enableBulkUpdate: Boolean, + cursorOffset: Int ): TextRange? { val virtualFile = source.originalFile.virtualFile if (virtualFile != null) { - ProgressManager.checkCanceled() + ProgressManager.checkCanceled() service().reformatFileSync(source.project, virtualFile) return range } diff --git a/src/main/kotlin/com/github/aarcangeli/ideaclangformat/experimental/ClangFormatStyleSettingsModifier.kt b/src/main/kotlin/com/github/aarcangeli/ideaclangformat/experimental/ClangFormatStyleSettingsModifier.kt index e712441..ac355c2 100644 --- a/src/main/kotlin/com/github/aarcangeli/ideaclangformat/experimental/ClangFormatStyleSettingsModifier.kt +++ b/src/main/kotlin/com/github/aarcangeli/ideaclangformat/experimental/ClangFormatStyleSettingsModifier.kt @@ -2,12 +2,11 @@ package com.github.aarcangeli.ideaclangformat.experimental import com.github.aarcangeli.ideaclangformat.ClangFormatConfig import com.github.aarcangeli.ideaclangformat.MyBundle -import com.github.aarcangeli.ideaclangformat.exceptions.ClangValidationError import com.github.aarcangeli.ideaclangformat.exceptions.ClangFormatError +import com.github.aarcangeli.ideaclangformat.exceptions.ClangValidationError import com.github.aarcangeli.ideaclangformat.services.ClangFormatService import com.github.aarcangeli.ideaclangformat.services.ClangFormatStyleService import com.github.aarcangeli.ideaclangformat.utils.ClangFormatCommons -import com.intellij.CodeStyleBundle import com.intellij.icons.AllIcons import com.intellij.ide.actions.ShowSettingsUtilImpl import com.intellij.ide.util.PsiNavigationSupport @@ -32,8 +31,6 @@ import com.intellij.psi.codeStyle.IndentStatusBarUIContributor import com.intellij.psi.codeStyle.modifier.CodeStyleSettingsModifier import com.intellij.psi.codeStyle.modifier.CodeStyleStatusBarUIContributor import com.intellij.psi.codeStyle.modifier.TransientCodeStyleSettings -import com.intellij.ui.ColorUtil -import com.intellij.ui.JBColor import org.jetbrains.annotations.Nls import javax.swing.Icon @@ -56,7 +53,7 @@ class ClangFormatStyleSettingsModifier : CodeStyleSettingsModifier { if (!formatService.mayBeFormatted(file, true)) { // clang format disabled for this file file.putUserData(LAST_PROVIDED_SETTINGS, null) - return true + return false } try { @@ -77,7 +74,7 @@ class ClangFormatStyleSettingsModifier : CodeStyleSettingsModifier { // ignore other error } - return false; + return false } override fun getName(): @Nls(capitalization = Nls.Capitalization.Title) String { @@ -88,12 +85,10 @@ class ClangFormatStyleSettingsModifier : CodeStyleSettingsModifier { return object : IndentStatusBarUIContributor(settings.indentOptions) { override fun getTooltip(): String { val builder = HtmlBuilder() - builder.append( - HtmlChunk.span("color:" + ColorUtil.toHtmlColor(JBColor.GRAY)) - .addText(MyBundle.message("error.clang-format.status.hint")) - ) + builder.append(MyBundle.message("error.clang-format.status.hint")) + .br() builder - .append(CodeStyleBundle.message("indent.status.bar.indent.tooltip")) + .append("Indent:") .append(" ") .append( HtmlChunk.tag("b").addText( @@ -212,21 +207,13 @@ class ClangFormatStyleSettingsModifier : CodeStyleSettingsModifier { * This is used to apply the settings to the IDE. */ private class ClangFormatStyle(formatStyle: Map) { - private val columnLimit: Int - private val indentWidth: Int - private val tabWidth: Int - private val useTab: Boolean - - init { - columnLimit = getInt(formatStyle, "ColumnLimit") - indentWidth = getInt(formatStyle, "IndentWidth") - tabWidth = getInt(formatStyle, "TabWidth") + private val columnLimit: Int = getInt(formatStyle, "ColumnLimit") + private val indentWidth: Int = getInt(formatStyle, "IndentWidth") + private val tabWidth: Int = getInt(formatStyle, "TabWidth") - // fixme: unsupported values "ForIndentation", "ForContinuationAndIndentation", etc - val useTabProp = formatStyle["UseTab"] - useTab = useTabProp != null && !useTabProp.toString() - .equals("false", ignoreCase = true) && !useTabProp.toString().equals("never", ignoreCase = true) - } + // fixme: unsupported values "ForIndentation", "ForContinuationAndIndentation", etc + private val useTab: Boolean = formatStyle["UseTab"] != null && !formatStyle["UseTab"].toString() + .equals("false", ignoreCase = true) && !formatStyle["UseTab"].toString().equals("never", ignoreCase = true) fun apply(settings: TransientCodeStyleSettings) { if (columnLimit > 0) { diff --git a/src/main/kotlin/com/github/aarcangeli/ideaclangformat/lang/ClangEditorNotificationProvider.kt b/src/main/kotlin/com/github/aarcangeli/ideaclangformat/lang/ClangEditorNotificationProvider.kt index 8d8c6db..1199436 100644 --- a/src/main/kotlin/com/github/aarcangeli/ideaclangformat/lang/ClangEditorNotificationProvider.kt +++ b/src/main/kotlin/com/github/aarcangeli/ideaclangformat/lang/ClangEditorNotificationProvider.kt @@ -19,42 +19,42 @@ import javax.swing.JComponent * Show an error if .clang-format is not saved in UTF-8 */ class ClangEditorNotificationProvider : EditorNotificationProvider, DumbAware { - override fun collectNotificationData( - project: Project, - file: VirtualFile - ): Function? { - if (ClangFormatCommons.isClangFormatFile(file.name)) { - return Function { fileEditor -> createPanel(fileEditor) } - } - return null + override fun collectNotificationData( + project: Project, + file: VirtualFile + ): Function? { + if (ClangFormatCommons.isClangFormatFile(file.name)) { + return Function { fileEditor -> createPanel(fileEditor) } } + return null + } - @RequiresEdt - private fun createPanel( - fileEditor: FileEditor, - ): EditorNotificationPanel? { - if (fileEditor.file.charset.name() != "UTF-8") { - val panel = EditorNotificationPanel(fileEditor, EditorNotificationPanel.Status.Error) - panel.text = "ClangFormat file is not UTF-8 encoded" - return panel - } - return null + @RequiresEdt + private fun createPanel( + fileEditor: FileEditor, + ): EditorNotificationPanel? { + if (fileEditor.file.charset.name() != "UTF-8") { + val panel = EditorNotificationPanel(fileEditor, EditorNotificationPanel.Status.Error) + panel.text = "ClangFormat file is not UTF-8 encoded" + return panel } + return null + } } /** * Ensure that the editor notification is updated when the file encoding changes. */ class ClangFileListener(val project: Project) : BulkFileListener { - override fun after(events: List) { - for (event in events) { - if (event is VFilePropertyChangeEvent) { - if (event.propertyName == VirtualFile.PROP_ENCODING) { - if (ClangFormatCommons.isClangFormatFile(event.file.name)) { - EditorNotifications.getInstance(project).updateNotifications(event.file) - } - } - } + override fun after(events: List) { + for (event in events) { + if (event is VFilePropertyChangeEvent) { + if (event.propertyName == VirtualFile.PROP_ENCODING) { + if (ClangFormatCommons.isClangFormatFile(event.file.name)) { + EditorNotifications.getInstance(project).updateNotifications(event.file) + } } + } } + } } diff --git a/src/main/kotlin/com/github/aarcangeli/ideaclangformat/services/ClangFormatStyleServiceImpl.kt b/src/main/kotlin/com/github/aarcangeli/ideaclangformat/services/ClangFormatStyleServiceImpl.kt index d5ec295..cbde51b 100644 --- a/src/main/kotlin/com/github/aarcangeli/ideaclangformat/services/ClangFormatStyleServiceImpl.kt +++ b/src/main/kotlin/com/github/aarcangeli/ideaclangformat/services/ClangFormatStyleServiceImpl.kt @@ -8,8 +8,6 @@ import com.github.aarcangeli.ideaclangformat.utils.ProcessUtils import com.intellij.execution.ExecutionException import com.intellij.execution.configurations.PathEnvironmentVariableUtil import com.intellij.openapi.Disposable -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.application.WriteAction import com.intellij.openapi.components.service import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.fileEditor.FileDocumentManager @@ -63,8 +61,6 @@ class ClangFormatStyleServiceImpl : ClangFormatStyleService, Disposable { } override fun getRawFormatStyle(psiFile: PsiFile): Map { - // save changed documents - saveUnsavedClangFormatFiles() val result = CachedValuesManager.getCachedValue(psiFile, CLANG_STYLE, FormatStyleProvider(this, psiFile)) if (result.second != null) { throw result.second!! @@ -120,19 +116,6 @@ class ClangFormatStyleServiceImpl : ClangFormatStyleService, Disposable { return getClangFormatFiles(virtualFile).isNotEmpty() } - private fun saveUnsavedClangFormatFiles() { - // save changed documents - if (ClangFormatCommons.getUnsavedClangFormats().isNotEmpty()) { - ApplicationManager.getApplication().invokeLater { - WriteAction.run { - for (document in ClangFormatCommons.getUnsavedClangFormats()) { - FileDocumentManager.getInstance().saveDocument(document) - } - } - } - } - } - override fun dispose() {} private fun dropCaches() { diff --git a/src/main/kotlin/com/github/aarcangeli/ideaclangformat/utils/ClangFormatCommons.kt b/src/main/kotlin/com/github/aarcangeli/ideaclangformat/utils/ClangFormatCommons.kt index 62b446e..26a36ad 100644 --- a/src/main/kotlin/com/github/aarcangeli/ideaclangformat/utils/ClangFormatCommons.kt +++ b/src/main/kotlin/com/github/aarcangeli/ideaclangformat/utils/ClangFormatCommons.kt @@ -1,8 +1,8 @@ package com.github.aarcangeli.ideaclangformat.utils -import com.github.aarcangeli.ideaclangformat.exceptions.ClangValidationError import com.github.aarcangeli.ideaclangformat.exceptions.ClangFormatError import com.github.aarcangeli.ideaclangformat.exceptions.ClangMissingLanguageException +import com.github.aarcangeli.ideaclangformat.exceptions.ClangValidationError import com.intellij.build.FileNavigatable import com.intellij.build.FilePosition import com.intellij.execution.configurations.GeneralCommandLine diff --git a/src/main/resources/messages/ClangFormatBundle.properties b/src/main/resources/messages/ClangFormatBundle.properties index 435ab87..5ba5f59 100644 --- a/src/main/resources/messages/ClangFormatBundle.properties +++ b/src/main/resources/messages/ClangFormatBundle.properties @@ -1,7 +1,6 @@ clang-format.title=Clang-Format Tools clang-format.disable=Disable for Project clang-format.disabled.notification=ClangFormat disabled - error.clang-format.name=Clang-Format error.clang-format.formatting=Formatting with Clang-Format error.clang-format.command.name=Reformat Code @@ -11,5 +10,4 @@ error.clang-format.error.dump.not.yaml=Invalid yaml returned by clang-format\n{0 error.clang-format.status.hint=From clang-format error.clang-format.status.open=Open Clang-Format Configuration error.clang-format.open.style=Open style - crash.report.action=Create Issue on &GitHub