Skip to content

Commit

Permalink
feat(intellij): implemented support for highlightning embedded argume…
Browse files Browse the repository at this point in the history
…nts, escape sequences, python expressions and so on
  • Loading branch information
d-biehl committed Jan 6, 2025
1 parent 039682d commit c5d6cf3
Show file tree
Hide file tree
Showing 19 changed files with 251 additions and 151 deletions.
92 changes: 46 additions & 46 deletions intellij-client/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import org.jetbrains.changelog.Changelog
import org.jetbrains.changelog.markdownToHTML
import org.jetbrains.intellij.platform.gradle.Constants.Constraints
import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType
import org.jetbrains.intellij.platform.gradle.TestFrameworkType
import org.jetbrains.intellij.platform.gradle.tasks.PrepareSandboxTask
import java.net.URI
import java.net.http.HttpClient
import java.net.http.HttpRequest
Expand Down Expand Up @@ -29,7 +31,7 @@ kotlin {
// Configure project's dependencies
repositories {
mavenCentral()

// IntelliJ Platform Gradle Plugin Repositories Extension - read more: https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-repositories-extension.html
intellijPlatform {
defaultRepositories()
Expand All @@ -41,39 +43,19 @@ dependencies {
compileOnly(libs.kotlinxSerialization)
testImplementation(kotlin("test"))
testImplementation(libs.junit)

// IntelliJ Platform Gradle Plugin Dependencies Extension - read more: https://plugins.jetbrains.com/docs/intellij/tools-intellij-platform-gradle-plugin-dependencies-extension.html
intellijPlatform {
create(
providers.gradleProperty("platformType"),
providers.gradleProperty("platformVersion"),
useInstaller = false
)

// Plugin Dependencies. Uses `platformBundledPlugins` property from the gradle.properties file for bundled IntelliJ Platform plugins.
bundledPlugins(providers.gradleProperty("platformBundledPlugins").map { it.split(',') })

// Plugin Dependencies. Uses `platformPlugins` property from the gradle.properties file for plugin from JetBrains Marketplace.
// plugins(providers.gradleProperty("platformPlugins").map { it.split(',') })

val platformPlugins = ArrayList<String>()
// val localLsp4ij = file("../lsp4ij.old/build/idea-sandbox/plugins/LSP4IJ").absoluteFile
// if (localLsp4ij.isDirectory) {
// // In case Gradle fails to build because it can't find some missing jar, try deleting
// // ~/.gradle/caches/modules-2/files-2.1/com.jetbrains.intellij.idea/unzipped.com.jetbrains.plugins/com.redhat.devtools.lsp4ij*
// localPlugin(localLsp4ij.toString())
// } else {
// // When running on CI or when there's no local lsp4ij
// val latestLsp4ijNightlyVersion = fetchLatestLsp4ijNightlyVersion()
// platformPlugins.add("com.redhat.devtools.lsp4ij:$latestLsp4ijNightlyVersion@nightly")
// }

platformPlugins.add("com.redhat.devtools.lsp4ij:0.9.0")
//Uses `platformPlugins` property from the gradle.properties file.
platformPlugins.addAll(providers.gradleProperty("platformPlugins").map { it.split(',').map(String::trim).filter(String::isNotEmpty) }.get())

plugins(platformPlugins)

plugins(providers.gradleProperty("platformPlugins").map { it.split(',') })

pluginVerifier()
zipSigner()
testFramework(TestFrameworkType.Platform)
Expand All @@ -85,20 +67,20 @@ intellijPlatform {
pluginConfiguration {
name = providers.gradleProperty("pluginName")
version = providers.gradleProperty("pluginVersion")

// Extract the <!-- Plugin description --> section from README.md and provide for the plugin's manifest
description = providers.fileContents(layout.projectDirectory.file("README.md")).asText.map {
val start = "<!-- Plugin description -->"
val end = "<!-- Plugin description end -->"

with(it.lines()) {
if (!containsAll(listOf(start, end))) {
throw GradleException("Plugin description section not found in README.md:\n$start ... $end")
}
subList(indexOf(start) + 1, indexOf(end)).joinToString("\n").let(::markdownToHTML)
}
}

val changelog = project.changelog // local variable for configuration cache compatibility
// Get the latest available change notes from the changelog file
changeNotes = providers.gradleProperty("pluginVersion").map { pluginVersion ->
Expand All @@ -111,19 +93,19 @@ intellijPlatform {
)
}
}

ideaVersion {
sinceBuild = providers.gradleProperty("pluginSinceBuild")
untilBuild = providers.gradleProperty("pluginUntilBuild")
}
}

signing {
certificateChain = providers.environmentVariable("CERTIFICATE_CHAIN")
privateKey = providers.environmentVariable("PRIVATE_KEY")
password = providers.environmentVariable("PRIVATE_KEY_PASSWORD")
}

publishing {
token = providers.environmentVariable("PUBLISH_TOKEN")
// The pluginVersion is based on the SemVer (https://semver.org) and supports pre-release labels, like 2.1.7-alpha.3
Expand All @@ -132,7 +114,7 @@ intellijPlatform {
channels = providers.gradleProperty("pluginVersion")
.map { listOf(it.substringAfter('-', "").substringBefore('.').ifEmpty { "default" }) }
}

pluginVerification {
ides {
recommended()
Expand All @@ -158,6 +140,15 @@ kover {
}
}

val prepareSandboxConfig: PrepareSandboxTask.() -> Unit = {
from("..") {
include("package.json", "language-configuration.json", "syntaxes/**/*", "bundled/**/*")
exclude("**/bin")
exclude("**/__pycache__")
into("robotcode4ij/data")
}
}

tasks {
runIde {
// From https://app.slack.com/client/T5P9YATH9/C5U8BM1MK
Expand All @@ -166,25 +157,20 @@ tasks {
// systemProperty("terminal.new.ui", "false")
// systemProperty("ide.tree.painter.compact.default", "true")
}

wrapper {
gradleVersion = providers.gradleProperty("gradleVersion").get()
}

publishPlugin {
dependsOn(patchChangelog)
}
prepareSandbox {
from("..") {
include("package.json", "language-configuration.json", "syntaxes/**/*", "bundled/**/*" )

exclude("**/bin")
exclude("**/__pycache__")
into("robotcode4ij/data")
}
}

prepareSandbox(prepareSandboxConfig)
}



// Configure UI tests plugin
// Read more: https://github.com/JetBrains/intellij-ui-test-robot
val runIdeForUiTests by intellijPlatformTesting.runIde.registering {
Expand All @@ -198,12 +184,26 @@ val runIdeForUiTests by intellijPlatformTesting.runIde.registering {
)
}
}


prepareSandboxTask(prepareSandboxConfig)

plugins {
robotServerPlugin(Constraints.LATEST_VERSION)
}
}

val runIdePyCharmProf by intellijPlatformTesting.runIde.registering {
type = IntelliJPlatformType.PyCharmProfessional

prepareSandboxTask(prepareSandboxConfig)
}

val runIdeIntellijIdeaC by intellijPlatformTesting.runIde.registering {
type = IntelliJPlatformType.IntellijIdeaCommunity

prepareSandboxTask(prepareSandboxConfig)
}

fun fetchLatestLsp4ijNightlyVersion(): String {
val client = HttpClient.newBuilder().build();
var onlineVersion = ""
Expand All @@ -220,10 +220,10 @@ fun fetchLatestLsp4ijNightlyVersion(): String {
onlineVersion = matcher.group(1)
println("Latest approved nightly build: $onlineVersion")
}
} catch (e:Exception) {
} catch (e: Exception) {
println("Failed to fetch LSP4IJ nightly build version: ${e.message}")
}

val minVersion = "0.0.1-20231213-012910"
return if (minVersion < onlineVersion) onlineVersion else minVersion
}
3 changes: 1 addition & 2 deletions intellij-client/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ platformVersion = 2024.3.1

# Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html
# Example: platformPlugins = com.jetbrains.php:203.4449.22, org.intellij.scala:2023.3.27@EAP
#platformPlugins = com.redhat.devtools.lsp4ij:0.3.0
platformPlugins =
platformPlugins = com.redhat.devtools.lsp4ij:0.9.0
# Example: platformBundledPlugins = com.intellij.java
platformBundledPlugins = PythonCore, org.jetbrains.plugins.textmate

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.robotcode.robotcode4ij.execution

import com.intellij.execution.Executor
import com.intellij.execution.compound.CompoundRunConfigurationSettingsEditor
import com.intellij.execution.configurations.ConfigurationFactory
import com.intellij.execution.configurations.LocatableConfigurationBase
import com.intellij.execution.configurations.RunConfiguration
Expand All @@ -17,7 +18,8 @@ class RobotCodeRunConfiguration(project: Project, factory: ConfigurationFactory)
}

override fun getConfigurationEditor(): SettingsEditor<out RunConfiguration> {
TODO("Not yet implemented")
// TODO: Implement configuration editor
return RobotCodeRunConfigurationEditor()
}

var suite: String = ""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package dev.robotcode.robotcode4ij.execution

import com.intellij.execution.configuration.EnvironmentVariablesComponent
import com.intellij.util.ui.ComponentWithEmptyText
import com.intellij.ui.RawCommandLineEditor
import com.intellij.openapi.options.SettingsEditor
import com.intellij.ui.dsl.builder.AlignX
import com.intellij.ui.dsl.builder.panel
import javax.swing.JComponent

class RobotCodeRunConfigurationEditor : SettingsEditor<RobotCodeRunConfiguration>() {

private val environmentVariablesField = EnvironmentVariablesComponent()

private val argumentsField =
RawCommandLineEditor().apply {
if (textField is ComponentWithEmptyText) {
(textField as ComponentWithEmptyText).emptyText.text =
"Additional flags, e.g. --skip-cache, or --parallel=2"
}
}

override fun resetEditorFrom(s: RobotCodeRunConfiguration) {
// TODO("Not yet implemented")
}

override fun applyEditorTo(s: RobotCodeRunConfiguration) {
// TODO("Not yet implemented")
}

override fun createEditor(): JComponent {
return panel {
row("&Robot:") {
textField().label("Suite:")
}
row(environmentVariablesField.label) {
cell(environmentVariablesField.component).align(AlignX.FILL)
}
row("A&rguments:") { cell(argumentsField).align(AlignX.FILL) }
}
}

}
Original file line number Diff line number Diff line change
@@ -1,30 +1,21 @@
package dev.robotcode.robotcode4ij.execution

import com.intellij.execution.configurations.CommandLineState
import com.intellij.execution.configurations.GeneralCommandLine
import com.intellij.execution.process.KillableProcessHandler
import com.intellij.execution.process.ProcessHandler
import com.intellij.execution.process.ProcessTerminatedListener

import com.intellij.execution.runners.ExecutionEnvironment
import com.jetbrains.python.sdk.pythonSdk
import dev.robotcode.robotcode4ij.RobotCodeHelpers
import kotlin.io.path.pathString
import dev.robotcode.robotcode4ij.buildRobotCodeCommandLine

class RobotCodeRunProfileState(environment: ExecutionEnvironment) : CommandLineState(environment) {
override fun startProcess(): ProcessHandler {
val project = environment.project
val pythonInterpreter = project.pythonSdk?.homePath
?: throw IllegalArgumentException("PythonSDK is not defined for project ${project.name}")
val profile = environment.runProfile as? RobotCodeRunConfiguration
// TODO: Add support for configurable paths
val defaultPaths = arrayOf("--default-path", ".")

val commandLine = project.buildRobotCodeCommandLine(arrayOf(*defaultPaths, "run"))

val commandLine = GeneralCommandLine(
pythonInterpreter, "-u", "-X", "utf8",
RobotCodeHelpers.robotCodePath.pathString,
//"--log", "--log-level", "DEBUG",
// "--debugpy",
// "--debugpy-wait-for-client"
"run"
).withWorkDirectory(project.basePath).withCharset(Charsets.UTF_8)
val handler = KillableProcessHandler(commandLine)
ProcessTerminatedListener.attach(handler)
return handler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import com.intellij.openapi.editor.DefaultLanguageHighlighterColors
import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey

object RobotColors {
object Colors {

val HEADER: TextAttributesKey =
createTextAttributesKey("ROBOTFRAMEWORK_HEADER", DefaultLanguageHighlighterColors.KEYWORD)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import org.jetbrains.plugins.textmate.language.syntax.lexer.TextMateScope
import java.util.*
import kotlin.math.min

class RobotCodeTextMateHighlightingLexer : LexerBase() {
class RobotCodeLexer : LexerBase() {
companion object {
val mapping by lazy {
mapOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,31 +30,31 @@ import org.jetbrains.plugins.textmate.language.syntax.lexer.TextMateScope
import java.util.function.Function


class RobotCodeHighlighter : SyntaxHighlighterBase() {
class RobotCodeSyntaxHighlighter : SyntaxHighlighterBase() {
companion object {
val elementTypeMap = mapOf(
COMMENT_LINE to arrayOf(RobotColors.LINE_COMMENT),
COMMENT_BLOCK to arrayOf(RobotColors.BLOCK_COMMENT),
VARIABLE_BEGIN to arrayOf(RobotColors.VARIABLE_BEGIN),
VARIABLE_END to arrayOf(RobotColors.VARIABLE_END),
ENVIRONMENT_VARIABLE_BEGIN to arrayOf(RobotColors.VARIABLE_BEGIN),
ENVIRONMENT_VARIABLE_END to arrayOf(RobotColors.VARIABLE_END),
TESTCASE_NAME to arrayOf(RobotColors.TESTCASE_NAME),
KEYWORD_NAME to arrayOf(RobotColors.KEYWORD_NAME),
HEADER to arrayOf(RobotColors.HEADER),
SETTING to arrayOf(RobotColors.SETTING),
KEYWORD_CALL to arrayOf(RobotColors.KEYWORD_CALL),
CONTROL_FLOW to arrayOf(RobotColors.CONTROL_FLOW),
VARIABLE to arrayOf(RobotColors.VARIABLE),
OPERATOR to arrayOf(RobotColors.OPERATOR),
ARGUMENT to arrayOf(RobotColors.ARGUMENT),
CONTINUATION to arrayOf(RobotColors.CONTINUATION),
COMMENT_LINE to arrayOf(Colors.LINE_COMMENT),
COMMENT_BLOCK to arrayOf(Colors.BLOCK_COMMENT),
VARIABLE_BEGIN to arrayOf(Colors.VARIABLE_BEGIN),
VARIABLE_END to arrayOf(Colors.VARIABLE_END),
ENVIRONMENT_VARIABLE_BEGIN to arrayOf(Colors.VARIABLE_BEGIN),
ENVIRONMENT_VARIABLE_END to arrayOf(Colors.VARIABLE_END),
TESTCASE_NAME to arrayOf(Colors.TESTCASE_NAME),
KEYWORD_NAME to arrayOf(Colors.KEYWORD_NAME),
HEADER to arrayOf(Colors.HEADER),
SETTING to arrayOf(Colors.SETTING),
KEYWORD_CALL to arrayOf(Colors.KEYWORD_CALL),
CONTROL_FLOW to arrayOf(Colors.CONTROL_FLOW),
VARIABLE to arrayOf(Colors.VARIABLE),
OPERATOR to arrayOf(Colors.OPERATOR),
ARGUMENT to arrayOf(Colors.ARGUMENT),
CONTINUATION to arrayOf(Colors.CONTINUATION),
)

val PLAIN_SYNTAX_HIGHLIGHTER: PlainSyntaxHighlighter = PlainSyntaxHighlighter()
}

private val myLexer = RobotTextMateHighlightingLexer()
private val myLexer = RobotCodeLexer()

override fun getHighlightingLexer(): Lexer {
return myLexer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ import com.intellij.openapi.vfs.VirtualFile

class RobotCodeSyntaxHighlighterFactory : SyntaxHighlighterFactory() {
override fun getSyntaxHighlighter(project: Project?, virtualFile: VirtualFile?): SyntaxHighlighter {
return RobotCodeHighlighter()
return RobotCodeSyntaxHighlighter()
}
}
Loading

0 comments on commit c5d6cf3

Please sign in to comment.