zwirn-0.2.3.1: app/zwirnmill/Docs/Util.hs
module Docs.Util where
import Data.Bifunctor (second)
import Data.List (elemIndex, mapAccumL, (!?))
import Data.Maybe (fromMaybe)
import qualified Data.Text as T
import UI.Core (Doc (..), DocBlock (..), DocFocus (..), DocInline (..))
getCodeAt :: Doc -> Int -> Maybe T.Text
getCodeAt (Doc []) _ = Nothing
getCodeAt (Doc ((CodeBlock t) : _)) 0 = Just t
getCodeAt (Doc ((CodeBlock _) : ds)) n = getCodeAt (Doc ds) (n - 1)
getCodeAt (Doc (_ : ds)) n = getCodeAt (Doc ds) n
getLinkAt :: Doc -> Int -> Maybe T.Text
getLinkAt (Doc []) _ = Nothing
getLinkAt (Doc ((Paragraph ps) : ds)) n = case getLinkAtPar ps n of
Left i -> getLinkAt (Doc ds) i
Right x -> Just x
getLinkAt (Doc ((CodeBlock _) : ds)) n = getLinkAt (Doc ds) n
getLinkAtPar :: [DocInline] -> Int -> Either Int T.Text
getLinkAtPar [] i = Left i
getLinkAtPar ((Link _ d) : _) 0 = Right d
getLinkAtPar ((Link _ _) : ds) n = getLinkAtPar ds (n - 1)
getLinkAtPar (_ : ds) n = getLinkAtPar ds n
currentLink :: DocFocus -> Int -> Bool
currentLink (LinkFocus t) k = t == k
currentLink _ _ = False
currentCodeBlock :: DocFocus -> Int -> Bool
currentCodeBlock (CodeFocus i) j = i == j
currentCodeBlock _ _ = False
docFoci :: Doc -> [DocFocus]
docFoci (Doc ds) = concat $ snd $ mapAccumL getFociBlock (0, 0) ds
getFociBlock :: (Int, Int) -> DocBlock -> ((Int, Int), [DocFocus])
getFociBlock (i, j) (CodeBlock _) = ((i + 1, j), [CodeFocus i])
getFociBlock (i, j) (Paragraph ls) = second concat $ mapAccumL getFociInline (i, j) ls
getFociInline :: (Int, Int) -> DocInline -> ((Int, Int), [DocFocus])
getFociInline (i, j) (Link _ _) = ((i, j + 1), [LinkFocus j])
getFociInline (i, j) _ = ((i, j), [])
moveNext :: Doc -> DocFocus -> DocFocus
moveNext d NoFocus = fromMaybe NoFocus $ docFoci d !? 0
moveNext d cur = next
where
fs = docFoci d
i = fromMaybe 0 $ elemIndex cur fs
next = case fs !? (i + 1) of
Just n -> n
Nothing -> fromMaybe cur (fs !? 0)