Skip to content

Commit

Permalink
update BigMonospaceText transformation listener to be fired before de…
Browse files Browse the repository at this point in the history
…letion, so that it can determine how to transform
  • Loading branch information
sunny-chung committed Sep 22, 2024
1 parent 7600310 commit c7902c5
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ infix fun IntRange.intersect(other: IntRange): IntRange {
return from .. to
}

infix fun IntRange.hasIntersectWith(other: IntRange): Boolean {
return !intersect(other).isEmpty()
}

fun IntRange.toNonEmptyRange(): IntRange {
if (length <= 0) {
return start .. start
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -430,18 +430,42 @@ private fun CoreBigMonospaceText(
.sum()
}

fun onValueChange(eventType: BigTextChangeEventType, changeStartIndex: Int, changeEndExclusiveIndex: Int) {
viewState.lastVisibleRow = minOf(viewState.lastVisibleRow, transformedText.lastRowIndex)

viewState.version = Random.nextLong()
val event = BigTextChangeEvent(
fun generateChangeEvent(eventType: BigTextChangeEventType, changeStartIndex: Int, changeEndExclusiveIndex: Int) : BigTextChangeEvent {
return BigTextChangeEvent(
changeId = viewState.version,
bigText = text,
eventType = eventType,
changeStartIndex = changeStartIndex,
changeEndExclusiveIndex = changeEndExclusiveIndex,
)
(textTransformation as? IncrementalTextTransformation<Any?>)?.onTextChange(event, transformedText, transformedState)
}

fun onValuePreChange(eventType: BigTextChangeEventType, changeStartIndex: Int, changeEndExclusiveIndex: Int) {
if (eventType == BigTextChangeEventType.Delete) {
viewState.version = Random.nextLong()
val event = generateChangeEvent(eventType, changeStartIndex, changeEndExclusiveIndex)

// invoke textTransformation listener before deletion, so that it knows what will be deleted and transform accordingly
(textTransformation as? IncrementalTextTransformation<Any?>)?.onTextChange(
event,
transformedText,
transformedState
)
}
}

fun onValuePostChange(eventType: BigTextChangeEventType, changeStartIndex: Int, changeEndExclusiveIndex: Int) {
viewState.lastVisibleRow = minOf(viewState.lastVisibleRow, transformedText.lastRowIndex)

viewState.version = Random.nextLong()
val event = generateChangeEvent(eventType, changeStartIndex, changeEndExclusiveIndex)
if (eventType != BigTextChangeEventType.Delete) {
(textTransformation as? IncrementalTextTransformation<Any?>)?.onTextChange(
event,
transformedText,
transformedState
)
}
onTextChange(event)
}

Expand All @@ -454,8 +478,10 @@ private fun CoreBigMonospaceText(
viewState.transformedSelection = IntRange.EMPTY
}
val insertPos = viewState.cursorIndex
onValuePreChange(BigTextChangeEventType.Insert, insertPos, insertPos + textInput.length)
text.insertAt(insertPos, textInput)
onValueChange(BigTextChangeEventType.Insert, insertPos, insertPos + textInput.length)
onValuePostChange(BigTextChangeEventType.Insert, insertPos, insertPos + textInput.length)
// update cursor after invoking listeners, because a transformation or change may take place
viewState.cursorIndex = minOf(text.length, insertPos + textInput.length)
viewState.updateTransformedCursorIndexByOriginal(transformedText)
viewState.transformedSelectionStart = viewState.transformedCursorIndex
Expand All @@ -467,15 +493,18 @@ private fun CoreBigMonospaceText(
when (direction) {
TextFBDirection.Forward -> {
if (cursor + 1 <= text.length) {
onValuePreChange(BigTextChangeEventType.Delete, cursor, cursor + 1)
text.delete(cursor, cursor + 1)
onValueChange(BigTextChangeEventType.Delete, cursor, cursor + 1)
onValuePostChange(BigTextChangeEventType.Delete, cursor, cursor + 1)
return true
}
}
TextFBDirection.Backward -> {
if (cursor - 1 >= 0) {
onValuePreChange(BigTextChangeEventType.Delete, cursor - 1, cursor)
text.delete(cursor - 1, cursor)
onValueChange(BigTextChangeEventType.Delete, cursor - 1, cursor)
onValuePostChange(BigTextChangeEventType.Delete, cursor - 1, cursor)
// update cursor after invoking listeners, because a transformation or change may take place
viewState.cursorIndex = maxOf(0, cursor - 1)
viewState.updateTransformedCursorIndexByOriginal(transformedText)
viewState.transformedSelectionStart = viewState.transformedCursorIndex
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.sunnychung.application.multiplatform.hellohttp.ux.transformation.incremental

import com.sunnychung.application.multiplatform.hellohttp.extension.hasIntersectWith
import com.sunnychung.application.multiplatform.hellohttp.extension.intersect
import com.sunnychung.application.multiplatform.hellohttp.util.log
import com.sunnychung.application.multiplatform.hellohttp.ux.bigtext.BigText
import com.sunnychung.application.multiplatform.hellohttp.ux.bigtext.BigTextChangeEvent
Expand All @@ -10,7 +12,9 @@ import com.sunnychung.application.multiplatform.hellohttp.ux.bigtext.Incremental
import com.sunnychung.application.multiplatform.hellohttp.ux.bigtext.TextFBDirection

class EnvironmentVariableIncrementalTransformation : IncrementalTextTransformation<Unit> {
private val variableRegex = "\\$\\{\\{([^{}]{1,20})\\}\\}".toRegex()
val processLengthLimit = 30

private val variableRegex = "\\$\\{\\{([^{}]{1,$processLengthLimit})\\}\\}".toRegex()

override fun initialize(text: BigText, transformer: BigTextTransformer) {
// if (true) return
Expand All @@ -24,32 +28,66 @@ class EnvironmentVariableIncrementalTransformation : IncrementalTextTransformati
}

override fun onTextChange(change: BigTextChangeEvent, transformer: BigTextTransformer, context: Unit) {
// TODO handle delete
if (change.eventType != BigTextChangeEventType.Insert) return
// TODO handle multiple matches (e.g. triggered by pasting text)

val originalText = change.bigText
originalText.findPositionByPattern(change.changeStartIndex, change.changeEndExclusiveIndex, "}}", TextFBDirection.Forward).also {
log.d { "EnvironmentVariableIncrementalTransformation search end end=$it" }
}?.let {
val anotherBracket = originalText.findPositionByPattern(it - 20, it - 1, "\${{", TextFBDirection.Backward)
log.d { "EnvironmentVariableIncrementalTransformation search end start=$it" }
if (anotherBracket != null) {
val variableName = originalText.substring(anotherBracket + "\${{".length, it)
log.d { "EnvironmentVariableIncrementalTransformation add '$variableName'" }
transformer.replace(anotherBracket until it + "}}".length, createSpan(variableName), BigTextTransformOffsetMapping.WholeBlock)
when (change.eventType) {
BigTextChangeEventType.Insert -> {
// Find if there is pattern match ("\${{" or "}}") in the inserted text.
// If yes, try to locate the pair within `processLengthLimit`, and make desired replacement.

originalText.findPositionByPattern(change.changeStartIndex, change.changeEndExclusiveIndex, "}}", TextFBDirection.Forward).also {
log.d { "EnvironmentVariableIncrementalTransformation search end end=$it" }
}?.let {
val anotherBracket = originalText.findPositionByPattern(it - processLengthLimit, it - 1, "\${{", TextFBDirection.Backward)
log.d { "EnvironmentVariableIncrementalTransformation search end start=$it" }
if (anotherBracket != null) {
val variableName = originalText.substring(anotherBracket + "\${{".length, it)
log.d { "EnvironmentVariableIncrementalTransformation add '$variableName'" }
transformer.replace(anotherBracket until it + "}}".length, createSpan(variableName), BigTextTransformOffsetMapping.WholeBlock)
}
}
originalText.findPositionByPattern(change.changeStartIndex, change.changeEndExclusiveIndex, "\${{", TextFBDirection.Forward).also {
log.d { "EnvironmentVariableIncrementalTransformation search start start=$it" }
}?.let {
val anotherBracket = originalText.findPositionByPattern(it + "\${{".length, it + processLengthLimit, "}}", TextFBDirection.Forward)
log.d { "EnvironmentVariableIncrementalTransformation search start end=$it" }
if (anotherBracket != null) {
val variableName = originalText.substring(it + "\${{".length, anotherBracket)
log.d { "EnvironmentVariableIncrementalTransformation add '$variableName'" }
transformer.replace(it until anotherBracket + "}}".length, createSpan(variableName), BigTextTransformOffsetMapping.WholeBlock)
}
}
}
}
originalText.findPositionByPattern(change.changeStartIndex, change.changeEndExclusiveIndex, "\${{", TextFBDirection.Forward).also {
log.d { "EnvironmentVariableIncrementalTransformation search start start=$it" }
}?.let {
val anotherBracket = originalText.findPositionByPattern(it + "\${{".length, it + 20, "}}", TextFBDirection.Forward)
log.d { "EnvironmentVariableIncrementalTransformation search start end=$it" }
if (anotherBracket != null) {
val variableName = originalText.substring(it + "\${{".length, anotherBracket)
log.d { "EnvironmentVariableIncrementalTransformation add '$variableName'" }
transformer.replace(it until anotherBracket + "}}".length, createSpan(variableName), BigTextTransformOffsetMapping.WholeBlock)

BigTextChangeEventType.Delete -> {
// Find if there is pattern match ("\${{" or "}}") in the inserted text.
// If yes, try to locate the pair within `processLengthLimit`, and remove the transformation by restoring them to original.

val changeRange = change.changeStartIndex until change.changeEndExclusiveIndex

originalText.findPositionByPattern(change.changeStartIndex - processLengthLimit, change.changeEndExclusiveIndex, "}}", TextFBDirection.Backward)
?.takeIf { (it until it + "}}".length) hasIntersectWith changeRange }
?.let {
originalText.findPositionByPattern(it - processLengthLimit, it - 1, "\${{", TextFBDirection.Backward)
?.let { anotherStart ->
log.d { "EnvironmentVariableIncrementalTransformation delete A" }
transformer.restoreToOriginal(anotherStart until it + "}}".length)
}
}
originalText.findPositionByPattern(change.changeStartIndex - processLengthLimit, change.changeEndExclusiveIndex, "\${{", TextFBDirection.Forward)
?.takeIf { (it until it + "\${{".length) hasIntersectWith changeRange }
?.let {
originalText.findPositionByPattern(it + "\${{".length, it + processLengthLimit, "}}", TextFBDirection.Forward)
?.let { anotherStart ->
log.d { "EnvironmentVariableIncrementalTransformation delete B" }
transformer.restoreToOriginal(it until anotherStart + "}}".length)
}
}
}
}


}

fun createSpan(variableName: String): String { // TODO change to AnnotatedString
Expand Down

0 comments on commit c7902c5

Please sign in to comment.