packages feed

forml-0.2: src/hs/Forml/CLI.hs

module Forml.CLI where

import Control.Monad.State hiding (lift)

import System.Console.ANSI
import System.Exit
import System.IO
import System.Process

import Data.String.Utils


data TestMode  = NoTest | Node | Phantom

data RunConfig = RunConfig { inputs :: [String]
                           , output :: String
                           , show_types :: Bool
                           , optimize :: Bool
                           , silent :: Bool
                           , flush :: Bool
                           , run_tests :: TestMode
                           , write_docs :: Bool
                           , implicit_prelude :: Bool
                           , watch :: Bool }


parseArgs :: [String] -> RunConfig
parseArgs = fst . runState argsParser
  where argsParser = do args <- get
                        case args of
                          []      -> return $ RunConfig [] "default" False True False False Phantom False True False
                          (x':xs) -> do put xs
                                        case x' of
                                          "-w"          -> do x <- argsParser
                                                              return $ x { watch = True }
                                          "-docs"       -> do x <- argsParser
                                                              return $ x { write_docs = True }
                                          "-t"          -> do x <- argsParser
                                                              return $ x { show_types = True }
                                          "-no-prelude" -> do x <- argsParser
                                                              return $ x { implicit_prelude = False }
                                          "-no-opt"     -> do x <- argsParser
                                                              return $ x { optimize = False }
                                          "-silent"     -> do x <- argsParser
                                                              return $ x { silent = True }
                                          "-flush"      -> do x <- argsParser
                                                              return $ x { flush = True }
                                          "-no-test"    -> do x <- argsParser
                                                              return $ x { run_tests = NoTest }
                                          "-node-test"  -> do x <- argsParser
                                                              return $ x { run_tests = Node }
                                          "-o"          -> do (name:ys) <- get
                                                              put ys
                                                              RunConfig a _ c d e f g h i j <- argsParser
                                                              return $ RunConfig a name c d e f g h i j
                                          ('-':_)       -> error "Could not parse options"
                                          z             -> do RunConfig a _ c d e f g h i j <- argsParser
                                                              let b = last $ split "/" $ head $ split "." z
                                                              return $ RunConfig (x':a) b c d e f g h i j

type StatusLogger a = String -> a -> IO a

status_logger :: [SGR] -> String -> StatusLogger a
status_logger sgrs rep = 
  let logger str out =  
        colors ((putStr $ "[" ++ rep ++ "] " ++ str) >> return out) $
        do  putStr "\r["
            setSGR sgrs
            putStr rep
            setSGR []
            putStrLn$ "] " ++ str
            return out in
  logger

success :: String -> a -> IO a
success = status_logger [SetColor Foreground Dull Green] "*"

warn :: String -> a -> IO a
warn = status_logger [SetColor Foreground Dull Yellow] "-"

failure :: String -> a -> IO a
failure = status_logger [SetColor Foreground Dull Red] "X"

colors :: IO a -> IO a -> IO a
colors failure success =
          do (_, Just std_out', _, p) <-
                 createProcess (shell "tput colors 2> /dev/null") { std_out = CreatePipe }
             waitForProcess p
             c <- hGetContents std_out'
             case reads (strip c) of
                [(x, "")] | x > (2 :: Integer) -> success
                _ -> failure

type Runner a = String -> IO (Either [String] a) -> IO a

run_silent :: Runner a
run_silent _ d = 
  do  d' <- d
      case d' of 
        Right y -> do return y
        Left  y -> do exitFailure

monitor :: Runner a
monitor x d = do colors (return ()) $ putStr $ "[ ] " ++ x
                 hFlush stdout
                 d' <- d
                 case d' of
                   Right y -> success x y
                   Left  y -> do  failure x y 
                                  if length y <= 5
                                    then mapM putStrLn y >> return ()
                                    else mapM putStrLn (take 5 y) >> putStrLn ("\n" ++ show (length y - 5) ++ " additional errors")
                                  exitFailure