From b8428c6c40a290efdf2536972f69981ff053dc59 Mon Sep 17 00:00:00 2001 From: tkadziolka Date: Sat, 2 Nov 2024 17:04:58 +0100 Subject: [PATCH 1/8] Updated highlights dependency to 1.0.0 --- .gitignore | 1 + androidExample/build.gradle.kts | 2 +- desktopExample/build.gradle.kts | 4 ++-- gradle/libs.versions.toml | 2 +- webExample/build.gradle.kts | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 17a4290..9edf612 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ .externalNativeBuild .cxx local.properties +/.kotlin/ diff --git a/androidExample/build.gradle.kts b/androidExample/build.gradle.kts index ca013c2..06405c8 100644 --- a/androidExample/build.gradle.kts +++ b/androidExample/build.gradle.kts @@ -59,5 +59,5 @@ dependencies { implementation(compose.material3) implementation(compose.ui) implementation(compose.materialIconsExtended) - implementation(libs.kodeview) + implementation(project(":kodeview")) } \ No newline at end of file diff --git a/desktopExample/build.gradle.kts b/desktopExample/build.gradle.kts index 511e5c5..3b39176 100644 --- a/desktopExample/build.gradle.kts +++ b/desktopExample/build.gradle.kts @@ -2,6 +2,7 @@ plugins { alias(libs.plugins.jvm) alias(libs.plugins.compose) + alias(libs.plugins.compose.compiler) } dependencies { @@ -14,8 +15,7 @@ dependencies { @OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class) implementation(compose.components.resources) implementation(compose.desktop.currentOs) - implementation(libs.kodeview) - alias(libs.plugins.compose.compiler) + implementation(project(":kodeview")) } compose.desktop { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e82fd9a..78767f8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ kotlinMultiplatform = "2.0.20" compose = "1.6.11" androidLibrary = "8.6.1" kodeview = "0.8.0" -highlights = "0.7.1" +highlights = "1.0.0" composeMaterial = "1.4.0" [libraries] diff --git a/webExample/build.gradle.kts b/webExample/build.gradle.kts index 8b62e53..7606433 100644 --- a/webExample/build.gradle.kts +++ b/webExample/build.gradle.kts @@ -19,7 +19,7 @@ kotlin { implementation(compose.material) implementation(compose.material3) implementation(compose.materialIconsExtended) - implementation(libs.kodeview) + implementation(project(":kodeview")) } } } From 5da558bb8eb9444d54be7958cbd6aaad8c154cca Mon Sep 17 00:00:00 2001 From: tkadziolka Date: Sun, 3 Nov 2024 11:16:44 +0100 Subject: [PATCH 2/8] Added new API for desktop example --- .run/iosExample.run.xml | 2 +- desktopExample/src/main/kotlin/Main.kt | 117 ++++++++++-------- .../dev/snipme/kodeview/view/CodeEditText.kt | 26 ++-- .../kodeview/view/CodeEditTextExtensions.kt | 44 ------- .../dev/snipme/kodeview/view/CodeTextView.kt | 50 ++++---- .../dev/snipme/kodeview/view/Extensions.kt | 42 +++++++ .../kodeview/view/material3/CodeEditText.kt | 42 ++++--- 7 files changed, 172 insertions(+), 151 deletions(-) delete mode 100644 kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeEditTextExtensions.kt create mode 100644 kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/Extensions.kt diff --git a/.run/iosExample.run.xml b/.run/iosExample.run.xml index 4419f81..f91f1c3 100644 --- a/.run/iosExample.run.xml +++ b/.run/iosExample.run.xml @@ -1,5 +1,5 @@ - + diff --git a/desktopExample/src/main/kotlin/Main.kt b/desktopExample/src/main/kotlin/Main.kt index 69f2bec..86eea8c 100644 --- a/desktopExample/src/main/kotlin/Main.kt +++ b/desktopExample/src/main/kotlin/Main.kt @@ -1,13 +1,17 @@ package dev.snipme.desktopexample +import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Divider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface @@ -78,44 +82,49 @@ fun main() = application { ) ) { Surface { - Column( + Row( modifier = Modifier .fillMaxSize() .padding(16.dp), - horizontalAlignment = Alignment.Start, - verticalArrangement = Arrangement.SpaceBetween + horizontalArrangement = Arrangement.Center, ) { - Spacer(Modifier.height(8.dp)) - - ThemeSwitcher( - isDarkMode, - modifier = Modifier.fillMaxWidth(), - ) { setToDarkMode -> - isDarkModeState.value = setToDarkMode - updateSyntaxTheme(highlights.getTheme().useDark(setToDarkMode)!!) - } - - Spacer(Modifier.height(16.dp)) - - Text( - modifier = Modifier.fillMaxWidth(), - text = "KodeView", - fontSize = 18.sp, - textAlign = TextAlign.Center, +// Spacer(Modifier.height(8.dp)) +// +// ThemeSwitcher( +// isDarkMode, +// modifier = Modifier.fillMaxWidth().weight(1f), +// ) { setToDarkMode -> +// isDarkModeState.value = setToDarkMode +// updateSyntaxTheme(highlights.getTheme().useDark(setToDarkMode)!!) +// } +// +// Spacer(Modifier.height(16.dp)) + +// Text( +// modifier = Modifier.fillMaxWidth(), +// text = "KodeView", +// fontSize = 18.sp, +// textAlign = TextAlign.Center, +// ) +// +// Spacer(modifier = Modifier.size(16.dp)) + + CodeTextView( + highlights = highlights, + modifier = Modifier.weight(1f) + .verticalScroll(rememberScrollState()) + .horizontalScroll(rememberScrollState()), ) - - Spacer(modifier = Modifier.size(16.dp)) - - CodeTextView(highlights = highlights) - - Spacer(modifier = Modifier.size(16.dp)) - - Divider() - - Spacer(modifier = Modifier.size(16.dp)) - - Text("Edit this...") +// +// Spacer(modifier = Modifier.size(16.dp)) +// +// Divider() +// +// Spacer(modifier = Modifier.size(16.dp)) +// +// Text("Edit this...") CodeEditText( + modifier = Modifier.fillMaxWidth().weight(1f), highlights = highlights, onValueChange = { textValue -> highlightsState.value = highlights.getBuilder() @@ -132,28 +141,28 @@ fun main() = application { ), ) - Spacer(modifier = Modifier.size(16.dp)) - - Spacer(modifier = Modifier.weight(1f)) - - Dropdown( - options = SyntaxThemes.getNames(), - selected = SyntaxThemes.themes().keys.indexOf(highlights.getTheme().key), - ) { selectedThemeName -> - updateSyntaxTheme( - SyntaxThemes.themes(isDarkMode)[selectedThemeName.lowercase()]!! - ) - } - - Spacer(modifier = Modifier.size(16.dp)) - - Dropdown( - options = SyntaxLanguage.getNames(), - selected = SyntaxLanguage.getNames().indexOfFirst { - it.equals(highlights.getLanguage().name, ignoreCase = true) - }) { selectedLanguage -> - updateSyntaxLanguage(SyntaxLanguage.getByName(selectedLanguage)!!) - } +// Spacer(modifier = Modifier.size(16.dp)) +// +// Spacer(modifier = Modifier.weight(1f)) +// +// Dropdown( +// options = SyntaxThemes.getNames(), +// selected = SyntaxThemes.themes().keys.indexOf(highlights.getTheme().key), +// ) { selectedThemeName -> +// updateSyntaxTheme( +// SyntaxThemes.themes(isDarkMode)[selectedThemeName.lowercase()]!! +// ) +// } +// +// Spacer(modifier = Modifier.size(16.dp)) +// +// Dropdown( +// options = SyntaxLanguage.getNames(), +// selected = SyntaxLanguage.getNames().indexOfFirst { +// it.equals(highlights.getLanguage().name, ignoreCase = true) +// }) { selectedLanguage -> +// updateSyntaxLanguage(SyntaxLanguage.getByName(selectedLanguage)!!) +// } } } } diff --git a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeEditText.kt b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeEditText.kt index 6d43a6c..01c9077 100644 --- a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeEditText.kt +++ b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeEditText.kt @@ -9,17 +9,17 @@ import androidx.compose.material.TextField import androidx.compose.material.TextFieldColors import androidx.compose.material.TextFieldDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.VisualTransformation import calculateFieldPhraseUpdate import dev.snipme.highlights.Highlights -import generateAnnotatedString @Composable fun CodeEditText( @@ -47,10 +47,22 @@ fun CodeEditText( ) { val currentText = remember { mutableStateOf( - TextFieldValue() + TextFieldValue( + annotatedString = AnnotatedString(highlights.getCode()) + ) ) } + LaunchedEffect(highlights) { +// highlights.getHighlightsAsync(object : DefaultHighlightsResultListener() { +// override fun onSuccess(result: List) { +// currentText.value = currentText.value.copy( +// annotatedString = result.generateAnnotatedString(currentText.value.text), +// ) +// } +// }) + } + TextField( modifier = modifier.fillMaxWidth(), onValueChange = { @@ -58,13 +70,7 @@ fun CodeEditText( currentText.value = fieldUpdate onValueChange(fieldUpdate.text) }, - value = TextFieldValue( - selection = currentText.value.selection, - composition = currentText.value.composition, - annotatedString = buildAnnotatedString { - generateAnnotatedString(highlights) - }, - ), + value = currentText.value, enabled = enabled, readOnly = readOnly, textStyle = textStyle, diff --git a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeEditTextExtensions.kt b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeEditTextExtensions.kt deleted file mode 100644 index 2365479..0000000 --- a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeEditTextExtensions.kt +++ /dev/null @@ -1,44 +0,0 @@ -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.text.SpanStyle -import androidx.compose.ui.text.TextRange -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.input.TextFieldValue -import dev.snipme.highlights.Highlights -import dev.snipme.highlights.model.BoldHighlight -import dev.snipme.highlights.model.ColorHighlight - -internal const val TAB_LENGTH = 4 -internal const val TAB_CHAR = "\t" - -internal fun TextFieldValue.calculateFieldPhraseUpdate(translateTabToSpaces: Boolean) = - if (translateTabToSpaces && text.contains(TAB_CHAR)) { - val result = text.replace(TAB_CHAR, " ".repeat(TAB_LENGTH)) - this.copy(text = result, TextRange(selection.start + TAB_LENGTH - 1)) - } else { - this - } - -internal fun AnnotatedString.Builder.generateAnnotatedString(highlights: Highlights) { - append(highlights.getCode()) - - highlights.getHighlights() - .filterIsInstance() - .forEach { - addStyle( - SpanStyle(color = Color(it.rgb).copy(alpha = 1f)), - start = it.location.start, - end = it.location.end, - ) - } - - highlights.getHighlights() - .filterIsInstance() - .forEach { - addStyle( - SpanStyle(fontWeight = FontWeight.Bold), - start = it.location.start, - end = it.location.end, - ) - } -} \ No newline at end of file diff --git a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeTextView.kt b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeTextView.kt index 7b7dd68..433478a 100644 --- a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeTextView.kt +++ b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeTextView.kt @@ -1,48 +1,42 @@ package dev.snipme.kodeview.view import androidx.compose.foundation.background +import androidx.compose.foundation.horizontalScroll +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.SpanStyle -import androidx.compose.ui.text.buildAnnotatedString -import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.AnnotatedString import dev.snipme.highlights.Highlights -import dev.snipme.highlights.model.BoldHighlight -import dev.snipme.highlights.model.ColorHighlight +import generateAnnotatedString @Composable fun CodeTextView( modifier: Modifier = Modifier.background(Color.Transparent), highlights: Highlights ) { + var textState by remember { + mutableStateOf(AnnotatedString(highlights.getCode())) + } + + LaunchedEffect(highlights) { + textState = highlights + .getHighlights() + .generateAnnotatedString(highlights.getCode()) + } + Surface { Text( modifier = modifier, - text = buildAnnotatedString { - append(highlights.getCode()) - - highlights.getHighlights() - .filterIsInstance() - .forEach { - addStyle( - SpanStyle(color = Color(it.rgb).copy(alpha = 1f)), - start = it.location.start, - end = it.location.end, - ) - } - - highlights.getHighlights() - .filterIsInstance() - .forEach { - addStyle( - SpanStyle(fontWeight = FontWeight.Bold), - start = it.location.start, - end = it.location.end, - ) - } - }) + text = textState + ) } } \ No newline at end of file diff --git a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/Extensions.kt b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/Extensions.kt new file mode 100644 index 0000000..df7d19f --- /dev/null +++ b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/Extensions.kt @@ -0,0 +1,42 @@ +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.TextRange +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.TextFieldValue +import dev.snipme.highlights.model.BoldHighlight +import dev.snipme.highlights.model.CodeHighlight +import dev.snipme.highlights.model.ColorHighlight + +internal const val TAB_LENGTH = 4 +internal const val TAB_CHAR = "\t" + +fun List.generateAnnotatedString(code: String) = + buildAnnotatedString { + append(code) + + forEach { + when (it) { + is BoldHighlight -> addStyle( + SpanStyle(fontWeight = FontWeight.Bold), + start = it.location.start, + end = it.location.end, + ) + + is ColorHighlight -> addStyle( + SpanStyle(color = Color(it.rgb).copy(alpha = 1f)), + start = it.location.start, + end = it.location.end, + ) + } + } + } + + +internal fun TextFieldValue.calculateFieldPhraseUpdate(translateTabToSpaces: Boolean) = + if (translateTabToSpaces && text.contains(TAB_CHAR)) { + val result = text.replace(TAB_CHAR, " ".repeat(TAB_LENGTH)) + this.copy(text = result, TextRange(selection.start + TAB_LENGTH - 1)) + } else { + this + } \ No newline at end of file diff --git a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/material3/CodeEditText.kt b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/material3/CodeEditText.kt index 45c5f41..a6a359b 100644 --- a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/material3/CodeEditText.kt +++ b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/material3/CodeEditText.kt @@ -5,16 +5,22 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.TextUnitType import calculateFieldPhraseUpdate +import dev.snipme.highlights.DefaultHighlightsResultListener import dev.snipme.highlights.Highlights +import dev.snipme.highlights.model.CodeHighlight import generateAnnotatedString import androidx.compose.material3.LocalTextStyle as LocalTextStyle3 import androidx.compose.material3.TextField as TextField3 @@ -47,10 +53,22 @@ fun CodeEditText( ) { val currentText = remember { mutableStateOf( - TextFieldValue() + TextFieldValue( + AnnotatedString(highlights.getCode()) + ) ) } + LaunchedEffect(highlights) { + highlights.getHighlightsAsync(object : DefaultHighlightsResultListener() { + override fun onSuccess(result: List) { + currentText.value = currentText.value.copy( + annotatedString = result.generateAnnotatedString(currentText.value.text), + ) + } + }) + } + TextField3( modifier = modifier.fillMaxWidth(), onValueChange = { @@ -58,13 +76,7 @@ fun CodeEditText( currentText.value = fieldUpdate onValueChange(fieldUpdate.text) }, - value = TextFieldValue( - selection = currentText.value.selection, - composition = currentText.value.composition, - annotatedString = buildAnnotatedString { - generateAnnotatedString(highlights) - }, - ), + value = currentText.value, enabled = enabled, readOnly = readOnly, textStyle = textStyle, @@ -116,13 +128,15 @@ fun CodeEditTextSwiftUi( val currentText = remember { mutableStateOf( TextFieldValue().copy( - annotatedString = buildAnnotatedString { - generateAnnotatedString(highlightsState.value) - } +// annotatedString = buildAnnotatedString { +// generateAnnotatedString(highlightsState.value) +// } ) ) } + + TextField3( modifier = modifier.fillMaxWidth(), value = currentText.value, @@ -133,9 +147,9 @@ fun CodeEditTextSwiftUi( onValueChange(fieldUpdate) currentText.value = fieldUpdate.copy( - annotatedString = buildAnnotatedString { - generateAnnotatedString(highlightsState.value) - } +// annotatedString = buildAnnotatedString { +// generateAnnotatedString(highlightsState.value) +// } ) }, enabled = enabled, From a5c5caf57db8b048fd93046943d1153856ed52eb Mon Sep 17 00:00:00 2001 From: tkadziolka Date: Sun, 3 Nov 2024 13:58:10 +0100 Subject: [PATCH 3/8] Corrected split desktop view --- desktopExample/src/main/kotlin/Main.kt | 158 +++++++++--------- .../dev/snipme/kodeview/view/CodeTextView.kt | 9 +- 2 files changed, 84 insertions(+), 83 deletions(-) diff --git a/desktopExample/src/main/kotlin/Main.kt b/desktopExample/src/main/kotlin/Main.kt index 86eea8c..a24afb1 100644 --- a/desktopExample/src/main/kotlin/Main.kt +++ b/desktopExample/src/main/kotlin/Main.kt @@ -1,5 +1,7 @@ package dev.snipme.desktopexample +import androidx.compose.foundation.background +import androidx.compose.foundation.gestures.scrollable import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -12,11 +14,14 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material.Colors import androidx.compose.material3.Divider +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextFieldDefaults +import androidx.compose.material3.VerticalDivider import androidx.compose.material3.darkColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.mutableStateOf @@ -38,8 +43,6 @@ import dev.snipme.highlights.model.SyntaxThemes.useDark import dev.snipme.kodeview.view.material3.CodeEditText import dev.snipme.kodeview.view.CodeTextView -private val windowSize = 600.dp - private val sampleCode = """ class Main { @@ -76,93 +79,86 @@ fun main() = application { Window( onCloseRequest = ::exitApplication, title = "KodeView example", - state = rememberWindowState( - width = windowSize, - height = windowSize, - ) + state = rememberWindowState() ) { Surface { - Row( + Column( modifier = Modifier .fillMaxSize() .padding(16.dp), - horizontalArrangement = Arrangement.Center, + verticalArrangement = Arrangement.Center, ) { -// Spacer(Modifier.height(8.dp)) -// -// ThemeSwitcher( -// isDarkMode, -// modifier = Modifier.fillMaxWidth().weight(1f), -// ) { setToDarkMode -> -// isDarkModeState.value = setToDarkMode -// updateSyntaxTheme(highlights.getTheme().useDark(setToDarkMode)!!) -// } -// -// Spacer(Modifier.height(16.dp)) - -// Text( -// modifier = Modifier.fillMaxWidth(), -// text = "KodeView", -// fontSize = 18.sp, -// textAlign = TextAlign.Center, -// ) -// -// Spacer(modifier = Modifier.size(16.dp)) - - CodeTextView( - highlights = highlights, - modifier = Modifier.weight(1f) - .verticalScroll(rememberScrollState()) - .horizontalScroll(rememberScrollState()), - ) -// -// Spacer(modifier = Modifier.size(16.dp)) -// -// Divider() -// -// Spacer(modifier = Modifier.size(16.dp)) -// -// Text("Edit this...") - CodeEditText( - modifier = Modifier.fillMaxWidth().weight(1f), - highlights = highlights, - onValueChange = { textValue -> - highlightsState.value = highlights.getBuilder() - .code(textValue) - .build() - }, - colors = TextFieldDefaults.colors( - unfocusedContainerColor = Color.Transparent, - focusedContainerColor = Color.Transparent, - focusedIndicatorColor = Color.Transparent, - unfocusedIndicatorColor = Color.Transparent, - disabledIndicatorColor = Color.Transparent, - errorIndicatorColor = Color.Transparent, - ), + Spacer(Modifier.height(8.dp)) + + ThemeSwitcher( + isDarkMode, + modifier = Modifier.fillMaxWidth(), + ) { setToDarkMode -> + isDarkModeState.value = setToDarkMode + updateSyntaxTheme(highlights.getTheme().useDark(setToDarkMode)!!) + } + + Spacer(Modifier.height(16.dp)) + + Text( + modifier = Modifier.fillMaxWidth(), + text = "KodeView", + fontSize = 18.sp, + textAlign = TextAlign.Center, ) -// Spacer(modifier = Modifier.size(16.dp)) -// -// Spacer(modifier = Modifier.weight(1f)) -// -// Dropdown( -// options = SyntaxThemes.getNames(), -// selected = SyntaxThemes.themes().keys.indexOf(highlights.getTheme().key), -// ) { selectedThemeName -> -// updateSyntaxTheme( -// SyntaxThemes.themes(isDarkMode)[selectedThemeName.lowercase()]!! -// ) -// } -// -// Spacer(modifier = Modifier.size(16.dp)) -// -// Dropdown( -// options = SyntaxLanguage.getNames(), -// selected = SyntaxLanguage.getNames().indexOfFirst { -// it.equals(highlights.getLanguage().name, ignoreCase = true) -// }) { selectedLanguage -> -// updateSyntaxLanguage(SyntaxLanguage.getByName(selectedLanguage)!!) -// } + Spacer(modifier = Modifier.size(16.dp)) + + Row( + modifier = Modifier + .weight(1f) + .fillMaxWidth(), + ) { + CodeTextView( + modifier = Modifier.weight(1f), + highlights = highlights, + ) + VerticalDivider(Modifier.padding(8.dp)) + CodeEditText( + modifier = Modifier.weight(1f), + label = { Text("Edit code") }, + highlights = highlights, + onValueChange = { textValue -> + highlightsState.value = highlights.getBuilder() + .code(textValue) + .build() + }, + colors = TextFieldDefaults.colors( + unfocusedContainerColor = Color.Transparent, + focusedContainerColor = Color.Transparent, + focusedIndicatorColor = Color.Transparent, + unfocusedIndicatorColor = Color.Transparent, + disabledIndicatorColor = Color.Transparent, + errorIndicatorColor = Color.Transparent, + ), + ) + } + + Spacer(modifier = Modifier.size(16.dp)) + + Dropdown( + options = SyntaxThemes.getNames(), + selected = SyntaxThemes.themes().keys.indexOf(highlights.getTheme().key), + ) { selectedThemeName -> + updateSyntaxTheme( + SyntaxThemes.themes(isDarkMode)[selectedThemeName.lowercase()]!! + ) + } + + Spacer(modifier = Modifier.size(16.dp)) + + Dropdown( + options = SyntaxLanguage.getNames(), + selected = SyntaxLanguage.getNames().indexOfFirst { + it.equals(highlights.getLanguage().name, ignoreCase = true) + }) { selectedLanguage -> + updateSyntaxLanguage(SyntaxLanguage.getByName(selectedLanguage)!!) + } } } } diff --git a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeTextView.kt b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeTextView.kt index 433478a..0035379 100644 --- a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeTextView.kt +++ b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeTextView.kt @@ -33,9 +33,14 @@ fun CodeTextView( .generateAnnotatedString(highlights.getCode()) } - Surface { + Surface( + modifier = modifier, + color = Color.Transparent + ) { Text( - modifier = modifier, + modifier = modifier + .verticalScroll(rememberScrollState()) + .horizontalScroll(rememberScrollState()), text = textState ) } From 56910fd62aeb9804d62761f37dc84fa3df9ded43 Mon Sep 17 00:00:00 2001 From: tkadziolka Date: Sun, 3 Nov 2024 14:39:40 +0100 Subject: [PATCH 4/8] Cleaned desktop example --- desktopExample/src/main/kotlin/Main.kt | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/desktopExample/src/main/kotlin/Main.kt b/desktopExample/src/main/kotlin/Main.kt index a24afb1..1b04ab1 100644 --- a/desktopExample/src/main/kotlin/Main.kt +++ b/desktopExample/src/main/kotlin/Main.kt @@ -1,8 +1,5 @@ package dev.snipme.desktopexample -import androidx.compose.foundation.background -import androidx.compose.foundation.gestures.scrollable -import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -12,11 +9,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material.Colors -import androidx.compose.material3.Divider -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -26,7 +18,6 @@ import androidx.compose.material3.darkColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextAlign @@ -40,8 +31,8 @@ import dev.snipme.highlights.model.SyntaxLanguage import dev.snipme.highlights.model.SyntaxTheme import dev.snipme.highlights.model.SyntaxThemes import dev.snipme.highlights.model.SyntaxThemes.useDark -import dev.snipme.kodeview.view.material3.CodeEditText import dev.snipme.kodeview.view.CodeTextView +import dev.snipme.kodeview.view.material3.CodeEditText private val sampleCode = """ From 32a5bf48072aa97fa52d215ca6962e0bc09b9007 Mon Sep 17 00:00:00 2001 From: tkadziolka Date: Sun, 3 Nov 2024 16:33:33 +0100 Subject: [PATCH 5/8] Designed annotated string persistence --- .../kodeview/view/material3/CodeEditText.kt | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/material3/CodeEditText.kt b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/material3/CodeEditText.kt index a6a359b..ed6cab2 100644 --- a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/material3/CodeEditText.kt +++ b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/material3/CodeEditText.kt @@ -15,8 +15,6 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.VisualTransformation -import androidx.compose.ui.unit.TextUnit -import androidx.compose.ui.unit.TextUnitType import calculateFieldPhraseUpdate import dev.snipme.highlights.DefaultHighlightsResultListener import dev.snipme.highlights.Highlights @@ -71,10 +69,29 @@ fun CodeEditText( TextField3( modifier = modifier.fillMaxWidth(), - onValueChange = { - val fieldUpdate = it.calculateFieldPhraseUpdate(translateTabToSpaces) - currentText.value = fieldUpdate - onValueChange(fieldUpdate.text) + onValueChange = { change -> +// val fieldUpdate = it.calculateFieldPhraseUpdate(translateTabToSpaces) + if (change.text != currentText.value.text) + onValueChange(change.text) + currentText.value = change.copy( + annotatedString = buildAnnotatedString { + append(change.text) + + currentText.value.annotatedString.spanStyles.forEach { + try { + if (it.start >= 0 && it.end > it.start && it.end <= change.text.length) { + addStyle( + it.item, + maxOf(it.start, 0), + minOf(it.end, change.text.length - 1) + ) + } + } catch (e: Exception) { + e.printStackTrace() + } + } + } + ) }, value = currentText.value, enabled = enabled, @@ -135,8 +152,6 @@ fun CodeEditTextSwiftUi( ) } - - TextField3( modifier = modifier.fillMaxWidth(), value = currentText.value, From 0430e8309c62a00609b0df88403fcd9aa6ed32b3 Mon Sep 17 00:00:00 2001 From: tkadziolka Date: Sun, 3 Nov 2024 17:58:48 +0100 Subject: [PATCH 6/8] Refactored new logic --- .../dev/snipme/kodeview/view/CodeEditText.kt | 4 +- .../dev/snipme/kodeview/view/Extensions.kt | 16 ++++++- .../kodeview/view/material3/CodeEditText.kt | 44 +++++++------------ 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeEditText.kt b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeEditText.kt index 01c9077..7972d0c 100644 --- a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeEditText.kt +++ b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeEditText.kt @@ -18,7 +18,7 @@ import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.VisualTransformation -import calculateFieldPhraseUpdate +import updateIndentations import dev.snipme.highlights.Highlights @Composable @@ -66,7 +66,7 @@ fun CodeEditText( TextField( modifier = modifier.fillMaxWidth(), onValueChange = { - val fieldUpdate = it.calculateFieldPhraseUpdate(translateTabToSpaces) + val fieldUpdate = it.updateIndentations(translateTabToSpaces) currentText.value = fieldUpdate onValueChange(fieldUpdate.text) }, diff --git a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/Extensions.kt b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/Extensions.kt index df7d19f..ef36f0f 100644 --- a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/Extensions.kt +++ b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/Extensions.kt @@ -33,10 +33,22 @@ fun List.generateAnnotatedString(code: String) = } -internal fun TextFieldValue.calculateFieldPhraseUpdate(translateTabToSpaces: Boolean) = +internal fun TextFieldValue.updateIndentations(translateTabToSpaces: Boolean) = if (translateTabToSpaces && text.contains(TAB_CHAR)) { val result = text.replace(TAB_CHAR, " ".repeat(TAB_LENGTH)) this.copy(text = result, TextRange(selection.start + TAB_LENGTH - 1)) } else { this - } \ No newline at end of file + } + +internal fun TextFieldValue.copySpanStyles(source: TextFieldValue) = + this.copy( + annotatedString = buildAnnotatedString { + append(text) + source.annotatedString.spanStyles.forEach { + if (it.start >= 0 && it.end > it.start && it.end < text.length) { + addStyle(it.item, it.start, it.end) + } + } + } + ) \ No newline at end of file diff --git a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/material3/CodeEditText.kt b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/material3/CodeEditText.kt index ed6cab2..6c8cb07 100644 --- a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/material3/CodeEditText.kt +++ b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/material3/CodeEditText.kt @@ -12,10 +12,10 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Shape import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.VisualTransformation -import calculateFieldPhraseUpdate +import copySpanStyles +import updateIndentations import dev.snipme.highlights.DefaultHighlightsResultListener import dev.snipme.highlights.Highlights import dev.snipme.highlights.model.CodeHighlight @@ -32,7 +32,7 @@ fun CodeEditText( modifier: Modifier = Modifier, enabled: Boolean = true, readOnly: Boolean = false, - translateTabToSpaces: Boolean = true, + handleIndentations: Boolean = true, textStyle: TextStyle = LocalTextStyle3.current, label: @Composable (() -> Unit)? = null, placeholder: @Composable (() -> Unit)? = null, @@ -67,32 +67,20 @@ fun CodeEditText( }) } + fun onValueChange(change: TextFieldValue) { + val updated = change.updateIndentations(handleIndentations) + if (updated.text != currentText.value.text) { + onValueChange(updated.text) + } + + currentText.value = updated.copySpanStyles( + currentText.value + ) + } + TextField3( modifier = modifier.fillMaxWidth(), - onValueChange = { change -> -// val fieldUpdate = it.calculateFieldPhraseUpdate(translateTabToSpaces) - if (change.text != currentText.value.text) - onValueChange(change.text) - currentText.value = change.copy( - annotatedString = buildAnnotatedString { - append(change.text) - - currentText.value.annotatedString.spanStyles.forEach { - try { - if (it.start >= 0 && it.end > it.start && it.end <= change.text.length) { - addStyle( - it.item, - maxOf(it.start, 0), - minOf(it.end, change.text.length - 1) - ) - } - } catch (e: Exception) { - e.printStackTrace() - } - } - } - ) - }, + onValueChange = ::onValueChange, value = currentText.value, enabled = enabled, readOnly = readOnly, @@ -156,7 +144,7 @@ fun CodeEditTextSwiftUi( modifier = modifier.fillMaxWidth(), value = currentText.value, onValueChange = { - val fieldUpdate = it.calculateFieldPhraseUpdate(translateTabToSpaces) + val fieldUpdate = it.updateIndentations(translateTabToSpaces) highlightsState.value = highlightsState.value.getBuilder().code(fieldUpdate.text).build() onValueChange(fieldUpdate) From 133975e1989ab50f322a5a9ceb8f4045886d870b Mon Sep 17 00:00:00 2001 From: tkadziolka Date: Sun, 3 Nov 2024 19:33:17 +0100 Subject: [PATCH 7/8] Corrected SwiftUI component --- .../dev/snipme/kodeview/view/CodeEditText.kt | 4 +- .../dev/snipme/kodeview/view/Extensions.kt | 4 +- .../kodeview/view/material3/CodeEditText.kt | 51 ++++++++++--------- 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeEditText.kt b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeEditText.kt index 7972d0c..7007c20 100644 --- a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeEditText.kt +++ b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeEditText.kt @@ -28,7 +28,7 @@ fun CodeEditText( modifier: Modifier = Modifier, enabled: Boolean = true, readOnly: Boolean = false, - translateTabToSpaces: Boolean = true, + handleIndentations: Boolean = true, textStyle: TextStyle = LocalTextStyle.current, label: @Composable (() -> Unit)? = null, placeholder: @Composable (() -> Unit)? = null, @@ -66,7 +66,7 @@ fun CodeEditText( TextField( modifier = modifier.fillMaxWidth(), onValueChange = { - val fieldUpdate = it.updateIndentations(translateTabToSpaces) + val fieldUpdate = it.updateIndentations(handleIndentations) currentText.value = fieldUpdate onValueChange(fieldUpdate.text) }, diff --git a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/Extensions.kt b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/Extensions.kt index ef36f0f..3156faa 100644 --- a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/Extensions.kt +++ b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/Extensions.kt @@ -33,8 +33,8 @@ fun List.generateAnnotatedString(code: String) = } -internal fun TextFieldValue.updateIndentations(translateTabToSpaces: Boolean) = - if (translateTabToSpaces && text.contains(TAB_CHAR)) { +internal fun TextFieldValue.updateIndentations(handleIndentations: Boolean) = + if (handleIndentations && text.contains(TAB_CHAR)) { val result = text.replace(TAB_CHAR, " ".repeat(TAB_LENGTH)) this.copy(text = result, TextRange(selection.start + TAB_LENGTH - 1)) } else { diff --git a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/material3/CodeEditText.kt b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/material3/CodeEditText.kt index 6c8cb07..07b207f 100644 --- a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/material3/CodeEditText.kt +++ b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/material3/CodeEditText.kt @@ -67,7 +67,7 @@ fun CodeEditText( }) } - fun onValueChange(change: TextFieldValue) { + fun updateNewValue(change: TextFieldValue) { val updated = change.updateIndentations(handleIndentations) if (updated.text != currentText.value.text) { onValueChange(updated.text) @@ -80,7 +80,7 @@ fun CodeEditText( TextField3( modifier = modifier.fillMaxWidth(), - onValueChange = ::onValueChange, + onValueChange = ::updateNewValue, value = currentText.value, enabled = enabled, readOnly = readOnly, @@ -109,7 +109,7 @@ fun CodeEditTextSwiftUi( modifier: Modifier = Modifier, enabled: Boolean = true, readOnly: Boolean = false, - translateTabToSpaces: Boolean = true, + handleIndentations: Boolean = true, textStyle: TextStyle = LocalTextStyle3.current, label: @Composable (() -> Unit)? = null, placeholder: @Composable (() -> Unit)? = null, @@ -126,35 +126,40 @@ fun CodeEditTextSwiftUi( shape: Shape = TextFieldDefaults3.shape, colors: TextFieldColors3 = TextFieldDefaults3.colors() ) { - val highlightsState = remember { - mutableStateOf(highlights) - } - val currentText = remember { mutableStateOf( - TextFieldValue().copy( -// annotatedString = buildAnnotatedString { -// generateAnnotatedString(highlightsState.value) -// } + TextFieldValue( + AnnotatedString(highlights.getCode()) ) ) } + LaunchedEffect(highlights) { + highlights.getHighlightsAsync(object : DefaultHighlightsResultListener() { + override fun onSuccess(result: List) { + currentText.value = currentText.value.copy( + annotatedString = result.generateAnnotatedString(currentText.value.text), + ) + } + }) + } + + fun updateNewValue(change: TextFieldValue) { + val updated = change.updateIndentations(handleIndentations) + + if (updated.text != currentText.value.text) { + onValueChange(updated) + } + + currentText.value = updated.copySpanStyles( + currentText.value + ) + } + TextField3( modifier = modifier.fillMaxWidth(), value = currentText.value, - onValueChange = { - val fieldUpdate = it.updateIndentations(translateTabToSpaces) - highlightsState.value = - highlightsState.value.getBuilder().code(fieldUpdate.text).build() - onValueChange(fieldUpdate) - currentText.value = - fieldUpdate.copy( -// annotatedString = buildAnnotatedString { -// generateAnnotatedString(highlightsState.value) -// } - ) - }, + onValueChange = ::updateNewValue, enabled = enabled, readOnly = readOnly, textStyle = textStyle, From c47f2373990b0f5a450a1db5d7f614edc2daee74 Mon Sep 17 00:00:00 2001 From: tkadziolka Date: Sun, 3 Nov 2024 19:43:10 +0100 Subject: [PATCH 8/8] Updated base edit text component --- .../dev/snipme/kodeview/view/CodeEditText.kt | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeEditText.kt b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeEditText.kt index 7007c20..80230a5 100644 --- a/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeEditText.kt +++ b/kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeEditText.kt @@ -18,8 +18,12 @@ import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.VisualTransformation +import copySpanStyles +import dev.snipme.highlights.DefaultHighlightsResultListener import updateIndentations import dev.snipme.highlights.Highlights +import dev.snipme.highlights.model.CodeHighlight +import generateAnnotatedString @Composable fun CodeEditText( @@ -48,28 +52,35 @@ fun CodeEditText( val currentText = remember { mutableStateOf( TextFieldValue( - annotatedString = AnnotatedString(highlights.getCode()) + AnnotatedString(highlights.getCode()) ) ) } LaunchedEffect(highlights) { -// highlights.getHighlightsAsync(object : DefaultHighlightsResultListener() { -// override fun onSuccess(result: List) { -// currentText.value = currentText.value.copy( -// annotatedString = result.generateAnnotatedString(currentText.value.text), -// ) -// } -// }) + highlights.getHighlightsAsync(object : DefaultHighlightsResultListener() { + override fun onSuccess(result: List) { + currentText.value = currentText.value.copy( + annotatedString = result.generateAnnotatedString(currentText.value.text), + ) + } + }) + } + + fun updateNewValue(change: TextFieldValue) { + val updated = change.updateIndentations(handleIndentations) + if (updated.text != currentText.value.text) { + onValueChange(updated.text) + } + + currentText.value = updated.copySpanStyles( + currentText.value + ) } TextField( modifier = modifier.fillMaxWidth(), - onValueChange = { - val fieldUpdate = it.updateIndentations(handleIndentations) - currentText.value = fieldUpdate - onValueChange(fieldUpdate.text) - }, + onValueChange = ::updateNewValue, value = currentText.value, enabled = enabled, readOnly = readOnly,