diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 274b614..0000000 Binary files a/.DS_Store and /dev/null differ diff --git a/src/commonMain/kotlin/dev/snipme/highlights/internal/CodeAnalyzer.kt b/src/commonMain/kotlin/dev/snipme/highlights/internal/CodeAnalyzer.kt index 61019fb..9f0e92b 100644 --- a/src/commonMain/kotlin/dev/snipme/highlights/internal/CodeAnalyzer.kt +++ b/src/commonMain/kotlin/dev/snipme/highlights/internal/CodeAnalyzer.kt @@ -125,7 +125,7 @@ internal object CodeAnalyzer { // TODO Apply ignored ranges to other locators return CodeStructure( marks = MarkLocator.locate(code), - punctuations = PunctuationLocator.locate(code), + punctuations = PunctuationLocator.locate(code, plainTextRanges), keywords = KeywordLocator.locate(code, keywords, plainTextRanges), strings = strings, literals = NumericLiteralLocator.locate(code), diff --git a/src/commonMain/kotlin/dev/snipme/highlights/internal/Extensions.kt b/src/commonMain/kotlin/dev/snipme/highlights/internal/Extensions.kt index 692691a..f1a7e8c 100644 --- a/src/commonMain/kotlin/dev/snipme/highlights/internal/Extensions.kt +++ b/src/commonMain/kotlin/dev/snipme/highlights/internal/Extensions.kt @@ -1,8 +1,6 @@ package dev.snipme.highlights.internal import dev.snipme.highlights.internal.locator.NUMBER_TYPE_CHARACTERS -import dev.snipme.highlights.internal.SyntaxTokens.MARK_CHARACTERS -import dev.snipme.highlights.internal.SyntaxTokens.PUNCTUATION_CHARACTERS import dev.snipme.highlights.model.CodeHighlight import dev.snipme.highlights.model.PhraseLocation import kotlinx.coroutines.Job diff --git a/src/commonMain/kotlin/dev/snipme/highlights/internal/locator/PunctuationLocator.kt b/src/commonMain/kotlin/dev/snipme/highlights/internal/locator/PunctuationLocator.kt index f61c65f..fefce05 100644 --- a/src/commonMain/kotlin/dev/snipme/highlights/internal/locator/PunctuationLocator.kt +++ b/src/commonMain/kotlin/dev/snipme/highlights/internal/locator/PunctuationLocator.kt @@ -6,7 +6,7 @@ import dev.snipme.highlights.internal.indicesOf import dev.snipme.highlights.model.PhraseLocation internal object PunctuationLocator { - fun locate(code: String): Set { + fun locate(code: String, ignoreRanges: Set = emptySet()): Set { val locations = mutableSetOf() code.asSequence() .map { it.toString().trim() } @@ -15,6 +15,7 @@ internal object PunctuationLocator { .filter { it in PUNCTUATION_CHARACTERS } .forEach { val indices = code.indicesOf(it) + .filterNot { index -> ignoreRanges.any { range -> index >= range.first && index < range.last } } for (index in indices) { if (code[index].isWhitespace()) return@forEach locations.add(PhraseLocation(index, index + 1)) diff --git a/src/commonTest/kotlin/dev/snipme/highlights/internal/CodeAnalyzerTest.kt b/src/commonTest/kotlin/dev/snipme/highlights/internal/CodeAnalyzerTest.kt index 742a030..da4c37b 100644 --- a/src/commonTest/kotlin/dev/snipme/highlights/internal/CodeAnalyzerTest.kt +++ b/src/commonTest/kotlin/dev/snipme/highlights/internal/CodeAnalyzerTest.kt @@ -10,75 +10,76 @@ internal class CodeAnalyzerTest { @Test fun `Returns structure of code analyzed first time`() { val testCode = """ - /** a */ - // b + /** a.b */ + // a, b and c class C extends {} - "d"; + ;"d"; @E ... 123.00f """.trimIndent() - val result = CodeAnalyzer.analyze(testCode) + val result = CodeAnalyzer.analyze(testCode).also { it.printStructure(testCode) } assertEquals( setOf( - PhraseLocation(30, 31), - PhraseLocation(31, 32) + PhraseLocation(41, 42), + PhraseLocation(42, 43) ), result.marks ) assertEquals( setOf( - PhraseLocation(36, 37), - PhraseLocation(41, 42), - PhraseLocation(42, 43), - PhraseLocation(43, 44), + PhraseLocation(44, 45), PhraseLocation(48, 49), + PhraseLocation(53, 54), + PhraseLocation(54, 55), + PhraseLocation(55, 56), + PhraseLocation(60, 61), ), result.punctuations ) assertEquals( setOf( - PhraseLocation(14, 19), - PhraseLocation(22, 29) + PhraseLocation(25, 30), + PhraseLocation(33, 40) ), result.keywords ) assertEquals( setOf( - PhraseLocation(33, 36), + PhraseLocation(45, 48), ), result.strings ) assertEquals( setOf( - PhraseLocation(45, 52), + PhraseLocation(57, 64), ), result.literals ) assertEquals( setOf( - PhraseLocation(9, 13), + PhraseLocation(11, 24), ), result.comments ) assertEquals( setOf( - PhraseLocation(0, 8), + PhraseLocation(0, 10), ), result.multilineComments ) assertEquals( setOf( - PhraseLocation(38, 40), + PhraseLocation(50, 52), ), result.annotations ) @@ -86,6 +87,37 @@ internal class CodeAnalyzerTest { assertEquals(false, result.incremental) } + + @Test + fun `Ignores punctuation in comments and strings`() { + val testCode = "\"a,b\"; // c,d\n\"e:f\";" + + val result = CodeAnalyzer.analyze(testCode) + + assertEquals( + setOf( + PhraseLocation(5, 6), + PhraseLocation(19, 20), + ), + result.punctuations + ) + } + + @Test + fun `Ignores punctuation inside multiline comments and string literals`() { + val testCode = "\"a,b\"; /* c,d */ \"e;f\";" + + val result = CodeAnalyzer.analyze(testCode) + + assertEquals( + setOf( + PhraseLocation(5, 6), + PhraseLocation(22, 23), + ), + result.punctuations + ) + } + @Test fun `Returns incremental structure of code analyzed second time`() { val testCode = """ diff --git a/src/commonTest/kotlin/dev/snipme/highlights/internal/locator/PunctuationLocatorTest.kt b/src/commonTest/kotlin/dev/snipme/highlights/internal/locator/PunctuationLocatorTest.kt index ed6f566..cef01cb 100644 --- a/src/commonTest/kotlin/dev/snipme/highlights/internal/locator/PunctuationLocatorTest.kt +++ b/src/commonTest/kotlin/dev/snipme/highlights/internal/locator/PunctuationLocatorTest.kt @@ -91,4 +91,53 @@ internal class PunctuationLocatorTest { assertEquals(1, result.size) assertEquals(PhraseLocation(12, 13), result[0]) } + + @Test + fun `Ignores punctuation inside an ignored range`() { + val testCode = "a,b;" + val ignoreRanges = setOf(IntRange(1, 3)) + + val result = PunctuationLocator.locate(testCode, ignoreRanges) + + assertEquals(1, result.size) + assertEquals(PhraseLocation(3, 4), result.first()) + } + + @Test + fun `Returns punctuation outside an ignored range`() { + val testCode = "a,b;" + val ignoreRanges = setOf(IntRange(0, 1)) + + val result = PunctuationLocator.locate(testCode, ignoreRanges) + + assertEquals(2, result.size) + assertEquals(PhraseLocation(1, 2), result.first()) + assertEquals(PhraseLocation(3, 4), result.last()) + } + + @Test + fun `Handles multiple ignored ranges`() { + val testCode = "a,b;c,d;" + val ignoreRanges = setOf( + IntRange(1, 2), + IntRange(5, 6), + ) + + val result = PunctuationLocator.locate(testCode, ignoreRanges) + + assertEquals(2, result.size) + assertEquals(PhraseLocation(3, 4), result[0]) + assertEquals(PhraseLocation(7, 8), result[1]) + } + + @Test + fun `Handles range boundaries correctly`() { + val testCode = ";\"d\";" + val ignoreRanges = setOf(IntRange(0, 3)) + + val result = PunctuationLocator.locate(testCode, ignoreRanges) + + assertEquals(1, result.size) + assertEquals(PhraseLocation(4, 5), result.first()) + } } \ No newline at end of file