-- | module Brick.Widgets.Search where import Text.Regex.TDFA import qualified Data.Text as T import Hum.Attributes import Brick.Types import Brick.Widgets.Core import qualified Data.Array as A searchW :: Int -> Text -> Text -> Widget n searchW highlight term contents = let splits = T.splitOn term <$> lines contents numMatches = sum $ (\ls -> max 0 (length ls - 1)) <$> splits mkLine :: [Text] -> State Int (Widget n) mkLine [] = pure emptyWidget mkLine [""] = pure $ txt " " mkLine [t] = pure $ txt t mkLine (t:ts) = do num <- get let hl = (num - highlight) `mod` numMatches == 0 modify (+1) let (rest,numFinal) = runState (mkLine ts) (num+1) put numFinal pure $ txt t <+> ((if hl then visible . withAttr searchFocusedAttr else withAttr searchAttr) $ txt term) <+> rest mkWidget :: [[Text]] -> State Int (Widget n) mkWidget [] = pure emptyWidget mkWidget [t] = join . pure $ mkLine t mkWidget (t:ts) = do num <- get let (line,numLine) = runState (mkLine t) num let (rest,numFinal) = runState (mkWidget ts) numLine put numFinal pure $ line <=> rest in evalState (mkWidget splits) 0 splitRegex :: Regex -> Text -> [[(Text, Text)]] splitRegex rg source = go [] rg <$> lines source where go :: [(Text, Text)] -> Regex -> Text -> [(Text, Text)] go prev rg' rest = let matches = matchOnceText rg' rest in case matches of Nothing -> prev ++ [(rest, "")] Just (pre, mt, post) -> go (prev ++ [(pre, maybe "" fst $ viaNonEmpty head (A.elems mt))]) rg post regexW :: Int -> Regex -> Text -> Widget n regexW highlight term contents = let splits = splitRegex term contents numMatches = sum $ (\ls -> max 0 (length ls - 1)) <$> splits mkLine :: [(Text,Text)] -> State Int (Widget n) mkLine [] = pure emptyWidget mkLine [("",_)] = pure $ txt " " mkLine [(tx,_)] = pure $ txt tx mkLine ((tx,mtch):ts) = do num <- get let hl = (num - highlight) `mod` numMatches == 0 modify (+1) let (rest,numFinal) = runState (mkLine ts) (num+1) put numFinal pure $ txt tx <+> ((if hl then visible . withAttr searchFocusedAttr else withAttr searchAttr) $ txt mtch) <+> rest mkWidget :: [[(Text,Text)]] -> State Int (Widget n) mkWidget [] = pure emptyWidget mkWidget [t] = join . pure $ mkLine t mkWidget (t:ts) = do num <- get let (line,numLine) = runState (mkLine t) num let (rest,numFinal) = runState (mkWidget ts) numLine put numFinal pure $ line <=> rest in evalState (mkWidget splits) 0