View test reports →

Coverage Summary for Class: TextHighlightUtilKt (dev.skymansandy.wiretap.helper.util)

Class Class, % Method, % Branch, % Line, % Instruction, %
TextHighlightUtilKt 100% (1/1) 100% (1/1) 91.7% (11/12) 100% (20/20) 99.2% (128/129)


 /*
  * Copyright (c) 2026 skymansandy. All rights reserved.
  */
 
 package dev.skymansandy.wiretap.helper.util
 
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.text.AnnotatedString
 import androidx.compose.ui.text.SpanStyle
 import androidx.compose.ui.text.buildAnnotatedString
 import androidx.compose.ui.text.withStyle
 import dev.skymansandy.wiretap.ui.theme.WiretapColors
 
 internal fun highlightText(
     text: String,
     query: String,
     activeRange: IntRange? = null,
 ): AnnotatedString {
     if (query.isBlank()) return AnnotatedString(text)
 
     return buildAnnotatedString {
         var cursor = 0
         // Scan the original text rather than a lowercased copy: lowercase() is not
         // length-preserving (U+0130 expands to two chars), so offsets taken from a
         // lowercased copy can drift out of bounds of the string we slice.
         var match = text.indexOf(query, cursor, ignoreCase = true)
         while (match >= 0) {
             append(text.substring(cursor, match))
             val isActive = activeRange != null &&
                 match == activeRange.first &&
                 match + query.length - 1 == activeRange.last
             val background = if (isActive) {
                 WiretapColors.SearchHighlightActiveBackground
             } else {
                 WiretapColors.SearchHighlightBackground
             }
             withStyle(SpanStyle(background = background, color = Color.Black)) {
                 append(text.substring(match, match + query.length))
             }
             cursor = match + query.length
             match = text.indexOf(query, cursor, ignoreCase = true)
         }
         append(text.substring(cursor))
     }
 }