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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## [1.1.0]

### Changed
- Kotlin version to 2.2.0

### Fixed
- keywords found at start and end of the input

## [1.0.0]

### Added
Expand Down
4 changes: 2 additions & 2 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-2.0.20-blue.svg?logo=kotlin)](http://kotlinlang.org)
[![Kotlin](https://img.shields.io/badge/kotlin-2.2.0-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:1.0.0")
implementation("dev.snipme:highlights:1.1.0")
```

## Features ✨
Expand Down
43 changes: 35 additions & 8 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework

apply(from = "publish-root.gradle")

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

group = "dev.snipme"
version = "1.0.0"
version = "1.1.0"

kotlin {
// Android
jvm {
compilations.all {
kotlinOptions.jvmTarget = "1.8"
}
withJava()
testRuns["test"].executionTask.configure {
useJUnitPlatform()
}
}
// iOS

val xcf = XCFramework()
val iosTargets = listOf(iosX64(), iosArm64(), iosSimulatorArm64())

Expand All @@ -46,6 +42,7 @@ kotlin {
browser()
nodejs()
}
@OptIn(ExperimentalWasmDsl::class)
wasmJs()
// Dependencies
sourceSets {
Expand Down Expand Up @@ -124,4 +121,34 @@ signing {
rootProject.ext["signing.password"] as String
)
sign(publishing.publications)
}

tasks.withType<PublishToMavenLocal> {
dependsOn(":signIosSimulatorArm64Publication")
dependsOn(":signIosArm64Publication")
dependsOn(":signIosX64Publication")
dependsOn(":signMacosArm64Publication")
dependsOn(":signMacosX64Publication")
dependsOn(":signJvmPublication")
dependsOn(":signJsPublication")
dependsOn(":signLinuxArm64Publication")
dependsOn(":signLinuxX64Publication")
dependsOn(":signMingwX64Publication")
dependsOn(":signWasmJsPublication")
dependsOn(":signKotlinMultiplatformPublication")
}

tasks.withType<PublishToMavenRepository> {
dependsOn(":signIosSimulatorArm64Publication")
dependsOn(":signIosArm64Publication")
dependsOn(":signIosX64Publication")
dependsOn(":signMacosArm64Publication")
dependsOn(":signMacosX64Publication")
dependsOn(":signJvmPublication")
dependsOn(":signJsPublication")
dependsOn(":signLinuxArm64Publication")
dependsOn(":signLinuxX64Publication")
dependsOn(":signMingwX64Publication")
dependsOn(":signWasmJsPublication")
dependsOn(":signKotlinMultiplatformPublication")
}
4 changes: 3 additions & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
4 changes: 2 additions & 2 deletions publish-root.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ nexusPublishing {
stagingProfileId = sonatypeStagingProfileId
username = ossrhUsername
password = ossrhPassword
nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/"))
snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/"))
nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/"))
snapshotRepositoryUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/content/repositories/snapshots/"))
}
}
}
5 changes: 2 additions & 3 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 "2.0.20"
kotlin("jvm") version "2.2.0"
application
}

Expand All @@ -11,11 +11,10 @@ version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
mavenLocal()
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
}

dependencies {
implementation("dev.snipme:highlights:1.0.0")
implementation("dev.snipme:highlights:1.1.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")

testImplementation(kotlin("test"))
Expand Down
77 changes: 70 additions & 7 deletions src/commonMain/kotlin/dev/snipme/highlights/internal/Extensions.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
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
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.coroutines.Job
import kotlin.coroutines.cancellation.CancellationException

fun List<CodeHighlight>.toJson(): String {
Expand All @@ -15,7 +18,7 @@ fun String.phraseLocationSetFromJson(): Set<PhraseLocation> {
return Json.decodeFromString(this)
}

inline operator fun <E> Set<E>.get(i: Int): E? {
operator fun <E> Set<E>.get(i: Int): E? {
this.forEachIndexed { index, t ->
if (i == index) return t
}
Expand Down Expand Up @@ -74,15 +77,75 @@ fun String.isIndependentPhrase(
if (index == code.lastIndex) return true
if (code.length == this.length) return true

val charBefore = code[maxOf(index - 1, 0)]
// Token is at start of the code
val charAfter = code[minOf(index + this.length, code.lastIndex)]

if (index == 0) {
return charAfter.isDigit().not() && charAfter.isLetter().not()
return charAfter.isDigit().not() && charAfter.isLetter().not() && charAfter != '_'
}

// Token is at end of the code
val charBefore = code[maxOf(index - 1, 0)]
if (index + this.length == code.length) {
return (charBefore.isLetter().not() && charBefore != '_') || isAfterNumericSuffix(code, index)
}

// Token is in the middle of the code
return ((charBefore.isLetter().not() || isAfterNumericSuffix(code, index)) &&
charAfter.isDigit().not() && charAfter.isLetter().not() && charAfter != '_')
}

private fun String.isAfterNumericSuffix(code: String, keywordIndex: Int): Boolean {
if (keywordIndex == 0) return false

val charBefore = code[keywordIndex - 1]

// Check if the character before is a valid numeric suffix
val validSuffixes = NUMBER_TYPE_CHARACTERS
if (charBefore !in validSuffixes) return false

// Walk backwards to validate the number structure
var i = keywordIndex - 2
var hasDigit = false
var hasDot = false

while (i >= 0) {
val char = code[i]

when {
char.isDigit() -> {
hasDigit = true
i--
}
char == '.' -> {
if (hasDot) return false
hasDot = true
i--
}
char == '-' -> {
if (i == 0) {
break
} else {
val prevChar = code[i - 1]
if (prevChar.isLetterOrDigit() || prevChar == '_') {
return false
} else {
break
}
}
}
char == '_' -> {
i--
}
char.isLetter() -> {
return false
}
else -> {
break
}
}
}

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

fun Set<PhraseLocation>.toRangeSet(): Set<IntRange> =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ internal object KeywordLocator {
ignoreRanges: Set<IntRange> = emptySet(),
): Set<PhraseLocation> {
val locations = mutableSetOf<PhraseLocation>()
val foundKeywords = findKeywords(code, keywords)

foundKeywords.forEach { keyword ->
keywords.forEach { keyword ->
val indices = code
.indicesOf(keyword)
.filterNot { index -> ignoreRanges.any { index in it } }
Expand All @@ -28,15 +27,4 @@ internal object KeywordLocator {

return locations
}

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
.filter { it.isNotBlank() } // Remove empty
.map { it.trim() } // Remove whitespaces from phrase
.map { it.lowercase() } // Standardize
.filter { it in keywords } // Get supported
.toSet() // Filter duplicates
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import dev.snipme.highlights.internal.indicesOf
import dev.snipme.highlights.model.PhraseLocation

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('_')
public val NUMBER_TYPE_CHARACTERS = listOf('e', 'u', 'f', 'l')

internal object NumericLiteralLocator {

Expand Down Expand Up @@ -67,8 +67,6 @@ internal object NumericLiteralLocator {
}

private fun calculateNumberLength(number: String): Int {
val letters = number.filter { it.isLetter() }

if (number.startsWith("0x")) {
return getLengthOfSubstringFor(number) {
it.isDigit() || HEX_NUMBER_CHARACTERS.contains(it)
Expand All @@ -81,23 +79,47 @@ internal object NumericLiteralLocator {
}
}

// Highlight only 4f when e.g. number is like 4fff
if (NUMBER_TYPE_CHARACTERS.any { letters.contains(it) }) {
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
var length = 0
var foundE = false
var foundSignAfterE = false
var foundDot = false
var suffixCount = 0
val maxSuffixes = 1

for (i in number.indices) {
val char = number[i]
when {
char.isDigit() -> {
length++
}
((char == '-' && i == 0) || char == '_') -> {
length++
}
char == '.' && !foundDot -> {
foundDot = true
length++
}
(char.lowercaseChar() == 'e' && !foundE) -> {
foundE = true
length++
}
((char == '+' || char == '-') && foundE && !foundSignAfterE) -> {
foundSignAfterE = true
length++
}
NUMBER_TYPE_CHARACTERS.contains(char) -> {
if (suffixCount < maxSuffixes) {
length++
suffixCount++
} else {
break
}
}
else -> break
}
}

return number.filter {
it.isDigit() ||
NUMBER_START_CHARACTERS.contains(it) ||
NUMBER_TYPE_CHARACTERS.contains(it) ||
NUMBER_SPECIAL_CHARACTERS.contains(it)

}.length
return length
}

private fun getLengthOfSubstringFor(number: String, condition: (Char) -> Boolean): Int {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1312,3 +1312,26 @@ val longJavaCode = """
}
}
""".trimIndent()

val longPythonCode = """
import polars as pl

def transform_dataframe(df: pl.DataFrame, max_seq_len: int, end_action_value: int) -> pl.DataFrame:
end_val = pl.lit(end_action_value)
max_len = pl.lit(max_seq_len)
df_with_ends = df.with_columns(
end_indices=pl.col("actionType").list.eval(
pl.int_range(0, pl.len()).filter(pl.element() == end_val)
)
)
df_exploded = df_with_ends.explode("end_indices")
start_offset = (pl.col("end_indices") + 1 - max_len).clip(lower_bound=0)
slice_len = pl.col("end_indices") - start_offset + 1
list_cols = ["actionType", "engagementTimeMs", "actionTweetIds"]
for col in list_cols:
df_exploded = df_exploded.with_columns(
pl.col(col).list.slice(start_offset, slice_len).alias(col)
)
result = df_exploded.select(["userId", "actionType", "engagementTimeMs", "actionTweetIds"])
return result
""".trimIndent()
Loading