Skip to content
Merged
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
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
## [0.9.0]

### Added
- Atom One theme. Thanks Nek-12!
- languages snippet tests

### Fixed
- keyword highlighted in oneline comment
- keyword highlighted inside other word

### Changed
- Kotlin version to 1.9.23

## [0.8.1]

### Added
Expand Down
44 changes: 37 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.22-blue.svg?logo=kotlin)](http://kotlinlang.org)
[![Kotlin](https://img.shields.io/badge/kotlin-1.9.23-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
Expand All @@ -15,7 +15,7 @@ repositories {
```

```shell
implementation("dev.snipme:highlights:0.8.1")
implementation("dev.snipme:highlights:0.9.0")
```

## Features ✨
Expand Down Expand Up @@ -97,6 +97,7 @@ The library comes with predefined syntax coloring themes available in `SyntaxThe
<th>Notepad</th>
<th>Matrix</th>
<th>Pastel</th>
<th>Atom One</th>
<tr>
<td>

Expand Down Expand Up @@ -157,6 +158,19 @@ The library comes with predefined syntax coloring themes available in `SyntaxThe
- ![#888A85](https://placehold.co/15x15/888A85/888A85.png) Multiline Comment
- ![#CB956D](https://placehold.co/15x15/CB956D/CB956D.png) Punctuation
- ![#CB956D](https://placehold.co/15x15/CB956D/CB956D.png) Mark
</td>
<td>

- ![#DFDEE0](https://placehold.co/15x15/BBBBBB/BBBBBB.png) Code
- ![#729FCF](https://placehold.co/15x15/D55FDE/D55FDE.png) Keyword
- ![#93CF55](https://placehold.co/15x15/89CA78/89CA78.png) String
- ![#8AE234](https://placehold.co/15x15/D19A66/D19A66.png) Literal
- ![#888A85](https://placehold.co/15x15/5C6370/5C6370.png) Comment
- ![#5DB895](https://placehold.co/15x15/E5C07B/E5C07B.png) Metadata
- ![#888A85](https://placehold.co/15x15/5C6370/5C6370.png) Multiline Comment
- ![#CB956D](https://placehold.co/15x15/EF596F/EF596F.png) Punctuation
- ![#CB956D](https://placehold.co/15x15/2BBAC5/2BBAC5.png) Mark

</td>
</tr>
</table>
Expand All @@ -169,6 +183,7 @@ The library comes with predefined syntax coloring themes available in `SyntaxThe
<th>Notepad</th>
<th>Matrix</th>
<th>Pastel</th>
<th>Atom One</th>
<tr>
<td>

Expand Down Expand Up @@ -229,6 +244,19 @@ The library comes with predefined syntax coloring themes available in `SyntaxThe
- ![#888A85](https://placehold.co/15x15/888A85/888A85.png) Multiline Comment
- ![#CB956D](https://placehold.co/15x15/CB956D/CB956D.png) Punctuation
- ![#CB956D](https://placehold.co/15x15/CB956D/CB956D.png) Mark
</td>
<td>

- ![#DFDEE0](https://placehold.co/15x15/383A42/383A42.png) Code
- ![#729FCF](https://placehold.co/15x15/A626A4/A626A4.png) Keyword
- ![#93CF55](https://placehold.co/15x15/50A14F/50A14F.png) String
- ![#8AE234](https://placehold.co/15x15/986801/986801.png) Literal
- ![#888A85](https://placehold.co/15x15/A1A1A1/A1A1A1.png) Comment
- ![#5DB895](https://placehold.co/15x15/C18401/C18401.png) Metadata
- ![#888A85](https://placehold.co/15x15/A1A1A1/A1A1A1.png) Multiline Comment
- ![#CB956D](https://placehold.co/15x15/E45649/E45649.png) Punctuation
- ![#CB956D](https://placehold.co/15x15/526FFF/526FFF.png) Mark

</td>
</tr>
</table>
Expand Down Expand Up @@ -265,14 +293,16 @@ If your project uses this code, please write me or add your info
</tr>
<tr>
<td>Application</td>
<td>
<a href="https://play.google.com/store/apps/details?id=pl.tkadziolka.snipbook">SnippLog</a>
</td>
<td> <a href="https://play.google.com/store/apps/details?id=pl.tkadziolka.snipbook">SnippLog</a> </td>
</tr>
<tr>
<td>Application</td>
<td> <a href="https://opensource.respawn.pro/FlowMVI/sample/">FlowMVI Sample</a> </td>
</tr>
</table>

## TODO 🚧
- [ ] Migrate some lists to sets
- [X] Migrate some lists to sets
- [ ] Optimize code analysis
- [ ] Add more themes and languages
- [ ] Support italic and underline text style
Expand All @@ -289,7 +319,7 @@ Then make sure:
License 🖋️
=======

Copyright 2023 Tomasz Kądziołka.
Copyright 2023-2024 Tomasz Kądziołka.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
5 changes: 3 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
apply(from = "publish-root.gradle")

plugins {
kotlin("multiplatform") version "1.9.22"
kotlin("multiplatform") version "1.9.23"
id("maven-publish")
id("io.github.gradle-nexus.publish-plugin") version "1.3.0"
id("signing")
}

group = "dev.snipme"
version = "0.8.1"
version = "0.9.0"

kotlin {
// Android
Expand Down Expand Up @@ -36,6 +36,7 @@ kotlin {
browser()
nodejs()
}
wasmJs()
// Dependencies
sourceSets {
val commonTest by getting {
Expand Down
4 changes: 2 additions & 2 deletions sample/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
kotlin("jvm") version "1.9.22"
kotlin("jvm") version "1.9.23"
application
}

Expand Down Expand Up @@ -31,5 +31,5 @@ application {
}

dependencies {
implementation("dev.snipme:highlights:0.7.0")
implementation(":highlights")
}
1 change: 0 additions & 1 deletion sample/src/main/kotlin/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ val sampleClass = """
}
}
""".trimIndent()

fun main() {
println("### HIGHLIGHTS ###")
println()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,15 @@ internal object CodeAnalyzer {
PHP -> analyzeCodeWithKeywords(code, PHP_KEYWORDS)
}

private fun analyzeCodeWithKeywords(code: String, keywords: List<String>): CodeStructure {
private fun analyzeCodeWithKeywords(code: String, keywords: Set<String>): CodeStructure {
val comments = CommentLocator.locate(code)
val multiLineComments = MultilineCommentLocator.locate(code)
val strings = StringLocator.locate(code)
val commentRanges = (comments + multiLineComments).toRangeSet()

val plainTextRanges = comments + multiLineComments + strings
val strings = StringLocator.locate(code, commentRanges)
val plainTextRanges = (comments + multiLineComments + strings).toRangeSet()

// TODO Apply ignored ranges to other locators
return CodeStructure(
marks = MarkLocator.locate(code),
punctuations = PunctuationLocator.locate(code),
Expand Down
27 changes: 24 additions & 3 deletions src/commonMain/kotlin/dev/snipme/highlights/internal/Extensions.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
package dev.snipme.highlights.internal

import dev.snipme.highlights.model.PhraseLocation

inline operator fun <E> Set<E>.get(i: Int): E? {
this.forEachIndexed { index, t ->
if (i == index) return t
}

return null
}

fun String.indicesOf(
phrase: String,
): Set<Int> {
Expand Down Expand Up @@ -42,18 +52,29 @@ fun String.lengthToEOF(start: Int = 0): Int {
return endIndex - start
}

// TODO Create unit tests for this
// Sometimes keyword can be found in the middle of word.
// This returns information if index points only to the keyword
fun String.isIndependentPhrase(
code: String,
index: Int,
): Boolean {
if (index == 0) return true
if (index == code.lastIndex) return true
if (code.length == this.length) return true

val charBefore = code[maxOf(index - 1, 0)]
val charAfter = code[minOf(index + this.length, code.lastIndex)]

return charBefore.isLetter().not() && charAfter.isDigit().not()
if (index == 0) {
return charAfter.isDigit().not() && charAfter.isLetter().not()
}

return charBefore.isLetter().not() &&
charAfter.isDigit().not() && (charAfter == code.last() || charAfter.isLetter().not())
}

fun Set<PhraseLocation>.toRangeSet(): Set<IntRange> =
this.map { IntRange(it.start, it.end) }.toSet()

operator fun IntRange.contains(range: IntRange): Boolean {
return range.first >= this.first && range.last <= this.last
}
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,6 @@ internal object SyntaxTokens {
val PUNCTUATION_CHARACTERS = listOf(",", ".", ":", ";")
val MARK_CHARACTERS = listOf("(", ")", "=", "{", "}", "<", ">", "-", "+", "[", "]", "|", "&")

private fun String.toTokenList() = trimIndent().split(",")
private fun String.toTokenList() = trimIndent().split(",").toSet()
}

Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import dev.snipme.highlights.internal.indicesOf

internal object AnnotationLocator {

fun locate(code: String): List<PhraseLocation> {
fun locate(code: String): Set<PhraseLocation> {
val foundAnnotations = emptyList<String>()
val locations = mutableSetOf<PhraseLocation>()
code.split(*TOKEN_DELIMITERS.toTypedArray())
Expand All @@ -28,6 +28,6 @@ internal object AnnotationLocator {
}
}

return locations.toList()
return locations.toSet()
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package dev.snipme.highlights.internal.locator

import dev.snipme.highlights.model.PhraseLocation
import dev.snipme.highlights.internal.SyntaxTokens.COMMENT_DELIMITERS
import dev.snipme.highlights.internal.indicesOf
import dev.snipme.highlights.internal.lengthToEOF
import dev.snipme.highlights.model.PhraseLocation

internal object CommentLocator {

fun locate(code: String): List<PhraseLocation> {
fun locate(code: String): Set<PhraseLocation> {
val locations = mutableListOf<PhraseLocation>()
val indices = mutableListOf<Int>()
COMMENT_DELIMITERS.forEach { delimiter ->
Expand All @@ -18,6 +18,7 @@ internal object CommentLocator {
val end = start + code.lengthToEOF(start)
locations.add(PhraseLocation(start, end))
}
return locations

return locations.toSet()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,27 @@ internal object KeywordLocator {

fun locate(
code: String,
keywords: List<String>,
ignoreRanges: List<PhraseLocation> = emptyList(),
): List<PhraseLocation> {
val locations = mutableListOf<PhraseLocation>()
keywords: Set<String>,
ignoreRanges: Set<IntRange> = emptySet(),
): Set<PhraseLocation> {
val locations = mutableSetOf<PhraseLocation>()
val foundKeywords = findKeywords(code, keywords)

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 ->
foundKeywords.forEach { keyword ->
val indices = code
.indicesOf(keyword)
.filterNot { index -> ignoreRanges.any { index in it } }
.filter { keyword.isIndependentPhrase(code, it) }

indices.forEach { index ->
locations.add(PhraseLocation(index, index + keyword.length))
}
}

return locations.toList()
return locations
}

private fun findKeywords(code: String, keywords: List<String>): Set<String> =
private fun findKeywords(code: String, keywords: Set<String>): Set<String> =
TOKEN_DELIMITERS.toTypedArray().let { delimiters ->
code.split(*delimiters, ignoreCase = true) // Split into words
.asSequence() // Reduce amount of operations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import dev.snipme.highlights.internal.indicesOf
import dev.snipme.highlights.model.PhraseLocation

internal object MarkLocator {
fun locate(code: String): List<PhraseLocation> {
fun locate(code: String): Set<PhraseLocation> {
val locations = mutableListOf<PhraseLocation>()
code.asSequence()
.toSet()
Expand All @@ -16,6 +16,6 @@ internal object MarkLocator {
}
}

return locations
return locations.toSet()
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package dev.snipme.highlights.internal.locator

import dev.snipme.highlights.model.PhraseLocation
import dev.snipme.highlights.internal.SyntaxTokens.MULTILINE_COMMENT_DELIMITERS
import dev.snipme.highlights.internal.indicesOf
import dev.snipme.highlights.model.PhraseLocation

private const val START_INDEX = 0

internal object MultilineCommentLocator {

fun locate(code: String): List<PhraseLocation> {
fun locate(code: String): Set<PhraseLocation> {
val locations = mutableListOf<PhraseLocation>()
val comments = mutableListOf<Pair<Int, Int>>()
val startIndices = mutableListOf<Int>()
Expand All @@ -30,6 +30,6 @@ internal object MultilineCommentLocator {
locations.add(PhraseLocation(start, end))
}

return locations
return locations.toSet()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ private val NUMBER_SPECIAL_CHARACTERS = listOf('_')

internal object NumericLiteralLocator {

fun locate(code: String): List<PhraseLocation> {
fun locate(code: String): Set<PhraseLocation> {
return findDigitIndices(code)
}

private fun findDigitIndices(code: String): List<PhraseLocation> {
private fun findDigitIndices(code: String): Set<PhraseLocation> {
val foundPhrases = mutableSetOf<String>()
val locations = mutableSetOf<PhraseLocation>()

Expand Down Expand Up @@ -45,7 +45,7 @@ internal object NumericLiteralLocator {
foundPhrases.add(number)
}

return locations.toList()
return locations.toSet()
}

// Returns if given index is the beginning of word (there is no letter before)
Expand Down
Loading