{-# LANGUAGE OverloadedStrings #-}

module HieDb.Html
    ( Color (..)
    , Span (..)
    , generate
    ) where

import           Control.Monad (forM_)
import           Data.Function (on)
import           Data.IntMap.Strict (IntMap)
import qualified Data.IntMap.Strict as IM
import           Data.List (foldl', sortBy)
import           Data.Text   (Text)
import qualified Data.Text as T
import           Lucid

import           HieDb.Compat

generate :: FilePath -> ModuleName -> [Text] -> [Span] -> IO ()
generate :: FilePath -> ModuleName -> [Text] -> [Span] -> IO ()
generate FilePath
fp ModuleName
mn [Text]
ts [Span]
sps = FilePath -> Html () -> IO ()
forall a. FilePath -> Html a -> IO ()
renderToFile FilePath
fp (Html () -> IO ()) -> Html () -> IO ()
forall a b. (a -> b) -> a -> b
$ Html () -> Html ()
forall (m :: * -> *) a. Applicative m => HtmlT m a -> HtmlT m a
doctypehtml_ (Html () -> Html ()) -> Html () -> Html ()
forall a b. (a -> b) -> a -> b
$ do
    Html () -> Html ()
forall arg result. Term arg result => arg -> result
head_ (Html () -> Html ()) -> Html () -> Html ()
forall a b. (a -> b) -> a -> b
$ Html () -> Html ()
forall arg result. Term arg result => arg -> result
title_ (Html () -> Html ()) -> Html () -> Html ()
forall a b. (a -> b) -> a -> b
$ FilePath -> Html ()
forall a (m :: * -> *). (ToHtml a, Monad m) => a -> HtmlT m ()
toHtml (FilePath -> Html ()) -> FilePath -> Html ()
forall a b. (a -> b) -> a -> b
$ ModuleName -> FilePath
moduleNameString ModuleName
mn
    Html () -> Html ()
forall arg result. Term arg result => arg -> result
body_ (Html () -> Html ()) -> Html () -> Html ()
forall a b. (a -> b) -> a -> b
$
        [(Int, Text, [LineSpan])]
-> ((Int, Text, [LineSpan]) -> Html ()) -> Html ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ ([Text] -> [Span] -> [(Int, Text, [LineSpan])]
layout [Text]
ts [Span]
sps) (Int, Text, [LineSpan]) -> Html ()
generateLine'
  where
    generateLine' :: (Int, Text, [LineSpan]) -> Html ()
    generateLine' :: (Int, Text, [LineSpan]) -> Html ()
generateLine' (Int
i, Text
t, [LineSpan]
lsps) = [Attribute] -> Html () -> Html ()
forall arg result. Term arg result => arg -> result
pre_ [Text -> Attribute
forall arg result. TermRaw arg result => arg -> result
style_ Text
"margin:0em;font-size:large"] (Html () -> Html ()) -> Html () -> Html ()
forall a b. (a -> b) -> a -> b
$ do
        [Attribute] -> Html () -> Html ()
forall arg result. Term arg result => arg -> result
span_ [Text -> Attribute
forall arg result. TermRaw arg result => arg -> result
style_ Text
"background-color:lightcyan;padding-right:1em"] (Html () -> Html ()) -> Html () -> Html ()
forall a b. (a -> b) -> a -> b
$ Int -> Html ()
padLineNumber Int
i
        Int -> Text -> [LineSpan] -> Html ()
go Int
1 Text
t [LineSpan]
lsps

    go :: Int -> Text -> [LineSpan] -> Html ()
    go :: Int -> Text -> [LineSpan] -> Html ()
go Int
_   Text
t [] = Text -> Html ()
forall a (m :: * -> *). (ToHtml a, Monad m) => a -> HtmlT m ()
toHtml Text
t
    go Int
col Text
t lsps :: [LineSpan]
lsps@(LineSpan
lsp : [LineSpan]
lsps')
        | Int
col Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< LineSpan -> Int
lspStartColumn LineSpan
lsp = do
            let (Text
t1, Text
t2) = Int -> Text -> (Text, Text)
T.splitAt (LineSpan -> Int
lspStartColumn LineSpan
lsp Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
col) Text
t
            Text -> Html ()
forall a (m :: * -> *). (ToHtml a, Monad m) => a -> HtmlT m ()
toHtml Text
t1
            Int -> Text -> [LineSpan] -> Html ()
go (LineSpan -> Int
lspStartColumn LineSpan
lsp) Text
t2 [LineSpan]
lsps
        | Bool
otherwise = do
            let l :: Int
l        = LineSpan -> Int
lspEndColumn LineSpan
lsp Int -> Int -> Int
forall a. Num a => a -> a -> a
- LineSpan -> Int
lspStartColumn LineSpan
lsp Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
                (Text
t1, Text
t2) = Int -> Text -> (Text, Text)
T.splitAt Int
l Text
t
            [Attribute] -> Html () -> Html ()
forall arg result. Term arg result => arg -> result
span_ [LineSpan -> Attribute
lineSpanAttribute LineSpan
lsp] (Html () -> Html ()) -> Html () -> Html ()
forall a b. (a -> b) -> a -> b
$ Text -> Html ()
forall a (m :: * -> *). (ToHtml a, Monad m) => a -> HtmlT m ()
toHtml Text
t1
            Int -> Text -> [LineSpan] -> Html ()
go (LineSpan -> Int
lspEndColumn LineSpan
lsp Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Text
t2 [LineSpan]
lsps'

padLineNumber :: Int -> Html ()
padLineNumber :: Int -> Html ()
padLineNumber Int
n = let s :: FilePath
s = Int -> FilePath
forall a. Show a => a -> FilePath
show Int
n in FilePath -> Int -> Html ()
forall t (m :: * -> *).
(Ord t, Num t, Monad m) =>
FilePath -> t -> HtmlT m ()
go FilePath
s (Int -> Html ()) -> Int -> Html ()
forall a b. (a -> b) -> a -> b
$ FilePath -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length FilePath
s
  where
    go :: FilePath -> t -> HtmlT m ()
go FilePath
s t
l
        | t
l t -> t -> Bool
forall a. Ord a => a -> a -> Bool
>= t
6    = FilePath -> HtmlT m ()
forall a (m :: * -> *). (ToHtml a, Monad m) => a -> HtmlT m ()
toHtml FilePath
s
        | Bool
otherwise = FilePath -> t -> HtmlT m ()
go (Char
' ' Char -> FilePath -> FilePath
forall a. a -> [a] -> [a]
: FilePath
s) (t
l t -> t -> t
forall a. Num a => a -> a -> a
+ t
1)

data Color = Reachable | Unreachable deriving (Int -> Color -> FilePath -> FilePath
[Color] -> FilePath -> FilePath
Color -> FilePath
(Int -> Color -> FilePath -> FilePath)
-> (Color -> FilePath)
-> ([Color] -> FilePath -> FilePath)
-> Show Color
forall a.
(Int -> a -> FilePath -> FilePath)
-> (a -> FilePath) -> ([a] -> FilePath -> FilePath) -> Show a
showList :: [Color] -> FilePath -> FilePath
$cshowList :: [Color] -> FilePath -> FilePath
show :: Color -> FilePath
$cshow :: Color -> FilePath
showsPrec :: Int -> Color -> FilePath -> FilePath
$cshowsPrec :: Int -> Color -> FilePath -> FilePath
Show, ReadPrec [Color]
ReadPrec Color
Int -> ReadS Color
ReadS [Color]
(Int -> ReadS Color)
-> ReadS [Color]
-> ReadPrec Color
-> ReadPrec [Color]
-> Read Color
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Color]
$creadListPrec :: ReadPrec [Color]
readPrec :: ReadPrec Color
$creadPrec :: ReadPrec Color
readList :: ReadS [Color]
$creadList :: ReadS [Color]
readsPrec :: Int -> ReadS Color
$creadsPrec :: Int -> ReadS Color
Read, Color -> Color -> Bool
(Color -> Color -> Bool) -> (Color -> Color -> Bool) -> Eq Color
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Color -> Color -> Bool
$c/= :: Color -> Color -> Bool
== :: Color -> Color -> Bool
$c== :: Color -> Color -> Bool
Eq, Eq Color
Eq Color
-> (Color -> Color -> Ordering)
-> (Color -> Color -> Bool)
-> (Color -> Color -> Bool)
-> (Color -> Color -> Bool)
-> (Color -> Color -> Bool)
-> (Color -> Color -> Color)
-> (Color -> Color -> Color)
-> Ord Color
Color -> Color -> Bool
Color -> Color -> Ordering
Color -> Color -> Color
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Color -> Color -> Color
$cmin :: Color -> Color -> Color
max :: Color -> Color -> Color
$cmax :: Color -> Color -> Color
>= :: Color -> Color -> Bool
$c>= :: Color -> Color -> Bool
> :: Color -> Color -> Bool
$c> :: Color -> Color -> Bool
<= :: Color -> Color -> Bool
$c<= :: Color -> Color -> Bool
< :: Color -> Color -> Bool
$c< :: Color -> Color -> Bool
compare :: Color -> Color -> Ordering
$ccompare :: Color -> Color -> Ordering
$cp1Ord :: Eq Color
Ord)

data Span = Span
    { Span -> Int
spStartLine   :: !Int
    , Span -> Int
spStartColumn :: !Int
    , Span -> Int
spEndLine     :: !Int
    , Span -> Int
spEndColumn   :: !Int
    , Span -> Color
spColor       :: !Color
    } deriving (Int -> Span -> FilePath -> FilePath
[Span] -> FilePath -> FilePath
Span -> FilePath
(Int -> Span -> FilePath -> FilePath)
-> (Span -> FilePath)
-> ([Span] -> FilePath -> FilePath)
-> Show Span
forall a.
(Int -> a -> FilePath -> FilePath)
-> (a -> FilePath) -> ([a] -> FilePath -> FilePath) -> Show a
showList :: [Span] -> FilePath -> FilePath
$cshowList :: [Span] -> FilePath -> FilePath
show :: Span -> FilePath
$cshow :: Span -> FilePath
showsPrec :: Int -> Span -> FilePath -> FilePath
$cshowsPrec :: Int -> Span -> FilePath -> FilePath
Show, ReadPrec [Span]
ReadPrec Span
Int -> ReadS Span
ReadS [Span]
(Int -> ReadS Span)
-> ReadS [Span] -> ReadPrec Span -> ReadPrec [Span] -> Read Span
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Span]
$creadListPrec :: ReadPrec [Span]
readPrec :: ReadPrec Span
$creadPrec :: ReadPrec Span
readList :: ReadS [Span]
$creadList :: ReadS [Span]
readsPrec :: Int -> ReadS Span
$creadsPrec :: Int -> ReadS Span
Read, Span -> Span -> Bool
(Span -> Span -> Bool) -> (Span -> Span -> Bool) -> Eq Span
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Span -> Span -> Bool
$c/= :: Span -> Span -> Bool
== :: Span -> Span -> Bool
$c== :: Span -> Span -> Bool
Eq, Eq Span
Eq Span
-> (Span -> Span -> Ordering)
-> (Span -> Span -> Bool)
-> (Span -> Span -> Bool)
-> (Span -> Span -> Bool)
-> (Span -> Span -> Bool)
-> (Span -> Span -> Span)
-> (Span -> Span -> Span)
-> Ord Span
Span -> Span -> Bool
Span -> Span -> Ordering
Span -> Span -> Span
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Span -> Span -> Span
$cmin :: Span -> Span -> Span
max :: Span -> Span -> Span
$cmax :: Span -> Span -> Span
>= :: Span -> Span -> Bool
$c>= :: Span -> Span -> Bool
> :: Span -> Span -> Bool
$c> :: Span -> Span -> Bool
<= :: Span -> Span -> Bool
$c<= :: Span -> Span -> Bool
< :: Span -> Span -> Bool
$c< :: Span -> Span -> Bool
compare :: Span -> Span -> Ordering
$ccompare :: Span -> Span -> Ordering
$cp1Ord :: Eq Span
Ord)

data LineSpan = LineSpan
    { LineSpan -> Int
lspLine        :: !Int
    , LineSpan -> Int
lspStartColumn :: !Int
    , LineSpan -> Int
lspEndColumn   :: !Int
    , LineSpan -> Color
lspColor       :: !Color
    } deriving (Int -> LineSpan -> FilePath -> FilePath
[LineSpan] -> FilePath -> FilePath
LineSpan -> FilePath
(Int -> LineSpan -> FilePath -> FilePath)
-> (LineSpan -> FilePath)
-> ([LineSpan] -> FilePath -> FilePath)
-> Show LineSpan
forall a.
(Int -> a -> FilePath -> FilePath)
-> (a -> FilePath) -> ([a] -> FilePath -> FilePath) -> Show a
showList :: [LineSpan] -> FilePath -> FilePath
$cshowList :: [LineSpan] -> FilePath -> FilePath
show :: LineSpan -> FilePath
$cshow :: LineSpan -> FilePath
showsPrec :: Int -> LineSpan -> FilePath -> FilePath
$cshowsPrec :: Int -> LineSpan -> FilePath -> FilePath
Show, ReadPrec [LineSpan]
ReadPrec LineSpan
Int -> ReadS LineSpan
ReadS [LineSpan]
(Int -> ReadS LineSpan)
-> ReadS [LineSpan]
-> ReadPrec LineSpan
-> ReadPrec [LineSpan]
-> Read LineSpan
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [LineSpan]
$creadListPrec :: ReadPrec [LineSpan]
readPrec :: ReadPrec LineSpan
$creadPrec :: ReadPrec LineSpan
readList :: ReadS [LineSpan]
$creadList :: ReadS [LineSpan]
readsPrec :: Int -> ReadS LineSpan
$creadsPrec :: Int -> ReadS LineSpan
Read, LineSpan -> LineSpan -> Bool
(LineSpan -> LineSpan -> Bool)
-> (LineSpan -> LineSpan -> Bool) -> Eq LineSpan
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LineSpan -> LineSpan -> Bool
$c/= :: LineSpan -> LineSpan -> Bool
== :: LineSpan -> LineSpan -> Bool
$c== :: LineSpan -> LineSpan -> Bool
Eq, Eq LineSpan
Eq LineSpan
-> (LineSpan -> LineSpan -> Ordering)
-> (LineSpan -> LineSpan -> Bool)
-> (LineSpan -> LineSpan -> Bool)
-> (LineSpan -> LineSpan -> Bool)
-> (LineSpan -> LineSpan -> Bool)
-> (LineSpan -> LineSpan -> LineSpan)
-> (LineSpan -> LineSpan -> LineSpan)
-> Ord LineSpan
LineSpan -> LineSpan -> Bool
LineSpan -> LineSpan -> Ordering
LineSpan -> LineSpan -> LineSpan
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: LineSpan -> LineSpan -> LineSpan
$cmin :: LineSpan -> LineSpan -> LineSpan
max :: LineSpan -> LineSpan -> LineSpan
$cmax :: LineSpan -> LineSpan -> LineSpan
>= :: LineSpan -> LineSpan -> Bool
$c>= :: LineSpan -> LineSpan -> Bool
> :: LineSpan -> LineSpan -> Bool
$c> :: LineSpan -> LineSpan -> Bool
<= :: LineSpan -> LineSpan -> Bool
$c<= :: LineSpan -> LineSpan -> Bool
< :: LineSpan -> LineSpan -> Bool
$c< :: LineSpan -> LineSpan -> Bool
compare :: LineSpan -> LineSpan -> Ordering
$ccompare :: LineSpan -> LineSpan -> Ordering
$cp1Ord :: Eq LineSpan
Ord)

lineSpanAttribute :: LineSpan -> Attribute
lineSpanAttribute :: LineSpan -> Attribute
lineSpanAttribute LineSpan
lsp =
    let color :: Text
color = case LineSpan -> Color
lspColor LineSpan
lsp of
            Color
Reachable   -> Text
"lightgreen"
            Color
Unreachable -> Text
"yellow"
    in  Text -> Attribute
forall arg result. TermRaw arg result => arg -> result
style_ (Text -> Attribute) -> Text -> Attribute
forall a b. (a -> b) -> a -> b
$ Text
"background-color:" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
color

lineSpans :: (Int -> Int) -> Span -> [LineSpan]
lineSpans :: (Int -> Int) -> Span -> [LineSpan]
lineSpans Int -> Int
cols Span
sp
    | Span -> Int
spStartLine Span
sp Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Span -> Int
spEndLine Span
sp = LineSpan -> [LineSpan]
forall (m :: * -> *) a. Monad m => a -> m a
return LineSpan :: Int -> Int -> Int -> Color -> LineSpan
LineSpan
        { lspLine :: Int
lspLine        = Span -> Int
spStartLine Span
sp
        , lspStartColumn :: Int
lspStartColumn = Span -> Int
spStartColumn Span
sp
        , lspEndColumn :: Int
lspEndColumn   = Span -> Int
spEndColumn Span
sp
        , lspColor :: Color
lspColor       = Span -> Color
spColor Span
sp
        }
    | Bool
otherwise =
        let lsp1 :: LineSpan
lsp1  = LineSpan :: Int -> Int -> Int -> Color -> LineSpan
LineSpan
                        { lspLine :: Int
lspLine        = Span -> Int
spStartLine Span
sp
                        , lspStartColumn :: Int
lspStartColumn = Span -> Int
spStartColumn Span
sp
                        , lspEndColumn :: Int
lspEndColumn   = Int -> Int
cols (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ Span -> Int
spStartLine Span
sp
                        , lspColor :: Color
lspColor       = Span -> Color
spColor Span
sp
                        }
            lsp :: Int -> LineSpan
lsp Int
i = LineSpan :: Int -> Int -> Int -> Color -> LineSpan
LineSpan
                        { lspLine :: Int
lspLine        = Int
i
                        , lspStartColumn :: Int
lspStartColumn = Int
1
                        , lspEndColumn :: Int
lspEndColumn   = Int -> Int
cols Int
i
                        , lspColor :: Color
lspColor       = Span -> Color
spColor Span
sp
                        }
            lsp2 :: LineSpan
lsp2  = LineSpan :: Int -> Int -> Int -> Color -> LineSpan
LineSpan
                        { lspLine :: Int
lspLine        = Span -> Int
spEndLine Span
sp
                        , lspStartColumn :: Int
lspStartColumn = Int
1
                        , lspEndColumn :: Int
lspEndColumn   = Span -> Int
spEndColumn Span
sp
                        , lspColor :: Color
lspColor       = Span -> Color
spColor Span
sp
                        }
        in  LineSpan
lsp1 LineSpan -> [LineSpan] -> [LineSpan]
forall a. a -> [a] -> [a]
: [Int -> LineSpan
lsp Int
i | Int
i <- [Span -> Int
spStartLine Span
sp Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 .. Span -> Int
spEndLine Span
sp Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1]] [LineSpan] -> [LineSpan] -> [LineSpan]
forall a. [a] -> [a] -> [a]
++ [LineSpan
lsp2]

layout :: [Text] -> [Span] -> [(Int, Text, [LineSpan])]
layout :: [Text] -> [Span] -> [(Int, Text, [LineSpan])]
layout [Text]
ts [Span]
ss =
    let m1 :: IntMap (Text, Int, [a])
m1 = [(Int, (Text, Int, [a]))] -> IntMap (Text, Int, [a])
forall a. [(Int, a)] -> IntMap a
IM.fromList [(Int
i, (Text
t, Text -> Int
T.length Text
t, [])) | (Int
i, Text
t) <- [Int] -> [Text] -> [(Int, Text)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
1..] [Text]
ts]
        m2 :: IntMap (Text, Int, [LineSpan])
m2 = (IntMap (Text, Int, [LineSpan])
 -> Span -> IntMap (Text, Int, [LineSpan]))
-> IntMap (Text, Int, [LineSpan])
-> [Span]
-> IntMap (Text, Int, [LineSpan])
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' IntMap (Text, Int, [LineSpan])
-> Span -> IntMap (Text, Int, [LineSpan])
f IntMap (Text, Int, [LineSpan])
forall a. IntMap (Text, Int, [a])
m1 [Span]
ss :: IntMap (Text, Int, [LineSpan])
    in  [(Int
i, Text
t, [LineSpan]
lsps) | (Int
i, (Text
t, [LineSpan]
lsps)) <- IntMap (Text, [LineSpan]) -> [(Int, (Text, [LineSpan]))]
forall a. IntMap a -> [(Int, a)]
IM.toList (IntMap (Text, [LineSpan]) -> [(Int, (Text, [LineSpan]))])
-> IntMap (Text, [LineSpan]) -> [(Int, (Text, [LineSpan]))]
forall a b. (a -> b) -> a -> b
$ (Text, Int, [LineSpan]) -> (Text, [LineSpan])
j ((Text, Int, [LineSpan]) -> (Text, [LineSpan]))
-> IntMap (Text, Int, [LineSpan]) -> IntMap (Text, [LineSpan])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IntMap (Text, Int, [LineSpan])
m2]
  where
    f :: IntMap (Text, Int, [LineSpan]) -> Span -> IntMap (Text, Int, [LineSpan])
    f :: IntMap (Text, Int, [LineSpan])
-> Span -> IntMap (Text, Int, [LineSpan])
f IntMap (Text, Int, [LineSpan])
m = (IntMap (Text, Int, [LineSpan])
 -> LineSpan -> IntMap (Text, Int, [LineSpan]))
-> IntMap (Text, Int, [LineSpan])
-> [LineSpan]
-> IntMap (Text, Int, [LineSpan])
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' IntMap (Text, Int, [LineSpan])
-> LineSpan -> IntMap (Text, Int, [LineSpan])
g IntMap (Text, Int, [LineSpan])
m ([LineSpan] -> IntMap (Text, Int, [LineSpan]))
-> (Span -> [LineSpan]) -> Span -> IntMap (Text, Int, [LineSpan])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Int) -> Span -> [LineSpan]
lineSpans Int -> Int
lookup'
      where lookup' :: Int -> Int
lookup' Int
i = case Int
-> IntMap (Text, Int, [LineSpan]) -> Maybe (Text, Int, [LineSpan])
forall a. Int -> IntMap a -> Maybe a
IM.lookup Int
i IntMap (Text, Int, [LineSpan])
m of
                Maybe (Text, Int, [LineSpan])
Nothing        -> Int
0
                Just (Text
_, Int
l, [LineSpan]
_) -> Int
l

    g :: IntMap (Text, Int, [LineSpan]) -> LineSpan -> IntMap (Text, Int, [LineSpan])
    g :: IntMap (Text, Int, [LineSpan])
-> LineSpan -> IntMap (Text, Int, [LineSpan])
g IntMap (Text, Int, [LineSpan])
m LineSpan
lsp = ((Text, Int, [LineSpan]) -> (Text, Int, [LineSpan]))
-> Int
-> IntMap (Text, Int, [LineSpan])
-> IntMap (Text, Int, [LineSpan])
forall a. (a -> a) -> Int -> IntMap a -> IntMap a
IM.adjust (LineSpan -> (Text, Int, [LineSpan]) -> (Text, Int, [LineSpan])
h LineSpan
lsp) (LineSpan -> Int
lspLine LineSpan
lsp) IntMap (Text, Int, [LineSpan])
m

    h :: LineSpan -> (Text, Int, [LineSpan]) -> (Text, Int, [LineSpan])
    h :: LineSpan -> (Text, Int, [LineSpan]) -> (Text, Int, [LineSpan])
h LineSpan
lsp (Text
t, Int
l, [LineSpan]
lsps) = (Text
t, Int
l, LineSpan
lsp LineSpan -> [LineSpan] -> [LineSpan]
forall a. a -> [a] -> [a]
: [LineSpan]
lsps)

    j :: (Text, Int, [LineSpan]) -> (Text, [LineSpan])
    j :: (Text, Int, [LineSpan]) -> (Text, [LineSpan])
j (Text
t, Int
_, [LineSpan]
lsps) = (Text
t, (LineSpan -> LineSpan -> Ordering) -> [LineSpan] -> [LineSpan]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Int -> Int -> Ordering)
-> (LineSpan -> Int) -> LineSpan -> LineSpan -> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` LineSpan -> Int
lspStartColumn) [LineSpan]
lsps)