packages feed

shaker-0.3.1: src/Shaker/Cli.hs

-- | Command line manager
-- This manager will listen to the standard input as soon as the MVar token is filled.
-- Then, it will fill another MVar (input) with the parsed command.
-- Autocompletion is supported throught haskeline configuration.
module Shaker.Cli(
  getInput
  ,listActions
  ,InputState(..)
)
 where

import Shaker.Parser
import Shaker.Type
import Control.Concurrent
import Control.Monad.Trans
import System.Console.Haskeline
import qualified Data.Map as M
import Data.List
import Control.Monad.Reader
 
-- | The input mvar is used to push the parsed command
type Input = MVar Command
-- | Token is used to manage the token between action executor and command-line listener
type Token = MVar Int

data InputState = InputState {  
  input :: Input,
  token :: Token
}

-- | Listen to keyboard input and parse command
getInput :: InputState -> Shaker IO()
getInput inSt = do
        shIn <- ask 
        lift $ runInputT (myDefaultSettings shIn) $ processInput shIn inSt

-- | Execute the entered command 
processInput :: ShakerInput ->  InputState -> InputT IO()
processInput shIn (InputState inputMv tokenMv) = do
  _ <- lift $ takeMVar tokenMv 
  minput <- getInputLine "% "
  case minput of 
     Nothing -> return()
     Just str -> lift $ tryPutMVar inputMv (parseCommand shIn str) >> return() 

-- * Auto-completion management 

-- | Settings for haskeline
myDefaultSettings :: MonadIO m => ShakerInput-> Settings m
myDefaultSettings shIn = Settings {
  complete = completeAction shIn,
  historyFile = Just ".haskelineHistory",
  autoAddHistory = True
}

completeAction :: Monad m => ShakerInput -> CompletionFunc m
completeAction shIn = completeWord (Just '\\') "\"'~" (listActions shIn)

listActions :: Monad m => ShakerInput -> String -> m [Completion]
listActions shIn str = return $ autocompleteFunction (commandMap shIn) str

autocompleteFunction :: CommandMap  -> String -> [Completion]
autocompleteFunction cmdMap [] = map simpleCompletion $ M.keys cmdMap
autocompleteFunction cmdMap cliInput = map simpleCompletion  compleListProp
  where inpWords = words cliInput
        lastWord = last inpWords 
        listProp = filter (lastWord `isPrefixOf`) $ M.keys cmdMap
        commonPref = unwords (init inpWords)
        compleListProp = trimList $ map  (\a -> commonPref ++ " " ++ a) listProp

trimList :: [String] -> [String]
trimList = map (dropWhile (== ' '))