diff --git a/.idea/gradle.xml b/.idea/gradle.xml
deleted file mode 100644
index e16b16d..0000000
--- a/.idea/gradle.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
diff --git a/build.gradle.kts b/build.gradle.kts
index aabb8cc..a2e6efe 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,6 +1,5 @@
import org.jetbrains.changelog.Changelog
import org.jetbrains.changelog.markdownToHTML
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
fun properties(key: String) = providers.gradleProperty(key)
fun environment(key: String) = providers.environmentVariable(key)
@@ -9,11 +8,11 @@ plugins {
// Java support
id("java")
// Kotlin support
- id("org.jetbrains.kotlin.jvm") version "1.8.10"
+ id("org.jetbrains.kotlin.jvm") version "1.9.25"
// Gradle IntelliJ Plugin
- id("org.jetbrains.intellij") version "1.13.2"
+ id("org.jetbrains.intellij") version "1.17.2"
// Gradle Changelog Plugin
- id("org.jetbrains.changelog") version "2.0.0"
+ id("org.jetbrains.changelog") version "2.2.1"
// Gradle Qodana Plugin
id("org.jetbrains.qodana") version "0.1.13"
// Gradle Kover Plugin
@@ -30,7 +29,7 @@ repositories {
// Set the JVM language level used to build the project. Use Java 11 for 2020.3+, and Java 17 for 2022.2+.
kotlin {
- jvmToolchain(11)
+ jvmToolchain(17)
}
// Configure Gradle IntelliJ Plugin - read more: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html
diff --git a/gradle.properties b/gradle.properties
index 75e36d7..f5cd7d4 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -4,7 +4,7 @@
pluginGroup = dev.encore.intellij
pluginName = Encore
# SemVer format -> https://semver.org
-pluginVersion = 0.2.0
+pluginVersion = 0.3.0
# See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
# for insight into build numbers and IntelliJ Platform versions.
@@ -21,7 +21,7 @@ platformDownloadSources = true
platformPlugins = org.jetbrains.plugins.go, com.intellij.database
# Gradle Releases -> https://github.com/gradle/gradle/releases
-gradleVersion = 8.0.2
+gradleVersion = 8.12
# Opt-out flag for bundling Kotlin standard library.
# See https://jb.gg/intellij-platform-kotlin-stdlib for details.
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index bdc9a83..18362b7 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/src/main/kotlin/dev/encore/intellij/annotators/ApiDecls.kt b/src/main/kotlin/dev/encore/intellij/annotators/ApiDecls.kt
index 7e0da64..7adde2a 100644
--- a/src/main/kotlin/dev/encore/intellij/annotators/ApiDecls.kt
+++ b/src/main/kotlin/dev/encore/intellij/annotators/ApiDecls.kt
@@ -1,37 +1,37 @@
package dev.encore.intellij.annotators
import com.goide.highlighting.GoSyntaxHighlightingColors
+import com.goide.psi.GoFunctionDeclaration
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.lang.annotation.Annotator
import com.intellij.lang.annotation.HighlightSeverity
import com.intellij.openapi.editor.DefaultLanguageHighlighterColors
-import com.intellij.openapi.editor.markup.GutterIconRenderer
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement
+import com.intellij.psi.util.PsiTreeUtil
class ApiDecls : Annotator {
override fun annotate(element: PsiElement, holder: AnnotationHolder) {
- // If it's not a comment and doesn't start with "//encore:", return
- // as we're not interested in it
- if (element !is PsiComment) {
+ // If it's not a comment, doesn't start with "//encore:" or is not
+ // followed by a func definition, return as we're not interested in it
+ if (element !is PsiComment || PsiTreeUtil.skipWhitespacesForward(element) !is GoFunctionDeclaration) {
return
}
val comment: PsiComment = element
- if (!comment.text.startsWith(API_DECL_PREFIX)) {
- return
- }
- val parts = comment.text.removePrefix("//").split(" ")
- if (parts.isEmpty() || !PREFIXES.containsKey(parts[0]) ) {
+
+ // Parse the comment. Return if prefix is not known to us
+ val (prefix, cfg, args) = parseApiAnnotation(comment)
+ if (cfg == null) {
return
}
- val cfg: DeclCfg = PREFIXES[parts[0]]!!
+ // Skip the initial "//"
+ val startOffset = comment.textRange.startOffset + 2
-
- // Highlight the "//encore:" part of the comment as a comment keyword
- val directiveRange = TextRange.from(comment.textRange.startOffset + 2, parts[0].length)
+ // Highlight the "encore:" part of the comment as a comment keyword
+ val directiveRange = TextRange.from(startOffset, prefix.length)
holder.newSilentAnnotation(HighlightSeverity.INFORMATION)
.range(directiveRange)
.textAttributes(GoSyntaxHighlightingColors.COMMENT_KEYWORD)
@@ -39,17 +39,17 @@ class ApiDecls : Annotator {
.create()
// Highlight the rest of the comment
- var lastIndex = comment.textRange.startOffset + parts[0].length + 3
+ var lastOffset = startOffset + prefix.length + 1
val used = mutableSetOf()
- for (part in parts.drop(1)) {
+ for (part in args) {
if (part.contains('=')) {
// It's a field
val splitPoint = part.indexOf('=')
val fieldName = part.take(splitPoint)
val fieldValue = part.drop(splitPoint + 1)
- val nameRange = TextRange.from(lastIndex, splitPoint)
- val valueRange = TextRange.from(lastIndex + splitPoint + 1, fieldValue.length)
+ val nameRange = TextRange.from(lastOffset, splitPoint)
+ val valueRange = TextRange.from(lastOffset + splitPoint + 1, fieldValue.length)
// Check it's not already used once
@@ -74,13 +74,13 @@ class ApiDecls : Annotator {
.create()
}
- highlightFieldValue(holder, cfg, fieldName, fieldValue, valueRange)
+ highlightFieldValue(holder, fieldName, fieldValue, valueRange)
used.add(fieldName)
} else {
// It's an option
- val partRange = TextRange.from(lastIndex, part.length)
+ val partRange = TextRange.from(lastOffset, part.length)
// Check it's not already used once
if (used.contains(part)) {
@@ -106,11 +106,11 @@ class ApiDecls : Annotator {
used.add(part)
}
- lastIndex += part.length + 1
+ lastOffset += part.length + 1
}
}
- private fun highlightFieldValue(holder: AnnotationHolder, cfg: DeclCfg, fieldName: String, fieldValue: String, range: TextRange) {
+ private fun highlightFieldValue(holder: AnnotationHolder, fieldName: String, fieldValue: String, range: TextRange) {
if (fieldName == "path" && (fieldValue.contains(":") || fieldValue.contains("*"))) {
// highlight each segment starting with ":" as a different colour
var lastIndex = range.startOffset
@@ -156,33 +156,44 @@ class ApiDecls : Annotator {
.create()
}
}
+}
- companion object {
- private const val API_DECL_PREFIX = "//encore:"
-
- private val PREFIXES = mapOf(
- "encore:api" to DeclCfg(
- "This defines an API endpoint",
- arrayOf("raw", "public", "private", "auth"),
- arrayOf("path", "method"),
- ),
- "encore:service" to DeclCfg(
- "This defines a service singleton which will be started up along side your service",
- arrayOf(),
- arrayOf(),
- ),
- "encore:authhandler" to DeclCfg(
- "This defines an authentication handler which will be used to authenticate requests for your whole application.",
- arrayOf(),
- arrayOf(),
- ),
- "encore:middleware" to DeclCfg(
- "This defines a middleware which will be used to process requests",
- arrayOf("global"),
- arrayOf("target"),
- )
- )
+private const val API_DECL_PREFIX = "//encore:"
+
+private val PREFIXES = mapOf(
+ "encore:api" to DeclCfg(
+ "This defines an API endpoint",
+ arrayOf("raw", "public", "private", "auth"),
+ arrayOf("path", "method"),
+ ),
+ "encore:service" to DeclCfg(
+ "This defines a service singleton which will be started up along side your service",
+ arrayOf(),
+ arrayOf(),
+ ),
+ "encore:authhandler" to DeclCfg(
+ "This defines an authentication handler which will be used to authenticate requests for your whole application.",
+ arrayOf(),
+ arrayOf(),
+ ),
+ "encore:middleware" to DeclCfg(
+ "This defines a middleware which will be used to process requests",
+ arrayOf("global"),
+ arrayOf("target"),
+ )
+)
+
+fun isApiAnnotation(comment: PsiComment) = parseApiAnnotation(comment).second != null
+
+private fun parseApiAnnotation(comment: PsiComment): Triple> {
+ val text = comment.text
+ if (!text.startsWith(API_DECL_PREFIX)) {
+ return Triple("", null, emptyList())
}
+ val parts = text.removePrefix("//").split(" ")
+ val prefix = parts.getOrNull(0) ?: ""
+
+ return Triple(prefix, PREFIXES[prefix], parts.drop(1))
}
data class DeclCfg(
diff --git a/src/main/kotlin/dev/encore/intellij/inspections/ApiUnusedSuppressor.kt b/src/main/kotlin/dev/encore/intellij/inspections/ApiUnusedSuppressor.kt
new file mode 100644
index 0000000..93a2da2
--- /dev/null
+++ b/src/main/kotlin/dev/encore/intellij/inspections/ApiUnusedSuppressor.kt
@@ -0,0 +1,28 @@
+package dev.encore.intellij.inspections
+
+import com.goide.psi.GoFunctionDeclaration
+import com.intellij.codeInspection.InspectionSuppressor
+import com.intellij.codeInspection.SuppressQuickFix
+import com.intellij.psi.PsiComment
+import com.intellij.psi.PsiElement
+import com.intellij.psi.util.PsiTreeUtil
+import dev.encore.intellij.annotators.isApiAnnotation
+
+class ApiUnusedSuppressor : InspectionSuppressor {
+
+ override fun isSuppressedFor(element: PsiElement, toolId: String): Boolean {
+ if (element !is GoFunctionDeclaration || toolId != TOOL_ID) {
+ return false
+ }
+ val prevElement = PsiTreeUtil.skipWhitespacesBackward(element)
+ if (prevElement !is PsiComment) {
+ return false
+ }
+ val comment: PsiComment = prevElement
+ return isApiAnnotation(comment)
+ }
+
+ override fun getSuppressActions(element: PsiElement?, toolId: String) = SuppressQuickFix.EMPTY_ARRAY!!
+}
+
+private const val TOOL_ID = "GoUnusedExportedFunction"
diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml
index 5f93fa5..5142ce5 100644
--- a/src/main/resources/META-INF/plugin.xml
+++ b/src/main/resources/META-INF/plugin.xml
@@ -52,6 +52,8 @@
id="dev.encore.intellij.settings.Settings"
displayName="Encore"/>
/>
+
+