Skip to content

Commit

Permalink
Merge in main for 0.25.0
Browse files Browse the repository at this point in the history
# Conflicts:
#	buildSrc/src/main/kotlin/icon-keys-generator.gradle.kts
#	gradle.properties
#	gradle/libs.versions.toml
#	ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/icon/IntelliJIconKey.kt
  • Loading branch information
rock3r committed Sep 30, 2024
2 parents 0f4a357 + d6e516f commit 484a494
Show file tree
Hide file tree
Showing 38 changed files with 619 additions and 192 deletions.
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/icon-keys-generator.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ open class IconKeysGeneratorTask : DefaultTask() {

if (field.annotations.any { it.annotationClass == java.lang.Deprecated::class }) {
logger.lifecycle("Ignoring deprecated field: $fieldName")
return
return@forEach
}

val icon = field.get(sourceClass)
Expand Down
83 changes: 83 additions & 0 deletions foundation/api/foundation.api
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,89 @@ public final class org/jetbrains/jewel/foundation/actionSystem/ProvideDataKt {
public static final fun provideData (Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
}

public final class org/jetbrains/jewel/foundation/code/MimeType {
public static final field ATTR_FOLDER_TYPE Ljava/lang/String;
public static final field ATTR_ROLE Ljava/lang/String;
public static final field ATTR_ROOT_TAG Ljava/lang/String;
public static final field VALUE_MANIFEST Ljava/lang/String;
public static final field VALUE_RESOURCE Ljava/lang/String;
public static final fun base-9EQw4cI (Ljava/lang/String;)Ljava/lang/String;
public static final synthetic fun box-impl (Ljava/lang/String;)Lorg/jetbrains/jewel/foundation/code/MimeType;
public static fun constructor-impl (Ljava/lang/String;)Ljava/lang/String;
public static final fun displayName-impl (Ljava/lang/String;)Ljava/lang/String;
public fun equals (Ljava/lang/Object;)Z
public static fun equals-impl (Ljava/lang/String;Ljava/lang/Object;)Z
public static final fun equals-impl0 (Ljava/lang/String;Ljava/lang/String;)Z
public fun hashCode ()I
public static fun hashCode-impl (Ljava/lang/String;)I
public fun toString ()Ljava/lang/String;
public static fun toString-impl (Ljava/lang/String;)Ljava/lang/String;
public final synthetic fun unbox-impl ()Ljava/lang/String;
}

public final class org/jetbrains/jewel/foundation/code/MimeType$Known {
public static final field $stable I
public static final field INSTANCE Lorg/jetbrains/jewel/foundation/code/MimeType$Known;
public final fun fromMarkdownLanguageName-YABSuFg (Ljava/lang/String;)Ljava/lang/String;
public final fun getAGSL-9EQw4cI ()Ljava/lang/String;
public final fun getAIDL-9EQw4cI ()Ljava/lang/String;
public final fun getC-9EQw4cI ()Ljava/lang/String;
public final fun getCPP-9EQw4cI ()Ljava/lang/String;
public final fun getDART-9EQw4cI ()Ljava/lang/String;
public final fun getGO-9EQw4cI ()Ljava/lang/String;
public final fun getGRADLE-9EQw4cI ()Ljava/lang/String;
public final fun getGRADLE_KTS-9EQw4cI ()Ljava/lang/String;
public final fun getGROOVY-9EQw4cI ()Ljava/lang/String;
public final fun getJAVA-9EQw4cI ()Ljava/lang/String;
public final fun getJAVASCRIPT-9EQw4cI ()Ljava/lang/String;
public final fun getJSON-9EQw4cI ()Ljava/lang/String;
public final fun getKOTLIN-9EQw4cI ()Ljava/lang/String;
public final fun getMANIFEST-9EQw4cI ()Ljava/lang/String;
public final fun getPROGUARD-9EQw4cI ()Ljava/lang/String;
public final fun getPROPERTIES-9EQw4cI ()Ljava/lang/String;
public final fun getPROTO-9EQw4cI ()Ljava/lang/String;
public final fun getPYTHON-9EQw4cI ()Ljava/lang/String;
public final fun getREGEX-9EQw4cI ()Ljava/lang/String;
public final fun getRESOURCE-9EQw4cI ()Ljava/lang/String;
public final fun getRUST-9EQw4cI ()Ljava/lang/String;
public final fun getSHELL-9EQw4cI ()Ljava/lang/String;
public final fun getSQL-9EQw4cI ()Ljava/lang/String;
public final fun getSVG-9EQw4cI ()Ljava/lang/String;
public final fun getTEXT-9EQw4cI ()Ljava/lang/String;
public final fun getTOML-9EQw4cI ()Ljava/lang/String;
public final fun getTYPESCRIPT-9EQw4cI ()Ljava/lang/String;
public final fun getUNKNOWN-9EQw4cI ()Ljava/lang/String;
public final fun getVERSION_CATALOG-9EQw4cI ()Ljava/lang/String;
public final fun getXML-9EQw4cI ()Ljava/lang/String;
public final fun getYAML-9EQw4cI ()Ljava/lang/String;
}

public final class org/jetbrains/jewel/foundation/code/MimeTypeKt {
public static final fun isGradle-KcqRzx0 (Ljava/lang/String;)Z
public static final fun isJava-KcqRzx0 (Ljava/lang/String;)Z
public static final fun isKotlin-KcqRzx0 (Ljava/lang/String;)Z
public static final fun isManifest-KcqRzx0 (Ljava/lang/String;)Z
public static final fun isProto-KcqRzx0 (Ljava/lang/String;)Z
public static final fun isRegex-KcqRzx0 (Ljava/lang/String;)Z
public static final fun isSql-KcqRzx0 (Ljava/lang/String;)Z
public static final fun isVersionCatalog-KcqRzx0 (Ljava/lang/String;)Z
public static final fun isXml-KcqRzx0 (Ljava/lang/String;)Z
}

public abstract interface class org/jetbrains/jewel/foundation/code/highlighting/CodeHighlighter {
public abstract fun highlight-C7ITchA (Ljava/lang/String;Ljava/lang/String;)Lkotlinx/coroutines/flow/Flow;
}

public final class org/jetbrains/jewel/foundation/code/highlighting/CodeHighlighterKt {
public static final fun getLocalCodeHighlighter ()Landroidx/compose/runtime/ProvidableCompositionLocal;
}

public final class org/jetbrains/jewel/foundation/code/highlighting/NoOpCodeHighlighter : org/jetbrains/jewel/foundation/code/highlighting/CodeHighlighter {
public static final field $stable I
public static final field INSTANCE Lorg/jetbrains/jewel/foundation/code/highlighting/NoOpCodeHighlighter;
public fun highlight-C7ITchA (Ljava/lang/String;Ljava/lang/String;)Lkotlinx/coroutines/flow/Flow;
}

public class org/jetbrains/jewel/foundation/lazy/DefaultMacOsSelectableColumnKeybindings : org/jetbrains/jewel/foundation/lazy/DefaultSelectableColumnKeybindings {
public static final field $stable I
public static final field Companion Lorg/jetbrains/jewel/foundation/lazy/DefaultMacOsSelectableColumnKeybindings$Companion;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package org.jetbrains.jewel.markdown

import org.jetbrains.jewel.markdown.MimeType.Known.AGSL
import org.jetbrains.jewel.markdown.MimeType.Known.DART
import org.jetbrains.jewel.markdown.MimeType.Known.JSON
import org.jetbrains.jewel.markdown.MimeType.Known.KOTLIN
import org.jetbrains.jewel.markdown.MimeType.Known.PYTHON
import org.jetbrains.jewel.markdown.MimeType.Known.RUST
import org.jetbrains.jewel.markdown.MimeType.Known.TYPESCRIPT
import org.jetbrains.jewel.markdown.MimeType.Known.YAML
package org.jetbrains.jewel.foundation.code

import org.jetbrains.jewel.foundation.code.MimeType.Known.AGSL
import org.jetbrains.jewel.foundation.code.MimeType.Known.DART
import org.jetbrains.jewel.foundation.code.MimeType.Known.JSON
import org.jetbrains.jewel.foundation.code.MimeType.Known.KOTLIN
import org.jetbrains.jewel.foundation.code.MimeType.Known.PYTHON
import org.jetbrains.jewel.foundation.code.MimeType.Known.RUST
import org.jetbrains.jewel.foundation.code.MimeType.Known.TYPESCRIPT
import org.jetbrains.jewel.foundation.code.MimeType.Known.YAML

/**
* Represents the language and dialect of a source snippet, as an RFC 2046 mime type.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.jetbrains.jewel.foundation.code.highlighting

import androidx.compose.runtime.ProvidableCompositionLocal
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.text.AnnotatedString
import kotlinx.coroutines.flow.Flow
import org.jetbrains.jewel.foundation.ExperimentalJewelApi
import org.jetbrains.jewel.foundation.code.MimeType

@ExperimentalJewelApi
public interface CodeHighlighter {
/**
* Highlights [code] according to rules for the language specified by [mimeType], and returns flow of styled
* strings. For basic highlighters with rigid color schemes it is enough to return a flow of one element:
* ```
* return flowOf(highlightedString(code, mimeType))
* ```
*
* However, some implementations might want gradual highlighting (for example, apply something simple while waiting
* for the extensive info from server), or they might rely upon a color scheme that can change at any time.
*
* In such cases, they need to produce more than one styled string for the same piece of code, and that's when flows
* come in handy.
*
* @see [NoOpCodeHighlighter]
*/
public fun highlight(code: String, mimeType: MimeType): Flow<AnnotatedString>
}

public val LocalCodeHighlighter: ProvidableCompositionLocal<CodeHighlighter> = staticCompositionLocalOf {
NoOpCodeHighlighter
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.jetbrains.jewel.foundation.code.highlighting

import androidx.compose.ui.text.AnnotatedString
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import org.jetbrains.jewel.foundation.code.MimeType

public object NoOpCodeHighlighter : CodeHighlighter {
override fun highlight(code: String, mimeType: MimeType): Flow<AnnotatedString> = flowOf(AnnotatedString(code))
}
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ org.jetbrains.intellij.platform.buildFeature.useBinaryReleases=false

jdk.level=17
ijp.target=233
jewel.release.version=0.24.2
jewel.release.version=0.25.0
4 changes: 2 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[versions]
commonmark = "0.22.0"
composeDesktop = "1.7.0-beta01"
composeDesktop = "1.7.0-beta02"
detekt = "1.23.6"
dokka = "1.9.20"
idea = "233.15619.7"
ideaPlugin = "1.17.4"
jna = "5.14.0"
kotlin = "1.9.21"
kotlin = "1.9.24"
kotlinSarif = "0.5.0"
kotlinpoet = "1.17.0"
kotlinterGradlePlugin = "4.4.1"
Expand Down
11 changes: 11 additions & 0 deletions ide-laf-bridge/api/ide-laf-bridge.api
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,17 @@ public final class org/jetbrains/jewel/bridge/actionSystem/RootDataProviderNode
public final fun getData (Ljava/lang/String;)Ljava/lang/Object;
}

public final class org/jetbrains/jewel/bridge/code/highlighting/CodeHighlighterFactory {
public static final field $stable I
public static final field Companion Lorg/jetbrains/jewel/bridge/code/highlighting/CodeHighlighterFactory$Companion;
public fun <init> (Lcom/intellij/openapi/project/Project;Lkotlinx/coroutines/CoroutineScope;)V
public final fun createHighlighter ()Lorg/jetbrains/jewel/foundation/code/highlighting/CodeHighlighter;
}

public final class org/jetbrains/jewel/bridge/code/highlighting/CodeHighlighterFactory$Companion {
public final fun getInstance (Lcom/intellij/openapi/project/Project;)Lorg/jetbrains/jewel/bridge/code/highlighting/CodeHighlighterFactory;
}

public final class org/jetbrains/jewel/bridge/icon/IntelliJIconKeyKt {
public static final fun fromPlatformIcon (Lorg/jetbrains/jewel/ui/icon/IntelliJIconKey$Companion;Ljavax/swing/Icon;Ljava/lang/Class;)Lorg/jetbrains/jewel/ui/icon/IconKey;
public static synthetic fun fromPlatformIcon$default (Lorg/jetbrains/jewel/ui/icon/IntelliJIconKey$Companion;Ljavax/swing/Icon;Ljava/lang/Class;ILjava/lang/Object;)Lorg/jetbrains/jewel/ui/icon/IconKey;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.jetbrains.jewel.bridge.code.highlighting

import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.editor.colors.EditorColorsListener
import com.intellij.openapi.editor.colors.EditorColorsManager
import com.intellij.openapi.project.Project
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.launch
import org.jetbrains.jewel.foundation.code.highlighting.CodeHighlighter

@Service(Service.Level.PROJECT)
public class CodeHighlighterFactory(private val project: Project, private val coroutineScope: CoroutineScope) {
private val reHighlightingRequests = MutableSharedFlow<Unit>(replay = 0)

init {
project.messageBus
.connect(coroutineScope)
.subscribe(
EditorColorsManager.TOPIC,
EditorColorsListener { coroutineScope.launch { reHighlightingRequests.emit(Unit) } },
)
}

public fun createHighlighter(): CodeHighlighter = LexerBasedCodeHighlighter(project, reHighlightingRequests)

public companion object {
public fun getInstance(project: Project): CodeHighlighterFactory = project.service()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package org.jetbrains.jewel.bridge.code.highlighting

import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.withStyle
import com.intellij.lang.Language
import com.intellij.lang.LanguageUtil
import com.intellij.openapi.editor.colors.EditorColorsManager
import com.intellij.openapi.editor.colors.EditorColorsScheme
import com.intellij.openapi.editor.markup.EffectType
import com.intellij.openapi.editor.markup.TextAttributes
import com.intellij.openapi.fileTypes.SyntaxHighlighter
import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory
import com.intellij.openapi.project.Project
import com.intellij.testFramework.LightVirtualFile
import java.awt.Font
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.withContext
import org.jetbrains.jewel.bridge.toComposeColorOrUnspecified
import org.jetbrains.jewel.foundation.code.MimeType
import org.jetbrains.jewel.foundation.code.highlighting.CodeHighlighter

internal class LexerBasedCodeHighlighter(
private val project: Project,
private val reHighlightingRequests: Flow<Unit>,
private val highlightDispatcher: CoroutineDispatcher = Dispatchers.Default,
) : CodeHighlighter {
override fun highlight(code: String, mimeType: MimeType): Flow<AnnotatedString> {
val language = mimeType.toLanguageOrNull() ?: return flowOf(AnnotatedString(code))
val fileExtension = language.associatedFileType?.defaultExtension ?: return flowOf(AnnotatedString(code))
val virtualFile = LightVirtualFile("markdown_code_block_${code.hashCode()}.$fileExtension", language, code)
val colorScheme = EditorColorsManager.getInstance().globalScheme
val highlighter =
SyntaxHighlighterFactory.getSyntaxHighlighter(language, project, virtualFile)
?: return flowOf(AnnotatedString(code))

return flow {
highlightAndEmit(highlighter, code, colorScheme)
reHighlightingRequests.collect { highlightAndEmit(highlighter, code, colorScheme) }
}
}

private suspend fun FlowCollector<AnnotatedString>.highlightAndEmit(
highlighter: SyntaxHighlighter,
code: String,
colorScheme: EditorColorsScheme,
) {
emit(withContext(highlightDispatcher) { doHighlight(highlighter, code, colorScheme) })
}

private fun doHighlight(
highlighter: SyntaxHighlighter,
code: String,
colorScheme: EditorColorsScheme,
): AnnotatedString = buildAnnotatedString {
with(highlighter.highlightingLexer) {
start(code)

while (tokenType != null) {
val attributes: TextAttributes? = run {
val attrKey = highlighter.getTokenHighlights(tokenType).lastOrNull() ?: return@run null
colorScheme.getAttributes(attrKey) ?: attrKey.defaultAttributes
}
withTextAttributes(attributes) { append(tokenText) }
advance()
}
}
}

private fun MimeType.toLanguageOrNull(): Language? = LanguageUtil.findRegisteredLanguage(displayName().lowercase())

private fun AnnotatedString.Builder.withTextAttributes(
textAttributes: TextAttributes?,
block: AnnotatedString.Builder.() -> Unit,
) {
if (textAttributes == null) {
return block()
}
withStyle(textAttributes.toSpanStyle(), block)
}

private fun TextAttributes.toSpanStyle() =
SpanStyle(
color = foregroundColor.toComposeColorOrUnspecified(),
fontWeight = if (fontType and Font.BOLD != 0) FontWeight.Bold else null,
fontStyle = if (fontType and Font.ITALIC != 0) FontStyle.Italic else null,
background = backgroundColor.toComposeColorOrUnspecified(),
textDecoration =
when (effectType) {
EffectType.LINE_UNDERSCORE -> TextDecoration.Underline
EffectType.STRIKEOUT -> TextDecoration.LineThrough
else -> null
},
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public val ThemeColorPalette.windowsPopupBorder: Color?
get() = lookup("windowsPopupBorder")

public fun ThemeColorPalette.Companion.readFromLaF(): ThemeColorPalette {
val gray = readPaletteColors("Grey")
val gray = readPaletteColors("Gray")
val blue = readPaletteColors("Blue")
val green = readPaletteColors("Green")
val red = readPaletteColors("Red")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public fun JewelTheme.Companion.createDefaultTextStyle(
hyphens: Hyphens = Hyphens.Unspecified,
textMotion: TextMotion? = null,
): TextStyle =
TextStyle.Default.copy(
TextStyle(
color = color,
fontSize = fontSize,
fontWeight = fontWeight,
Expand Down Expand Up @@ -108,7 +108,7 @@ public fun JewelTheme.Companion.createDefaultTextStyle(
hyphens: Hyphens = Hyphens.Unspecified,
textMotion: TextMotion? = null,
): TextStyle =
TextStyle.Default.copy(
TextStyle(
brush = brush,
alpha = alpha,
fontSize = fontSize,
Expand Down Expand Up @@ -162,7 +162,7 @@ public fun JewelTheme.Companion.createEditorTextStyle(
hyphens: Hyphens = Hyphens.Unspecified,
textMotion: TextMotion? = null,
): TextStyle =
TextStyle.Default.copy(
TextStyle(
color = color,
fontSize = fontSize,
fontWeight = fontWeight,
Expand Down Expand Up @@ -216,7 +216,7 @@ public fun JewelTheme.Companion.createEditorTextStyle(
hyphens: Hyphens = Hyphens.Unspecified,
textMotion: TextMotion? = null,
): TextStyle =
TextStyle.Default.copy(
TextStyle(
brush = brush,
alpha = alpha,
fontSize = fontSize,
Expand Down
Loading

0 comments on commit 484a494

Please sign in to comment.