module System.Console.Haskeline.Command.KillRing where
import System.Console.Haskeline.LineState
import System.Console.Haskeline.Command
import System.Console.Haskeline.Monads
import System.Console.Haskeline.Command.Undo
import Control.Monad
import Data.IORef
data Stack a = Stack [a] [a]
deriving Show
emptyStack :: Stack a
emptyStack = Stack [] []
peek :: Stack a -> Maybe a
peek (Stack [] []) = Nothing
peek (Stack (x:_) _) = Just x
peek (Stack [] ys) = peek (Stack (reverse ys) [])
rotate :: Stack a -> Stack a
rotate s@(Stack [] []) = s
rotate (Stack (x:xs) ys) = Stack xs (x:ys)
rotate (Stack [] ys) = rotate (Stack (reverse ys) [])
push :: a -> Stack a -> Stack a
push x (Stack xs ys) = Stack (x:xs) ys
type KillRing = Stack [Grapheme]
runKillRing :: MonadIO m => ReaderT (IORef KillRing) m a -> m a
runKillRing act = do
ringRef <- liftIO $ newIORef emptyStack
runReaderT act ringRef
pasteCommand :: (Save s, MonadState KillRing m, MonadState Undo m)
=> ([Grapheme] -> s -> s) -> Command m (ArgMode s) s
pasteCommand use = \s -> do
ms <- liftM peek get
case ms of
Nothing -> return $ argState s
Just p -> do
modify $ saveToUndo $ argState s
setState $ applyArg (use p) s
deleteFromDiff' :: InsertMode -> InsertMode -> ([Grapheme],InsertMode)
deleteFromDiff' (IMode xs1 ys1) (IMode xs2 ys2)
| posChange >= 0 = (take posChange ys1, IMode xs1 ys2)
| otherwise = (take (negate posChange) ys2 ,IMode xs2 ys1)
where
posChange = length xs2 - length xs1
killFromHelper :: (MonadState KillRing m, MonadState Undo m,
Save s, Save t)
=> KillHelper -> Command m s t
killFromHelper helper = saveForUndo >|> \oldS -> do
let (gs,newIM) = applyHelper helper (save oldS)
modify (push gs)
setState (restore newIM)
killFromArgHelper :: (MonadState KillRing m, MonadState Undo m, Save s, Save t)
=> KillHelper -> Command m (ArgMode s) t
killFromArgHelper helper = saveForUndo >|> \oldS -> do
let (gs,newIM) = applyArgHelper helper (fmap save oldS)
modify (push gs)
setState (restore newIM)
copyFromArgHelper :: (MonadState KillRing m, Save s)
=> KillHelper -> Command m (ArgMode s) s
copyFromArgHelper helper = \oldS -> do
let (gs,_) = applyArgHelper helper (fmap save oldS)
modify (push gs)
setState (argState oldS)
data KillHelper = SimpleMove (InsertMode -> InsertMode)
| GenericKill (InsertMode -> ([Grapheme],InsertMode))
killAll :: KillHelper
killAll = GenericKill $ \(IMode xs ys) -> (reverse xs ++ ys, emptyIM)
applyHelper :: KillHelper -> InsertMode -> ([Grapheme],InsertMode)
applyHelper (SimpleMove move) im = deleteFromDiff' im (move im)
applyHelper (GenericKill act) im = act im
applyArgHelper :: KillHelper -> ArgMode InsertMode -> ([Grapheme],InsertMode)
applyArgHelper (SimpleMove move) im = deleteFromDiff' (argState im) (applyArg move im)
applyArgHelper (GenericKill act) im = act (argState im)