module Language.Haskell.Stylish.Block
( Block (..)
, LineBlock
, SpanBlock
, blockLength
, moveBlock
, adjacent
, merge
, mergeAdjacent
, overlapping
, groupAdjacent
) where
import qualified Data.IntSet as IS
data Block a = Block
{ blockStart :: Int
, blockEnd :: Int
}
deriving (Eq, Ord, Show)
type LineBlock = Block String
type SpanBlock = Block Char
blockLength :: Block a -> Int
blockLength (Block start end) = end - start + 1
moveBlock :: Int -> Block a -> Block a
moveBlock offset (Block start end) = Block (start + offset) (end + offset)
adjacent :: Block a -> Block a -> Bool
adjacent b1 b2 = follows b1 b2 || follows b2 b1
where
follows (Block _ e1) (Block s2 _) = e1 + 1 == s2
merge :: Block a -> Block a -> Block a
merge (Block s1 e1) (Block s2 e2) = Block (min s1 s2) (max e1 e2)
overlapping :: [Block a] -> Bool
overlapping = go IS.empty
where
go _ [] = False
go acc (b : bs) =
let ints = [blockStart b .. blockEnd b] in
if any (`IS.member` acc) ints
then True
else go (IS.union acc $ IS.fromList ints) bs
groupAdjacent :: [(Block a, b)]
-> [(Block a, [b])]
groupAdjacent = foldr go []
where
go (b1, x) gs = case break (adjacent b1 . fst) gs of
(_, []) -> (b1, [x]) : gs
(ys, ((b2, xs) : zs)) -> (merge b1 b2, x : xs) : (ys ++ zs)
mergeAdjacent :: [Block a] -> [Block a]
mergeAdjacent (a : b : rest) | a `adjacent` b = merge a b : mergeAdjacent rest
mergeAdjacent (a : rest) = a : mergeAdjacent rest
mergeAdjacent [] = []