diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d180d4b..0f37d0e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,7 +35,7 @@ jobs: # Validate wrapper - name: Gradle Wrapper Validation - uses: gradle/wrapper-validation-action@v1.1.0 + uses: gradle/wrapper-validation-action@v3 # Set up Java environment for the next steps - name: Setup Java @@ -46,7 +46,7 @@ jobs: # Setup Gradle - name: Setup Gradle - uses: gradle/gradle-build-action@v2 + uses: gradle/gradle-build-action@v3 with: gradle-home-cache-cleanup: true @@ -86,7 +86,7 @@ jobs: # Store already-built plugin as an artifact for downloading - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ steps.artifact.outputs.filename }} path: ./build/distributions/content/*/* @@ -110,7 +110,7 @@ jobs: # Setup Gradle - name: Setup Gradle - uses: gradle/gradle-build-action@v2 + uses: gradle/gradle-build-action@v3 with: gradle-home-cache-cleanup: true @@ -121,14 +121,14 @@ jobs: # Collect Tests Result of failed tests - name: Collect Tests Result if: ${{ failure() }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: tests-result path: ${{ github.workspace }}/build/reports/tests # Upload the Kover report to CodeCov - name: Upload Code Coverage Report - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: files: ${{ github.workspace }}/build/reports/kover/report.xml @@ -158,13 +158,13 @@ jobs: # Setup Gradle - name: Setup Gradle - uses: gradle/gradle-build-action@v2 + uses: gradle/gradle-build-action@v3 with: gradle-home-cache-cleanup: true # Cache Plugin Verifier IDEs - name: Setup Plugin Verifier IDEs Cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ needs.build.outputs.pluginVerifierHomeDir }}/ides key: plugin-verifier-${{ hashFiles('build/listProductsReleases.txt') }} @@ -176,7 +176,7 @@ jobs: # Collect Plugin Verifier Result - name: Collect Plugin Verifier Result if: ${{ always() }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: pluginVerifier-result path: ${{ github.workspace }}/build/reports/pluginVerifier diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6763e5a..c74ffc7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,7 +31,7 @@ jobs: # Setup Gradle - name: Setup Gradle - uses: gradle/gradle-build-action@v2 + uses: gradle/gradle-build-action@v3 with: gradle-home-cache-cleanup: true diff --git a/.gitignore b/.gitignore index e0d53d8..46e4e59 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .gradle +.kotlin .idea build diff --git a/CHANGELOG.md b/CHANGELOG.md index 53ee87e..b3c71af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ ## [Unreleased] +- Fixed an issue where initialisation could get into an infinite loop. +- Default to the IntelliJ formatter when the canFormat cache is cold for a file. +- Stop self-healing restarts and show error baloons every time a startup fails. + ## 0.6.0 - 2024-02-08 - Fixed issue where on save actions were running twice per save. diff --git a/gradle.properties b/gradle.properties index b897060..78e712e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,15 +2,15 @@ # -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html pluginGroup=com.dprint.intellij.plugin pluginName=dprint-intellij-plugin -pluginVersion=0.6.0 +pluginVersion=0.7.0 # See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html # for insight into build numbers and IntelliJ Platform versions. pluginSinceBuild=232 # Plugin Verifier integration -> https://github.com/JetBrains/gradle-intellij-plugin#plugin-verifier-dsl # See https://jb.gg/intellij-platform-builds-list for available build versions. -pluginVerifierIdeVersions=IC-2023.2,IU-2023.2,LATEST-EAP-SNAPSHOT +pluginVerifierIdeVersions=IC-2023.3,IU-2023.3,LATEST-EAP-SNAPSHOT platformType=IU -platformVersion=2023.2 +platformVersion=2023.3 platformDownloadSources=true # Opt-out flag for bundling Kotlin standard library. # See https://plugins.jetbrains.com/docs/intellij/kotlin.html#kotlin-standard-library for details. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a72acf1..0a3405e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,13 +1,13 @@ [versions] annotations = "24.0.1" -changelog = "2.2.0" +changelog = "2.2.1" commonsCollection4 = "4.4" -gradleIntelliJPlugin = "1.17.3" -kotestAssertions = "5.8.1" -kotestRunner = "5.8.1" -kotlin = "1.9.23" -ktlint = "12.1.0" -mockk = "1.13.10" +gradleIntelliJPlugin = "1.17.4" +kotestAssertions = "5.9.1" +kotestRunner = "5.9.1" +kotlin = "2.0.0" +ktlint = "12.1.1" +mockk = "1.13.11" versionCatalogUpdate = "0.8.4" versions = "0.51.0" diff --git a/src/main/kotlin/com/dprint/formatter/DprintExternalFormatter.kt b/src/main/kotlin/com/dprint/formatter/DprintExternalFormatter.kt index aee85d3..8934665 100644 --- a/src/main/kotlin/com/dprint/formatter/DprintExternalFormatter.kt +++ b/src/main/kotlin/com/dprint/formatter/DprintExternalFormatter.kt @@ -7,6 +7,7 @@ import com.dprint.services.editorservice.EditorServiceManager import com.dprint.utils.infoConsole import com.dprint.utils.infoLogWithConsole import com.dprint.utils.isFormattableFile +import com.dprint.utils.warnLogWithConsole import com.intellij.formatting.service.AsyncDocumentFormattingService import com.intellij.formatting.service.AsyncFormattingRequest import com.intellij.formatting.service.FormattingService @@ -51,11 +52,16 @@ class DprintExternalFormatter : AsyncDocumentFormattingService() { // optimisation because they are not part of the project and thus never in config. val virtualFile = file.virtualFile ?: file.originalFile.virtualFile val canFormat = - virtualFile != null && - isFormattableFile(file.project, virtualFile) && - editorServiceManager.canFormatCached(virtualFile.path) != false + if (virtualFile != null && isFormattableFile(file.project, virtualFile)) { + editorServiceManager.canFormatCached(virtualFile.path) + } else { + false + } - if (canFormat) { + if (canFormat == null) { + warnLogWithConsole(DprintBundle.message("external.formatter.can.format.unknown"), file.project, LOGGER) + return false + } else if (canFormat) { infoConsole(DprintBundle.message("external.formatter.can.format", virtualFile.path), file.project) } else if (virtualFile?.path != null) { // If a virtual file path doesn't exist then it is an ephemeral file such as a scratch file. Dprint needs @@ -78,10 +84,6 @@ class DprintExternalFormatter : AsyncDocumentFormattingService() { return null } - // This exists as well as the condition in the canFormat method as that will prime the cache if - // the file hasn't already been checked. Should probably never happen but let's be safe. - if (editorServiceManager.canFormatCached(path) != true) return null - if (!editorServiceManager.canRangeFormat() && isRangeFormat(formattingRequest)) { infoLogWithConsole(DprintBundle.message("external.formatter.range.formatting"), project, LOGGER) return null diff --git a/src/main/kotlin/com/dprint/services/editorservice/EditorServiceManager.kt b/src/main/kotlin/com/dprint/services/editorservice/EditorServiceManager.kt index 3930f92..246487e 100644 --- a/src/main/kotlin/com/dprint/services/editorservice/EditorServiceManager.kt +++ b/src/main/kotlin/com/dprint/services/editorservice/EditorServiceManager.kt @@ -39,16 +39,10 @@ class EditorServiceManager(private val project: Project) { private val editorServiceTaskQueue = EditorServiceTaskQueue(project) private var canFormatCache = LRUMap() - // The following flags are used to optimise user experience - // - isInitialising stops multiple initialisation events triggering if the user spams save, and it isn't working - // - hasBeenNotifiedOfInitialisationFailure ensures that the user is only notified once of initialisation failures - // so that they don't get spammed while fixing problems. This resets on successful initialisation. - private var hasBeenNotifiedOfInitialisationFailure = false private var hasAttemptedInitialisation = false private fun getSchemaVersion(configPath: String?): Int? { val executablePath = getValidExecutablePath(project) - // The entire timeout will be val timeout = project.service().state.initialisationTimeout val commandLine = @@ -60,6 +54,7 @@ class EditorServiceManager(private val project: Project) { val workingDir = File(it).parent commandLine.withWorkDirectory(workingDir) } + val result = ExecUtil.execAndGetOutput(commandLine, timeout.toInt()) return try { @@ -89,6 +84,7 @@ class EditorServiceManager(private val project: Project) { result.stdout.trim(), result.stderr.trim(), ) + else -> DprintBundle.message("error.failed.to.parse.json.schema") } errorLogWithConsole( @@ -150,7 +146,6 @@ class EditorServiceManager(private val project: Project) { } }, timeout, - { restartEditorService() }, ) } @@ -191,7 +186,6 @@ class EditorServiceManager(private val project: Project) { timeout, { onFinished(FormatResult()) - restartEditorService() }, ) } @@ -235,8 +229,6 @@ class EditorServiceManager(private val project: Project) { } editorService?.initialiseEditorService() - // Reset state flags for optimising user experience - hasBeenNotifiedOfInitialisationFailure = false return true } @@ -245,6 +237,7 @@ class EditorServiceManager(private val project: Project) { return } + // Slightly larger incase the json schema step times out val timeout = project.service().state.initialisationTimeout editorServiceTaskQueue.createTaskWithTimeout( TaskInfo(TaskType.Initialisation, null, null), @@ -262,26 +255,27 @@ class EditorServiceManager(private val project: Project) { }, timeout, { - if (!hasBeenNotifiedOfInitialisationFailure) { - NotificationGroupManager - .getInstance() - .getNotificationGroup("Dprint") - .createNotification( - DprintBundle.message( - "editor.service.manager.initialising.editor.service.failed.title", - ), - DprintBundle.message( - "editor.service.manager.initialising.editor.service.failed.content", - ), - NotificationType.ERROR, - ) - .notify(project) - hasBeenNotifiedOfInitialisationFailure = true - } + this.notifyFailedToStart() }, ) } + private fun notifyFailedToStart() { + NotificationGroupManager + .getInstance() + .getNotificationGroup("Dprint") + .createNotification( + DprintBundle.message( + "editor.service.manager.initialising.editor.service.failed.title", + ), + DprintBundle.message( + "editor.service.manager.initialising.editor.service.failed.content", + ), + NotificationType.ERROR, + ) + .notify(project) + } + fun destroyEditorService() { editorService?.destroyEditorService() } diff --git a/src/main/kotlin/com/dprint/toolwindow/ConsoleToolWindowFactory.kt b/src/main/kotlin/com/dprint/toolwindow/ConsoleToolWindowFactory.kt index 1b2d91f..57ceff6 100644 --- a/src/main/kotlin/com/dprint/toolwindow/ConsoleToolWindowFactory.kt +++ b/src/main/kotlin/com/dprint/toolwindow/ConsoleToolWindowFactory.kt @@ -1,6 +1,5 @@ package com.dprint.toolwindow -import com.dprint.config.ProjectConfiguration import com.intellij.openapi.components.service import com.intellij.openapi.project.DumbAware import com.intellij.openapi.project.Project @@ -23,6 +22,6 @@ class ConsoleToolWindowFactory : ToolWindowFactory, DumbAware { } override fun isApplicable(project: Project): Boolean { - return project.service().state.enabled + return true } } diff --git a/src/main/resources/messages/Bundle.properties b/src/main/resources/messages/Bundle.properties index ee5b08b..28ffc30 100644 --- a/src/main/resources/messages/Bundle.properties +++ b/src/main/resources/messages/Bundle.properties @@ -57,7 +57,8 @@ editor.service.manager.creating.formatting.task=Creating formatting task for {0} editor.service.manager.initialising.editor.service=Initialising editor service editor.service.manager.initialising.editor.service.failed.title=Dprint failed to initialise editor.service.manager.initialising.editor.service.failed.content=Please check the IDE errors and the dprint console \ - tool window to diagnose the issue. + tool window to diagnose the issue. It is likely that dprint took too long to resolve your editor schema. Try running \ + `dprint editor-info` to start to diagnose. editor.service.manager.not.initialised=Editor Service is not initialised. Please check your environment and restart \ the dprint plugin. editor.service.manager.no.cached.can.format=Did not find cached can format result for {0} @@ -79,6 +80,7 @@ error.failed.to.parse.json.schema.received=Failed to parse JSON schema.\n\tRecei error.failed.to.parse.json.schema.error=Failed to parse JSON schema.\n\tError: {0}. error.failed.to.parse.json.schema.received.error=Failed to parse JSON schema.\n\tReceived: {0}.\n\tError: {1}. external.formatter.can.format=Dprint can format {0}, overriding default IntelliJ formatter. +external.formatter.can.format.unknown=Unable to determine if dprint can format the file, falling back to the IntelliJ formatter. external.formatter.cancelling.task=Cancelling CodeStyle formatting task {0} external.formatter.cannot.format=Dprint cannot format {0}, IntelliJ formatter will be used. external.formatter.creating.task=Creating IntelliJ CodeStyle Formatting Task for {0}.