Skip to content

Commit 701426e

Browse files
committed
Use IDEA code highlighting functionality
1 parent 7c19398 commit 701426e

9 files changed

Lines changed: 192 additions & 107 deletions

File tree

tools/idea-plugin/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Unreleased
44

5+
### Changed
6+
7+
- Migrate to IDEA code highlighting for tooltip snippets
8+
59
## 1.3.0 - 2026-02-28
610

711
### Added

tools/idea-plugin/build.gradle.kts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ dependencies {
4545
implementation(projects.components.parser.jvm.svg)
4646
implementation(projects.components.parser.unified)
4747
implementation(projects.sdk.compose.foundation)
48-
implementation(projects.sdk.compose.highlightsCore)
4948
implementation(projects.sdk.compose.icons)
5049
implementation(projects.sdk.core.extensions)
5150
implementation(projects.sdk.intellij.psi.iconpack)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package io.github.composegears.valkyrie.jewel
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.ui.Alignment
5+
import androidx.compose.ui.Modifier
6+
import io.github.composegears.valkyrie.jewel.highlight.HighlightedCode
7+
import io.github.composegears.valkyrie.jewel.tooling.PreviewTheme
8+
import org.jetbrains.compose.ui.tooling.preview.Preview
9+
import org.jetbrains.jewel.foundation.theme.JewelTheme
10+
import org.jetbrains.jewel.ui.component.Text
11+
import org.jetbrains.jewel.ui.typography
12+
13+
@Composable
14+
fun EditorText(
15+
code: HighlightedCode,
16+
modifier: Modifier = Modifier,
17+
) {
18+
Text(
19+
modifier = modifier,
20+
text = code.value,
21+
style = JewelTheme.typography.editorTextStyle,
22+
)
23+
}
24+
25+
@Preview
26+
@Composable
27+
private fun EditorTextPreview() = PreviewTheme(alignment = Alignment.Center) {
28+
Text(text = "editor text style")
29+
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package io.github.composegears.valkyrie.jewel.highlight
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.runtime.collectAsState
5+
import androidx.compose.runtime.getValue
6+
import androidx.compose.runtime.remember
7+
import androidx.compose.ui.Alignment
8+
import androidx.compose.ui.Modifier
9+
import androidx.compose.ui.text.AnnotatedString
10+
import androidx.compose.ui.text.SpanStyle
11+
import androidx.compose.ui.text.buildAnnotatedString
12+
import androidx.compose.ui.text.style.TextDecoration
13+
import io.github.composegears.valkyrie.jewel.EditorText
14+
import io.github.composegears.valkyrie.jewel.platform.LocalProject
15+
import io.github.composegears.valkyrie.jewel.tooling.ProjectPreviewTheme
16+
import io.github.composegears.valkyrie.jewel.tooling.debugBounds
17+
import kotlinx.coroutines.flow.map
18+
import org.jetbrains.compose.ui.tooling.preview.Preview
19+
import org.jetbrains.jewel.bridge.code.highlighting.CodeHighlighterFactory
20+
import org.jetbrains.jewel.foundation.ExperimentalJewelApi
21+
import org.jetbrains.jewel.foundation.code.MimeType
22+
import org.jetbrains.jewel.foundation.theme.JewelTheme
23+
24+
@OptIn(ExperimentalJewelApi::class)
25+
@Composable
26+
fun rememberCodeHighlight(
27+
text: String,
28+
mimeType: MimeType = MimeType.Known.KOTLIN,
29+
style: UnderlineDsl.() -> Unit = {},
30+
): HighlightedCode {
31+
val dsl = UnderlineDsl(text).apply(style)
32+
33+
val project = LocalProject.current
34+
val underlineColor = JewelTheme.globalColors.outlines.warning
35+
val codeHighlighter = remember { CodeHighlighterFactory.getInstance(project).createHighlighter() }
36+
37+
val highlightedCode by codeHighlighter
38+
.highlight(code = text, mimeType = mimeType)
39+
.map {
40+
if (dsl.ranges.isNotEmpty()) {
41+
buildAnnotatedString {
42+
append(it)
43+
dsl.ranges.forEach { range ->
44+
addStyle(
45+
style = SpanStyle(
46+
background = underlineColor,
47+
textDecoration = TextDecoration.Underline,
48+
),
49+
start = range.first,
50+
end = range.last + 1,
51+
)
52+
}
53+
}
54+
} else {
55+
it
56+
}
57+
}
58+
.collectAsState(AnnotatedString(text))
59+
60+
return HighlightedCode(highlightedCode)
61+
}
62+
63+
@JvmInline
64+
value class HighlightedCode(val value: AnnotatedString)
65+
66+
@DslMarker
67+
annotation class UnderlineDslMarker
68+
69+
@UnderlineDslMarker
70+
class UnderlineDsl internal constructor(
71+
private val text: String,
72+
) {
73+
74+
internal val ranges = mutableListOf<IntRange>()
75+
76+
fun underline(range: IntRange) {
77+
require(range.first >= 0) { "Range start < 0" }
78+
require(range.last < text.length) { "Range out of bounds" }
79+
require(range.first <= range.last) { "Invalid range" }
80+
81+
ranges += range
82+
}
83+
84+
fun underline(highlightText: String) {
85+
require(highlightText.isNotEmpty())
86+
87+
var index = 0
88+
while (true) {
89+
index = text.indexOf(highlightText, startIndex = index)
90+
if (index == -1) break
91+
92+
ranges += index..<index + highlightText.length
93+
index += highlightText.length
94+
}
95+
}
96+
}
97+
98+
@Preview
99+
@Composable
100+
private fun KtCodeViewerPreview() = ProjectPreviewTheme(alignment = Alignment.Center) {
101+
val highlightedCode = rememberCodeHighlight(
102+
text = """
103+
package io.github.composegears.valkyrie
104+
105+
val Pack.MyIcon: ImageVector
106+
get() {
107+
if (_MyIcon != null) {
108+
return _MyIcon!!
109+
}
110+
...
111+
}
112+
""".trimIndent(),
113+
style = {
114+
underline(8..38)
115+
underline(highlightText = "_MyIcon")
116+
},
117+
)
118+
119+
EditorText(
120+
code = highlightedCode,
121+
modifier = Modifier.debugBounds(),
122+
)
123+
}

tools/idea-plugin/src/main/kotlin/io/github/composegears/valkyrie/jewel/highlight/CodeTooltip.kt

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,34 @@ package io.github.composegears.valkyrie.jewel.highlight
22

33
import androidx.compose.foundation.ExperimentalFoundationApi
44
import androidx.compose.runtime.Composable
5-
import dev.snipme.highlights.Highlights
6-
import io.github.composegears.valkyrie.jewel.tooling.PreviewTheme
7-
import io.github.composegears.valkyrie.sdk.compose.highlights.core.rememberCodeHighlight
5+
import androidx.compose.ui.Alignment
6+
import io.github.composegears.valkyrie.jewel.EditorText
7+
import io.github.composegears.valkyrie.jewel.tooling.ProjectPreviewTheme
88
import io.github.composegears.valkyrie.util.stringResource
99
import org.jetbrains.compose.ui.tooling.preview.Preview
10-
import org.jetbrains.jewel.foundation.theme.JewelTheme
1110
import org.jetbrains.jewel.ui.component.Icon
1211
import org.jetbrains.jewel.ui.component.Tooltip
1312
import org.jetbrains.jewel.ui.icons.AllIconsKeys
1413

1514
@OptIn(ExperimentalFoundationApi::class)
1615
@Composable
1716
fun CodeTooltip(
18-
highlights: Highlights,
17+
code: HighlightedCode,
1918
content: @Composable () -> Unit,
2019
) {
2120
Tooltip(
2221
tooltip = {
23-
KtCodeViewer(highlights = highlights)
22+
EditorText(code = code)
2423
},
2524
content = content,
2625
)
2726
}
2827

2928
@Preview
3029
@Composable
31-
private fun CodeTooltipPreview() = PreviewTheme {
30+
private fun CodeTooltipPreview() = ProjectPreviewTheme(alignment = Alignment.Center) {
3231
CodeTooltip(
33-
highlights = rememberCodeHighlight(codeBlock = "", isDark = JewelTheme.isDark),
32+
code = rememberCodeHighlight(text = "val t: Int = 0"),
3433
content = {
3534
Icon(
3635
key = AllIconsKeys.General.ContextHelp,

tools/idea-plugin/src/main/kotlin/io/github/composegears/valkyrie/jewel/highlight/KtCodeViewer.kt

Lines changed: 0 additions & 52 deletions
This file was deleted.

tools/idea-plugin/src/main/kotlin/io/github/composegears/valkyrie/ui/screen/mode/iconpack/common/CodeTooltipHeader.kt

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,29 @@ import androidx.compose.runtime.Composable
55
import androidx.compose.ui.Alignment
66
import androidx.compose.ui.Modifier
77
import androidx.compose.ui.unit.dp
8-
import dev.snipme.highlights.Highlights
98
import io.github.composegears.valkyrie.jewel.highlight.CodeTooltip
10-
import io.github.composegears.valkyrie.jewel.tooling.PreviewTheme
9+
import io.github.composegears.valkyrie.jewel.highlight.HighlightedCode
10+
import io.github.composegears.valkyrie.jewel.highlight.rememberCodeHighlight
11+
import io.github.composegears.valkyrie.jewel.tooling.ProjectPreviewTheme
1112
import io.github.composegears.valkyrie.sdk.compose.foundation.layout.CenterVerticalRow
1213
import io.github.composegears.valkyrie.sdk.compose.foundation.layout.Spacer
13-
import io.github.composegears.valkyrie.sdk.compose.highlights.core.getEmphasisLocations
14-
import io.github.composegears.valkyrie.sdk.compose.highlights.core.rememberCodeHighlight
1514
import io.github.composegears.valkyrie.util.stringResource
1615
import org.jetbrains.compose.ui.tooling.preview.Preview
17-
import org.jetbrains.jewel.foundation.theme.JewelTheme
1816
import org.jetbrains.jewel.ui.component.Icon
1917
import org.jetbrains.jewel.ui.component.Text
2018
import org.jetbrains.jewel.ui.icons.AllIconsKeys
2119

2220
@Composable
2321
fun CodeTooltipHeader(
2422
text: String,
25-
highlights: Highlights,
23+
code: HighlightedCode,
2624
modifier: Modifier = Modifier,
2725
) {
2826
CenterVerticalRow(modifier = modifier) {
2927
Text(text)
3028
Spacer(8.dp)
3129
CodeTooltip(
32-
highlights = highlights,
30+
code = code,
3331
content = {
3432
Icon(
3533
key = AllIconsKeys.General.ContextHelp,
@@ -44,7 +42,7 @@ fun CodeTooltipHeader(
4442
fun buildPackPackageHighlight(
4543
packageName: String,
4644
iconPackName: String,
47-
): Highlights {
45+
): HighlightedCode {
4846
val packagePlaceholder = packageName.ifEmpty { "com.test.iconpack" }
4947
val iconPackPlaceholder = iconPackName.ifEmpty { "YourPackName" }
5048

@@ -61,17 +59,15 @@ fun buildPackPackageHighlight(
6159
""".trimIndent()
6260

6361
return rememberCodeHighlight(
64-
codeBlock = codeBlock,
65-
emphasisLocation = getEmphasisLocations(
66-
codeBlock = codeBlock,
67-
highlightText = packagePlaceholder,
68-
),
69-
isDark = JewelTheme.isDark,
62+
text = codeBlock,
63+
style = {
64+
underline(packagePlaceholder)
65+
},
7066
)
7167
}
7268

7369
@Composable
74-
fun buildIconPackHighlight(iconPackName: String): Highlights {
70+
fun buildIconPackHighlight(iconPackName: String): HighlightedCode {
7571
val iconPackPlaceholder = iconPackName.ifEmpty { "YourPackName" }
7672
val codeBlock = """
7773
object $iconPackPlaceholder
@@ -86,30 +82,28 @@ fun buildIconPackHighlight(iconPackName: String): Highlights {
8682
""".trimIndent()
8783

8884
return rememberCodeHighlight(
89-
codeBlock = codeBlock,
90-
emphasisLocation = getEmphasisLocations(
91-
codeBlock = codeBlock,
92-
highlightText = iconPackPlaceholder,
93-
),
94-
isDark = JewelTheme.isDark,
85+
text = codeBlock,
86+
style = {
87+
underline(iconPackPlaceholder)
88+
},
9589
)
9690
}
9791

9892
@Preview
9993
@Composable
100-
private fun CodeTooltipHeaderPreview() = PreviewTheme(alignment = Alignment.Center) {
94+
private fun CodeTooltipHeaderPreview() = ProjectPreviewTheme(alignment = Alignment.Center) {
10195
Row {
10296
CodeTooltipHeader(
10397
text = "Package",
104-
highlights = buildPackPackageHighlight(
98+
code = buildPackPackageHighlight(
10599
packageName = "com.example.iconpack",
106100
iconPackName = "MyIconPack",
107101
),
108102
)
109103
Spacer(16.dp)
110104
CodeTooltipHeader(
111105
text = "IconPack",
112-
highlights = buildIconPackHighlight(
106+
code = buildIconPackHighlight(
113107
iconPackName = "MyIconPack",
114108
),
115109
)

0 commit comments

Comments
 (0)