module Yi.Buffer.Region
(
module Yi.Region
, swapRegionsB
, deleteRegionB
, replaceRegionB
, replaceRegionB'
, replaceRegionClever
, readRegionB
, readRegionB'
, mapRegionB
, modifyRegionB
, modifyRegionClever
, winRegionB
, inclusiveRegionB
, blockifyRegion
, joinLinesB
, concatLinesB
)
where
import Prelude ()
import Yi.Prelude
import Data.Algorithm.Diff
import Data.Char (isSpace)
import Data.List (filter, length, sort, dropWhile)
import Yi.Buffer.Misc
import Yi.Region
import Yi.String (lines')
import Yi.Window (winRegion)
winRegionB :: BufferM Region
winRegionB = askWindow winRegion
deleteRegionB :: Region -> BufferM ()
deleteRegionB r = deleteNAt (regionDirection r) (fromIntegral (regionEnd r ~- regionStart r)) (regionStart r)
readRegionB :: Region -> BufferM String
readRegionB r = nelemsB (fromIntegral (regionEnd r i)) i
where i = regionStart r
readRegionB' :: Region -> BufferM Rope
readRegionB' r = nelemsB' (fromIntegral (regionEnd r i)) i
where i = regionStart r
replaceRegionB :: Region -> String -> BufferM ()
replaceRegionB r s = do
deleteRegionB r
insertNAt s (regionStart r)
replaceRegionB' :: Region -> Rope -> BufferM ()
replaceRegionB' r s = do
deleteRegionB r
insertNAt' s (regionStart r)
replaceRegionClever :: Region -> String -> BufferM ()
replaceRegionClever region text' = savingExcursionB $ do
text <- readRegionB region
let diffs = getGroupedDiff text text'
moveTo (regionStart region)
#if MIN_VERSION_Diff(0,2,0)
forM_ diffs $ \d -> case d of
First str -> deleteN $ length str
Both str _ -> rightN $ length str
Second str -> insertN str
#else
forM_ diffs $ \(d,str) -> case d of
F -> deleteN $ length str
B -> rightN $ length str
S -> insertN str
#endif
mapRegionB :: Region -> (Char -> Char) -> BufferM ()
mapRegionB r f = do
text <- readRegionB r
replaceRegionB r (fmap f text)
swapRegionsB :: Region -> Region -> BufferM ()
swapRegionsB r r'
| regionStart r > regionStart r' = swapRegionsB r' r
| otherwise = do w0 <- readRegionB r
w1 <- readRegionB r'
replaceRegionB r' w0
replaceRegionB r w1
replToMod :: (Region -> a -> BufferM b) -> (String -> a) -> Region -> BufferM b
replToMod replace transform region = replace region =<< transform <$> readRegionB region
modifyRegionB :: (String -> String)
-> Region
-> BufferM ()
modifyRegionB = replToMod replaceRegionB
modifyRegionClever :: (String -> String) -> Region -> BufferM ()
modifyRegionClever = replToMod replaceRegionClever
inclusiveRegionB :: Region -> BufferM Region
inclusiveRegionB r =
if regionStart r <= regionEnd r
then mkRegion (regionStart r) <$> pointAfterCursorB (regionEnd r)
else mkRegion <$> pointAfterCursorB (regionStart r) <*> pure (regionEnd r)
blockifyRegion :: Region -> BufferM [Region]
blockifyRegion r = savingPointB $ do
[lowCol,highCol] <- sort <$> mapM colOf [regionStart r, regionEnd r]
startLine <- lineOf $ regionStart r
endLine <- lineOf $ regionEnd r
when (startLine > endLine) $ fail "blockifyRegion: impossible"
mapM (\line -> mkRegion <$> pointOfLineColB line lowCol <*> pointOfLineColB line (1 + highCol))
[startLine..endLine]
skippingFirst :: ([a] -> [a]) -> [a] -> [a]
skippingFirst f = list [] (\x -> (x :) . f)
skippingLast :: ([a] -> [a]) -> [a] -> [a]
skippingLast f xs = f (init xs) ++ [last xs]
skippingNull :: ([a] -> [b]) -> [a] -> [b]
skippingNull _ [] = []
skippingNull f xs = f xs
joinLinesB :: Region -> BufferM ()
joinLinesB =
savingPointB .
(modifyRegionClever $ skippingLast $
concat . (skippingFirst $ fmap $ skippingNull ((' ':) . dropWhile isSpace)) . lines')
concatLinesB :: Region -> BufferM ()
concatLinesB = savingPointB . (modifyRegionClever $ skippingLast $ filter (/='\n'))