Skip to content

Commit cf9d707

Browse files
[JEWEL-741] Use TextMate as Fallback for Languages Without Parsers
1 parent 81d015c commit cf9d707

File tree

12 files changed

+542
-148
lines changed

12 files changed

+542
-148
lines changed

platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/code/MimeType.kt

Lines changed: 161 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,30 @@ import org.jetbrains.jewel.foundation.code.MimeType.Known.AGSL
44
import org.jetbrains.jewel.foundation.code.MimeType.Known.AIDL
55
import org.jetbrains.jewel.foundation.code.MimeType.Known.C
66
import org.jetbrains.jewel.foundation.code.MimeType.Known.CPP
7+
import org.jetbrains.jewel.foundation.code.MimeType.Known.CSS
78
import org.jetbrains.jewel.foundation.code.MimeType.Known.DART
89
import org.jetbrains.jewel.foundation.code.MimeType.Known.DIFF
910
import org.jetbrains.jewel.foundation.code.MimeType.Known.GO
1011
import org.jetbrains.jewel.foundation.code.MimeType.Known.GRADLE
1112
import org.jetbrains.jewel.foundation.code.MimeType.Known.GRADLE_KTS
1213
import org.jetbrains.jewel.foundation.code.MimeType.Known.GROOVY
14+
import org.jetbrains.jewel.foundation.code.MimeType.Known.HTML
1315
import org.jetbrains.jewel.foundation.code.MimeType.Known.JAVA
1416
import org.jetbrains.jewel.foundation.code.MimeType.Known.JAVASCRIPT
1517
import org.jetbrains.jewel.foundation.code.MimeType.Known.JSON
18+
import org.jetbrains.jewel.foundation.code.MimeType.Known.JSON5
19+
import org.jetbrains.jewel.foundation.code.MimeType.Known.JSON_LINES
1620
import org.jetbrains.jewel.foundation.code.MimeType.Known.KOTLIN
1721
import org.jetbrains.jewel.foundation.code.MimeType.Known.MANIFEST
22+
import org.jetbrains.jewel.foundation.code.MimeType.Known.OBJECTIVE_C
1823
import org.jetbrains.jewel.foundation.code.MimeType.Known.PATCH
1924
import org.jetbrains.jewel.foundation.code.MimeType.Known.PROGUARD
2025
import org.jetbrains.jewel.foundation.code.MimeType.Known.PROPERTIES
2126
import org.jetbrains.jewel.foundation.code.MimeType.Known.PROTO
2227
import org.jetbrains.jewel.foundation.code.MimeType.Known.PYTHON
2328
import org.jetbrains.jewel.foundation.code.MimeType.Known.REGEX
2429
import org.jetbrains.jewel.foundation.code.MimeType.Known.RESOURCE
30+
import org.jetbrains.jewel.foundation.code.MimeType.Known.RUBY
2531
import org.jetbrains.jewel.foundation.code.MimeType.Known.RUST
2632
import org.jetbrains.jewel.foundation.code.MimeType.Known.SHELL
2733
import org.jetbrains.jewel.foundation.code.MimeType.Known.SQL
@@ -31,9 +37,47 @@ import org.jetbrains.jewel.foundation.code.MimeType.Known.TOML
3137
import org.jetbrains.jewel.foundation.code.MimeType.Known.TYPESCRIPT
3238
import org.jetbrains.jewel.foundation.code.MimeType.Known.UNKNOWN
3339
import org.jetbrains.jewel.foundation.code.MimeType.Known.VERSION_CATALOG
40+
import org.jetbrains.jewel.foundation.code.MimeType.Known.XHTML
3441
import org.jetbrains.jewel.foundation.code.MimeType.Known.XML
3542
import org.jetbrains.jewel.foundation.code.MimeType.Known.YAML
3643

44+
private val ALREADY_NORMALIZED_BUILTIN_TYPES =
45+
listOf(
46+
AGSL,
47+
AIDL,
48+
C,
49+
CPP,
50+
DART,
51+
DIFF,
52+
GO,
53+
GRADLE,
54+
GRADLE_KTS,
55+
GROOVY,
56+
JAVA,
57+
JAVASCRIPT,
58+
JSON,
59+
KOTLIN,
60+
MANIFEST,
61+
PATCH,
62+
PROGUARD,
63+
PROPERTIES,
64+
PROTO,
65+
PYTHON,
66+
REGEX,
67+
RESOURCE,
68+
RUST,
69+
SHELL,
70+
SQL,
71+
SVG,
72+
TEXT,
73+
TOML,
74+
TYPESCRIPT,
75+
UNKNOWN,
76+
VERSION_CATALOG,
77+
XML,
78+
YAML,
79+
)
80+
3781
/**
3882
* Represents the language and dialect of a source snippet, as an RFC 2046 mime type.
3983
*
@@ -56,7 +100,7 @@ import org.jetbrains.jewel.foundation.code.MimeType.Known.YAML
56100
@JvmInline
57101
public value class MimeType(private val mimeType: String) {
58102
public fun displayName(): String =
59-
when (normalizeString()) {
103+
when (getBaseMimeType()) {
60104
KOTLIN.mimeType -> if (isGradle()) "Gradle DSL" else "Kotlin"
61105
JAVA.mimeType -> "Java"
62106
XML.mimeType -> {
@@ -67,12 +111,14 @@ public value class MimeType(private val mimeType: String) {
67111
val folderType = getAttribute(ATTR_FOLDER_TYPE)
68112
folderType?.capitalizeAsciiOnly() ?: "XML"
69113
}
70-
71114
else -> "XML"
72115
}
73116
}
74-
117+
HTML.mimeType -> "HTML"
118+
XHTML.mimeType -> "XHTML"
75119
JSON.mimeType -> "JSON"
120+
JSON5.mimeType -> "JSON5"
121+
JSON_LINES.mimeType -> "JSON Lines"
76122
TEXT.mimeType -> "Text"
77123
REGEX.mimeType -> "Regular Expression"
78124
GROOVY.mimeType -> if (isGradle()) "Gradle" else "Groovy"
@@ -96,92 +142,98 @@ public value class MimeType(private val mimeType: String) {
96142
else -> mimeType
97143
}
98144

99-
private fun normalizeString(): String {
100-
when (this) {
101-
// Built-ins are already normalized, don't do string and sorting work
102-
AGSL,
103-
AIDL,
104-
C,
105-
CPP,
106-
DART,
107-
DIFF,
108-
GO,
109-
GRADLE,
110-
GRADLE_KTS,
111-
GROOVY,
112-
JAVA,
113-
JAVASCRIPT,
114-
JSON,
115-
KOTLIN,
116-
MANIFEST,
117-
PATCH,
118-
PROGUARD,
119-
PROPERTIES,
120-
PROTO,
121-
PYTHON,
122-
REGEX,
123-
RESOURCE,
124-
RUST,
125-
SHELL,
126-
SQL,
127-
SVG,
128-
TEXT,
129-
TOML,
130-
TYPESCRIPT,
131-
UNKNOWN,
132-
VERSION_CATALOG,
133-
XML,
134-
YAML -> return this.mimeType
145+
public fun toFileExtensionIfKnown(): String? =
146+
when (mimeType) {
147+
AGSL.mimeType -> "agsl"
148+
AIDL.mimeType -> "aidl"
149+
C.mimeType -> "c"
150+
CPP.mimeType -> "cpp"
151+
CSS.mimeType -> "css"
152+
DART.mimeType -> "dart"
153+
GO.mimeType -> "go"
154+
GRADLE.mimeType -> "gradle"
155+
GRADLE_KTS.mimeType -> "kts"
156+
GROOVY.mimeType -> "groovy"
157+
JAVA.mimeType -> "java"
158+
JAVASCRIPT.mimeType -> "js"
159+
JSON.mimeType -> "json"
160+
JSON5.mimeType -> "json5"
161+
JSON_LINES.mimeType -> "jsonl"
162+
KOTLIN.mimeType -> "kt"
163+
MANIFEST.mimeType -> "xml" // Manifest files
164+
PROGUARD.mimeType -> "pro"
165+
PROPERTIES.mimeType -> "properties"
166+
PROTO.mimeType -> "proto"
167+
PYTHON.mimeType -> "py"
168+
REGEX.mimeType -> "regex"
169+
RESOURCE.mimeType -> "xml" // Resource files
170+
RUST.mimeType -> "rs"
171+
SHELL.mimeType -> "sh"
172+
SQL.mimeType -> "sql"
173+
SVG.mimeType -> "svg"
174+
TEXT.mimeType -> "txt"
175+
TOML.mimeType -> "toml"
176+
TYPESCRIPT.mimeType -> "ts"
177+
VERSION_CATALOG.mimeType -> "toml"
178+
XML.mimeType -> "xml"
179+
YAML.mimeType -> "yaml"
180+
RUBY.mimeType -> "rb"
181+
OBJECTIVE_C.mimeType -> "m"
182+
"text/x-erlang" -> "erl"
183+
else -> null
135184
}
136185

137-
val baseEnd = mimeType.indexOf(';')
138-
val normalizedBase =
139-
when (val base = if (baseEnd == -1) mimeType else mimeType.substring(0, baseEnd)) {
140-
"text/x-java-source",
141-
"application/x-java",
142-
"text/x-java" -> JAVA.mimeType
143-
144-
"application/kotlin-source",
145-
"text/x-kotlin",
146-
"text/x-kotlin-source" -> KOTLIN.mimeType
147-
148-
"application/xml" -> XML.mimeType
149-
"application/json",
150-
"application/vnd.api+json",
151-
"application/hal+json",
152-
"application/ld+json" -> JSON.mimeType
153-
154-
"image/svg+xml" -> XML.mimeType
155-
"text/x-python",
156-
"application/x-python-script" -> PYTHON.mimeType
157-
158-
"text/dart",
159-
"text/x-dart",
160-
"application/dart",
161-
"application/x-dart" -> DART.mimeType
162-
163-
"application/javascript",
164-
"application/x-javascript",
165-
"text/ecmascript",
166-
"application/ecmascript",
167-
"application/x-ecmascript" -> JAVASCRIPT.mimeType
168-
169-
"application/typescript" + "application/x-typescript" -> TYPESCRIPT.mimeType
170-
"text/x-rust",
171-
"application/x-rust" -> RUST.mimeType
172-
173-
"text/x-sksl" -> AGSL.mimeType
174-
"application/yaml",
175-
"text/x-yaml",
176-
"application/x-yaml" -> YAML.mimeType
177-
"application/x-patch" -> PATCH.mimeType
178-
179-
else -> base
180-
}
181-
182-
if (baseEnd == -1) {
183-
return normalizedBase
186+
private fun getBaseMimeType(): String {
187+
val baseMimeType = base().toString()
188+
// Built-ins are already normalized, don't do string and sorting work
189+
if (this in ALREADY_NORMALIZED_BUILTIN_TYPES) return baseMimeType
190+
191+
return when (baseMimeType) {
192+
"text/x-java-source",
193+
"application/x-java",
194+
"text/x-java" -> JAVA.mimeType
195+
196+
"application/kotlin-source",
197+
"text/x-kotlin",
198+
"text/x-kotlin-source" -> KOTLIN.mimeType
199+
200+
"application/xml" -> XML.mimeType
201+
"application/json",
202+
"application/vnd.api+json",
203+
"application/hal+json",
204+
"application/ld+json" -> JSON.mimeType
205+
206+
"image/svg+xml" -> XML.mimeType
207+
"text/x-python",
208+
"application/x-python-script" -> PYTHON.mimeType
209+
210+
"text/dart",
211+
"text/x-dart",
212+
"application/dart",
213+
"application/x-dart" -> DART.mimeType
214+
215+
"application/javascript",
216+
"application/x-javascript",
217+
"text/ecmascript",
218+
"application/ecmascript",
219+
"application/x-ecmascript" -> JAVASCRIPT.mimeType
220+
221+
"application/typescript" + "application/x-typescript" -> TYPESCRIPT.mimeType
222+
"text/x-rust",
223+
"application/x-rust" -> RUST.mimeType
224+
225+
"text/x-sksl" -> AGSL.mimeType
226+
"application/yaml",
227+
"text/x-yaml",
228+
"application/x-yaml" -> YAML.mimeType
229+
"application/x-patch" -> PATCH.mimeType
230+
231+
else -> baseMimeType
184232
}
233+
}
234+
235+
private fun normalizeString(): String {
236+
val normalizedBase = getBaseMimeType()
185237

186238
val attributes =
187239
mimeType
@@ -297,7 +349,12 @@ public value class MimeType(private val mimeType: String) {
297349
public val XML: MimeType = MimeType("text/xml")
298350
public val PROPERTIES: MimeType = MimeType("text/properties")
299351
public val TOML: MimeType = MimeType("text/toml")
352+
public val HTML: MimeType = MimeType("text/html")
353+
public val XHTML: MimeType = MimeType("application/xhtml+xml")
354+
public val CSS: MimeType = MimeType("text/css")
300355
public val JSON: MimeType = MimeType("text/json")
356+
public val JSON5: MimeType = MimeType("text/json5")
357+
public val JSON_LINES: MimeType = MimeType("application/x-ndjson")
301358
public val REGEX: MimeType = MimeType("text/x-regex-source")
302359
public val GROOVY: MimeType = MimeType("text/groovy")
303360
public val C: MimeType = MimeType("text/c")
@@ -316,6 +373,9 @@ public value class MimeType(private val mimeType: String) {
316373
public val SHELL: MimeType = MimeType("application/x-sh")
317374
public val YAML: MimeType = MimeType("text/yaml")
318375
public val GO: MimeType = MimeType("text/go")
376+
public val RUBY: MimeType = MimeType("text/x-ruby")
377+
public val CLOJURE: MimeType = MimeType("text/x-clojure")
378+
public val OBJECTIVE_C: MimeType = MimeType("text/x-objectivec")
319379

320380
/** Note that most resource files will also have a folder type, so don't use equality on this mime type */
321381
public val RESOURCE: MimeType = MimeType("$XML; $ATTR_ROLE=resource")
@@ -326,21 +386,27 @@ public value class MimeType(private val mimeType: String) {
326386
public val DIFF: MimeType = MimeType("text/x-diff")
327387
public val PATCH: MimeType = MimeType("text/x-patch")
328388

329-
/** Maps from a markdown language [name] back to a mime type. */
389+
/** Maps from a Markdown language [name] back to a mime type. */
330390
public fun fromMarkdownLanguageName(name: String): MimeType? =
331391
when (name) {
332392
"kotlin",
333393
"kt",
334394
"kts" -> KOTLIN
335-
395+
"clj",
396+
"cljs",
397+
"cljr",
398+
"cljc",
399+
"cljd" -> CLOJURE
336400
"java" -> JAVA
337-
"xml" -> XML
338-
"json",
339-
"json5" -> JSON
340-
401+
"html" -> HTML
402+
"xhtml" -> XHTML
403+
"css" -> CSS
404+
"json" -> JSON
405+
"json5" -> JSON5
406+
"json lines",
407+
"jsonl" -> JSON_LINES
341408
"regex",
342409
"regexp" -> REGEX
343-
344410
"groovy" -> GROOVY
345411
"toml" -> TOML
346412
"c" -> C
@@ -354,28 +420,23 @@ public value class MimeType(private val mimeType: String) {
354420
"python3",
355421
"py",
356422
"python" -> PYTHON
357-
358423
"dart" -> DART
359424
"rust" -> RUST
360425
"js",
361426
"javascript" -> JAVASCRIPT
362-
427+
"ts",
363428
"typescript" -> TYPESCRIPT
364429
"sksl" -> AGSL
365430
"sh",
366431
"bash",
367432
"zsh",
368433
"shell" -> SHELL
369-
370434
"yaml",
371435
"yml" -> YAML
372-
373436
"go",
374-
"golang" -> YAML
375-
437+
"golang" -> GO
376438
"diff" -> DIFF
377439
"patch" -> PATCH
378-
379440
else -> null
380441
}
381442
}

platform/jewel/foundation/src/main/kotlin/org/jetbrains/jewel/foundation/code/highlighting/CodeHighlighter.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import androidx.compose.ui.text.AnnotatedString
66
import kotlinx.coroutines.flow.Flow
77
import org.jetbrains.annotations.ApiStatus
88
import org.jetbrains.jewel.foundation.ExperimentalJewelApi
9-
import org.jetbrains.jewel.foundation.code.MimeType
109

1110
@ApiStatus.Experimental
1211
@ExperimentalJewelApi
@@ -26,7 +25,7 @@ public interface CodeHighlighter {
2625
*
2726
* @see [NoOpCodeHighlighter]
2827
*/
29-
public fun highlight(code: String, mimeType: MimeType?): Flow<AnnotatedString>
28+
public fun highlight(code: String, langName: String?): Flow<AnnotatedString>
3029
}
3130

3231
public val LocalCodeHighlighter: ProvidableCompositionLocal<CodeHighlighter> = staticCompositionLocalOf {

0 commit comments

Comments
 (0)