packages feed

yi-0.4.6: Yi/Mode/Interactive.hs

module Yi.Mode.Interactive where

import Prelude ()
import Yi.Buffer
import Yi.Buffer.HighLevel
import Yi.Buffer.Region
import Yi.Core
import Yi.Core
import Yi.Editor
import Yi.Keymap
import Yi.Keymap.Keys
import Yi.Prelude
import Yi.Region
import Yi.Lexer.Alex (Tok(..))
import Yi.History
import qualified Yi.Lexer.Compilation         as Compilation
import qualified Yi.Mode.Compilation         as Compilation
import qualified Yi.Syntax.Linear as Linear

atLastLine :: BufferM Bool
atLastLine = savingPointB $ do
    moveToEol
    (==) <$> sizeB <*> pointB

mode :: Mode (Linear.Result (Tok Compilation.Token))
mode = Compilation.mode
  { 
       modeApplies = const False,
       modeName = "interactive",
       modeKeymap = (<||) 
        (choice 
         [spec KEnter ?>>! do
             eof <- withBuffer $ atLastLine
             if eof
               then feedCommand
               else withSyntax modeFollow,
          meta (char 'p') ?>>! interactHistoryMove 1,
          meta (char 'n') ?>>! interactHistoryMove (-1) 
         ])
  }

interactId :: String
interactId = "Interact"

interactHistoryMove :: Int -> EditorM ()
interactHistoryMove delta = historyMoveGen interactId delta (withBuffer0 getInput) >>= (withBuffer0 . setInput)

interactHistoryFinish :: EditorM ()
interactHistoryFinish = historyFinishGen interactId (withBuffer0 getInput)

interactHistoryStart :: EditorM ()
interactHistoryStart = historyStartGen interactId

getInputRegion :: BufferM Region
getInputRegion = do
    mo <- getMarkB (Just "StdOUT")
    p <- pointAt botB
    q <- getMarkPointB mo
    return $ mkRegion p q

getInput :: BufferM String
getInput = readRegionB =<< getInputRegion

setInput :: String -> BufferM ()
setInput val = flip replaceRegionB val =<< getInputRegion

-- | Open a new buffer for interaction with a process.
interactive :: String -> [String] -> YiM BufferRef
interactive cmd args = do
    b <- startSubprocess cmd args (\_ -> return ())
    withEditor $ interactHistoryStart
    withBuffer $ do m1 <- getMarkB (Just "StdERR")
                    m2 <- getMarkB (Just "StdOUT")
                    modifyMarkB m1 (\v -> v {markGravity = Backward})
                    modifyMarkB m2 (\v -> v {markGravity = Backward})
                    setMode mode
    return b



-- | Send the type command to the process
feedCommand :: YiM ()
feedCommand = do
    b <- withEditor $ getBuffer
    withEditor interactHistoryFinish
    cmd <- withBuffer $ do 
        botB
        insertN "\n"
        me <- getMarkB (Just "StdERR")
        mo <- getMarkB (Just "StdOUT")
        p <- pointB
        q <- getMarkPointB mo
        cmd <- readRegionB $ mkRegion p q
        setMarkPointB me p
        setMarkPointB mo p
        return $ cmd 
    withEditor interactHistoryStart
    sendToProcess b cmd