From 0313bf6ef0f093bd86d7746a3ce05e4eeb1859de Mon Sep 17 00:00:00 2001 From: tkadziolka Date: Wed, 11 Sep 2024 07:43:12 +0200 Subject: [PATCH 1/3] Added code difference full --- build.gradle.kts | 2 +- .../highlights/internal/CodeComparator.kt | 5 +- .../highlights/internal/CodeAnalyzerTest.kt | 70 +++++++++++++++++++ .../highlights/internal/CodeComparatorTest.kt | 44 ++++++++++++ 4 files changed, 119 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index bcb70c1..c00f902 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { } group = "dev.snipme" -version = "0.9.1" +version = "0.9.2" kotlin { // Android diff --git a/src/commonMain/kotlin/dev/snipme/highlights/internal/CodeComparator.kt b/src/commonMain/kotlin/dev/snipme/highlights/internal/CodeComparator.kt index 1298152..5141d29 100644 --- a/src/commonMain/kotlin/dev/snipme/highlights/internal/CodeComparator.kt +++ b/src/commonMain/kotlin/dev/snipme/highlights/internal/CodeComparator.kt @@ -5,6 +5,7 @@ private const val WORDS_DELIMITER = " " internal sealed class CodeDifference { data class Increase(val change: String) : CodeDifference() data class Decrease(val change: String) : CodeDifference() + object Full : CodeDifference() object None : CodeDifference() } @@ -14,7 +15,9 @@ internal object CodeComparator { val updatedWords = updated.tokenize() return when { - currentWords.size == updatedWords.size -> CodeDifference.None + currentWords.size == updatedWords.size -> + if (currentWords == updatedWords) CodeDifference.None + else CodeDifference.Full currentWords.size < updatedWords.size -> CodeDifference.Increase( findDifference( diff --git a/src/commonTest/kotlin/dev/snipme/highlights/internal/CodeAnalyzerTest.kt b/src/commonTest/kotlin/dev/snipme/highlights/internal/CodeAnalyzerTest.kt index 742a030..c0a6beb 100644 --- a/src/commonTest/kotlin/dev/snipme/highlights/internal/CodeAnalyzerTest.kt +++ b/src/commonTest/kotlin/dev/snipme/highlights/internal/CodeAnalyzerTest.kt @@ -1,5 +1,7 @@ package dev.snipme.highlights.internal +import dev.snipme.highlights.Highlights +import dev.snipme.highlights.model.ColorHighlight import dev.snipme.highlights.model.PhraseLocation import dev.snipme.highlights.model.SyntaxLanguage import kotlin.test.Test @@ -253,4 +255,72 @@ internal class CodeAnalyzerTest { result.annotations ) } + + + @Test + fun basic_getHighlights_location() { + val highlighter = Highlights.Builder() + .language(SyntaxLanguage.JAVASCRIPT) + .build() + + val code1 = "const foo = 'bar';"; + + highlighter.setCode(code1) + val highlights1 = highlighter.getHighlights().filterIsInstance().sortedBy { it.location.start } + highlights1.size shouldEqual 4 + highlights1[0].location shouldEqual PhraseLocation(start=0, end=5) + highlights1[1].location shouldEqual PhraseLocation(start=10, end=11) + highlights1[2].location shouldEqual PhraseLocation(start=12, end=17) + highlights1[3].location shouldEqual PhraseLocation(start=17, end=18) + + highlights1.map { it.location }.printResults(code1) + + val code2 = "const foo = 'barrr';" + + highlighter.setCode(code2) + val highlights2 = highlighter.getHighlights().filterIsInstance().sortedBy { it.location.start } + highlights2.map { it.location }.printResults(code2) + highlights2.size shouldEqual 4 + highlights2[0].location shouldEqual PhraseLocation(start=0, end=5) + highlights2[1].location shouldEqual PhraseLocation(start=10, end=11) + // FAILS HERE: + highlights2[2].location shouldEqual PhraseLocation(start=12, end=19) + highlights2[3].location shouldEqual PhraseLocation(start=19, end=20) + + } + + @Test + fun basic_getHighlights_location_alt() { + var highlighter = Highlights.Builder() + .language(SyntaxLanguage.JAVASCRIPT) + .build() + + highlighter = highlighter + .getBuilder() + .code("const foo = 'bar';") + .build() + + val highlights1 = highlighter.getHighlights().filterIsInstance().sortedBy { it.location.start } + highlights1.size shouldEqual 4 + highlights1[0].location shouldEqual PhraseLocation(start=0, end=5) + highlights1[1].location shouldEqual PhraseLocation(start=10, end=11) + highlights1[2].location shouldEqual PhraseLocation(start=12, end=17) + highlights1[3].location shouldEqual PhraseLocation(start=17, end=18) + + highlighter = highlighter + .getBuilder() + .code("const foo = 'barrr';") + .build() + val highlights2 = highlighter.getHighlights().filterIsInstance().sortedBy { it.location.start } + highlights2.size shouldEqual 4 + highlights2[0].location shouldEqual PhraseLocation(start=0, end=5) + highlights2[1].location shouldEqual PhraseLocation(start=10, end=11) + highlights2[2].location shouldEqual PhraseLocation(start=12, end=19) + highlights2[3].location shouldEqual PhraseLocation(start=19, end=20) + } + + private infix fun Any?.shouldEqual(expected: Any?) { + assertEquals(expected, this) + } + } \ No newline at end of file diff --git a/src/commonTest/kotlin/dev/snipme/highlights/internal/CodeComparatorTest.kt b/src/commonTest/kotlin/dev/snipme/highlights/internal/CodeComparatorTest.kt index 197b2ea..f73efe0 100644 --- a/src/commonTest/kotlin/dev/snipme/highlights/internal/CodeComparatorTest.kt +++ b/src/commonTest/kotlin/dev/snipme/highlights/internal/CodeComparatorTest.kt @@ -75,6 +75,50 @@ internal class CodeComparatorTest { assertEquals(CodeDifference.None, result) } +// @Test +// fun `Returns difference for the char change in token`() { +// val currentCode = "const foo = 'bar';" +// +// val newCode = "const foo = 'baz';" +// +// val result = CodeComparator.difference(currentCode, newCode) +// +// assertEquals(CodeDifference.Swap("'bar'", "'baz'"), result) +// } + +// @Test +// fun `Returns difference for the char change in token`() { +// val currentCode = "const foo = 'bar';" +// +// val newCode = "co,st foo = 'bar';" +// +// val result = CodeComparator.difference(currentCode, newCode) +// +// assertEquals(CodeDifference.Swap("const", "co,st"), result) +// } +// +// @Test +// fun `Returns difference for the char addition in single token`() { +// val currentCode = "const foo = 'bar';" +// +// val newCode = "const foo = 'barrr';" +// +// val result = CodeComparator.difference(currentCode, newCode) +// +// assertEquals(CodeDifference.Swap("'bar'", "'barrr'"), result) +// } +// +// @Test +// fun `Returns difference for the char subtraction in single token`() { +// val currentCode = "const foo = 'barrr';" +// +// val newCode = "const foo = 'bar';" +// +// val result = CodeComparator.difference(currentCode, newCode) +// +// assertEquals(CodeDifference.Swap("'barrr'", "'bar'"), result) +// } + @Test fun `Returns only difference for complex code change`() { val currentCode = """ From 02f6e92e1837f030ee0cf3c0a3c52b565da39c69 Mon Sep 17 00:00:00 2001 From: tkadziolka Date: Wed, 11 Sep 2024 07:58:21 +0200 Subject: [PATCH 2/3] Fixed partial analysis for strings same length --- CHANGELOG.md | 5 ++ .../highlights/internal/CodeAnalyzer.kt | 2 + .../highlights/internal/CodeComparator.kt | 8 +- .../highlights/internal/CodeAnalyzerTest.kt | 70 ---------------- .../highlights/internal/CodeComparatorTest.kt | 79 ++++++++----------- 5 files changed, 45 insertions(+), 119 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dc196d..8736058 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## [0.9.2] + +### Fixed +- partial analysis for same length strings + ## [0.9.1] ### Fixed diff --git a/src/commonMain/kotlin/dev/snipme/highlights/internal/CodeAnalyzer.kt b/src/commonMain/kotlin/dev/snipme/highlights/internal/CodeAnalyzer.kt index 42e4ef3..61019fb 100644 --- a/src/commonMain/kotlin/dev/snipme/highlights/internal/CodeAnalyzer.kt +++ b/src/commonMain/kotlin/dev/snipme/highlights/internal/CodeAnalyzer.kt @@ -84,6 +84,8 @@ internal object CodeAnalyzer { codeSnapshot.structure - newStructure.move(lengthDifference) } + is CodeDifference.Full -> analyzeForLanguage(code, codeSnapshot.language) + CodeDifference.None -> return codeSnapshot.structure } diff --git a/src/commonMain/kotlin/dev/snipme/highlights/internal/CodeComparator.kt b/src/commonMain/kotlin/dev/snipme/highlights/internal/CodeComparator.kt index 5141d29..89333eb 100644 --- a/src/commonMain/kotlin/dev/snipme/highlights/internal/CodeComparator.kt +++ b/src/commonMain/kotlin/dev/snipme/highlights/internal/CodeComparator.kt @@ -5,14 +5,14 @@ private const val WORDS_DELIMITER = " " internal sealed class CodeDifference { data class Increase(val change: String) : CodeDifference() data class Decrease(val change: String) : CodeDifference() - object Full : CodeDifference() - object None : CodeDifference() + data object Full : CodeDifference() + data object None : CodeDifference() } internal object CodeComparator { fun difference(current: String, updated: String): CodeDifference { - val currentWords = current.tokenize() - val updatedWords = updated.tokenize() + val currentWords = current.tokenize().map { it.trim() } + val updatedWords = updated.tokenize().map { it.trim() } return when { currentWords.size == updatedWords.size -> diff --git a/src/commonTest/kotlin/dev/snipme/highlights/internal/CodeAnalyzerTest.kt b/src/commonTest/kotlin/dev/snipme/highlights/internal/CodeAnalyzerTest.kt index c0a6beb..742a030 100644 --- a/src/commonTest/kotlin/dev/snipme/highlights/internal/CodeAnalyzerTest.kt +++ b/src/commonTest/kotlin/dev/snipme/highlights/internal/CodeAnalyzerTest.kt @@ -1,7 +1,5 @@ package dev.snipme.highlights.internal -import dev.snipme.highlights.Highlights -import dev.snipme.highlights.model.ColorHighlight import dev.snipme.highlights.model.PhraseLocation import dev.snipme.highlights.model.SyntaxLanguage import kotlin.test.Test @@ -255,72 +253,4 @@ internal class CodeAnalyzerTest { result.annotations ) } - - - @Test - fun basic_getHighlights_location() { - val highlighter = Highlights.Builder() - .language(SyntaxLanguage.JAVASCRIPT) - .build() - - val code1 = "const foo = 'bar';"; - - highlighter.setCode(code1) - val highlights1 = highlighter.getHighlights().filterIsInstance().sortedBy { it.location.start } - highlights1.size shouldEqual 4 - highlights1[0].location shouldEqual PhraseLocation(start=0, end=5) - highlights1[1].location shouldEqual PhraseLocation(start=10, end=11) - highlights1[2].location shouldEqual PhraseLocation(start=12, end=17) - highlights1[3].location shouldEqual PhraseLocation(start=17, end=18) - - highlights1.map { it.location }.printResults(code1) - - val code2 = "const foo = 'barrr';" - - highlighter.setCode(code2) - val highlights2 = highlighter.getHighlights().filterIsInstance().sortedBy { it.location.start } - highlights2.map { it.location }.printResults(code2) - highlights2.size shouldEqual 4 - highlights2[0].location shouldEqual PhraseLocation(start=0, end=5) - highlights2[1].location shouldEqual PhraseLocation(start=10, end=11) - // FAILS HERE: - highlights2[2].location shouldEqual PhraseLocation(start=12, end=19) - highlights2[3].location shouldEqual PhraseLocation(start=19, end=20) - - } - - @Test - fun basic_getHighlights_location_alt() { - var highlighter = Highlights.Builder() - .language(SyntaxLanguage.JAVASCRIPT) - .build() - - highlighter = highlighter - .getBuilder() - .code("const foo = 'bar';") - .build() - - val highlights1 = highlighter.getHighlights().filterIsInstance().sortedBy { it.location.start } - highlights1.size shouldEqual 4 - highlights1[0].location shouldEqual PhraseLocation(start=0, end=5) - highlights1[1].location shouldEqual PhraseLocation(start=10, end=11) - highlights1[2].location shouldEqual PhraseLocation(start=12, end=17) - highlights1[3].location shouldEqual PhraseLocation(start=17, end=18) - - highlighter = highlighter - .getBuilder() - .code("const foo = 'barrr';") - .build() - val highlights2 = highlighter.getHighlights().filterIsInstance().sortedBy { it.location.start } - highlights2.size shouldEqual 4 - highlights2[0].location shouldEqual PhraseLocation(start=0, end=5) - highlights2[1].location shouldEqual PhraseLocation(start=10, end=11) - highlights2[2].location shouldEqual PhraseLocation(start=12, end=19) - highlights2[3].location shouldEqual PhraseLocation(start=19, end=20) - } - - private infix fun Any?.shouldEqual(expected: Any?) { - assertEquals(expected, this) - } - } \ No newline at end of file diff --git a/src/commonTest/kotlin/dev/snipme/highlights/internal/CodeComparatorTest.kt b/src/commonTest/kotlin/dev/snipme/highlights/internal/CodeComparatorTest.kt index f73efe0..82eee50 100644 --- a/src/commonTest/kotlin/dev/snipme/highlights/internal/CodeComparatorTest.kt +++ b/src/commonTest/kotlin/dev/snipme/highlights/internal/CodeComparatorTest.kt @@ -66,58 +66,47 @@ internal class CodeComparatorTest { } @Test - fun `Returns none difference for the mixed new phrase`() { + fun `Returns full difference for the mixed new phrase`() { val currentCode = "@ABCD abcd dd ee" val newCode = "@ABCD abcd ee dd" val result = CodeComparator.difference(currentCode, newCode) - assertEquals(CodeDifference.None, result) + assertEquals(CodeDifference.Full, result) } -// @Test -// fun `Returns difference for the char change in token`() { -// val currentCode = "const foo = 'bar';" -// -// val newCode = "const foo = 'baz';" -// -// val result = CodeComparator.difference(currentCode, newCode) -// -// assertEquals(CodeDifference.Swap("'bar'", "'baz'"), result) -// } - -// @Test -// fun `Returns difference for the char change in token`() { -// val currentCode = "const foo = 'bar';" -// -// val newCode = "co,st foo = 'bar';" -// -// val result = CodeComparator.difference(currentCode, newCode) -// -// assertEquals(CodeDifference.Swap("const", "co,st"), result) -// } -// -// @Test -// fun `Returns difference for the char addition in single token`() { -// val currentCode = "const foo = 'bar';" -// -// val newCode = "const foo = 'barrr';" -// -// val result = CodeComparator.difference(currentCode, newCode) -// -// assertEquals(CodeDifference.Swap("'bar'", "'barrr'"), result) -// } -// -// @Test -// fun `Returns difference for the char subtraction in single token`() { -// val currentCode = "const foo = 'barrr';" -// -// val newCode = "const foo = 'bar';" -// -// val result = CodeComparator.difference(currentCode, newCode) -// -// assertEquals(CodeDifference.Swap("'barrr'", "'bar'"), result) -// } + @Test + fun `Returns full difference for the char change in token`() { + val currentCode = "const foo = 'bar';" + + val newCode = "const foo = 'baz';" + + val result = CodeComparator.difference(currentCode, newCode) + + assertEquals(CodeDifference.Full, result) + } + + @Test + fun `Returns difference for the char addition in single token`() { + val currentCode = "const foo = 'bar';" + + val newCode = "const foo = 'barrr';" + + val result = CodeComparator.difference(currentCode, newCode) + + assertEquals(CodeDifference.Full, result) + } + + @Test + fun `Returns difference for the char subtraction in single token`() { + val currentCode = "const foo = 'barrr';" + + val newCode = "const foo = 'bar';" + + val result = CodeComparator.difference(currentCode, newCode) + + assertEquals(CodeDifference.Full, result) + } @Test fun `Returns only difference for complex code change`() { From b1bd77321eb67082431ee71e47ef6c09a871cd34 Mon Sep 17 00:00:00 2001 From: tkadziolka Date: Wed, 11 Sep 2024 08:08:20 +0200 Subject: [PATCH 3/3] Updated readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 39d78c1..300ff75 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ repositories { ``` ```shell -implementation("dev.snipme:highlights:0.9.1") +implementation("dev.snipme:highlights:0.9.2") ``` ## Features ✨