Refactor theme generator gradle plugin and optimize sarif results (#95)

* "Refactor theme generator and optimize sarif results"

This commit includes the optimization and refactor of the codebase. In the build.gradle files, the 'intUiLight' and 'intUiDark' themes have been registered and their properties have been updated. The Theme Generation plugin has been changed to use project conventions and the color group reading process was simplified. There is an optimized caching strategy particularly for SVG loading. Sarif results are now generated with kotlinx.sarif, which allows fluent API for handling the sarif format. Also, it includes switching from the java-sarif library to kotlin-sarif.

The changes enhance the robustness and reliability of the code. They also make it easier to understand, modify, and maintain the code. And using Kotlin-based libraries optimizes the performance and simplifies future changes in the project.

* Update build config for cleaner syntax

The build config file has been updated to use a cleaner syntax. The redundant use of .set() has been replaced with direct assignment for better readability. Also, added a suppression for UnstableApiUsage warning at the top of the files.
GitOrigin-RevId: 729a71a47ee0126f69f3f4ef36293661df48b3f7
This commit is contained in:
Lamberto Basti
2023-08-23 15:03:24 +02:00
committed by intellij-monorepo-bot
parent 4356963934
commit 14f6afe0fc
14 changed files with 225 additions and 306 deletions

View File

@@ -2,16 +2,25 @@ plugins {
alias(libs.plugins.composeDesktop) apply false
}
tasks {
val check by registering {
group = "verification"
}
register<MergeSarifTask>("mergeSarifReports") {
dependsOn(check)
source = rootProject.fileTree("build/reports") {
include("*.sarif")
exclude("static-analysis.sarif")
}
outputs.file(rootProject.file("build/reports/static-analysis.sarif"))
val sarif: Configuration by configurations.creating {
isCanBeResolved = true
attributes {
attribute(Usage.USAGE_ATTRIBUTE, objects.named("sarif"))
}
}
dependencies {
sarif(projects.foundation)
sarif(projects.core)
sarif(projects.composeUtils)
sarif(projects.samples.standalone)
sarif(projects.themes.intUi.intUiStandalone)
sarif(projects.themes.intUi.intUiCore)
}
tasks {
register<MergeSarifTask>("mergeSarifReports") {
source(sarif)
include { it.file.extension == "sarif" }
}
}

View File

@@ -12,12 +12,21 @@ gradlePlugin {
}
}
kotlin {
sourceSets {
all {
languageSettings {
optIn("kotlinx.serialization.ExperimentalSerializationApi")
}
}
}
}
dependencies {
implementation(libs.kotlin.gradlePlugin)
implementation(libs.kotlinter.gradlePlugin)
implementation(libs.detekt.gradlePlugin)
implementation(libs.javaSarif)
implementation(libs.kotlinSarif)
implementation(libs.dokka.gradlePlugin)
implementation(libs.kotlinpoet)
implementation(libs.kotlinx.serialization.json)

View File

@@ -1,9 +1,10 @@
import com.contrastsecurity.sarif.Run
import com.contrastsecurity.sarif.SarifSchema210
import com.fasterxml.jackson.databind.ObjectMapper
import java.io.File
import java.net.URI
import io.github.detekt.sarif4k.SarifSchema210
import io.github.detekt.sarif4k.Version
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import kotlinx.serialization.json.encodeToStream
import org.gradle.api.file.FileTree
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.CacheableTask
import org.gradle.api.tasks.IgnoreEmptyDirectories
import org.gradle.api.tasks.InputFiles
@@ -13,85 +14,43 @@ import org.gradle.api.tasks.PathSensitivity
import org.gradle.api.tasks.SkipWhenEmpty
import org.gradle.api.tasks.SourceTask
import org.gradle.api.tasks.TaskAction
import com.contrastsecurity.sarif.Result
@CacheableTask
open class MergeSarifTask : SourceTask() {
@InputFiles
@SkipWhenEmpty
@IgnoreEmptyDirectories
@PathSensitive(PathSensitivity.RELATIVE)
override fun getSource(): FileTree = super.getSource()
init {
group = "verification"
}
@get:OutputFile
val mergedSarifPath: File
get() = project.rootProject.file("build/reports/static-analysis.sarif")
val mergedSarifPath: RegularFileProperty = project.objects.fileProperty()
.convention(project.layout.buildDirectory.file("reports/static-analysis.sarif"))
@TaskAction
fun merge() {
val sarifFiles = source.files
val json = Json { prettyPrint = true }
logger.lifecycle("Merging ${sarifFiles.size} SARIF file(s)...")
logger.debug(sarifFiles.joinToString("\n") { " * ${it.path}" })
val objectMapper = ObjectMapper()
val merged = SarifSchema210()
.`with$schema`(URI.create("https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json"))
.withVersion(SarifSchema210.Version._2_1_0)
.withRuns(mutableListOf())
sarifFiles.map { file -> objectMapper.readValue(file.readText(), SarifSchema210::class.java) }
.flatMap { report -> report.runs }
.groupBy { run -> run.tool.driver.guid ?: run.tool.driver.name }
.values
.filter { it.isNotEmpty() }
.forEach { runs ->
val mergedResults = mutableListOf<Result>()
runs.forEach { mergedResults.addAll(it.results) }
val mergedRun = runs.first().copy(mergedResults)
merged.runs.add(mergedRun)
}
logger.lifecycle("Merging ${source.files.size} SARIF file(s)...")
logger.lifecycle(source.files.joinToString("\n") { " * ~${it.path.removePrefix(project.rootDir.path)}" })
val merged = SarifSchema210(
schema = "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
version = Version.The210,
runs = source.files
.asSequence()
.filter { it.extension == "sarif" }
.map { file -> file.inputStream().use { json.decodeFromStream<SarifSchema210>(it) } }
.flatMap { report -> report.runs }
.groupBy { run -> run.tool.driver.guid ?: run.tool.driver.name }
.values
.asSequence()
.filter { it.isNotEmpty() }
.map { it.first().copy(results = it.flatMap { it.results ?: emptyList() }) }
.toList()
)
logger.lifecycle("Merged SARIF file contains ${merged.runs.size} run(s)")
logger.info("Writing merged SARIF file to $mergedSarifPath...")
objectMapper.writerWithDefaultPrettyPrinter()
.writeValue(mergedSarifPath, merged)
mergedSarifPath.asFile.get().outputStream()
.use { json.encodeToStream(merged, it) }
}
/**
* Poor man's copying of a Run.
*
* Note that this is NOT a deep copy; we're not defensively cloning field values,
* so mutating the copy will also mutate the original.
*/
private fun Run.copy(newResults: List<Result> = this.results) = Run()
.withAddresses(addresses)
.withArtifacts(artifacts)
.withAutomationDetails(automationDetails)
.withBaselineGuid(baselineGuid)
.withColumnKind(columnKind)
.withConversion(conversion)
.withDefaultEncoding(defaultEncoding)
.withDefaultSourceLanguage(defaultSourceLanguage)
.withExternalPropertyFileReferences(externalPropertyFileReferences)
.withGraphs(graphs)
.withInvocations(invocations)
.withLanguage(language)
.withLogicalLocations(logicalLocations)
.withNewlineSequences(newlineSequences)
.withOriginalUriBaseIds(originalUriBaseIds)
.withPolicies(policies)
.withProperties(properties)
.withRedactionTokens(redactionTokens)
.withResults(newResults)
.withRunAggregates(runAggregates)
.withSpecialLocations(specialLocations)
.withTaxonomies(taxonomies)
.withThreadFlowLocations(threadFlowLocations)
.withTool(tool)
.withTranslations(translations)
.withVersionControlProvenance(versionControlProvenance)
.withWebRequests(webRequests)
.withWebResponses(webResponses)
}

View File

@@ -1,3 +1,5 @@
@file:Suppress("UnstableApiUsage")
plugins {
`maven-publish`
id("org.jetbrains.dokka")
@@ -6,14 +8,14 @@ plugins {
val sourcesJar by tasks.registering(Jar::class) {
from(kotlin.sourceSets.main.get().kotlin)
archiveClassifier.set("sources")
into("$buildDir/artifacts")
archiveClassifier = "sources"
into(layout.buildDirectory.dir("artifacts"))
}
val javadocJar by tasks.registering(Jar::class) {
from(tasks.dokkaHtml)
archiveClassifier.set("javadoc")
into("$buildDir/artifacts")
archiveClassifier = "javadoc"
into(layout.buildDirectory.dir("artifacts"))
}
publishing {
@@ -34,19 +36,19 @@ publishing {
version = project.version.toString()
artifactId = "jewel-${project.name}"
pom {
name.set("Jewel")
description.set("intelliJ theming system in for Compose.")
url.set("https://github.com/JetBrains/jewel")
name = "Jewel"
description = "intelliJ theming system in for Compose."
url = "https://github.com/JetBrains/jewel"
licenses {
license {
name.set("Apache License 2.0")
url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
name = "Apache License 2.0"
url = "http://www.apache.org/licenses/LICENSE-2.0.txt"
}
}
scm {
connection.set("scm:git:https://github.com/JetBrains/jewel.git")
developerConnection.set("scm:git:https://github.com/JetBrains/jewel.git")
url.set("https://github.com/JetBrains/jewel")
connection = "scm:git:https://github.com/JetBrains/jewel.git"
developerConnection = "scm:git:https://github.com/JetBrains/jewel.git"
url = "https://github.com/JetBrains/jewel"
}
}
}

View File

@@ -1,3 +1,5 @@
@file:Suppress("UnstableApiUsage")
import io.gitlab.arturbosch.detekt.Detekt
import org.jmailen.gradle.kotlinter.tasks.LintTask
@@ -15,6 +17,7 @@ version = when {
gitHubRef.substringAfter("refs/tags/")
.removePrefix("v")
}
else -> "1.0.0-SNAPSHOT"
}
@@ -42,29 +45,42 @@ detekt {
buildUponDefaultConfig = true
}
tasks {
register<MergeSarifTask>("mergeSarifReports") {
dependsOn(check)
source = rootProject.fileTree("build/reports") {
include("*.sarif")
exclude("static-analysis.sarif")
}
outputs.file(rootProject.file("build/reports/static-analysis.sarif"))
}
withType<Detekt> {
reports {
sarif.required.set(true)
sarif.outputLocation.set(file(rootDir.resolve("build/reports/detekt-${project.name}.sarif")))
}
}
tasks.withType<LintTask> {
exclude { it.file.absolutePath.startsWith(buildDir.absolutePath) }
reports.set(
mapOf(
"plain" to rootDir.resolve("build/reports/ktlint-${project.name}.txt"),
"html" to rootDir.resolve("build/reports/ktlint-${project.name}.html"),
"sarif" to rootDir.resolve("build/reports/ktlint-${project.name}.sarif")
)
)
val sarif by configurations.creating {
isCanBeConsumed = true
attributes {
attribute(Usage.USAGE_ATTRIBUTE, objects.named("sarif"))
}
}
tasks {
withType<Detekt> {
val sarifOutputFile = layout.buildDirectory.file("reports/detekt-${project.name}.sarif")
exclude { it.file.absolutePath.startsWith(layout.buildDirectory.asFile.get().absolutePath) }
reports {
sarif.required = true
sarif.outputLocation = sarifOutputFile
}
sarif.outgoing {
artifact(sarifOutputFile) {
builtBy(this@withType)
}
}
}
withType<LintTask> {
exclude { it.file.absolutePath.startsWith(layout.buildDirectory.asFile.get().absolutePath) }
val sarifReport = layout.buildDirectory.file("reports/ktlint-${project.name}.sarif")
reports = provider {
mapOf(
"plain" to layout.buildDirectory.file("reports/ktlint-${project.name}.txt").get().asFile,
"html" to layout.buildDirectory.file("reports/ktlint-${project.name}.html").get().asFile,
"sarif" to sarifReport.get().asFile
)
}
sarif.outgoing {
artifact(sarifReport) {
builtBy(this@withType)
}
}
}
}

View File

@@ -1,76 +0,0 @@
package org.jetbrains.jewel.buildlogic.theme
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.file.Directory
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.api.tasks.TaskProvider
import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.property
import java.io.File
abstract class BaseIntelliJThemeGeneratorPlugin : Plugin<Project> {
final override fun apply(target: Project) {
val extension = createExtension(target)
target.afterEvaluate {
val tasks = createGenerateTask(target, extension)
val sourceSets = target.extensions.getByType<SourceSetContainer>()
val mainSourceSet = sourceSets.getByName("main")
mainSourceSet.java {
extension.map { it.targetDir }.forEach {
srcDir(it)
}
}
target.tasks.findByName("compileKotlin")?.dependsOn(*tasks.toTypedArray())
target.tasks.findByName("lintKotlinMain")?.dependsOn(*tasks.toTypedArray())
}
}
protected abstract fun createExtension(project: Project): ThemeGeneratorContainer
protected abstract fun createGenerateTask(project: Project, extension: ThemeGeneratorContainer): List<TaskProvider<out BaseThemeGeneratorTask>>
}
class ThemeGeneratorContainer(container: NamedDomainObjectContainer<ThemeGeneration>) : NamedDomainObjectContainer<ThemeGeneration> by container
class ThemeGeneration(val name: String, private val project: Project) {
val targetDir: DirectoryProperty = project.objects.directoryProperty()
val ideaVersion = project.objects.property<String>()
val themeClassName = project.objects.property<String>()
val themeFile = project.objects.property<String>()
fun targetDir(): String = targetDir.get().asFile.absolutePath
fun targetDir(path: File) {
targetDir.set(path)
}
fun targetDir(path: Directory) {
targetDir.set(path)
}
fun ideaVersion(): String = ideaVersion.get()
fun ideaVersion(version: String) {
ideaVersion.set(version)
}
fun themeClassName(): String = themeClassName.get()
fun themeClassName(name: String) {
themeClassName.set(name)
}
fun themeFile(): String = themeFile.get()
fun themeFile(path: String) {
themeFile.set(path)
}
}

View File

@@ -1,33 +0,0 @@
package org.jetbrains.jewel.buildlogic.theme
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.property
abstract class BaseThemeGeneratorTask : DefaultTask() {
@get:OutputFile
val output = project.objects.fileProperty()
@get:Input
val ideaVersion = project.objects.property<String>()
@get:Input
val themeFile = project.objects.property<String>()
@get:Input
val themeClassName = project.objects.property<String>()
init {
group = "jewel"
}
@TaskAction
fun generate() {
doGenerate()
}
protected abstract fun doGenerate()
}

View File

@@ -1,55 +1,94 @@
package org.jetbrains.jewel.buildlogic.theme
import com.squareup.kotlinpoet.ClassName
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import org.gradle.api.Project
import org.gradle.api.tasks.TaskProvider
import org.gradle.util.internal.GUtil
import io.gitlab.arturbosch.detekt.Detekt
import java.net.URL
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.decodeFromStream
import org.gradle.api.DefaultTask
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.container
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.getByType
import org.gradle.kotlin.dsl.property
import org.gradle.kotlin.dsl.register
import org.gradle.kotlin.dsl.withType
import org.gradle.util.internal.GUtil
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
class IntelliJThemeGeneratorPlugin : BaseIntelliJThemeGeneratorPlugin() {
abstract class IntelliJThemeGeneratorPlugin : Plugin<Project> {
override fun createExtension(project: Project): ThemeGeneratorContainer =
ThemeGeneratorContainer(project.container(ThemeGeneration::class.java) {
ThemeGeneration(it, project).apply {
targetDir.set(project.layout.buildDirectory.dir("generated/theme"))
ideaVersion.set("232.6734")
final override fun apply(target: Project): Unit = with(target) {
val extension = ThemeGeneratorContainer(container<ThemeGeneration> { ThemeGeneration(it, project) })
extensions.add("intelliJThemeGenerator", extension)
extension.all {
val task = tasks.register<IntelliJThemeGeneratorTask>("generate${GUtil.toCamelCase(name)}Theme") {
outputFile.set(targetDir.file(this@all.themeClassName.map {
val className = ClassName.bestGuess(it)
className.packageName.replace(".", "/")
.plus("/${className.simpleName}.kt")
}))
themeClassName.set(this@all.themeClassName)
ideaVersion.set(this@all.ideaVersion)
themeFile.set(this@all.themeFile)
}
}).apply {
project.extensions.add("intelliJThemeGenerator", this)
}
override fun createGenerateTask(
project: Project,
extension: ThemeGeneratorContainer
): List<TaskProvider<out BaseThemeGeneratorTask>> =
extension.map { config ->
project.tasks.register(
"generate${GUtil.toCamelCase(config.name)}Theme",
IntelliJThemeGeneratorTask::class.java
).apply {
configure {
output.set(config.targetDir.file(config.themeClassName.map {
val className = ClassName.bestGuess(it)
className.packageName.replace('.', '/') + "/${className.simpleName}.kt"
}))
themeClassName.set(config.themeClassName)
ideaVersion.set(config.ideaVersion)
themeFile.set(config.themeFile)
tasks.withType<KotlinCompile> {
dependsOn(task)
}
tasks.withType<Detekt> {
dependsOn(task)
}
pluginManager.withPlugin("org.jetbrains.kotlin.jvm") {
extensions.getByType<KotlinJvmProjectExtension>().apply {
sourceSets["main"].kotlin.srcDir(targetDir)
}
}
}
}
}
open class IntelliJThemeGeneratorTask : BaseThemeGeneratorTask() {
class ThemeGeneratorContainer(container: NamedDomainObjectContainer<ThemeGeneration>) : NamedDomainObjectContainer<ThemeGeneration> by container
private val json = Json {
ignoreUnknownKeys = true
class ThemeGeneration(val name: String, project: Project) {
val targetDir: DirectoryProperty = project.objects.directoryProperty()
.convention(project.layout.buildDirectory.dir("generated/theme"))
val ideaVersion = project.objects.property<String>()
.convention("232.6734")
val themeClassName = project.objects.property<String>()
val themeFile = project.objects.property<String>()
}
open class IntelliJThemeGeneratorTask : DefaultTask() {
@get:OutputFile
val outputFile = project.objects.fileProperty()
@get:Input
val ideaVersion = project.objects.property<String>()
@get:Input
val themeFile = project.objects.property<String>()
@get:Input
val themeClassName = project.objects.property<String>()
init {
group = "jewel"
}
@OptIn(ExperimentalSerializationApi::class)
override fun doGenerate() {
@TaskAction
fun generate() {
val json = Json { ignoreUnknownKeys = true }
val url = buildString {
append("https://raw.githubusercontent.com/JetBrains/intellij-community/")
append(ideaVersion.get())
@@ -58,23 +97,27 @@ open class IntelliJThemeGeneratorTask : BaseThemeGeneratorTask() {
}
logger.lifecycle("Fetching theme descriptor from $url...")
val themeDescriptor = URL(url).openStream()
.use { json.decodeFromStream<IntellijThemeDescriptor>(it) }
val themeDescriptor = URL(url).openStream().use {
json.decodeFromString<IntellijThemeDescriptor>(it.reader().readText())
}
logger.info("Theme descriptor fetched, parsing...")
val className = ClassName.bestGuess(themeClassName.get())
// TODO handle non-Int UI themes, too
val file = IntUiThemeDescriptorReader.readThemeFrom(themeDescriptor, className, ideaVersion.get(), url)
logger.info("Theme descriptor parsed, writing generated code to disk...")
val outputFile = output.get().asFile
outputFile.bufferedWriter().use {
file.writeTo(it)
}
val outputFile = outputFile.get().asFile
logger.lifecycle("Theme descriptor for ${themeDescriptor.name} parsed and code generated into ${outputFile.path}")
outputFile.bufferedWriter().use { file.writeTo(it) }
}
}
@Serializable
data class IntellijThemeDescriptor(
val name: String,
val author: String = "",
val dark: Boolean = false,
val editorScheme: String,
val colors: Map<String, String> = emptyMap(),
val ui: Map<String, JsonElement> = emptyMap(),
val icons: Map<String, JsonElement> = emptyMap(),
)

View File

@@ -1,15 +0,0 @@
package org.jetbrains.jewel.buildlogic.theme
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement
@Serializable
data class IntellijThemeDescriptor(
val name: String,
val author: String = "",
val dark: Boolean = false,
val editorScheme: String,
val colors: Map<String, String> = emptyMap(),
val ui: Map<String, JsonElement> = emptyMap(),
val icons: Map<String, JsonElement> = emptyMap(),
)

View File

@@ -5,6 +5,7 @@ detekt = "1.22.0"
idea = "232.8660.185"
ideaGradlePlugin = "1.13.0"
javaSarif = "2.0"
kotlinSarif = "0.4.0"
jna = "5.10.0"
kotlin = "1.8.20"
dokka = "1.8.20"
@@ -15,6 +16,7 @@ kotlinpoet = "1.14.2"
[libraries]
compose-components-splitpane = { module = "org.jetbrains.compose.components:components-splitpane", version.ref = "composeDesktop" }
javaSarif = { module = "com.contrastsecurity:java-sarif", version.ref = "javaSarif" }
kotlinSarif = { module = "io.github.detekt.sarif4k:sarif4k", version.ref = "kotlinSarif" }
jna = { module = "net.java.dev.jna:jna-platform", version.ref = "jna" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerialization" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -1,3 +1,5 @@
@file:Suppress("UnstableApiUsage")
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins {
@@ -21,12 +23,12 @@ compose.desktop {
packageVersion = "1.0"
description = "Jewel Sample Application"
vendor = "JetBrains"
licenseFile.set(File(rootDir, "LICENSE"))
licenseFile = rootProject.file("LICENSE")
macOS {
dockName = "Jewel Sample"
bundleID = "org.jetbrains.jewel.sample.standalone"
iconFile.set(File(projectDir, "icons/jewel.icns"))
iconFile = file("icons/jewel.icns")
}
}
}

View File

@@ -1,3 +1,5 @@
@file:Suppress("UnstableApiUsage")
plugins {
`jewel-publish`
alias(libs.plugins.composeDesktop)
@@ -11,17 +13,15 @@ dependencies {
}
intelliJThemeGenerator {
val ideaVersion = "232.6734"
create("intUiLight") {
themeClassName("org.jetbrains.jewel.themes.intui.core.theme.IntUiLightTheme")
themeFile("platform/platform-resources/src/themes/expUI/expUI_light.theme.json")
ideaVersion(ideaVersion)
register("intUiLight") {
themeClassName = "org.jetbrains.jewel.themes.intui.core.theme.IntUiLightTheme"
themeFile = "platform/platform-resources/src/themes/expUI/expUI_light.theme.json"
ideaVersion = "232.6734"
}
create("intUiDark") {
themeClassName("org.jetbrains.jewel.themes.intui.core.theme.IntUiDarkTheme")
themeFile("platform/platform-resources/src/themes/expUI/expUI_dark.theme.json")
ideaVersion(ideaVersion)
register("intUiDark") {
themeClassName = "org.jetbrains.jewel.themes.intui.core.theme.IntUiDarkTheme"
themeFile = "platform/platform-resources/src/themes/expUI/expUI_dark.theme.json"
ideaVersion = "232.6734"
}
}
@@ -36,3 +36,4 @@ tasks {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
}

View File

@@ -24,7 +24,7 @@ class IntelliJSvgLoader(private val svgPatcher: SvgPatcher) : SvgLoader {
pathPatcher: @Composable (String) -> String,
): Painter {
val patchedPath = pathPatcher(originalPath)
if (cache.containsKey(patchedPath)) return cache[patchedPath]!!
cache[patchedPath]?.let { return it }
val painter = rememberPatchedSvgResource(originalPath, patchedPath, resourceLoader)
cache[patchedPath] = painter