Skip to content

Commit

Permalink
Fix icon loading and errors in bridge for 241
Browse files Browse the repository at this point in the history
  • Loading branch information
rock3r committed Feb 7, 2024
1 parent 003eb1e commit d6f2df5
Show file tree
Hide file tree
Showing 63 changed files with 1,067 additions and 402 deletions.
1 change: 1 addition & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ indent_size = 2
ktlint_function_signature_body_expression_wrapping = multiline
ktlint_ignore_back_ticked_identifier = true
ij_kotlin_allow_trailing_comma = true
ktlint_function_naming_ignore_when_annotated_with = Composable

[gradlew.bat]
end_of_line = crlf
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
- name: Run :check task
run: ./gradlew check --continue

- uses: github/codeql-action/upload-sarif@v2
- uses: github/codeql-action/upload-sarif@v3
if: ${{ always() }}
with:
sarif_file: ${{ github.workspace }}/build/reports/static-analysis.sarif
Expand Down
12 changes: 0 additions & 12 deletions buildSrc/src/main/kotlin/LocalProperties.kt

This file was deleted.

2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/jewel.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ tasks {
formatKotlinMain { exclude { it.file.absolutePath.contains("build/generated") } }

lintKotlinMain {
exclude { it.file.absolutePath.contains("build/generated") }
exclude { it.file.absolutePath.replace('\\', '/').contains("build/generated") }

reports = provider {
mapOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.property
import org.gradle.kotlin.dsl.setProperty
import java.io.File
import java.net.URL
import java.net.URI

open class StudioVersionsGenerationExtension(project: Project) {

Expand Down Expand Up @@ -69,7 +69,7 @@ open class AndroidStudioReleasesGeneratorTask : DefaultTask() {
"Registered resources directories:\n" +
lookupDirs.joinToString("\n") { " * ${it.absolutePath}" }
)
val releases = URL(url).openStream()
val releases = URI.create(url).toURL().openStream()
.use { json.decodeFromStream<ApiAndroidStudioReleases>(it) }

val className = ClassName.bestGuess(STUDIO_RELEASES_OUTPUT_CLASS_NAME)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.tasks.TaskAction
import java.io.IOException
import java.net.URL
import java.net.URI

open class CheckIdeaVersionTask : DefaultTask() {

Expand Down Expand Up @@ -34,7 +34,7 @@ open class CheckIdeaVersionTask : DefaultTask() {
logger.lifecycle("Fetching IntelliJ Platform releases from $releasesUrl...")
val icReleases =
try {
URL(releasesUrl)
URI.create(releasesUrl).toURL()
.openStream()
.use { json.decodeFromStream<List<ApiIdeaReleasesItem>>(it) }
.first()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.property
import java.net.URL
import java.net.URI

class ThemeGeneratorContainer(container: NamedDomainObjectContainer<ThemeGeneration>) :
NamedDomainObjectContainer<ThemeGeneration> by container
Expand Down Expand Up @@ -59,7 +59,7 @@ open class IntelliJThemeGeneratorTask : DefaultTask() {
}

logger.lifecycle("Fetching theme descriptor from $url...")
val themeDescriptor = URL(url).openStream()
val themeDescriptor = URI.create(url).toURL().openStream()
.use { json.decodeFromStream<IntellijThemeDescriptor>(it) }

val className = ClassName.bestGuess(themeClassName.get())
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
composeDesktop = "1.6.0-dev1397"
detekt = "1.23.4"
dokka = "1.8.20"
idea = "241.9959.31-EAP-SNAPSHOT"
idea = "241.10840.26-EAP-SNAPSHOT"
ideaGradlePlugin = "1.17.0"
jna = "5.14.0"
kotlin = "1.8.21"
Expand Down
4 changes: 2 additions & 2 deletions ide-laf-bridge/api/ide-laf-bridge.api
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ public final class org/jetbrains/jewel/bridge/BridgeIconDataKt {
public static final fun readFromLaF (Lorg/jetbrains/jewel/foundation/theme/ThemeIconData$Companion;)Lorg/jetbrains/jewel/foundation/theme/ThemeIconData;
}

public final class org/jetbrains/jewel/bridge/BridgePainterHintsProvider : org/jetbrains/jewel/ui/painter/BasePainterHintsProvider {
public final class org/jetbrains/jewel/bridge/BridgePainterHintsProvider : org/jetbrains/jewel/ui/painter/PalettePainterHintsProvider {
public static final field $stable I
public static final field Companion Lorg/jetbrains/jewel/bridge/BridgePainterHintsProvider$Companion;
public synthetic fun <init> (ZLjava/util/Map;Ljava/util/Map;Ljava/util/Map;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun hints (Ljava/lang/String;Landroidx/compose/runtime/Composer;I)Ljava/util/List;
}

public final class org/jetbrains/jewel/bridge/BridgePainterHintsProvider$Companion {
public final fun invoke (Z)Lorg/jetbrains/jewel/ui/painter/BasePainterHintsProvider;
public final fun invoke (Z)Lorg/jetbrains/jewel/ui/painter/PalettePainterHintsProvider;
}

public final class org/jetbrains/jewel/bridge/BridgeResourceResolverKt {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import org.jetbrains.jewel.ui.painter.PainterPathHint
import org.jetbrains.jewel.ui.painter.PainterProviderScope
import org.jetbrains.jewel.ui.painter.ResourcePainterProviderScope

/**
* A [PainterPathHint] that implements the
* [New UI Icon Mapping](https://plugins.jetbrains.com/docs/intellij/icons.html#mapping-entries)
* by delegating to the IntelliJ Platform.
*/
internal object BridgeOverride : PainterPathHint {

private val dirProvider = DirProvider()
Expand All @@ -28,7 +33,8 @@ internal object BridgeOverride : PainterPathHint {
// 233 EAP 4 broke path patching horribly; now it can return a
// "reflective path", which is a FQN to an ExpUIIcons entry.
// As a (hopefully) temporary solution, we undo this transformation
// back into the original path.
// back into the original path. The initial transform is lossy, and
// this attempt might fail.
if (patchedPath?.startsWith("com.intellij.icons.ExpUiIcons") == true) {
return inferActualPathFromReflectivePath(patchedPath)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,121 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import com.intellij.ide.ui.UITheme
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.ui.NewUI
import org.jetbrains.jewel.bridge.theme.isNewUiTheme
import org.jetbrains.jewel.foundation.InternalJewelApi
import org.jetbrains.jewel.foundation.theme.JewelTheme
import org.jetbrains.jewel.ui.painter.BasePainterHintsProvider
import org.jetbrains.jewel.ui.painter.PainterHint
import org.jetbrains.jewel.ui.painter.PalettePainterHintsProvider
import org.jetbrains.jewel.ui.painter.hints.ColorBasedPaletteReplacement
import org.jetbrains.jewel.ui.painter.hints.Dark
import org.jetbrains.jewel.ui.painter.hints.HiDpi
import org.jetbrains.jewel.ui.painter.hints.KeyBasedPaletteReplacement
import org.jetbrains.jewel.ui.util.inDebugMode
import org.jetbrains.jewel.ui.util.toRgbaHexString

/**
* Provide the default [PainterHint]s to use in the IDE.
*
* This is an internal Jewel API and should not be used directly.
*/
@InternalJewelApi
public class BridgePainterHintsProvider private constructor(
isDark: Boolean,
intellijIconPalette: Map<String, String?> = emptyMap(),
themeIconPalette: Map<String, String?> = emptyMap(),
themeColorPalette: Map<String, Color?> = emptyMap(),
) : BasePainterHintsProvider(isDark, intellijIconPalette, themeIconPalette, themeColorPalette) {
) : PalettePainterHintsProvider(isDark, intellijIconPalette, themeIconPalette, themeColorPalette) {

@Composable
override fun hints(path: String): List<PainterHint> = buildList {
add(getPaletteHint(path))
add(BridgeOverride)
add(HiDpi())
add(Dark(JewelTheme.isDark))
override val checkBoxByColorPaletteHint: PainterHint
override val checkBoxByKeyPaletteHint: PainterHint
override val treePaletteHint: PainterHint
override val uiPaletteHint: PainterHint

init {
val ui = mutableMapOf<Color, Color>()
val checkBoxesByColor = mutableMapOf<Color, Color>()
val checkBoxesByKey = mutableMapOf<String, Color>()
val trees = mutableMapOf<Color, Color>()

@Suppress("LoopWithTooManyJumpStatements")
for ((key, value) in themeIconPalette) {
if (value == null) continue

// Checkbox (and radio button) entries work differently: the ID field
// for each element that needs patching has a "[fillKey]_[strokeKey]"
// format, starting from IJP 241. This is only enabled for the New UI.
if (key.startsWith("Checkbox.") && NewUI.isEnabled()) {
registerIdBasedReplacement(checkBoxesByKey, key, value)
}

val map = selectMap(key, checkBoxesByColor, trees, ui) ?: continue
registerColorBasedReplacement(map, key, value)
}

checkBoxByKeyPaletteHint = KeyBasedPaletteReplacement(checkBoxesByKey)
checkBoxByColorPaletteHint = ColorBasedPaletteReplacement(checkBoxesByColor)
treePaletteHint = ColorBasedPaletteReplacement(trees)
uiPaletteHint = ColorBasedPaletteReplacement(ui)
}

private fun registerColorBasedReplacement(
map: MutableMap<Color, Color>,
key: String,
value: String,
) {
// If either the key or the resolved value aren't valid colors, ignore the entry
val keyAsColor = resolveKeyColor(key, intellijIconPalette, isDark) ?: return
val resolvedColor = resolveColor(value) ?: return

// Save the new entry (oldColor -> newColor) in the map
map[keyAsColor] = resolvedColor
}

private fun registerIdBasedReplacement(
map: MutableMap<String, Color>,
key: String,
value: String,
) {
val adjustedKey = if (isDark) key.removeSuffix(".Dark") else key

if (adjustedKey !in supportedCheckboxKeys) {
if (inDebugMode) {
logger.warn("${if (isDark) "Dark" else "Light"} theme: color key $key is not supported, will be ignored")
}
return
}

if (adjustedKey != key && inDebugMode) {
logger.warn("${if (isDark) "Dark" else "Light"} theme: color key $key is deprecated, use $adjustedKey instead")
}

val parsedValue = resolveColor(value)
if (parsedValue == null) {
if (inDebugMode) {
logger.warn("${if (isDark) "Dark" else "Light"} theme: color key $key has invalid value: '$value'")
}
return
}

map[adjustedKey] = parsedValue
}

@Composable
override fun hints(path: String): List<PainterHint> =
buildList {
add(BridgeOverride)
add(getPaletteHint(path, isNewUi = isNewUiTheme()))
add(HiDpi())
add(Dark(JewelTheme.isDark))
}

public companion object {

private val logger = thisLogger()

@Suppress("UnstableApiUsage") // We need to call @Internal APIs
public operator fun invoke(isDark: Boolean): BasePainterHintsProvider {
public operator fun invoke(isDark: Boolean): PalettePainterHintsProvider {
val uiTheme = currentUiThemeOrNull() ?: return BridgePainterHintsProvider(isDark)
logger.info("Parsing theme info from theme ${uiTheme.name} (id: ${uiTheme.id}, isDark: ${uiTheme.isDark})")

Expand All @@ -41,13 +127,32 @@ public class BridgePainterHintsProvider private constructor(
(bean.colorPalette as Map<String, Any?>).mapValues {
when (val value = it.value) {
is String -> value
is java.awt.Color -> value.toRgbaHexString()
else -> null
}
}
val keyPalette = UITheme.getColorPalette()
val themeColors = bean.colors.mapValues { (_, v) -> Color(v) }

return BridgePainterHintsProvider(isDark, keyPalette, iconColorPalette, themeColors)
return BridgePainterHintsProvider(
isDark = isDark,
intellijIconPalette = keyPalette,
themeIconPalette = iconColorPalette,
themeColorPalette = themeColors,
)
}

private val supportedCheckboxKeys: Set<String> =
setOf(
"Checkbox.Background.Default",
"Checkbox.Border.Default",
"Checkbox.Foreground.Selected",
"Checkbox.Background.Selected",
"Checkbox.Border.Selected",
"Checkbox.Focus.Wide",
"Checkbox.Foreground.Disabled",
"Checkbox.Background.Disabled",
"Checkbox.Border.Disabled",
)
}
}
Loading

0 comments on commit d6f2df5

Please sign in to comment.