diff --git a/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/CodeLanguage.kt b/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/CodeLanguage.kt index 3f1affe..38ed910 100644 --- a/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/CodeLanguage.kt +++ b/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/CodeLanguage.kt @@ -16,6 +16,7 @@ package io.github.komodgn.codeview.core enum class CodeLanguage { - KOTLIN, JAVA, + KOTLIN, + PYTHON, } diff --git a/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/Token.kt b/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/Token.kt index 0098c4a..a343eb4 100644 --- a/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/Token.kt +++ b/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/Token.kt @@ -15,6 +15,8 @@ */ package io.github.komodgn.codeview.core +import io.github.komodgn.codeview.core.languages.base.LanguageDefinition + data class HighlightToken( val range: IntRange, val type: TokenType, @@ -26,43 +28,31 @@ object SyntaxParser { fun parse(code: String, definition: LanguageDefinition): List { val tokens = mutableListOf() - val multiLineCommentRegex = Regex("""/\*[\s\S]*?\*/""") - val singleLineCommentRegex = Regex("""//.*""") - - multiLineCommentRegex.findAll(code).forEach { - tokens.add(HighlightToken(it.range, TokenType.COMMENT)) - } - - singleLineCommentRegex.findAll(code).forEach { match -> - if (tokens.none { it.range.contains(match.range.first) }) { - tokens.add(HighlightToken(match.range, TokenType.COMMENT)) - } - } - - val stringRegex = Regex(""""([^"\\]|\\.)*"""") - stringRegex.findAll(code).forEach { match -> - if (tokens.none { it.range.contains(match.range.first) }) { - tokens.add(HighlightToken(match.range, TokenType.STRING)) + definition.getCustomRules().forEach { (type, regex) -> + regex.findAll(code).forEach { match -> + if (tokens.none { it.range.overlaps(match.range) }) { + tokens.add(HighlightToken(match.range, type)) + } } } val typeRegex = Regex("""\b[A-Z]\w*\b""") typeRegex.findAll(code).forEach { match -> - if (tokens.none { it.range.contains(match.range.first) }) { + if (tokens.none { it.range.overlaps(match.range) }) { tokens.add(HighlightToken(match.range, TokenType.TYPE)) } } val functionRegex = Regex("""\b\w+(?=\s*\()""") functionRegex.findAll(code).forEach { match -> - if (tokens.none { it.range.contains(match.range.first) }) { + if (tokens.none { it.range.overlaps(match.range) }) { tokens.add(HighlightToken(match.range, TokenType.FUNCTION)) } } val wordRegex = Regex("""\b(\w+)\b""") wordRegex.findAll(code).forEach { match -> - if (tokens.none { it.range.contains(match.range.first) }) { + if (tokens.none { it.range.overlaps(match.range) }) { if (match.value in definition.keywords) { tokens.add(HighlightToken(match.range, TokenType.KEYWORD)) } @@ -71,4 +61,10 @@ object SyntaxParser { return tokens.sortedBy { it.range.first } } + + /** + * Checks if this range overlaps with the [other] range. + * @return true if there is at least one common element between the two ranges. + */ + private fun IntRange.overlaps(other: IntRange): Boolean = this.first <= other.last && other.first <= this.last } diff --git a/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/extension/CodeLanguage.kt b/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/extension/CodeLanguage.kt index c9c6c6e..7f02997 100644 --- a/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/extension/CodeLanguage.kt +++ b/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/extension/CodeLanguage.kt @@ -16,11 +16,13 @@ package io.github.komodgn.codeview.core.extension import io.github.komodgn.codeview.core.CodeLanguage -import io.github.komodgn.codeview.core.JavaDefinition -import io.github.komodgn.codeview.core.KotlinDefinition -import io.github.komodgn.codeview.core.LanguageDefinition +import io.github.komodgn.codeview.core.languages.JavaDefinition +import io.github.komodgn.codeview.core.languages.KotlinDefinition +import io.github.komodgn.codeview.core.languages.PythonDefinition +import io.github.komodgn.codeview.core.languages.base.LanguageDefinition fun CodeLanguage.toDefinition(): LanguageDefinition = when (this) { CodeLanguage.KOTLIN -> KotlinDefinition CodeLanguage.JAVA -> JavaDefinition + CodeLanguage.PYTHON -> PythonDefinition } diff --git a/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/languages/JavaDefinition.kt b/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/languages/JavaDefinition.kt new file mode 100644 index 0000000..98b39a8 --- /dev/null +++ b/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/languages/JavaDefinition.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2026 komodgn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.github.komodgn.codeview.core.languages + +import io.github.komodgn.codeview.core.languages.base.CLikeLanguageDefinition +import kotlin.collections.plus + +object JavaDefinition : CLikeLanguageDefinition() { + override val name = "java" + + override val keywords = commonKeywords + setOf( + "void", "boolean", "char", "byte", "short", "int", "long", "float", "double", + "synchronized", "volatile", "transient", "native", "strictfp", + "enum", "record", "extends", "implements", "throws", "instanceof", + "assert", "yield", "var", "permits", "non-sealed", + ) +} diff --git a/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/languages/KotlinDefinition.kt b/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/languages/KotlinDefinition.kt new file mode 100644 index 0000000..483d2a0 --- /dev/null +++ b/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/languages/KotlinDefinition.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2026 komodgn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.github.komodgn.codeview.core.languages + +import io.github.komodgn.codeview.core.TokenType +import io.github.komodgn.codeview.core.languages.base.CLikeLanguageDefinition + +object KotlinDefinition : CLikeLanguageDefinition() { + override val name = "kotlin" + + override val keywords = commonKeywords + setOf( + "fun", "val", "var", "object", "typealias", "when", "by", + "internal", "override", "open", "data", "inline", "noinline", + "crossinline", "suspend", "tailrec", "operator", "infix", + "expect", "actual", "external", "reified", "companion", + ) + + override fun getCustomRules(): Map { + val rules = super.getCustomRules().toMutableMap() + + rules[TokenType.STRING] = Regex("\"\"\"[\\s\\S]*?\"\"\"|\".*?\"") + return rules + } +} diff --git a/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/languages/PythonDefinition.kt b/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/languages/PythonDefinition.kt new file mode 100644 index 0000000..eefdfbd --- /dev/null +++ b/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/languages/PythonDefinition.kt @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2026 komodgn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.github.komodgn.codeview.core.languages + +import io.github.komodgn.codeview.core.languages.base.ScriptLanguageDefinition + +object PythonDefinition : ScriptLanguageDefinition() { + override val name = "python" + + override val keywords = commonScriptKeywords + setOf( + "def", "class", "elif", "try", "except", "finally", "raise", + "with", "as", "pass", "import", "from", "lambda", "assert", + "is", "not", "and", "or", "global", "nonlocal", "del", + ) +} diff --git a/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/languages/base/CLikeLanguageDefinition.kt b/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/languages/base/CLikeLanguageDefinition.kt new file mode 100644 index 0000000..4f093ff --- /dev/null +++ b/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/languages/base/CLikeLanguageDefinition.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2026 komodgn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.github.komodgn.codeview.core.languages.base + +import io.github.komodgn.codeview.core.TokenType + +abstract class CLikeLanguageDefinition : LanguageDefinition { + protected val commonKeywords = setOf( + "if", "else", "for", "while", "do", "switch", "case", "default", "break", "continue", "return", + "try", "catch", "finally", "throw", + "class", "interface", "package", "import", "public", "private", "protected", "static", "final", "abstract", "sealed", + "this", "super", "true", "false", "null", "new", "instanceof", "is", "as", "in", + ) + + override fun getCustomRules(): Map = mapOf( + TokenType.COMMENT to Regex("//.*|/\\*[\\s\\S]*?\\*/"), + TokenType.STRING to Regex("\".*?\""), + ) +} diff --git a/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/LanguageDefinition.kt b/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/languages/base/LanguageDefinition.kt similarity index 55% rename from codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/LanguageDefinition.kt rename to codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/languages/base/LanguageDefinition.kt index 1a3cf5f..bc4940d 100644 --- a/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/LanguageDefinition.kt +++ b/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/languages/base/LanguageDefinition.kt @@ -13,7 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.github.komodgn.codeview.core +package io.github.komodgn.codeview.core.languages.base + +import io.github.komodgn.codeview.core.TokenType interface LanguageDefinition { val keywords: Set @@ -21,19 +23,3 @@ interface LanguageDefinition { fun getCustomRules(): Map = emptyMap() } - -object KotlinDefinition : LanguageDefinition { - override val name = "kotlin" - override val keywords = setOf( - "package", "import", "class", "object", "fun", "val", "var", - "if", "else", "for", "while", "return", "when", "is", "in", "interface", - ) -} - -object JavaDefinition : LanguageDefinition { - override val name = "java" - override val keywords = setOf( - "public", "private", "protected", "static", "final", "class", "interface", - "if", "else", "for", "while", "return", "try", "catch", "new", - ) -} diff --git a/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/languages/base/ScriptLanguageDefinition.kt b/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/languages/base/ScriptLanguageDefinition.kt new file mode 100644 index 0000000..f1a4d41 --- /dev/null +++ b/codeview/core/src/commonMain/kotlin/io/github/komodgn/codeview/core/languages/base/ScriptLanguageDefinition.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2026 komodgn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.github.komodgn.codeview.core.languages.base + +import io.github.komodgn.codeview.core.TokenType + +abstract class ScriptLanguageDefinition : LanguageDefinition { + protected val commonScriptKeywords = setOf( + "if", "else", "while", "for", "in", "return", "yield", "break", "continue", "true", "false", "None", + ) + + override fun getCustomRules(): Map = mapOf( + TokenType.COMMENT to Regex("#.*"), + TokenType.STRING to Regex("f?\"\"\"[\\s\\S]*?\"\"\"|f?\".*?\"|f?'''.*?'''|f?'.*?'"), + ) +} diff --git a/example/build.gradle.kts b/example/build.gradle.kts index efd5629..7c4bbe2 100644 --- a/example/build.gradle.kts +++ b/example/build.gradle.kts @@ -68,6 +68,7 @@ kotlin { implementation(libs.compose.material3) implementation(libs.compose.ui) implementation(libs.compose.components.resources) + implementation(compose.materialIconsExtended) implementation(project(":codeview:compose")) } diff --git a/example/src/commonMain/kotlin/io/github/komodgn/example/Application.kt b/example/src/commonMain/kotlin/io/github/komodgn/example/Application.kt index 947e195..cc66738 100644 --- a/example/src/commonMain/kotlin/io/github/komodgn/example/Application.kt +++ b/example/src/commonMain/kotlin/io/github/komodgn/example/Application.kt @@ -40,13 +40,16 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import io.github.komodgn.AppConfig -import io.github.komodgn.example.component.CodeViewSection -import io.github.komodgn.example.component.EditorSection +import io.github.komodgn.codeview.core.CodeLanguage +import io.github.komodgn.example.section.CodeViewSection +import io.github.komodgn.example.section.EditorSection import io.github.komodgn.example.theme.CodeViewTheme +import io.github.komodgn.example.util.getInitialCode @Composable fun App() { - var userInput by remember { mutableStateOf(getInitialCode(AppConfig.LIBRARY_VERSION)) } + var currentLang by remember { mutableStateOf(CodeLanguage.KOTLIN) } + var userInput by remember { mutableStateOf(getInitialCode(currentLang, AppConfig.LIBRARY_VERSION)) } val scrollState = rememberScrollState() CodeViewTheme { @@ -75,12 +78,38 @@ fun App() { verticalArrangement = Arrangement.Center, ) { if (isCompact) { - CodeViewSection(userInput, modifier = Modifier.fillMaxWidth()) - EditorSection(userInput, onValueChange = { userInput = it }, modifier = Modifier.fillMaxWidth()) + CodeViewSection( + code = userInput, + language = currentLang, + modifier = Modifier.fillMaxWidth(), + ) + EditorSection( + code = userInput, + selectedLanguage = currentLang, + onLanguageChange = { newLang -> + currentLang = newLang + userInput = getInitialCode(currentLang, AppConfig.LIBRARY_VERSION) + }, + onValueChange = { userInput = it }, + modifier = Modifier.fillMaxWidth(), + ) } else { Row(modifier = Modifier.fillMaxWidth().padding(16.dp, 0.dp, 16.dp, 0.dp)) { - EditorSection(userInput, onValueChange = { userInput = it }, modifier = Modifier.weight(1f)) - CodeViewSection(userInput, modifier = Modifier.weight(1f)) + EditorSection( + code = userInput, + selectedLanguage = currentLang, + onLanguageChange = { newLang -> + currentLang = newLang + userInput = getInitialCode(currentLang, AppConfig.LIBRARY_VERSION) + }, + onValueChange = { userInput = it }, + modifier = Modifier.weight(1f), + ) + CodeViewSection( + code = userInput, + language = currentLang, + modifier = Modifier.weight(1f), + ) } } } @@ -88,23 +117,3 @@ fun App() { } } } - -private fun getInitialCode(version: String) = """ -package io.github.komodgn.example - -/** - * Welcome to Compose CodeView v$version Demo! - * - * This library provides syntax highlighting for Compose Multiplatform. - * Feel free to edit the code on the left to see real-time updates. - */ -@Composable -fun CodeDisplay() { - val greeting = println("Hello, CodeView!") - - CodeView( - code = greeting, - language = CodeLanguage.KOTLIN, - ) -} -""".trimIndent() diff --git a/example/src/commonMain/kotlin/io/github/komodgn/example/component/LanguageDropDown.kt b/example/src/commonMain/kotlin/io/github/komodgn/example/component/LanguageDropDown.kt new file mode 100644 index 0000000..6fa5526 --- /dev/null +++ b/example/src/commonMain/kotlin/io/github/komodgn/example/component/LanguageDropDown.kt @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2026 komodgn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.github.komodgn.example.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import io.github.komodgn.codeview.core.CodeLanguage + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun LanguageDropDown( + selectedLanguage: CodeLanguage, + onLanguageChange: (CodeLanguage) -> Unit, +) { + var expanded by remember { mutableStateOf(false) } + + Box(modifier = Modifier.wrapContentSize(Alignment.TopEnd)) { + Row( + modifier = Modifier + .clip(RoundedCornerShape(8.dp)) + .clickable { expanded = true } + .padding(horizontal = 12.dp, vertical = 4.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = selectedLanguage.name, + style = MaterialTheme.typography.labelLarge, + color = MaterialTheme.colorScheme.onSurface, + ) + Icon( + imageVector = Icons.Default.ArrowDropDown, + contentDescription = "ArrowDropDown Icon", + tint = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.size(20.dp), + ) + } + + DropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false }, + modifier = Modifier.background(MaterialTheme.colorScheme.surface), + ) { + CodeLanguage.entries.forEach { language -> + DropdownMenuItem( + text = { + Text( + text = language.name, + style = MaterialTheme.typography.bodyMedium, + ) + }, + onClick = { + onLanguageChange(language) + expanded = false + }, + ) + } + } + } +} diff --git a/example/src/commonMain/kotlin/io/github/komodgn/example/component/CodeViewSection.kt b/example/src/commonMain/kotlin/io/github/komodgn/example/section/CodeViewSection.kt similarity index 88% rename from example/src/commonMain/kotlin/io/github/komodgn/example/component/CodeViewSection.kt rename to example/src/commonMain/kotlin/io/github/komodgn/example/section/CodeViewSection.kt index 8f64462..d418cff 100644 --- a/example/src/commonMain/kotlin/io/github/komodgn/example/component/CodeViewSection.kt +++ b/example/src/commonMain/kotlin/io/github/komodgn/example/section/CodeViewSection.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.github.komodgn.example.component +package io.github.komodgn.example.section import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth @@ -27,12 +27,16 @@ import io.github.komodgn.codeview.core.CodeLanguage import io.github.komodgn.example.theme.LocalAppFontFamily @Composable -fun CodeViewSection(code: String, modifier: Modifier) { +fun CodeViewSection( + code: String, + language: CodeLanguage, + modifier: Modifier, +) { Column(modifier = modifier.padding(8.dp)) { Text("Preview", modifier = Modifier.padding(4.dp)) CodeView( code = code, - language = CodeLanguage.KOTLIN, + language = language, modifier = Modifier.fillMaxWidth(), fontFamily = LocalAppFontFamily.current, ) diff --git a/example/src/commonMain/kotlin/io/github/komodgn/example/component/EditorSection.kt b/example/src/commonMain/kotlin/io/github/komodgn/example/section/EditorSection.kt similarity index 55% rename from example/src/commonMain/kotlin/io/github/komodgn/example/component/EditorSection.kt rename to example/src/commonMain/kotlin/io/github/komodgn/example/section/EditorSection.kt index e8448ce..aab4e2a 100644 --- a/example/src/commonMain/kotlin/io/github/komodgn/example/component/EditorSection.kt +++ b/example/src/commonMain/kotlin/io/github/komodgn/example/section/EditorSection.kt @@ -13,9 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.github.komodgn.example.component +package io.github.komodgn.example.section +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material3.MaterialTheme @@ -23,15 +25,40 @@ import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.material3.TextFieldDefaults import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp +import io.github.komodgn.codeview.core.CodeLanguage +import io.github.komodgn.example.component.LanguageDropDown import io.github.komodgn.example.theme.LocalAppFontFamily @Composable -fun EditorSection(code: String, onValueChange: (String) -> Unit, modifier: Modifier) { +fun EditorSection( + code: String, + selectedLanguage: CodeLanguage, + onLanguageChange: (CodeLanguage) -> Unit, + onValueChange: (String) -> Unit, + modifier: Modifier, +) { Column(modifier = modifier.padding(8.dp)) { - Text("Edit Code", modifier = Modifier.padding(4.dp)) + Row( + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 8.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Text( + text = "Edit Code", + style = MaterialTheme.typography.titleMedium, + ) + + LanguageDropDown( + selectedLanguage = selectedLanguage, + onLanguageChange = onLanguageChange, + ) + } TextField( value = code, onValueChange = onValueChange, @@ -40,7 +67,12 @@ fun EditorSection(code: String, onValueChange: (String) -> Unit, modifier: Modif fontFamily = LocalAppFontFamily.current, ), colors = TextFieldDefaults.colors( + unfocusedContainerColor = Color.Blue.copy(0.3f), focusedContainerColor = Color.Blue.copy(0.3f), + focusedIndicatorColor = Color.Transparent, + unfocusedIndicatorColor = Color.Transparent, + disabledIndicatorColor = Color.Transparent, + errorIndicatorColor = Color.Transparent, ), ) } diff --git a/example/src/commonMain/kotlin/io/github/komodgn/example/theme/CodeViewTheme.kt b/example/src/commonMain/kotlin/io/github/komodgn/example/theme/CodeViewTheme.kt index bb9ad24..5dd7f30 100644 --- a/example/src/commonMain/kotlin/io/github/komodgn/example/theme/CodeViewTheme.kt +++ b/example/src/commonMain/kotlin/io/github/komodgn/example/theme/CodeViewTheme.kt @@ -21,8 +21,9 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily +import compose_codeview.example.generated.resources.NotoColorEmoji +import compose_codeview.example.generated.resources.NotoSansKR_Regular import compose_codeview.example.generated.resources.Res -import compose_codeview.example.generated.resources.* import org.jetbrains.compose.resources.Font @Composable diff --git a/example/src/commonMain/kotlin/io/github/komodgn/example/util/SampleCode.kt b/example/src/commonMain/kotlin/io/github/komodgn/example/util/SampleCode.kt new file mode 100644 index 0000000..643215e --- /dev/null +++ b/example/src/commonMain/kotlin/io/github/komodgn/example/util/SampleCode.kt @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2026 komodgn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.github.komodgn.example.util + +import io.github.komodgn.codeview.core.CodeLanguage + +/** + * Provides the initial code snippet for the demo application. + */ +fun getInitialCode(language: CodeLanguage, version: String): String { + return when (language) { + CodeLanguage.KOTLIN -> """ + package io.github.komodgn.example + + /** + * Welcome to Compose CodeView v$version Demo! + * + * This library provides syntax highlighting for Compose Multiplatform. + * Feel free to edit the code on the left to see real-time updates. + */ + @Composable + fun CodeDisplay() { + val greeting = getWelcomeMessage() + + // You can apply custom fonts via the 'fontFamily' parameter. + CodeView( + code = greeting, + language = CodeLanguage.KOTLIN, + ) + } + + private fun getWelcomeMessage() = "Hello, CodeView!" + """.trimIndent() + + CodeLanguage.JAVA -> """ + package io.github.komodgn.example; + + /** + * Welcome to Compose CodeView v$version! + */ + public class Main { + public static void main(String[] args) { + String message = "Hello, Java!"; + System.out.println(message); + } + } + """.trimIndent() + + CodeLanguage.PYTHON -> """ + # Welcome to Compose CodeView v$version! + + def welcome_codeview(): + message = "Hello, Python!" + print(message) + + if __name__ == "__main__": + welcome_codeview() + """.trimIndent() + } +} \ No newline at end of file