Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed .DS_Store
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import dev.snipme.highlights.internal.indicesOf
import dev.snipme.highlights.model.PhraseLocation

internal object PunctuationLocator {
fun locate(code: String): Set<PhraseLocation> {
fun locate(code: String, ignoreRanges: Set<IntRange> = emptySet()): Set<PhraseLocation> {
val locations = mutableSetOf<PhraseLocation>()
code.asSequence()
.map { it.toString().trim() }
Expand All @@ -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))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,82 +10,114 @@ 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
)

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 = """
Expand Down

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like PunctuationLocator doesn't distinguish between comments, multiline comments, or strings - it just accepts ignored ranges.

Maybe the tests here could be more generic and just cover cases such as:

  • ignores punctuation inside an ignored range
  • returns punctuation outside an ignored range
  • handles multiple ignored ranges
  • handles range boundaries correctly

The comment/string-specific cases could live in CodeAnalyzerTest, where those ranges are actually created and combined.

Let me know what you think.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good point, you're right the knowledge about system shouldn't be written in small logic part (locator)

Original file line number Diff line number Diff line change
Expand Up @@ -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())
}
}