Skip to content

Commit

Permalink
fix a possible crash if search text result is at a position after var…
Browse files Browse the repository at this point in the history
…iables or functions
  • Loading branch information
sunny-chung committed Dec 12, 2023
1 parent 870f853 commit 6ba5d81
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.onPreviewKeyEvent
import androidx.compose.ui.input.key.type
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.font.FontFamily
Expand Down Expand Up @@ -192,17 +193,18 @@ fun CodeEditorView(
isCaseSensitive = false,
isWholeWord = false
)) }
var searchPattern by rememberLast(searchText, searchOptions) { mutableStateOf<Regex?>(null) }
val scrollState = rememberScrollState()
val searchBarFocusRequester = remember { FocusRequester() }
val textFieldFocusRequester = remember { FocusRequester() }

var searchResultViewIndex by rememberLast(text) { mutableStateOf(0) }
var lastSearchResultViewIndex by rememberLast(text) { mutableStateOf(0) }
var searchResultRanges by rememberLast(text, searchText, searchOptions) { mutableStateOf<List<IntRange>?>(null) }
var searchResultRanges by rememberLast(text, searchPattern) { mutableStateOf<List<IntRange>?>(null) }
var textLayoutResult by remember { mutableStateOf<TextLayoutResult?>(null) }
var textFieldSize by remember { mutableStateOf<IntSize?>(null) }

if (searchText.isNotEmpty() && searchResultRanges == null) {
if (searchText.isNotEmpty() && searchPattern == null) {
val regexOption = if (searchOptions.isCaseSensitive) setOf() else setOf(RegexOption.IGNORE_CASE)
try {
val pattern = if (searchOptions.isRegex) {
Expand All @@ -212,7 +214,7 @@ fun CodeEditorView(
} else {
Pattern.quote(searchText).toRegex(regexOption)
}
searchResultRanges = pattern.findAll(textValue.text).map { it.range }.sortedBy { it.start }.toList()
searchPattern = pattern
searchResultViewIndex = 0
lastSearchResultViewIndex = -1
} catch (_: Throwable) {}
Expand All @@ -237,14 +239,28 @@ fun CodeEditorView(
}

if (isSearchVisible) {
if (!searchResultRanges.isNullOrEmpty()) {
if (!searchResultRanges.isNullOrEmpty() && searchPattern != null) {
visualTransformations += SearchHighlightTransformation(
highlightRanges = searchResultRanges!!,
searchPattern = searchPattern!!,
currentIndex = searchResultViewIndex,
colours = themeColours,
)
}

if (searchPattern != null && searchResultRanges == null) {
try {
searchResultRanges = searchPattern!!
.findAll(
MultipleVisualTransformation(visualTransformations)
.filter(AnnotatedString(textValue.text))
.text.text
)
.map { it.range }
.sortedBy { it.start }
.toList()
} catch (_: Throwable) {}
}

if (lastSearchResultViewIndex != searchResultViewIndex && textLayoutResult != null && textFieldSize != null && searchResultRanges != null) {
lastSearchResultViewIndex = searchResultViewIndex
val index = searchResultRanges!!.getOrNull(searchResultViewIndex)?.start
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import androidx.compose.ui.text.input.TransformedText
import androidx.compose.ui.text.input.VisualTransformation
import com.sunnychung.application.multiplatform.hellohttp.ux.local.AppColor

class SearchHighlightTransformation(private val highlightRanges: List<IntRange>, private val currentIndex: Int?, colours: AppColor) : VisualTransformation {
class SearchHighlightTransformation(private val searchPattern: Regex, private val currentIndex: Int?, colours: AppColor) : VisualTransformation {
val highlightStyle = SpanStyle(background = colours.backgroundInputFieldHighlight)
val currentHighlightStyle = SpanStyle(background = colours.backgroundInputFieldHighlightEmphasize)

override fun filter(text: AnnotatedString): TransformedText {
val s = text.text
// highlightRanges must be recalculated at this point, because text offset can be changed by other VisualTransformation
val highlightRanges = searchPattern.findAll(s).map { it.range }.sortedBy { it.start }.toList()
val spans = highlightRanges.mapIndexed { index, it ->
val style = if (index == currentIndex) currentHighlightStyle else highlightStyle
AnnotatedString.Range(style, it.start, it.endInclusive + 1)
Expand Down

0 comments on commit 6ba5d81

Please sign in to comment.