module Language.Haskell.Stylish.Editor
( Change
, applyChanges
, change
, changeLine
, delete
, deleteLine
, insert
) where
import Data.List (intercalate, sortBy)
import Data.Ord (comparing)
import Language.Haskell.Stylish.Block
data Change a = Change
{ changeBlock :: Block a
, changeLines :: ([a] -> [a])
}
moveChange :: Int -> Change a -> Change a
moveChange offset (Change block ls) = Change (moveBlock offset block) ls
applyChanges :: [Change a] -> [a] -> [a]
applyChanges changes0
| overlapping blocks = error $
"Language.Haskell.Stylish.Editor.applyChanges: " ++
"refusing to make overlapping changes on lines " ++
intercalate ", " (map printBlock blocks)
| otherwise = go 1 changes1
where
changes1 = sortBy (comparing (blockStart . changeBlock)) changes0
blocks = map changeBlock changes1
printBlock b = show (blockStart b) ++ "-" ++ show (blockEnd b)
go _ [] ls = ls
go n (ch : chs) ls =
let block = changeBlock ch
(pre, ls') = splitAt (blockStart block - n) ls
(old, post) = splitAt (blockLength block) ls'
new = changeLines ch old
extraLines = length new - blockLength block
chs' = map (moveChange extraLines) chs
n' = blockStart block + blockLength block + extraLines
in pre ++ new ++ go n' chs' post
change :: Block a -> ([a] -> [a]) -> Change a
change = Change
changeLine :: Int -> (a -> [a]) -> Change a
changeLine start f = change (Block start start) $ \xs -> case xs of
[] -> []
(x : _) -> f x
delete :: Block a -> Change a
delete block = Change block $ const []
deleteLine :: Int -> Change a
deleteLine start = delete (Block start start)
insert :: Int -> [a] -> Change a
insert start = Change (Block start (start - 1)) . const