Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/idea-gradle-build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
java-version: '21'
- name: Run tests and build plugin
run: |
cd IDEA
Expand Down
65 changes: 30 additions & 35 deletions IDEA/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import org.jetbrains.grammarkit.tasks.GenerateLexerTask
import org.jetbrains.grammarkit.tasks.GenerateParserTask
import org.jetbrains.intellij.platform.gradle.TestFrameworkType
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
id("org.jetbrains.intellij.platform") version "2.0.1"
id("org.jetbrains.kotlin.jvm") version "2.0.20"
id("org.jetbrains.grammarkit") version "2022.3.2.2"
alias(libs.plugins.intellijPlattform)
alias(libs.plugins.kotlin)
alias(libs.plugins.grammarkit)
}

repositories {
Expand All @@ -18,7 +19,7 @@ repositories {

// Java target version
java {
sourceCompatibility = JavaVersion.VERSION_17
sourceCompatibility = JavaVersion.VERSION_21
}

sourceSets {
Expand All @@ -29,33 +30,36 @@ sourceSets {

kotlin {
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
compilerOptions {
jvmTarget = JvmTarget.JVM_21
freeCompilerArgs = listOf("-Xjvm-default=all")
}
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
}

dependencies {
intellijPlatform {
intellijIdeaCommunity("2024.2.1")
intellijIdeaCommunity("2025.1.1")

bundledPlugins(listOf("com.intellij.java"))
instrumentationTools()

testFramework(TestFrameworkType.Platform)
}

// From Kotlin documentation
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.8.22")
implementation(libs.kotlin.stdlib)
// just in case, version number specified in buildscript is used by default
implementation("org.jetbrains.kotlin:kotlin-reflect:1.8.22")
implementation(libs.kotlin.reflect)

// IntelliJ test framework needs junit 4.
testImplementation("junit:junit:4.13")
testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.7.0")
testImplementation(libs.junit4)
testRuntimeOnly(libs.junit.vintage.engine)

// Use junit 5.
testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.0")
testImplementation(libs.junit.jupiter.api)
testRuntimeOnly(libs.junit.jupiter.engine)
}

// Configure Gradle IntelliJ Plugin
Expand All @@ -74,39 +78,30 @@ intellijPlatform {
}

project(":") {
val generateLexer = task<GenerateLexerTask>("generateMyLexer") {
sourceFile.set(file("src/main/grammar/KerboScript.flex"))
targetOutputDir.set(file("src/gen/ksp/kos/ideaplugin/parser"))
// targetClass.set("KerboScriptLexer")
purgeOldFiles.set(true)
}

val generateParser = task<GenerateParserTask>("generateMyParser") {
val generateLexer =
tasks.register<GenerateLexerTask>("generateMyLexer", fun GenerateLexerTask.() {
sourceFile.set(file("src/main/grammar/KerboScript.flex"))
targetOutputDir.set(file("src/gen/ksp/kos/ideaplugin/parser"))
purgeOldFiles.set(true)
})

val generateParser = tasks.register<GenerateParserTask>("generateMyParser", fun GenerateParserTask.() {
sourceFile.set(file("src/main/grammar/KerboScript.bnf"))
targetRootOutputDir.set(file("src/gen"))
pathToParser.set("/ksp/kos/ideaplugin/parser/KerboScriptParser.java")
pathToPsiRoot.set("/ksp/kos/ideaplugin/psi")
purgeOldFiles.set(true)
}
})

tasks {
withType<KotlinCompile> {
dependsOn(generateLexer, generateParser)
}

// Set the compatibility versions to 17
// Set the compatibility versions to 21
withType<JavaCompile> {
sourceCompatibility = "17"
targetCompatibility = "17"
}

listOf("compileKotlin", "compileTestKotlin").forEach {
getByName<KotlinCompile>(it) {
kotlinOptions {
jvmTarget = "17"
freeCompilerArgs = listOf("-Xjvm-default=all")
}
}
sourceCompatibility = "21"
targetCompatibility = "21"
}

publishPlugin {
Expand Down
21 changes: 21 additions & 0 deletions IDEA/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[versions]
intellij = "2.5.0"
kotlin = "2.1.20"
kotlin-std-lib = "1.8.22"
grammarkit = "2022.3.2.2"
junit4 = "4.13.1"
junit5 = "5.7.0"

[libraries]
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }

junit4 = { module = "junit:junit", version.ref = "junit4" }
junit-vintage-engine = { module = "org.junit.vintage:junit-vintage-engine", version.ref = "junit5" }
junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit5"}
junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit5"}

[plugins]
intellijPlattform = { id = "org.jetbrains.intellij.platform", version.ref = "intellij" }
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
grammarkit = { id = "org.jetbrains.grammarkit", version.ref = "grammarkit" }
2 changes: 1 addition & 1 deletion IDEA/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
10 changes: 5 additions & 5 deletions IDEA/src/main/grammar/KerboScript.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
tokenTypeClass="ksp.kos.ideaplugin.psi.KerboScriptTokenType"

extends(".*_stmt|directive|instruction_block")=instruction
extends("lazyglobal_directive")=directive
extends("lazyglobal_directive|clobberbuiltins_directive")=directive
extends("function_trailer|array_trailer")=suffixterm_trailer
extends("[a-z]*_expr|factor|suffix|suffixterm|atom|.*number")=expr

Expand Down Expand Up @@ -109,13 +109,14 @@
ALL = 'regexp:(?i)all'
IDENTIFIER = 'regexp:[a-zA-Z_][a-zA-Z0-9_]*'
FILEIDENT = 'regexp:[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z0-9_][a-zA-Z0-9_]*)*'
INTEGER = 'regexp:[0-9]+'
DOUBLE = 'regexp:[0-9]*\.[0-9]+'
INTEGER = 'regexp:[0-9][0-9_]*'
DOUBLE = 'regexp:([0-9]+(_[0-9]*)*)?\.[0-9]+(_[0-9]*)*'
STRING = 'regexp:@?"(""|[^"])*"'
EOI = '.'
//Compiler Directives
ATSIGN = '@'
LAZYGLOBAL = 'regexp:(?i)lazyglobal'
CLOBBERBUILTINS = 'regexp:(?i)clobberbuiltins'
//Special
//EOF = '$'
//[Skip]
Expand All @@ -127,7 +128,7 @@

// Rules
// ===================================================
Start ::= (instruction)*
Start ::= (directive|instruction)*
instruction_block ::= CURLYOPEN instruction* CURLYCLOSE
instruction ::= !(CURLYCLOSE | <<eof>>) instruction_inner {
pin = 1
Expand Down Expand Up @@ -174,7 +175,6 @@ private instruction_inner ::= empty_stmt |
unset_stmt |
instruction_block |
identifier_led_stmt | // any statement that starts with an identifier.
directive // allow directives anywhere for now, let the compiler decide if it's in the wrong place, not the parser.

// ------------ directives --------------------
lazyglobal_directive ::= LAZYGLOBAL onoff_trailer EOI
Expand Down
4 changes: 2 additions & 2 deletions IDEA/src/main/grammar/KerboScript.flex
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ ARRAYINDEX = #
ALL = all
IDENTIFIER = [a-zA-Z_][a-zA-Z0-9_]*
FILEIDENT = [a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z0-9_][a-zA-Z0-9_]*)*
INTEGER = [0-9]+
DOUBLE = [0-9]*\.[0-9]+
INTEGER = [0-9][0-9_]*
DOUBLE = ([0-9]+(_[0-9]*)*)?\.[0-9]+(_[0-9]*)*
STRING = @?\"(\"\"|[^\"])*\"
EOI = \.
//Compiler Directives
Expand Down
3 changes: 2 additions & 1 deletion IDEA/src/main/java/ksp/kos/ideaplugin/Magic.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ object Magic {
KerboScriptTypes.UNSET,
KerboScriptTypes.CHOOSE,
KerboScriptTypes.ATSIGN,
KerboScriptTypes.LAZYGLOBAL
KerboScriptTypes.LAZYGLOBAL,
KerboScriptTypes.CLOBBERBUILTINS
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ public DiffContext(FileContext origFile, FileDuality diffFile, FileContextResolv
registerFile(origFile.getName());
}

public static List<ReferenceResolver<LocalContext>> createDiffResolvers(FileContextResolver fileResolver) {
List<ReferenceResolver<LocalContext>> resolvers = FileContext.createResolvers(fileResolver);
public static List<ReferenceResolver> createDiffResolvers(FileContextResolver fileResolver) {
List<ReferenceResolver> resolvers = FileContext.createResolvers(fileResolver);
resolvers.add((context, reference, createAllowed) -> {
if (createAllowed && reference.getName().endsWith("_")) {
String name1 = reference.getName();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.util.ProcessingContext
import ksp.kos.ideaplugin.Magic
import java.util.Locale

class KerboScriptKeywordProvider : CompletionProvider<CompletionParameters>() {
override fun addCompletions(completionParameters: CompletionParameters, context: ProcessingContext, resultSet: CompletionResultSet) {
Expand All @@ -15,8 +16,8 @@ class KerboScriptKeywordProvider : CompletionProvider<CompletionParameters>() {
// when you type in lowercase, the completion shows uppercase (which can be somewhat unreadable when
// you're not used to it).
listOf(
LookupElementBuilder.create(it.toString().toUpperCase()),
LookupElementBuilder.create(it.toString().toLowerCase())
LookupElementBuilder.create(it.toString().uppercase(Locale.getDefault())),
LookupElementBuilder.create(it.toString().lowercase(Locale.getDefault()))
)
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,14 @@ public void visit(ExpressionVisitor visitor) {
}

public String getText() {
String text = "";
StringBuilder text = new StringBuilder();
for (Flow<?> flow : getList()) {
if (!text.isEmpty()) text += "\n";
text += flow.getText();
if (!text.isEmpty()) {
text.append("\n");
}
text.append(flow.getText());
}
return text;
return text.toString();
}

public void differentiate(LocalContext context, ContextBuilder contextBuilder) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ public class KerboScriptSyntaxHighlighter extends SyntaxHighlighterBase {
KerboScriptTypes.UNSET,
KerboScriptTypes.CHOOSE,
KerboScriptTypes.ATSIGN,
KerboScriptTypes.LAZYGLOBAL
KerboScriptTypes.LAZYGLOBAL,
KerboScriptTypes.CLOBBERBUILTINS
)
);

Expand All @@ -93,7 +94,7 @@ public Lexer getHighlightingLexer() {

@NotNull
@Override
public TextAttributesKey[] getTokenHighlights(IElementType tokenType) {
public TextAttributesKey @NotNull [] getTokenHighlights(IElementType tokenType) {
// TODO - Ideally syntax highlight based off of parser, not lexer, to handle keywords used as variables.
if (tokenType.equals(KerboScriptTypes.IDENTIFIER)) {
return createKeys(IDENTIFIER);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package ksp.kos.ideaplugin.psi

import com.intellij.openapi.util.Key
import com.intellij.psi.PsiElement
import com.intellij.psi.util.CachedValue
import ksp.kos.ideaplugin.dataflow.FlowParser
import ksp.kos.ideaplugin.dataflow.ReferenceFlow
import ksp.kos.ideaplugin.reference.OccurrenceType
import ksp.kos.ideaplugin.reference.PsiSelfResolvable
import ksp.kos.ideaplugin.reference.ReferableType
import ksp.kos.ideaplugin.reference.Reference
import ksp.kos.ideaplugin.reference.ReferenceType
import ksp.kos.ideaplugin.reference.context.LocalContext
import com.intellij.psi.PsiElement
import ksp.kos.ideaplugin.reference.*
import ksp.kos.ideaplugin.reference.context.PsiDuality
import java.util.function.Supplier

Expand All @@ -23,7 +23,6 @@ interface KerboScriptNamedElement : KerboScriptBase, PsiSelfResolvable {
var type: ReferenceType

// TODO duality can be pure virtual
@JvmDefault
val cachedFlow: ReferenceFlow<*>
get() {
var cached = getUserData(FLOW_KEY)
Expand All @@ -34,20 +33,15 @@ interface KerboScriptNamedElement : KerboScriptBase, PsiSelfResolvable {
return cached.value
}

@JvmDefault
override fun getKingdom(): LocalContext = scope.cachedScope

@JvmDefault
override fun getReferableType(): ReferableType = type.type

@JvmDefault
val isDeclaration: Boolean
get() = type.occurrenceType.isDeclaration

@JvmDefault
override fun resolve(): KerboScriptNamedElement = if (isDeclaration) this else super.resolve()

@JvmDefault
override fun matches(declaration: Reference): Boolean {
val declarationElement = when (declaration) {
is PsiDuality -> declaration.syntax
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import java.net.URL
abstract class FileContext protected constructor(
parent: LocalContext?,
private val name: String,
resolvers: List<ReferenceResolver<LocalContext>>,
resolvers: List<ReferenceResolver>,
) : LocalContext(parent, resolvers), ReferenceFlow<FileContext>, FileDuality {

constructor(parent: LocalContext?, name: String, fileResolver: FileContextResolver)
Expand All @@ -43,7 +43,7 @@ abstract class FileContext protected constructor(
}
}

class FileResolver(private val fileContextResolver: FileContextResolver) : ReferenceResolver<LocalContext> {
class FileResolver(private val fileContextResolver: FileContextResolver) : ReferenceResolver {
override fun resolve(context: LocalContext, reference: Reference, createAllowed: Boolean): Duality? =
if (reference.referableType == ReferableType.FILE) {
fileContextResolver.resolveFile(reference.name)
Expand All @@ -54,7 +54,7 @@ abstract class FileContext protected constructor(

override fun getSemantics(): FileContext = this

class ImportsResolver(private val fileContextResolver: FileContextResolver) : ReferenceResolver<LocalContext> {
class ImportsResolver(private val fileContextResolver: FileContextResolver) : ReferenceResolver {
override fun resolve(context: LocalContext, reference: Reference, createAllowed: Boolean): Duality? =
context.getDeclarations(ReferableType.FILE)
.values
Expand All @@ -66,7 +66,7 @@ abstract class FileContext protected constructor(
.firstOrNull()
}

class BuiltinResolver : ReferenceResolver<LocalContext> {
class BuiltinResolver : ReferenceResolver {
override fun resolve(context: LocalContext, reference: Reference, createAllowed: Boolean): Duality? {
if (ksFile == null) {
tryGetBuiltinKsFile()
Expand Down Expand Up @@ -102,7 +102,7 @@ abstract class FileContext protected constructor(

companion object {
@JvmStatic
fun createResolvers(fileResolver: FileContextResolver): MutableList<ReferenceResolver<LocalContext>> =
fun createResolvers(fileResolver: FileContextResolver) =
mutableListOf(
FileResolver(fileResolver),
LocalResolver(),
Expand Down
Loading