aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.editorconfig42
-rw-r--r--.gitattributes30
-rw-r--r--.gitignore46
-rw-r--r--.gitmodules3
-rw-r--r--build.gradle.kts10
-rw-r--r--detekt.yml53
m---------format0
-rw-r--r--gradle.properties8
-rw-r--r--gradle/libs.versions.toml6
-rw-r--r--gradle/wrapper/gradle-wrapper.jarbin63375 -> 63721 bytes
-rw-r--r--gradle/wrapper/gradle-wrapper.properties2
-rwxr-xr-xgradlew3
-rw-r--r--settings.gradle.kts4
-rw-r--r--src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/PreprocessorCompletion.kt35
-rw-r--r--src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/PreprocessorExtend.kt54
-rw-r--r--src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/PreprocessorFolding.kt51
-rw-r--r--src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/PreprocessorHighlight.kt300
-rw-r--r--src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/PreprocessorImport.kt54
-rw-r--r--src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/Preprocessor.kt (renamed from src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/Preprocessor.kt)13
-rw-r--r--src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/PreprocessorCompletion.kt35
-rw-r--r--src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/PreprocessorExtend.kt56
-rw-r--r--src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/PreprocessorFolding.kt63
-rw-r--r--src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/PreprocessorHighlight.kt325
-rw-r--r--src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/PreprocessorImport.kt59
-rw-r--r--src/main/resources/META-INF/plugin.xml18
25 files changed, 708 insertions, 562 deletions
diff --git a/.editorconfig b/.editorconfig
index db6b96d..0901bba 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,2 +1,40 @@
-[*.{gradle,java}]
-ij_java_class_count_to_use_import_on_demand = 999 \ No newline at end of file
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+indent_style = tab
+tab_width = 4
+trim_trailing_whitespace = true
+
+[*.gradle]
+indent_style = tab
+
+[*.java]
+indent_style = tab
+ij_continuation_indent_size = 8
+ij_java_imports_layout = $*,|,java.**,|,javax.**,|,*,|,net.minecraft.**,|,org.polyfrost.**
+ij_java_class_count_to_use_import_on_demand = 999
+
+[*.json]
+indent_style = space
+indent_size = 2
+
+[.editorconfig]
+indent_style = space
+indent_size = 4
+
+[*.md]
+trim_trailing_whitespace = false
+
+[*.gradle]
+indent_style = tab
+
+[*.toml]
+indent_style = tab
+tab_width = 2
+
+[*.properties]
+indent_style = space
+indent_size = 2
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..99d0367
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,30 @@
+*.java text eol=lf diff=java
+*.gradle text eol=lf diff=java
+*.kt text eol=lf diff=kotlin
+*.kts text eol=lf diff=kotlin
+gradlew text eol=lf
+*.bat text eol=crlf
+
+*.md text eol=lf diff=markdown
+
+.editorconfig text eol=lf
+
+*.json text eol=lf
+*.json5 text eol=lf
+*.properties text eol=lf
+*.toml text eol=lf
+*.xml text eol=lf diff=html
+
+# Modding specific
+*.accesswidener text eol=lf
+
+# These files are binary and should be left untouched
+# (binary is a macro for -text -diff)
+*.class binary
+*.dll binary
+*.ear binary
+*.jar binary
+*.jks binary
+*.png binary
+*.so binary
+*.war binary
diff --git a/.gitignore b/.gitignore
index f8d108f..aabe5fd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,35 +1,3 @@
-# eclipse
-bin
-*.launch
-.settings
-.metadata
-.classpath
-.project
-
-# idea
-out
-*.ipr
-*.iws
-*.iml
-.idea
-
-# fleet
-.fleet
-
-# gradle
-build
-.gradle
-
-# other
-eclipse
-run
-build - Copy.gradle
-git-story_media
-.vscode
-.devauth
-.DS_STORE
-
-
# Created by https://www.toptal.com/developers/gitignore/api/java,gradle,forgegradle,kotlin,macos,intellij,intellij+all,eclipse,visualstudiocode
# Edit at https://www.toptal.com/developers/gitignore?templates=java,gradle,forgegradle,kotlin,macos,intellij,intellij+all,eclipse,visualstudiocode
@@ -365,12 +333,6 @@ Temporary Items
.history
.ionide
-# Support for Project snippet scope
-.vscode/*.code-snippets
-
-# Ignore code-workspaces
-*.code-workspace
-
### Gradle ###
.gradle
**/build/
@@ -385,8 +347,6 @@ gradle-app.setting
# Avoid ignore Gradle wrappper properties
!gradle-wrapper.properties
-!*.api
-
# Cache of project
.gradletasknamecache
@@ -396,4 +356,8 @@ gradle-app.setting
# JDT-specific (Eclipse Java Development Tools)
.classpath
-# End of https://www.toptal.com/developers/gitignore/api/java,gradle,forgegradle,kotlin,macos,intellij,intellij+all,eclipse,visualstudiocode \ No newline at end of file
+### Gradle Patch ###
+# Java heap dump
+*.hprof
+
+# End of https://www.toptal.com/developers/gitignore/api/java,gradle,forgegradle,kotlin,macos,intellij,intellij+all,eclipse,visualstudiocode
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..ea4d92e
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "format"]
+ path = format
+ url = https://github.com/polyfrost/buildformat
diff --git a/build.gradle.kts b/build.gradle.kts
index 8668e3e..da0ea43 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -4,17 +4,23 @@ plugins {
id("java")
alias(libs.plugins.kotlin)
alias(libs.plugins.intellij)
+ alias(libs.plugins.kotlinter)
}
group = properties("pluginGroup").get()
version = properties("pluginVersion").get()
repositories {
- maven("https://repo.polyfrost.cc/releases")
+ maven("https://repo.polyfrost.org/releases")
}
kotlin {
- jvmToolchain(17)
+ jvmToolchain(21)
+}
+
+kotlinter {
+ ignoreFailures = false
+ reporters = arrayOf("checkstyle", "plain")
}
intellij {
diff --git a/detekt.yml b/detekt.yml
new file mode 100644
index 0000000..e944b47
--- /dev/null
+++ b/detekt.yml
@@ -0,0 +1,53 @@
+build:
+ maxIssues: 0
+ weights:
+ comments: 0
+
+style:
+ CanBeNonNullable:
+ active: true
+ CollapsibleIfStatements:
+ active: true
+ LibraryCodeMustSpecifyReturnType:
+ active: true
+ MagicNumber:
+ active: true
+ ignorePropertyDeclaration: true
+ ignoreAnnotation: true
+ ignoreEnums: true
+ MaxLineLength:
+ active: true
+ maxLineLength: 120
+ MandatoryBracesIfStatements:
+ active: true
+ MandatoryBracesLoops:
+ active: true
+ NewLineAtEndOfFile:
+ active: true
+ UnusedImports:
+ active: true
+ UnusedPrivateMember:
+ active: true
+ UnusedPrivateClass:
+ active: true
+
+naming:
+ ClassNaming:
+ active: true
+ FunctionNaming:
+ active: true
+
+coroutines:
+ active: true
+ RedundantSuspendModifier:
+ active: true
+
+comments:
+ UndocumentedPublicClass:
+ active: true
+ UndocumentedPublicFunction:
+ active: true
+ UndocumentedPublicProperty:
+ active: true
+ EndOfSentenceFormat:
+ active: true
diff --git a/format b/format
new file mode 160000
+Subproject 4cf6d56acce63bf7f553638c86e835c203a420c
diff --git a/gradle.properties b/gradle.properties
index a9b6fee..4653e92 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,9 +1,9 @@
-pluginGroup=cc.polyfrost.sorbet.intelliprocessor
+pluginGroup=org.polyfrost.sorbet.intelliprocessor
pluginName=IntelliProcessor
pluginRepositoryUrl=https://github.com/Polyfrost/IntelliProcessor
-pluginVersion=1.0.0
+pluginVersion=1.0.1
pluginSinceBuild=223
-pluginUntilBuild=232.*
+pluginUntilBuild=242.*
platformType=IC
platformVersion=2022.3.3
platformPlugins=com.intellij.java
@@ -14,4 +14,4 @@ org.gradle.daemon=true
org.gradle.parallel=true
org.gradle.configureoncommand=true
org.gradle.parallel.threads=4
-org.gradle.jvmargs=-Xmx4G \ No newline at end of file
+org.gradle.jvmargs=-Xmx4G
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 30e4cc4..3979485 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,7 +1,9 @@
[versions]
-kotlin = "1.9.0"
-intellij = "1.15.0"
+kotlin = "1.9.23"
+intellij = "1.17.3"
+kotlinter = "4.3.0"
[plugins]
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
intellij = { id = "org.jetbrains.intellij", version.ref = "intellij" }
+kotlinter = { id = "org.jmailen.kotlinter", version.ref = "kotlinter" }
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 033e24c..7f93135 100644
--- a/gradle/wrapper/gradle-wrapper.jar
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index ac72c34..b82aa23 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.3-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
diff --git a/gradlew b/gradlew
index fcb6fca..0adc8e1 100755
--- a/gradlew
+++ b/gradlew
@@ -83,7 +83,8 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 2faaf35..daf6e92 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,8 +1,8 @@
pluginManagement {
repositories {
gradlePluginPortal()
- maven("https://repo.polyfrost.cc/releases")
+ maven("https://repo.polyfrost.org/releases")
}
}
-rootProject.name = "IntelliProcessor" \ No newline at end of file
+rootProject.name = "IntelliProcessor"
diff --git a/src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/PreprocessorCompletion.kt b/src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/PreprocessorCompletion.kt
deleted file mode 100644
index ce66bc5..0000000
--- a/src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/PreprocessorCompletion.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-package cc.polyfrost.sorbet.intelliprocessor
-
-import com.intellij.codeInsight.completion.*
-import com.intellij.codeInsight.lookup.LookupElementBuilder
-import com.intellij.openapi.project.DumbAware
-import com.intellij.patterns.PlatformPatterns.psiComment
-import com.intellij.patterns.StandardPatterns
-import com.intellij.util.ProcessingContext
-
-class PreprocessorCompletion : CompletionContributor(), DumbAware {
- init {
- extend(
- CompletionType.BASIC,
- psiComment().withText(
- StandardPatterns.or(
- StandardPatterns.string().startsWith("//"),
- StandardPatterns.string().startsWith("#")
- )
- ),
- PreprocessorCompletionProvider
- )
- }
-
- object PreprocessorCompletionProvider : CompletionProvider<CompletionParameters>() {
- override fun addCompletions(
- parameters: CompletionParameters,
- context: ProcessingContext,
- result: CompletionResultSet
- ) {
- for (keyword in KEYWORDS) result.addElement(LookupElementBuilder.create(keyword).bold())
- }
-
- private val KEYWORDS = listOf("#if", "#else", "#elseif", "#endif", "#ifdef")
- }
-} \ No newline at end of file
diff --git a/src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/PreprocessorExtend.kt b/src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/PreprocessorExtend.kt
deleted file mode 100644
index 2c7ea43..0000000
--- a/src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/PreprocessorExtend.kt
+++ /dev/null
@@ -1,54 +0,0 @@
-package cc.polyfrost.sorbet.intelliprocessor
-
-import com.intellij.codeInsight.editorActions.EnterHandler
-import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegate.Result
-import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegateAdapter
-import com.intellij.openapi.actionSystem.DataContext
-import com.intellij.openapi.editor.Editor
-import com.intellij.openapi.editor.actionSystem.EditorActionHandler
-import com.intellij.openapi.project.DumbAware
-import com.intellij.openapi.util.Ref
-import com.intellij.psi.PsiFile
-import com.intellij.psi.impl.source.tree.PsiCommentImpl
-import com.intellij.refactoring.suggested.startOffset
-import java.util.Locale
-
-class PreprocessorExtend : EnterHandlerDelegateAdapter(), DumbAware {
- override fun preprocessEnter(
- file: PsiFile,
- editor: Editor,
- caretOffset: Ref<Int>,
- caretAdvance: Ref<Int>,
- dataContext: DataContext,
- originalHandler: EditorActionHandler?
- ): Result {
- if (
- EnterHandler.getLanguage(dataContext)
- ?.associatedFileType
- ?.name?.uppercase(Locale.getDefault()) !in ALLOWED_TYPES
- ) return Result.Continue
-
- val caret: Int = caretOffset.get().toInt()
- val psiAtOffset = file.findElementAt(caret)
-
- if (psiAtOffset is PsiCommentImpl) {
- if (!psiAtOffset.text.startsWith("//$$")) return Result.Continue
- val posInText = caret - psiAtOffset.startOffset
- if (posInText < 4) return Result.DefaultForceIndent
-
- editor.document.insertString(editor.caretModel.offset, "//$$ ")
- caretAdvance.set(5)
- return Result.DefaultForceIndent
- } else if (psiAtOffset?.prevSibling is PsiCommentImpl) {
- if (!psiAtOffset.prevSibling.text.startsWith("//$$")) return Result.Continue
- val posInText = caret - psiAtOffset.prevSibling.startOffset
- if (posInText < 4) return Result.DefaultForceIndent
-
- editor.document.insertString(editor.caretModel.offset, "//$$ ")
- caretAdvance.set(5)
- return Result.DefaultForceIndent
- }
-
- return Result.Continue
- }
-} \ No newline at end of file
diff --git a/src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/PreprocessorFolding.kt b/src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/PreprocessorFolding.kt
deleted file mode 100644
index 1bcbb66..0000000
--- a/src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/PreprocessorFolding.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package cc.polyfrost.sorbet.intelliprocessor
-
-import com.intellij.lang.ASTNode
-import com.intellij.lang.LanguageCommenters
-import com.intellij.lang.folding.FoldingBuilderEx
-import com.intellij.lang.folding.FoldingDescriptor
-import com.intellij.openapi.editor.Document
-import com.intellij.openapi.project.DumbAware
-import com.intellij.openapi.util.TextRange
-import com.intellij.psi.PsiComment
-import com.intellij.psi.PsiElement
-import com.intellij.psi.PsiWhiteSpace
-import com.intellij.psi.util.PsiTreeUtil
-import com.intellij.refactoring.suggested.endOffset
-import com.intellij.refactoring.suggested.startOffset
-
-class PreprocessorFolding : FoldingBuilderEx(), DumbAware {
- override fun getPlaceholderText(node: ASTNode): String {
- if (node !is PsiComment) return "...11".also { println("Not a comment? Is $node") }
- val directivePrefix = (LanguageCommenters.INSTANCE.forLanguage(node.language).lineCommentPrefix
- ?: return "...222".also { println("Null comment prefix?") })
- return (node as ASTNode).text.substring(directivePrefix.length)
- }
-
- override fun buildFoldRegions(root: PsiElement, document: Document, quick: Boolean): Array<FoldingDescriptor> {
- val descriptors = mutableListOf<FoldingDescriptor>()
- val directivePrefix = (LanguageCommenters.INSTANCE.forLanguage(root.language).lineCommentPrefix
- ?: return emptyArray()) + "#"
- val allDirectives = PsiTreeUtil.findChildrenOfType(root, PsiComment::class.java)
- .filter { it.text.startsWith(directivePrefix) }
-
- for ((index, directive) in allDirectives.withIndex()) if (directive.text.run {
- startsWith(directivePrefix + "if")
- || startsWith(directivePrefix + "ifdef")
- || startsWith(directivePrefix + "else")
- } && index + 1 < allDirectives.size) {
- val nextDirective = allDirectives[index + 1]
- val endOffset = when {
- nextDirective.text.startsWith(directivePrefix + "endif") -> nextDirective.endOffset
- nextDirective.prevSibling is PsiWhiteSpace -> nextDirective.prevSibling.startOffset
- else -> nextDirective.startOffset
- }
-
- descriptors.add(FoldingDescriptor(directive, TextRange(directive.startOffset, endOffset)))
- }
-
- return descriptors.toTypedArray()
- }
-
- override fun isCollapsedByDefault(node: ASTNode) = false
-} \ No newline at end of file
diff --git a/src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/PreprocessorHighlight.kt b/src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/PreprocessorHighlight.kt
deleted file mode 100644
index 2442028..0000000
--- a/src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/PreprocessorHighlight.kt
+++ /dev/null
@@ -1,300 +0,0 @@
-package cc.polyfrost.sorbet.intelliprocessor
-
-import com.intellij.codeInsight.daemon.impl.HighlightInfo
-import com.intellij.codeInsight.daemon.impl.HighlightInfoType
-import com.intellij.codeInsight.daemon.impl.HighlightVisitor
-import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder
-import com.intellij.lang.Commenter
-import com.intellij.lang.LanguageCommenters
-import com.intellij.lang.annotation.HighlightSeverity
-import com.intellij.openapi.diagnostic.Logger
-import com.intellij.openapi.editor.DefaultLanguageHighlighterColors
-import com.intellij.openapi.editor.colors.EditorColorsManager
-import com.intellij.openapi.editor.colors.TextAttributesKey
-import com.intellij.openapi.editor.markup.TextAttributes
-import com.intellij.openapi.fileTypes.SyntaxHighlighter
-import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory
-import com.intellij.openapi.project.DumbAware
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiElement
-import com.intellij.psi.PsiFile
-import com.intellij.psi.impl.source.tree.PsiCommentImpl
-import com.intellij.refactoring.suggested.endOffset
-import java.awt.Font
-import java.util.*
-import java.util.regex.Pattern
-
-class PreprocessorHighlight(private val project: Project) : HighlightVisitor, DumbAware {
- private lateinit var holder: HighlightInfoHolder
- private lateinit var commenter: Commenter
- private lateinit var highlighter: SyntaxHighlighter
-
- private var preprocessorState = ArrayDeque<PreprocessorState>()
-
- override fun suitableForFile(file: PsiFile): Boolean {
- return file.fileType.name.uppercase(Locale.getDefault()) in ALLOWED_TYPES
- }
-
- override fun clone(): PreprocessorHighlight {
- return PreprocessorHighlight(project)
- }
-
- override fun analyze(
- file: PsiFile,
- updateWholeFile: Boolean,
- holder: HighlightInfoHolder,
- action: Runnable
- ): Boolean {
- this.holder = holder
- this.commenter = LanguageCommenters.INSTANCE.forLanguage(file.language)
- this.highlighter = SyntaxHighlighterFactory.getSyntaxHighlighter(file.language, file.project, file.virtualFile)
-
- action.run()
- return true
- }
-
- override fun visit(element: PsiElement) {
- if (element !is PsiCommentImpl) return
- val commentSource = element.text
- if (commenter.lineCommentPrefix?.let {
- commentSource.startsWith(it)
- } != true) return
-
- val prefixLength = commenter.lineCommentPrefix?.length ?: return
-
- val comment = commentSource.substring(prefixLength)
- if (comment.isEmpty()) return
-
- EditorColorsManager.getInstance()
-
- if (comment.startsWith("#")) {
- val commentSegments = comment.substring(1).split(WHITESPACES_PATTERN, limit = 2)
-
- when (val directive = commentSegments[0]) {
- "if", "elseif" -> {
- if (directive == "elseif") {
- val existingIf = preprocessorState.pollFirst()
- if (existingIf != PreprocessorState.IF) {
- fail(
- element,
- "Preprocessor directive \"elseif\" must have a preceding \"if\" or \"elseif\"."
- )
- return
- }
- }
-
- preprocessorState.push(PreprocessorState.IF)
-
- holder.add(directive.toDirectiveHighlight(element, prefixLength))
-
- if (commentSegments.size < 2) {
- fail(element, "Preprocessor directive \"$directive\" is missing a condition.", eol = true)
- return
- }
-
- val conditionsSource = commentSegments[1]
- val conditions = conditionsSource.split(SPLIT_PATTERN)
-
- var nextStartPos = prefixLength + 3
- for (condition in conditions) {
- val trimmedCondition = condition.trim()
-
- val position = commentSource.indexOf(trimmedCondition, nextStartPos)
- nextStartPos = position + trimmedCondition.length
-
- val conditionMatcher = EXPR_PATTERN.find(trimmedCondition)
-
- if (conditionMatcher == null || conditionMatcher.groups.size < 4) {
- val identifierMatcher = IDENTIFIER_PATTERN.matchEntire(trimmedCondition)
-
- if (identifierMatcher != null) {
- holder.add(identifierMatcher.groups[0]?.toNumericOrVariableHighlight(element, position))
- } else {
- holder.add(trimmedCondition.toInvalidConditionErrorHighlight(element, position))
- }
-
- continue
- }
-
- holder.add(conditionMatcher.groups[1]?.toNumericOrVariableHighlight(element, position))
- holder.add(conditionMatcher.groups[3]?.toNumericOrVariableHighlight(element, position))
- }
- }
-
- "ifdef" -> {
- preprocessorState.push(PreprocessorState.IF)
-
- holder.add(directive.toDirectiveHighlight(element, prefixLength))
-
- if (commentSegments.size < 2) {
- fail(element, "Preprocessor directive \"ifdef\" is missing an identifier.", eol = true)
- return
- }
-
- val idInfo = HighlightInfo
- .newHighlightInfo(IDENTIFIER_TYPE)
- .range(
- element as PsiElement,
- element.startOffset + prefixLength + 7,
- element.startOffset + prefixLength + 7 + commentSegments[1].length
- )
- .textAttributes(IDENTIFIER_ATTRIBUTES)
- .create()
-
- holder.add(idInfo)
- }
-
- "else" -> {
- val state = preprocessorState.pollFirst()
- preprocessorState.push(PreprocessorState.ELSE)
-
- if (state != PreprocessorState.IF) {
- fail(element, "Preprocessor directive \"else\" must have an opening if.")
- return
- }
-
- if (commentSegments.size > 1) {
- fail(element, "Preprocessor directive \"else\" does not require any arguments.")
- return
- }
-
- holder.add(directive.toDirectiveHighlight(element, prefixLength))
- }
-
- "endif" -> {
- val state = preprocessorState.pollFirst()
-
- if (state != PreprocessorState.IF && state != PreprocessorState.ELSE) {
- fail(element, "Preprocessor directive \"endif\" must have an opening if.")
- return
- }
-
- if (commentSegments.size > 1) {
- fail(element, "Preprocessor directive \"endif\" does not require any arguments.")
- return
- }
-
- holder.add(directive.toDirectiveHighlight(element, prefixLength))
- }
-
- else -> {
- fail(element, "Unknown preprocessor directive \"$directive\"")
- }
- }
- } else if (comment.startsWith("$$")) {
- holder.add("$$".toDirectiveHighlight(element, prefixLength))
-
- highlightCodeBlock(element, element.startOffset + prefixLength + 2, comment.substring(2))
- }
- }
-
- private fun highlightCodeBlock(element: PsiCommentImpl, startOffset: Int, text: String) {
- val lexer = highlighter.highlightingLexer
-
- lexer.start(text)
- var token = lexer.tokenType
-
- while (token != null) {
- val attributes = highlighter.getTokenHighlights(token)
- .fold(TextAttributes(null, null, null, null, 0)) { first, second ->
- TextAttributes.merge(first, SCHEME.getAttributes(second))
- }
-
- val directiveInfo = HighlightInfo
- .newHighlightInfo(HighlightInfoType.INJECTED_LANGUAGE_FRAGMENT)
- .range(
- element as PsiElement,
- startOffset + lexer.tokenStart,
- startOffset + lexer.tokenEnd
- )
- .textAttributes(attributes)
- .create()
-
- holder.add(directiveInfo)
-
- lexer.advance()
- token = lexer.tokenType
- }
- }
-
- private fun fail(element: PsiElement, text: String, eol: Boolean = false) {
- val info = HighlightInfo
- .newHighlightInfo(HighlightInfoType.ERROR)
- .descriptionAndTooltip(text)
- .apply {
- if (eol) {
- endOfLine()
- range(element.endOffset, element.endOffset)
- } else {
- range(element)
- }
- }
- .create()
-
- holder.add(info)
- }
-
- private fun MatchGroup.toNumericOrVariableHighlight(element: PsiCommentImpl, offset: Int = 0): HighlightInfo? {
- val builder = if (value.trim().toIntOrNull() != null) {
- HighlightInfo
- .newHighlightInfo(NUMBER_TYPE)
- .textAttributes(NUMBER_ATTRIBUTES)
- } else {
- HighlightInfo
- .newHighlightInfo(IDENTIFIER_TYPE)
- .textAttributes(IDENTIFIER_ATTRIBUTES)
- }
-
- return builder
- .range(element, element.startOffset + offset + range.first, element.startOffset + offset + range.last + 1)
- .create()
- }
-
- private fun String.toDirectiveHighlight(element: PsiCommentImpl, offset: Int = 0): HighlightInfo? {
- return HighlightInfo
- .newHighlightInfo(DIRECTIVE_TYPE)
- .textAttributes(DIRECTIVE_ATTRIBUTES)
- .range(element, element.startOffset + offset, element.startOffset + offset + 1 + length)
- .create()
- }
-
- private fun String.toInvalidConditionErrorHighlight(element: PsiCommentImpl, offset: Int = 0): HighlightInfo? {
- return HighlightInfo
- .newHighlightInfo(HighlightInfoType.ERROR)
- .range(element, element.startOffset + offset, element.startOffset + offset + length)
- .descriptionAndTooltip("Invalid condition \"$this\"")
- .create()
- }
-
- companion object {
- private val BOLD_ATTRIBUTE = TextAttributes(null, null, null, null, Font.BOLD)
- val SCHEME = EditorColorsManager.getInstance().globalScheme
-
- private val DIRECTIVE_COLOR: TextAttributesKey = DefaultLanguageHighlighterColors.KEYWORD
- val DIRECTIVE_ATTRIBUTES: TextAttributes =
- TextAttributes.merge(SCHEME.getAttributes(DIRECTIVE_COLOR), BOLD_ATTRIBUTE)
- val DIRECTIVE_TYPE = HighlightInfoType.HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, DIRECTIVE_COLOR)
-
- private val OPERATOR_COLOR: TextAttributesKey = DefaultLanguageHighlighterColors.OPERATION_SIGN
- val OPERATOR_ATTRIBUTES = SCHEME.getAttributes(OPERATOR_COLOR)
- val OPERATOR_TYPE = HighlightInfoType.HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, OPERATOR_COLOR)
-
- private val IDENTIFIER_COLOR: TextAttributesKey = DefaultLanguageHighlighterColors.IDENTIFIER
- val IDENTIFIER_ATTRIBUTES: TextAttributes =
- TextAttributes.merge(SCHEME.getAttributes(IDENTIFIER_COLOR), BOLD_ATTRIBUTE)
- val IDENTIFIER_TYPE = HighlightInfoType.HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, IDENTIFIER_COLOR)
-
- private val NUMBER_COLOR: TextAttributesKey = DefaultLanguageHighlighterColors.NUMBER
- val NUMBER_ATTRIBUTES: TextAttributes = TextAttributes.merge(SCHEME.getAttributes(NUMBER_COLOR), BOLD_ATTRIBUTE)
- val NUMBER_TYPE = HighlightInfoType.HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, NUMBER_COLOR)
-
- private val LOGGER: Logger = Logger.getInstance(PreprocessorHighlight::class.java)
-
- private val WHITESPACES_PATTERN = "\\s+".toRegex()
- private val EXPR_PATTERN = "(.+)(==|!=|<=|>=|<|>)(.+)".toRegex()
- private val IDENTIFIER_PATTERN = "[A-Za-z0-9]+".toRegex()
- private val OR_PATTERN = Pattern.quote("||")
- private val AND_PATTERN = Pattern.quote("&&")
- private val SPLIT_PATTERN = Pattern.compile("$OR_PATTERN|$AND_PATTERN")
- }
-} \ No newline at end of file
diff --git a/src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/PreprocessorImport.kt b/src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/PreprocessorImport.kt
deleted file mode 100644
index 5ccf6f5..0000000
--- a/src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/PreprocessorImport.kt
+++ /dev/null
@@ -1,54 +0,0 @@
-package cc.polyfrost.sorbet.intelliprocessor
-
-import com.intellij.lang.ImportOptimizer
-import com.intellij.lang.LanguageImportStatements
-import com.intellij.lang.java.JavaImportOptimizer
-import com.intellij.openapi.util.EmptyRunnable
-import com.intellij.psi.*
-import com.intellij.psi.codeStyle.JavaCodeStyleManager
-import com.intellij.psi.impl.source.tree.PsiCommentImpl
-
-class PreprocessorImport : ImportOptimizer {
- override fun supports(file: PsiFile): Boolean {
- return file is PsiJavaFile
- }
-
- override fun processFile(file: PsiFile): Runnable {
- if (file !is PsiJavaFile) return EmptyRunnable.getInstance()
- val imports = file.importList ?: return EmptyRunnable.getInstance()
-
- if (!hasPreprocessorDirectives(imports))
- return LanguageImportStatements.INSTANCE
- .allForLanguage(file.language)
- .first { it !is JavaImportOptimizer }
- .processFile(file)
-
- val optimizedImportList = JavaCodeStyleManager
- .getInstance(file.project)
- .prepareOptimizeImportsResult(file)
-
- return Runnable {
- val manager = PsiDocumentManager.getInstance(file.project)
- val document = manager.getDocument(file)
- if (document != null) manager.commitDocument(document)
-
- for (import in imports.importStatements)
- if (optimizedImportList.findSingleClassImportStatement(import.qualifiedName) == null)
- import.delete()
-
- if (imports.firstChild is PsiWhiteSpace) imports.firstChild.delete()
- }
- }
-
- private fun hasPreprocessorDirectives(imports: PsiImportList): Boolean {
- var import = imports.firstChild
-
- while (import != null) {
- if (import is PsiCommentImpl && import.text.startsWith("//#"))
- return true
- else import = import.nextSibling
- }
-
- return false
- }
-} \ No newline at end of file
diff --git a/src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/Preprocessor.kt b/src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/Preprocessor.kt
index a79cb4e..03cb762 100644
--- a/src/main/kotlin/cc/polyfrost/sorbet/intelliprocessor/Preprocessor.kt
+++ b/src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/Preprocessor.kt
@@ -1,11 +1,16 @@
-package cc.polyfrost.sorbet.intelliprocessor
+package org.polyfrost.sorbet.intelliprocessor
val ALLOWED_TYPES = listOf("JAVA", "KOTLIN")
enum class PreprocessorState {
- NONE, IF, ELSE
+ NONE,
+ IF,
+ ELSE,
}
enum class PreprocessorDirective {
- IF, IFDEF, ELSE, ENDIF
-} \ No newline at end of file
+ IF,
+ IFDEF,
+ ELSE,
+ ENDIF,
+}
diff --git a/src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/PreprocessorCompletion.kt b/src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/PreprocessorCompletion.kt
new file mode 100644
index 0000000..b5f8417
--- /dev/null
+++ b/src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/PreprocessorCompletion.kt
@@ -0,0 +1,35 @@
+package org.polyfrost.sorbet.intelliprocessor
+
+import com.intellij.codeInsight.completion.*
+import com.intellij.codeInsight.lookup.LookupElementBuilder
+import com.intellij.openapi.project.DumbAware
+import com.intellij.patterns.PlatformPatterns.psiComment
+import com.intellij.patterns.StandardPatterns
+import com.intellij.util.ProcessingContext
+
+class PreprocessorCompletion : CompletionContributor(), DumbAware {
+ init {
+ extend(
+ CompletionType.BASIC,
+ psiComment().withText(
+ StandardPatterns.or(
+ StandardPatterns.string().startsWith("//"),
+ StandardPatterns.string().startsWith("#"),
+ ),
+ ),
+ PreprocessorCompletionProvider,
+ )
+ }
+
+ object PreprocessorCompletionProvider : CompletionProvider<CompletionParameters>() {
+ override fun addCompletions(
+ parameters: CompletionParameters,
+ context: ProcessingContext,
+ result: CompletionResultSet,
+ ) {
+ for (keyword in KEYWORDS) result.addElement(LookupElementBuilder.create(keyword).bold())
+ }
+
+ private val KEYWORDS = listOf("#if", "#else", "#elseif", "#endif", "#ifdef")
+ }
+}
diff --git a/src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/PreprocessorExtend.kt b/src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/PreprocessorExtend.kt
new file mode 100644
index 0000000..db59737
--- /dev/null
+++ b/src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/PreprocessorExtend.kt
@@ -0,0 +1,56 @@
+package org.polyfrost.sorbet.intelliprocessor
+
+import com.intellij.codeInsight.editorActions.EnterHandler
+import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegate.Result
+import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegateAdapter
+import com.intellij.openapi.actionSystem.DataContext
+import com.intellij.openapi.editor.Editor
+import com.intellij.openapi.editor.actionSystem.EditorActionHandler
+import com.intellij.openapi.project.DumbAware
+import com.intellij.openapi.util.Ref
+import com.intellij.psi.PsiFile
+import com.intellij.psi.impl.source.tree.PsiCommentImpl
+import com.intellij.refactoring.suggested.startOffset
+import java.util.Locale
+
+class PreprocessorExtend : EnterHandlerDelegateAdapter(), DumbAware {
+ override fun preprocessEnter(
+ file: PsiFile,
+ editor: Editor,
+ caretOffset: Ref<Int>,
+ caretAdvance: Ref<Int>,
+ dataContext: DataContext,
+ originalHandler: EditorActionHandler?,
+ ): Result {
+ if (
+ EnterHandler.getLanguage(dataContext)
+ ?.associatedFileType
+ ?.name?.uppercase(Locale.getDefault()) !in ALLOWED_TYPES
+ ) {
+ return Result.Continue
+ }
+
+ val caret: Int = caretOffset.get().toInt()
+ val psiAtOffset = file.findElementAt(caret)
+
+ if (psiAtOffset is PsiCommentImpl) {
+ if (!psiAtOffset.text.startsWith("//$$")) return Result.Continue
+ val posInText = caret - psiAtOffset.startOffset
+ if (posInText < 4) return Result.DefaultForceIndent
+
+ editor.document.insertString(editor.caretModel.offset, "//$$ ")
+ caretAdvance.set(5)
+ return Result.DefaultForceIndent
+ } else if (psiAtOffset?.prevSibling is PsiCommentImpl) {
+ if (!psiAtOffset.prevSibling.text.startsWith("//$$")) return Result.Continue
+ val posInText = caret - psiAtOffset.prevSibling.startOffset
+ if (posInText < 4) return Result.DefaultForceIndent
+
+ editor.document.insertString(editor.caretModel.offset, "//$$ ")
+ caretAdvance.set(5)
+ return Result.DefaultForceIndent
+ }
+
+ return Result.Continue
+ }
+}
diff --git a/src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/PreprocessorFolding.kt b/src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/PreprocessorFolding.kt
new file mode 100644
index 0000000..25d5ba0
--- /dev/null
+++ b/src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/PreprocessorFolding.kt
@@ -0,0 +1,63 @@
+package org.polyfrost.sorbet.intelliprocessor
+
+import com.intellij.lang.ASTNode
+import com.intellij.lang.LanguageCommenters
+import com.intellij.lang.folding.FoldingBuilderEx
+import com.intellij.lang.folding.FoldingDescriptor
+import com.intellij.openapi.editor.Document
+import com.intellij.openapi.project.DumbAware
+import com.intellij.openapi.util.TextRange
+import com.intellij.psi.PsiComment
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiWhiteSpace
+import com.intellij.psi.util.PsiTreeUtil
+import com.intellij.refactoring.suggested.endOffset
+import com.intellij.refactoring.suggested.startOffset
+
+class PreprocessorFolding : FoldingBuilderEx(), DumbAware {
+ override fun getPlaceholderText(node: ASTNode): String {
+ if (node !is PsiComment) return "...11".also { println("Not a comment? Is $node") }
+ val directivePrefix = (
+ LanguageCommenters.INSTANCE.forLanguage(node.language).lineCommentPrefix
+ ?: return "...222".also { println("Null comment prefix?") }
+ )
+ return (node as ASTNode).text.substring(directivePrefix.length)
+ }
+
+ override fun buildFoldRegions(
+ root: PsiElement,
+ document: Document,
+ quick: Boolean,
+ ): Array<FoldingDescriptor> {
+ val descriptors = mutableListOf<FoldingDescriptor>()
+ val directivePrefix =
+ (
+ LanguageCommenters.INSTANCE.forLanguage(root.language).lineCommentPrefix
+ ?: return emptyArray()
+ ) + "#"
+ val allDirectives =
+ PsiTreeUtil.findChildrenOfType(root, PsiComment::class.java)
+ .filter { it.text.startsWith(directivePrefix) }
+
+ for ((index, directive) in allDirectives.withIndex()) if (directive.text.run {
+ startsWith(directivePrefix + "if") ||
+ startsWith(directivePrefix + "ifdef") ||
+ startsWith(directivePrefix + "else")
+ } && index + 1 < allDirectives.size
+ ) {
+ val nextDirective = allDirectives[index + 1]
+ val endOffset =
+ when {
+ nextDirective.text.startsWith(directivePrefix + "endif") -> nextDirective.endOffset
+ nextDirective.prevSibling is PsiWhiteSpace -> nextDirective.prevSibling.startOffset
+ else -> nextDirective.startOffset
+ }
+
+ descriptors.add(FoldingDescriptor(directive, TextRange(directive.startOffset, endOffset)))
+ }
+
+ return descriptors.toTypedArray()
+ }
+
+ override fun isCollapsedByDefault(node: ASTNode) = false
+}
diff --git a/src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/PreprocessorHighlight.kt b/src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/PreprocessorHighlight.kt
new file mode 100644
index 0000000..9eba31b
--- /dev/null
+++ b/src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/PreprocessorHighlight.kt
@@ -0,0 +1,325 @@
+package org.polyfrost.sorbet.intelliprocessor
+
+import com.intellij.codeInsight.daemon.impl.HighlightInfo
+import com.intellij.codeInsight.daemon.impl.HighlightInfoType
+import com.intellij.codeInsight.daemon.impl.HighlightVisitor
+import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder
+import com.intellij.lang.Commenter
+import com.intellij.lang.LanguageCommenters
+import com.intellij.lang.annotation.HighlightSeverity
+import com.intellij.openapi.diagnostic.Logger
+import com.intellij.openapi.editor.DefaultLanguageHighlighterColors
+import com.intellij.openapi.editor.colors.EditorColorsManager
+import com.intellij.openapi.editor.colors.TextAttributesKey
+import com.intellij.openapi.editor.markup.TextAttributes
+import com.intellij.openapi.fileTypes.SyntaxHighlighter
+import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory
+import com.intellij.openapi.project.DumbAware
+import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiFile
+import com.intellij.psi.impl.source.tree.PsiCommentImpl
+import com.intellij.refactoring.suggested.endOffset
+import java.awt.Font
+import java.util.*
+import java.util.regex.Pattern
+
+class PreprocessorHighlight(private val project: Project) : HighlightVisitor, DumbAware {
+ private lateinit var holder: HighlightInfoHolder
+ private lateinit var commenter: Commenter
+ private lateinit var highlighter: SyntaxHighlighter
+
+ private var preprocessorState = ArrayDeque<PreprocessorState>()
+
+ override fun suitableForFile(file: PsiFile): Boolean {
+ return file.fileType.name.uppercase(Locale.getDefault()) in ALLOWED_TYPES
+ }
+
+ override fun clone(): PreprocessorHighlight {
+ return PreprocessorHighlight(project)
+ }
+
+ override fun analyze(
+ file: PsiFile,
+ updateWholeFile: Boolean,
+ holder: HighlightInfoHolder,
+ action: Runnable,
+ ): Boolean {
+ this.holder = holder
+ this.commenter = LanguageCommenters.INSTANCE.forLanguage(file.language)
+ this.highlighter = SyntaxHighlighterFactory.getSyntaxHighlighter(file.language, file.project, file.virtualFile)
+
+ action.run()
+ return true
+ }
+
+ override fun visit(element: PsiElement) {
+ if (element !is PsiCommentImpl) return
+ val commentSource = element.text
+ if (commenter.lineCommentPrefix?.let {
+ commentSource.startsWith(it)
+ } != true
+ ) {
+ return
+ }
+
+ val prefixLength = commenter.lineCommentPrefix?.length ?: return
+
+ val comment = commentSource.substring(prefixLength)
+ if (comment.isEmpty()) return
+
+ EditorColorsManager.getInstance()
+
+ if (comment.startsWith("#")) {
+ val commentSegments = comment.substring(1).split(WHITESPACES_PATTERN, limit = 2)
+
+ when (val directive = commentSegments[0]) {
+ "if", "elseif" -> {
+ if (directive == "elseif") {
+ val existingIf = preprocessorState.pollFirst()
+ if (existingIf != PreprocessorState.IF) {
+ fail(
+ element,
+ "Preprocessor directive \"elseif\" must have a preceding \"if\" or \"elseif\".",
+ )
+ return
+ }
+ }
+
+ preprocessorState.push(PreprocessorState.IF)
+
+ holder.add(directive.toDirectiveHighlight(element, prefixLength))
+
+ if (commentSegments.size < 2) {
+ fail(element, "Preprocessor directive \"$directive\" is missing a condition.", eol = true)
+ return
+ }
+
+ val conditionsSource = commentSegments[1]
+ val conditions = conditionsSource.split(SPLIT_PATTERN)
+
+ var nextStartPos = prefixLength + 3
+ for (condition in conditions) {
+ val trimmedCondition = condition.trim()
+
+ val position = commentSource.indexOf(trimmedCondition, nextStartPos)
+ nextStartPos = position + trimmedCondition.length
+
+ val conditionMatcher = EXPR_PATTERN.find(trimmedCondition)
+
+ if (conditionMatcher == null || conditionMatcher.groups.size < 4) {
+ val identifierMatcher = IDENTIFIER_PATTERN.matchEntire(trimmedCondition)
+
+ if (identifierMatcher != null) {
+ holder.add(identifierMatcher.groups[0]?.toNumericOrVariableHighlight(element, position))
+ } else {
+ holder.add(trimmedCondition.toInvalidConditionErrorHighlight(element, position))
+ }
+
+ continue
+ }
+
+ holder.add(conditionMatcher.groups[1]?.toNumericOrVariableHighlight(element, position))
+ holder.add(conditionMatcher.groups[3]?.toNumericOrVariableHighlight(element, position))
+ }
+ }
+
+ "ifdef" -> {
+ preprocessorState.push(PreprocessorState.IF)
+
+ holder.add(directive.toDirectiveHighlight(element, prefixLength))
+
+ if (commentSegments.size < 2) {
+ fail(element, "Preprocessor directive \"ifdef\" is missing an identifier.", eol = true)
+ return
+ }
+
+ val idInfo =
+ HighlightInfo
+ .newHighlightInfo(IDENTIFIER_TYPE)
+ .range(
+ element as PsiElement,
+ element.startOffset + prefixLength + 7,
+ element.startOffset + prefixLength + 7 + commentSegments[1].length,
+ )
+ .textAttributes(IDENTIFIER_ATTRIBUTES)
+ .create()
+
+ holder.add(idInfo)
+ }
+
+ "else" -> {
+ val state = preprocessorState.pollFirst()
+ preprocessorState.push(PreprocessorState.ELSE)
+
+ if (state != PreprocessorState.IF) {
+ fail(element, "Preprocessor directive \"else\" must have an opening if.")
+ return
+ }
+
+ if (commentSegments.size > 1) {
+ fail(element, "Preprocessor directive \"else\" does not require any arguments.")
+ return
+ }
+
+ holder.add(directive.toDirectiveHighlight(element, prefixLength))
+ }
+
+ "endif" -> {
+ val state = preprocessorState.pollFirst()
+
+ if (state != PreprocessorState.IF && state != PreprocessorState.ELSE) {
+ fail(element, "Preprocessor directive \"endif\" must have an opening if.")
+ return
+ }
+
+ if (commentSegments.size > 1) {
+ fail(element, "Preprocessor directive \"endif\" does not require any arguments.")
+ return
+ }
+
+ holder.add(directive.toDirectiveHighlight(element, prefixLength))
+ }
+
+ else -> {
+ fail(element, "Unknown preprocessor directive \"$directive\"")
+ }
+ }
+ } else if (comment.startsWith("$$")) {
+ holder.add("$$".toDirectiveHighlight(element, prefixLength))
+
+ highlightCodeBlock(element, element.startOffset + prefixLength + 2, comment.substring(2))
+ }
+ }
+
+ private fun highlightCodeBlock(
+ element: PsiCommentImpl,
+ startOffset: Int,
+ text: String,
+ ) {
+ val lexer = highlighter.highlightingLexer
+
+ lexer.start(text)
+ var token = lexer.tokenType
+
+ while (token != null) {
+ val attributes =
+ highlighter.getTokenHighlights(token)
+ .fold(TextAttributes(null, null, null, null, 0)) { first, second ->
+ TextAttributes.merge(first, SCHEME.getAttributes(second))
+ }
+
+ val directiveInfo =
+ HighlightInfo
+ .newHighlightInfo(HighlightInfoType.INJECTED_LANGUAGE_FRAGMENT)
+ .range(
+ element as PsiElement,
+ startOffset + lexer.tokenStart,
+ startOffset + lexer.tokenEnd,
+ )
+ .textAttributes(attributes)
+ .create()
+
+ holder.add(directiveInfo)
+
+ lexer.advance()
+ token = lexer.tokenType
+ }
+ }
+
+ private fun fail(
+ element: PsiElement,
+ text: String,
+ eol: Boolean = false,
+ ) {
+ val info =
+ HighlightInfo
+ .newHighlightInfo(HighlightInfoType.ERROR)
+ .descriptionAndTooltip(text)
+ .apply {
+ if (eol) {
+ endOfLine()
+ range(element.endOffset, element.endOffset)
+ } else {
+ range(element)
+ }
+ }
+ .create()
+
+ holder.add(info)
+ }
+
+ private fun MatchGroup.toNumericOrVariableHighlight(
+ element: PsiCommentImpl,
+ offset: Int = 0,
+ ): HighlightInfo? {
+ val builder =
+ if (value.trim().toIntOrNull() != null) {
+ HighlightInfo
+ .newHighlightInfo(NUMBER_TYPE)
+ .textAttributes(NUMBER_ATTRIBUTES)
+ } else {
+ HighlightInfo
+ .newHighlightInfo(IDENTIFIER_TYPE)
+ .textAttributes(IDENTIFIER_ATTRIBUTES)
+ }
+
+ return builder
+ .range(element, element.startOffset + offset + range.first, element.startOffset + offset + range.last + 1)
+ .create()
+ }
+
+ private fun String.toDirectiveHighlight(
+ element: PsiCommentImpl,
+ offset: Int = 0,
+ ): HighlightInfo? {
+ return HighlightInfo
+ .newHighlightInfo(DIRECTIVE_TYPE)
+ .textAttributes(DIRECTIVE_ATTRIBUTES)
+ .range(element, element.startOffset + offset, element.startOffset + offset + 1 + length)
+ .create()
+ }
+
+ private fun String.toInvalidConditionErrorHighlight(
+ element: PsiCommentImpl,
+ offset: Int = 0,
+ ): HighlightInfo? {
+ return HighlightInfo
+ .newHighlightInfo(HighlightInfoType.ERROR)
+ .range(element, element.startOffset + offset, element.startOffset + offset + length)
+ .descriptionAndTooltip("Invalid condition \"$this\"")
+ .create()
+ }
+
+ companion object {
+ private val BOLD_ATTRIBUTE = TextAttributes(null, null, null, null, Font.BOLD)
+ val SCHEME = EditorColorsManager.getInstance().globalScheme
+
+ private val DIRECTIVE_COLOR: TextAttributesKey = DefaultLanguageHighlighterColors.KEYWORD
+ val DIRECTIVE_ATTRIBUTES: TextAttributes =
+ TextAttributes.merge(SCHEME.getAttributes(DIRECTIVE_COLOR), BOLD_ATTRIBUTE)
+ val DIRECTIVE_TYPE = HighlightInfoType.HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, DIRECTIVE_COLOR)
+
+ private val OPERATOR_COLOR: TextAttributesKey = DefaultLanguageHighlighterColors.OPERATION_SIGN
+ val OPERATOR_ATTRIBUTES = SCHEME.getAttributes(OPERATOR_COLOR)
+ val OPERATOR_TYPE = HighlightInfoType.HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, OPERATOR_COLOR)
+
+ private val IDENTIFIER_COLOR: TextAttributesKey = DefaultLanguageHighlighterColors.IDENTIFIER
+ val IDENTIFIER_ATTRIBUTES: TextAttributes =
+ TextAttributes.merge(SCHEME.getAttributes(IDENTIFIER_COLOR), BOLD_ATTRIBUTE)
+ val IDENTIFIER_TYPE = HighlightInfoType.HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, IDENTIFIER_COLOR)
+
+ private val NUMBER_COLOR: TextAttributesKey = DefaultLanguageHighlighterColors.NUMBER
+ val NUMBER_ATTRIBUTES: TextAttributes = TextAttributes.merge(SCHEME.getAttributes(NUMBER_COLOR), BOLD_ATTRIBUTE)
+ val NUMBER_TYPE = HighlightInfoType.HighlightInfoTypeImpl(HighlightSeverity.INFORMATION, NUMBER_COLOR)
+
+ private val LOGGER: Logger = Logger.getInstance(PreprocessorHighlight::class.java)
+
+ private val WHITESPACES_PATTERN = "\\s+".toRegex()
+ private val EXPR_PATTERN = "(.+)(==|!=|<=|>=|<|>)(.+)".toRegex()
+ private val IDENTIFIER_PATTERN = "[A-Za-z0-9]+".toRegex()
+ private val OR_PATTERN = Pattern.quote("||")
+ private val AND_PATTERN = Pattern.quote("&&")
+ private val SPLIT_PATTERN = Pattern.compile("$OR_PATTERN|$AND_PATTERN")
+ }
+}
diff --git a/src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/PreprocessorImport.kt b/src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/PreprocessorImport.kt
new file mode 100644
index 0000000..1072ee0
--- /dev/null
+++ b/src/main/kotlin/org/polyfrost/sorbet/intelliprocessor/PreprocessorImport.kt
@@ -0,0 +1,59 @@
+package org.polyfrost.sorbet.intelliprocessor
+
+import com.intellij.lang.ImportOptimizer
+import com.intellij.lang.LanguageImportStatements
+import com.intellij.lang.java.JavaImportOptimizer
+import com.intellij.openapi.util.EmptyRunnable
+import com.intellij.psi.*
+import com.intellij.psi.codeStyle.JavaCodeStyleManager
+import com.intellij.psi.impl.source.tree.PsiCommentImpl
+
+class PreprocessorImport : ImportOptimizer {
+ override fun supports(file: PsiFile): Boolean {
+ return file is PsiJavaFile
+ }
+
+ override fun processFile(file: PsiFile): Runnable {
+ if (file !is PsiJavaFile) return EmptyRunnable.getInstance()
+ val imports = file.importList ?: return EmptyRunnable.getInstance()
+
+ if (!hasPreprocessorDirectives(imports)) {
+ return LanguageImportStatements.INSTANCE
+ .allForLanguage(file.language)
+ .first { it !is JavaImportOptimizer }
+ .processFile(file)
+ }
+
+ val optimizedImportList =
+ JavaCodeStyleManager
+ .getInstance(file.project)
+ .prepareOptimizeImportsResult(file)
+
+ return Runnable {
+ val manager = PsiDocumentManager.getInstance(file.project)
+ val document = manager.getDocument(file)
+ if (document != null) manager.commitDocument(document)
+
+ for (import in imports.importStatements)
+ if (optimizedImportList.findSingleClassImportStatement(import.qualifiedName) == null) {
+ import.delete()
+ }
+
+ if (imports.firstChild is PsiWhiteSpace) imports.firstChild.delete()
+ }
+ }
+
+ private fun hasPreprocessorDirectives(imports: PsiImportList): Boolean {
+ var import = imports.firstChild
+
+ while (import != null) {
+ if (import is PsiCommentImpl && import.text.startsWith("//#")) {
+ return true
+ } else {
+ import = import.nextSibling
+ }
+ }
+
+ return false
+ }
+}
diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml
index 9267a13..d20684e 100644
--- a/src/main/resources/META-INF/plugin.xml
+++ b/src/main/resources/META-INF/plugin.xml
@@ -1,10 +1,10 @@
<idea-plugin>
- <id>cc.polyfrost.sorbet.intelliprocessor</id>
+ <id>org.polyfrost.sorbet.intelliprocessor</id>
<name>IntelliProcessor</name>
- <vendor url="https://polyfrost.cc">Polyfrost</vendor>
+ <vendor url="https://polyfrost.org">Polyfrost</vendor>
<description><![CDATA[
- An IntelliJ plugin to add support for
+ An IntelliJ IDEA plugin to add support for
<a href="https://github.com/ReplayMod/preprocessor">preprocessor syntax</a>
]]></description>
@@ -13,25 +13,25 @@
<extensions defaultExtensionNs="com.intellij">
<highlightVisitor
- implementation="cc.polyfrost.sorbet.intelliprocessor.PreprocessorHighlight"
+ implementation="org.polyfrost.sorbet.intelliprocessor.PreprocessorHighlight"
/>
<enterHandlerDelegate
- implementation="cc.polyfrost.sorbet.intelliprocessor.PreprocessorExtend"
+ implementation="org.polyfrost.sorbet.intelliprocessor.PreprocessorExtend"
/>
<lang.importOptimizer
language="JAVA"
- implementationClass="cc.polyfrost.sorbet.intelliprocessor.PreprocessorImport"
+ implementationClass="org.polyfrost.sorbet.intelliprocessor.PreprocessorImport"
order="first"
/>
<lang.foldingBuilder
language="JAVA"
- implementationClass="cc.polyfrost.sorbet.intelliprocessor.PreprocessorFolding"
+ implementationClass="org.polyfrost.sorbet.intelliprocessor.PreprocessorFolding"
order="first"
/>
<lang.foldingBuilder
language="kotlin"
- implementationClass="cc.polyfrost.sorbet.intelliprocessor.PreprocessorFolding"
+ implementationClass="org.polyfrost.sorbet.intelliprocessor.PreprocessorFolding"
order="first"
/>
</extensions>
-</idea-plugin> \ No newline at end of file
+</idea-plugin>