module Yi.Rectangle where
import Yi.Prelude
import Prelude (subtract)
import Data.List (splitAt, unzip)
import Control.Applicative
import Data.Char
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