diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ccc1d1..2faaae1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## [0.8.0] + +### Changed +- Kotlin version to 1.9.22 + +### Fixed +- scientific notation numbers highlight length +- redundant keyword highlights in strings and comments +- ambiguous nested forEach returns + ## [0.7.1] ### Fixed diff --git a/README.md b/README.md index 9603825..03336d5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ![highlights_banner_opaque](https://github.com/SnipMeDev/Highlights/assets/8405055/e123ce0f-6f58-451a-9e0a-893c0809b909) [![Maven Central](https://img.shields.io/maven-central/v/dev.snipme/highlights)](https://mvnrepository.com/artifact/dev.snipme) -[![Kotlin](https://img.shields.io/badge/kotlin-1.9.0-blue.svg?logo=kotlin)](http://kotlinlang.org) +[![Kotlin](https://img.shields.io/badge/kotlin-1.9.22-blue.svg?logo=kotlin)](http://kotlinlang.org) [![GitHub License](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](http://www.apache.org/licenses/LICENSE-2.0) # Highlights @@ -15,7 +15,7 @@ repositories { ``` ```shell -implementation("dev.snipme:highlights:0.7.1") +implementation("dev.snipme:highlights:0.8.0") ``` ## Features ✨ diff --git a/build.gradle.kts b/build.gradle.kts index 8ce9b1a..b29a0a9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,19 +1,14 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -import org.gradle.api.publish.maven.MavenPublication -import org.gradle.configurationcache.extensions.capitalized -import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.archivesName - apply(from = "publish-root.gradle") plugins { - kotlin("multiplatform") version "1.9.0" + kotlin("multiplatform") version "1.9.22" id("maven-publish") id("io.github.gradle-nexus.publish-plugin") version "1.3.0" id("signing") } group = "dev.snipme" -version = "0.7.1" +version = "0.8.0" kotlin { // Android diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts index 5aeae6e..a616c35 100644 --- a/sample/build.gradle.kts +++ b/sample/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - kotlin("jvm") version "1.9.0" + kotlin("jvm") version "1.9.22" application } diff --git a/src/commonMain/kotlin/dev/snipme/highlights/internal/CodeAnalyzer.kt b/src/commonMain/kotlin/dev/snipme/highlights/internal/CodeAnalyzer.kt index 3a44bb6..2c1f5d1 100644 --- a/src/commonMain/kotlin/dev/snipme/highlights/internal/CodeAnalyzer.kt +++ b/src/commonMain/kotlin/dev/snipme/highlights/internal/CodeAnalyzer.kt @@ -1,9 +1,5 @@ package dev.snipme.highlights.internal -import dev.snipme.highlights.internal.locator.AnnotationLocator -import dev.snipme.highlights.model.CodeStructure -import dev.snipme.highlights.model.SyntaxLanguage -import dev.snipme.highlights.model.SyntaxLanguage.* import dev.snipme.highlights.internal.SyntaxTokens.ALL_KEYWORDS import dev.snipme.highlights.internal.SyntaxTokens.ALL_MIXED_KEYWORDS import dev.snipme.highlights.internal.SyntaxTokens.COFFEE_KEYWORDS @@ -19,13 +15,31 @@ import dev.snipme.highlights.internal.SyntaxTokens.RUBY_KEYWORDS import dev.snipme.highlights.internal.SyntaxTokens.RUST_KEYWORDS import dev.snipme.highlights.internal.SyntaxTokens.SH_KEYWORDS import dev.snipme.highlights.internal.SyntaxTokens.SWIFT_KEYWORDS +import dev.snipme.highlights.internal.locator.AnnotationLocator import dev.snipme.highlights.internal.locator.CommentLocator import dev.snipme.highlights.internal.locator.KeywordLocator -import dev.snipme.highlights.internal.locator.NumericLiteralLocator import dev.snipme.highlights.internal.locator.MarkLocator import dev.snipme.highlights.internal.locator.MultilineCommentLocator +import dev.snipme.highlights.internal.locator.NumericLiteralLocator import dev.snipme.highlights.internal.locator.PunctuationLocator import dev.snipme.highlights.internal.locator.StringLocator +import dev.snipme.highlights.model.CodeStructure +import dev.snipme.highlights.model.SyntaxLanguage +import dev.snipme.highlights.model.SyntaxLanguage.C +import dev.snipme.highlights.model.SyntaxLanguage.COFFEESCRIPT +import dev.snipme.highlights.model.SyntaxLanguage.CPP +import dev.snipme.highlights.model.SyntaxLanguage.CSHARP +import dev.snipme.highlights.model.SyntaxLanguage.DEFAULT +import dev.snipme.highlights.model.SyntaxLanguage.JAVA +import dev.snipme.highlights.model.SyntaxLanguage.JAVASCRIPT +import dev.snipme.highlights.model.SyntaxLanguage.KOTLIN +import dev.snipme.highlights.model.SyntaxLanguage.MIXED +import dev.snipme.highlights.model.SyntaxLanguage.PERL +import dev.snipme.highlights.model.SyntaxLanguage.PYTHON +import dev.snipme.highlights.model.SyntaxLanguage.RUBY +import dev.snipme.highlights.model.SyntaxLanguage.RUST +import dev.snipme.highlights.model.SyntaxLanguage.SHELL +import dev.snipme.highlights.model.SyntaxLanguage.SWIFT data class CodeSnapshot( val code: String, @@ -90,14 +104,20 @@ internal object CodeAnalyzer { } private fun analyzeCodeWithKeywords(code: String, keywords: List): CodeStructure { + val comments = CommentLocator.locate(code) + val multiLineComments = MultilineCommentLocator.locate(code) + val strings = StringLocator.locate(code) + + val plainTextRanges = comments + multiLineComments + strings + return CodeStructure( marks = MarkLocator.locate(code), punctuations = PunctuationLocator.locate(code), - keywords = KeywordLocator.locate(code, keywords), - strings = StringLocator.locate(code), + keywords = KeywordLocator.locate(code, keywords, plainTextRanges), + strings = strings, literals = NumericLiteralLocator.locate(code), - comments = CommentLocator.locate(code), - multilineComments = MultilineCommentLocator.locate(code), + comments = comments, + multilineComments = multiLineComments, annotations = AnnotationLocator.locate(code), incremental = false, ) diff --git a/src/commonMain/kotlin/dev/snipme/highlights/internal/locator/KeywordLocator.kt b/src/commonMain/kotlin/dev/snipme/highlights/internal/locator/KeywordLocator.kt index bace199..bd65bc8 100644 --- a/src/commonMain/kotlin/dev/snipme/highlights/internal/locator/KeywordLocator.kt +++ b/src/commonMain/kotlin/dev/snipme/highlights/internal/locator/KeywordLocator.kt @@ -1,17 +1,27 @@ package dev.snipme.highlights.internal.locator -import dev.snipme.highlights.model.PhraseLocation import dev.snipme.highlights.internal.SyntaxTokens.TOKEN_DELIMITERS import dev.snipme.highlights.internal.indicesOf import dev.snipme.highlights.internal.isIndependentPhrase - +import dev.snipme.highlights.model.PhraseLocation internal object KeywordLocator { - fun locate(code: String, keywords: List): List { + fun locate( + code: String, + keywords: List, + ignoreRanges: List = emptyList(), + ): List { val locations = mutableListOf() val foundKeywords = findKeywords(code, keywords) - foundKeywords.forEach { keyword -> + + val interpretedKeywords = foundKeywords.filterNot { keyword -> + val index = code.indexOf(keyword) + val length = keyword.length + ignoreRanges.any { it.start <= index && it.end >= index + length } + } + + interpretedKeywords.forEach { keyword -> val indices = code .indicesOf(keyword) .filter { keyword.isIndependentPhrase(code, it) } diff --git a/src/commonMain/kotlin/dev/snipme/highlights/internal/locator/NumericLiteralLocator.kt b/src/commonMain/kotlin/dev/snipme/highlights/internal/locator/NumericLiteralLocator.kt index c3aa17b..c50f4ab 100644 --- a/src/commonMain/kotlin/dev/snipme/highlights/internal/locator/NumericLiteralLocator.kt +++ b/src/commonMain/kotlin/dev/snipme/highlights/internal/locator/NumericLiteralLocator.kt @@ -1,13 +1,13 @@ package dev.snipme.highlights.internal.locator -import dev.snipme.highlights.model.PhraseLocation import dev.snipme.highlights.internal.SyntaxTokens.TOKEN_DELIMITERS import dev.snipme.highlights.internal.indicesOf +import dev.snipme.highlights.model.PhraseLocation -private const val NUMBER_ENDING_LETTER_COUNT = 1 private val NUMBER_START_CHARACTERS = listOf('-', '.') private val NUMBER_TYPE_CHARACTERS = listOf('e', 'u', 'f', 'l') private val HEX_NUMBER_CHARACTERS = listOf('a', 'b', 'c', 'd', 'e', 'f') +private val NUMBER_SPECIAL_CHARACTERS = listOf('_') internal object NumericLiteralLocator { @@ -24,7 +24,7 @@ internal object NumericLiteralLocator { code.split(*delimiters) // Separate words .asSequence() // Manipulate on given word separately .filterNot { foundPhrases.contains(it) } - .filter { it.isNotEmpty() } // Filter spaces and others + .filter { it.isNotBlank() } // Filter spaces and others .filter { it.first().isDigit() || (NUMBER_START_CHARACTERS.contains(it.first()) && it.getOrNull(1)?.isDigit() == true) @@ -36,7 +36,7 @@ internal object NumericLiteralLocator { // Omit in the middle of text, probably variable name (this100) if (code.isNumberFirstIndex(startIndex).not()) return@forEach // Add matching occurrence to the output locations - val length = calculateNumberLength(number) + val length = calculateNumberLength(number.lowercase()) locations.add(PhraseLocation(startIndex, startIndex + length)) } @@ -79,13 +79,23 @@ internal object NumericLiteralLocator { } } + // Highlight only 4f when e.g. number is like 4fff if (NUMBER_TYPE_CHARACTERS.any { letters.contains(it) }) { - return number.count { it.isDigit() } + - number.count { NUMBER_START_CHARACTERS.contains(it) } + - NUMBER_ENDING_LETTER_COUNT + var length = 1 // Single letter + length += number.count { it.isDigit() } + length += number.count { NUMBER_START_CHARACTERS.contains(it) } + length += number.count { NUMBER_SPECIAL_CHARACTERS.contains(it) } + if ("e+" in number) length++ + return length } - return number.length + return number.filter { + it.isDigit() || + NUMBER_START_CHARACTERS.contains(it) || + NUMBER_TYPE_CHARACTERS.contains(it) || + NUMBER_SPECIAL_CHARACTERS.contains(it) + + }.length } private fun getLengthOfSubstringFor(number: String, condition: (Char) -> Boolean): Int { diff --git a/src/commonTest/kotlin/dev/snipme/highlights/internal/locator/KeywordLocatorTest.kt b/src/commonTest/kotlin/dev/snipme/highlights/internal/locator/KeywordLocatorTest.kt index db93094..c2d1fa1 100644 --- a/src/commonTest/kotlin/dev/snipme/highlights/internal/locator/KeywordLocatorTest.kt +++ b/src/commonTest/kotlin/dev/snipme/highlights/internal/locator/KeywordLocatorTest.kt @@ -96,4 +96,42 @@ internal class KeywordLocatorTest { assertEquals(0, result.size) } + + @Test + fun `Not returns keywords from single comment`() { + val testCode = """ + // This class is static and should extend another class + """.trimIndent() + val keywords = listOf("static", "class", "extends") + + val result = KeywordLocator.locate(testCode, keywords, listOf(PhraseLocation(0, 55))) + + assertEquals(0, result.size) + } + + @Test + fun `Not returns keywords from multiline comment`() { + val testCode = """ + /* + This class is static and should extend another class + */ + """.trimIndent() + val keywords = listOf("static", "class", "extends") + + val result = KeywordLocator.locate(testCode, keywords, listOf(PhraseLocation(0, 56))) + + assertEquals(0, result.size) + } + + @Test + fun `Not returns keywords from string`() { + val testCode = """ + val text = "This class is static and should extend another class" + """.trimIndent() + val keywords = listOf("static", "class", "extends") + + val result = KeywordLocator.locate(testCode, keywords, listOf(PhraseLocation(0, 54))) + + assertEquals(0, result.size) + } } \ No newline at end of file diff --git a/src/commonTest/kotlin/dev/snipme/highlights/internal/locator/NumericLiteralLocatorTest.kt b/src/commonTest/kotlin/dev/snipme/highlights/internal/locator/NumericLiteralLocatorTest.kt index 89889c1..7aecbcd 100644 --- a/src/commonTest/kotlin/dev/snipme/highlights/internal/locator/NumericLiteralLocatorTest.kt +++ b/src/commonTest/kotlin/dev/snipme/highlights/internal/locator/NumericLiteralLocatorTest.kt @@ -142,4 +142,50 @@ internal class NumericLiteralLocatorTest { assertEquals(0, result.size) } + + @Test + fun `Returns whole location of the all scientific notations`() { + val testCode = """ + 1e+10 + 100e100 + 0.11E-10 + 123.456E+10 + 100_00E10 + 12e+1000 + """.trimIndent() + + val result = NumericLiteralLocator.locate(testCode) + + assertEquals(6, result.size) + assertEquals(PhraseLocation(0, 5), result[0]) + assertEquals(PhraseLocation(6, 13), result[1]) + assertEquals(PhraseLocation(14, 22), result[2]) + assertEquals(PhraseLocation(23, 34), result[3]) + assertEquals(PhraseLocation(35, 44), result[4]) + assertEquals(PhraseLocation(45, 53), result[5]) + } + + @Test + fun `Returns only proper length number with letter`() { + val testCode = """ + 12e+1000 + 12.dp + 12f.d + -2b + 12sss + 0b10000 + 13.22f + """.trimIndent() + + val result = NumericLiteralLocator.locate(testCode) + + assertEquals(7, result.size) + assertEquals(PhraseLocation(0, 8), result[0]) + assertEquals(PhraseLocation(9, 12), result[1]) + assertEquals(PhraseLocation(15, 19), result[2]) + assertEquals(PhraseLocation(21, 23), result[3]) + assertEquals(PhraseLocation(25, 27), result[4]) + assertEquals(PhraseLocation(31, 38), result[5]) + assertEquals(PhraseLocation(39, 45), result[6]) + } } \ No newline at end of file diff --git a/src/commonTest/kotlin/dev/snipme/highlights/internal/locator/StringLocatorTest.kt b/src/commonTest/kotlin/dev/snipme/highlights/internal/locator/StringLocatorTest.kt index 09b5758..e854675 100644 --- a/src/commonTest/kotlin/dev/snipme/highlights/internal/locator/StringLocatorTest.kt +++ b/src/commonTest/kotlin/dev/snipme/highlights/internal/locator/StringLocatorTest.kt @@ -1,6 +1,5 @@ package dev.snipme.highlights.internal.locator -import dev.snipme.highlights.internal.printResults import dev.snipme.highlights.model.PhraseLocation import kotlin.test.Test import kotlin.test.assertEquals