module Yi.Rectangle where
import Yi.Prelude
import Prelude (subtract)
import Data.List (splitAt, unzip)
import Data.List (sort, length, zipWith, transpose)
import Yi.Buffer
import Yi.Editor
import Yi.String
import Text.Regex.TDFA
alignRegion :: String -> BufferM ()
alignRegion str = modifyRegionClever (alignText str) =<< unitWiseRegion Line =<< getSelectRegionB
where regexSplit :: String -> String -> [String]
regexSplit regex l = case l =~ regex of
AllTextSubmatches (_:matches) -> matches
_ -> error "regexSplit: text does not match"
alignText :: String -> String -> String
alignText regex text = unlines' ls'
where ls, ls' :: [String]
ls = lines' text
columns, columns' :: [[String]]
columns = fmap (regexSplit regex) ls
columnsWidth :: [Int]
columnsWidth = fmap (maximum . fmap length) $ transpose columns
columns' = fmap (zipWith padLeft columnsWidth) columns
ls' = fmap concat columns'
alignRegionOn :: String -> BufferM ()
alignRegionOn s = alignRegion ("^(.*)(" ++ s ++ ")(.*)")
getRectangle :: BufferM (Region, Int, Int)
getRectangle = do
r <- getSelectRegionB
extR <- unitWiseRegion Line r
[lowCol,highCol] <- sort <$> mapM colOf [regionStart r, regionEnd r]
return (extR, lowCol, highCol)
multiSplit :: [Int] -> [a] -> [[a]]
multiSplit [] l = [l]
multiSplit (x:xs) l = left : multiSplit (fmap (subtract x) xs) right
where (left,right) = splitAt x l
onRectangle :: (Int -> Int -> String -> String) -> BufferM ()
onRectangle f = do
(reg, l, r) <- getRectangle
modifyRegionB (mapLines (f l r)) reg
openRectangle :: BufferM ()
openRectangle = onRectangle openLine
where openLine l r line = left ++ replicate (rl) ' ' ++ right
where (left,right) = splitAt l line
stringRectangle :: String -> BufferM ()
stringRectangle inserted = onRectangle stringLine
where stringLine l r line = left ++ inserted ++ right
where [left,_,right] = multiSplit [l,r] line
killRectangle :: EditorM ()
killRectangle = do
cutted <- withBuffer0 $ do
(reg, l, r) <- getRectangle
text <- readRegionB reg
let (cutted, rest) = unzip $ fmap cut $ lines' text
cut line = let [left,mid,right] = multiSplit [l,r] line in (mid, left ++ right)
replaceRegionB reg (unlines' rest)
return cutted
setRegE (unlines' cutted)
yankRectangle :: EditorM ()
yankRectangle = do
text <- lines' <$> getRegE
withBuffer0 $ do
forM_ text $ \t -> do
savingPointB $ insertN t
lineDown