Skip to content

Commit

Permalink
Issue 6 percent escaping (#7)
Browse files Browse the repository at this point in the history
* Issue-6: Fixed capture of %% immediately after an argument match when annotated/spanned
* Updated the version to 1.0.1
  • Loading branch information
brianwernick authored Jun 25, 2024
1 parent fb493e9 commit b29c8cc
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 8 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ repositories {
dependencies {
//...
implementation 'com.devbrackets.android:annores:1.0.0'
implementation 'com.devbrackets.android:annores:1.0.1'
}
```

Expand All @@ -51,7 +51,7 @@ fun AnAnnotatedComposable() {

# License

Copyright 2023 Brian Wernick
Copyright 2024 Brian Wernick

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,16 @@ object SpannedFormatter {
formatArgs: Array<out Any>
): SpannableStringBuilder {
val state = FormatState(locale, formatArgs)

FORMAT_REGEX.findAll(this, 0).forEach { match ->
replace(state, match)
}
var startIndex = 0

// Manually iterate over the matches for 2 reasons:
// 1. The `FORMAT_REGEX.findAll()` wasn't correctly capturing all cases (e.g. %1$d%% only caught the first match)
// 2. Use the `startIndex` so that a replacement of another format doesn't work (e.g. %d -> %d) since that would cause a cycle
do {
val match = FORMAT_REGEX.find(this, startIndex)?.also {
startIndex = replace(state, it)
}
} while (match != null)

return this
}
Expand All @@ -87,12 +93,14 @@ object SpannedFormatter {
*
* @param state The [FormatState] to use for replacing the format placeholder from [match]
* @param match The [MatchResult] holding a match from the [FORMAT_REGEX] which should be replaced
*
* @return The end index of the replacement
*/
@Suppress("MoveVariableDeclarationIntoWhen")
private fun SpannableStringBuilder.replace(
state: FormatState,
match: MatchResult
) {
): Int {
val argIndex = match.groupValues[1]
val format = match.groupValues[2]
val conversion = match.groupValues[3]
Expand All @@ -104,6 +112,7 @@ object SpannedFormatter {
}

replace(match.range.first, match.range.last + 1, replacementValue)
return match.range.first + replacementValue.length
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,19 @@ class SpannedFormatterTest {
Assert.assertEquals("A string %", actual.toString())
}

@Test
fun formatPercentReplacement() {
// Given
val locale = Locale("en", "us")
val spanned = SpannedString("%1\$d%%")

// When
val actual = SpannedFormatter.format(locale, spanned, 25)

// Then
Assert.assertEquals("25%", actual.toString())
}

@Test
fun formatNewLine() {
// Given
Expand Down
2 changes: 1 addition & 1 deletion libraryInfo.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ GROUP_ID = com.devbrackets.android

VERSION_MAJOR = 1
VERSION_MINOR = 0
VERSION_PATCH = 0
VERSION_PATCH = 1

0 comments on commit b29c8cc

Please sign in to comment.