@@ -33,25 +33,32 @@ import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)
3333import Control.Monad.Trans.State.Strict
3434import qualified Control.Monad.Trans.State.Lazy as L
3535
36+import Options.Applicative as Opts
37+
3638import System.Console.Haskeline
3739import System.Directory (createDirectoryIfMissing, getModificationTime, doesFileExist, findExecutable, getHomeDirectory, getCurrentDirectory)
3840import System.Exit
3941import System.FilePath (pathSeparator, takeDirectory, (</>), isPathSeparator)
4042import System.IO.Error (tryIOError)
4143import System.Process (readProcessWithExitCode)
42−import qualified System.Console.CmdTheLine as Cmd
4344import qualified System.IO.UTF8 as U (writeFile, putStrLn, print, readFile)
4445
45−import Text.Parsec (ParseError)
46+import qualified Text.Parsec as Par (ParseError)
4647
4748import qualified Language.PureScript as P
4849import qualified Language.PureScript.AST as D
4950import qualified Language.PureScript.Names as N
5051import qualified Paths_purescript as Paths
5152
52−import Commands
53+import Commands as C
5354import Parser
5455
56+
57+data PSCiOptions = PSCiOptions
58+ { psciSingleLineFlag :: Bool
59+ , psciInputFile :: [FilePath]
60+ }
61+
5562-- |
5663-- The PSCI state.
5764-- Holds a list of imported modules, loaded files, and partial let bindings.
@@ -125,7 +132,7 @@ loadModule filename = either (Left . show) Right . P.runIndentParser filename P.
125132-- |
126133-- Load all modules, including the Prelude
127134--
128−loadAllModules :: [FilePath] -> IO (Either ParseError [(Either P.RebuildPolicy FilePath, P.Module)])
135+loadAllModules :: [FilePath] -> IO (Either Par.ParseError [(Either P.RebuildPolicy FilePath, P.Module)])
129136loadAllModules files = do
130137 filesAndContent <- forM files $ \filename -> do
131138 content <- U.readFile filename
@@ -146,7 +153,7 @@ expandTilde p = return p
146153--
147154helpMessage :: String
148155helpMessage = "The following commands are available:\n\n " ++
149− intercalate "\n " (map (intercalate " ") help)
156+ intercalate "\n " (map (intercalate " ") C.help)
150157
151158-- |
152159-- The welcome prologue.
@@ -180,10 +187,10 @@ completion :: CompletionFunc (StateT PSCiState IO)
180187completion = completeWord Nothing " \t\n\r" findCompletions
181188 where
182189 findCompletions :: String -> StateT PSCiState IO [Completion]
183− findCompletions str = do
190+ findCompletions st = do
184191 ms <- map snd . psciLoadedModules <$> get
185− files <- listFiles str
186− let matches = filter (isPrefixOf str) (names ms)
192+ files <- listFiles st
193+ let matches = filter (isPrefixOf st) (names ms)
187194 return $ sortBy sorter $ map simpleCompletion matches ++ files
188195 getDeclName :: Maybe [P.DeclarationRef] -> P.Declaration -> Maybe P.Ident
189196 getDeclName Nothing (P.ValueDeclaration ident _ _ _) = Just ident
@@ -248,13 +255,13 @@ mkdirp = createDirectoryIfMissing True . takeDirectory
248255-- Makes a volatile module to execute the current expression.
249256--
250257createTemporaryModule :: Bool -> PSCiState -> P.Expr -> P.Module
251−createTemporaryModule exec PSCiState{psciImportedModuleNames = imports, psciLetBindings = lets} value =
258+createTemporaryModule exec PSCiState{psciImportedModuleNames = imports, psciLetBindings = lets} val =
252259 let
253260 moduleName = P.ModuleName [P.ProperName "$PSCI"]
254261 importDecl m = P.ImportDeclaration m P.Unqualified Nothing
255262 traceModule = P.ModuleName [P.ProperName "Debug", P.ProperName "Trace"]
256263 trace = P.Var (P.Qualified (Just traceModule) (P.Ident "print"))
257− itValue = foldl (\x f -> f x) value lets
264+ itValue = foldl (\x f -> f x) val lets
258265 mainValue = P.App trace (P.Var (P.Qualified Nothing (P.Ident "it")))
259266 itDecl = P.ValueDeclaration (P.Ident "it") P.Value [] $ Right itValue
260267 mainDecl = P.ValueDeclaration (P.Ident "main") P.Value [] $ Right mainValue
@@ -295,9 +302,9 @@ indexFile = ".psci_modules" ++ pathSeparator : "index.js"
295302-- Takes a value declaration and evaluates it with the current state.
296303--
297304handleDeclaration :: P.Expr -> PSCI ()
298−handleDeclaration value = do
305+handleDeclaration val = do
299306 st <- PSCI $ lift get
300− let m = createTemporaryModule True st value
307+ let m = createTemporaryModule True st val
301308 e <- psciIO . runMake $ P.make modulesDir options (psciLoadedModules st ++ [(Left P.RebuildAlways, m)]) []
302309 case e of
303310 Left err -> PSCI $ outputStrLn err
@@ -363,9 +370,9 @@ handleImport moduleName = do
363370-- Takes a value and prints its type
364371--
365372handleTypeOf :: P.Expr -> PSCI ()
366−handleTypeOf value = do
373+handleTypeOf val = do
367374 st <- PSCI $ lift get
368− let m = createTemporaryModule False st value
375+ let m = createTemporaryModule False st val
369376 e <- psciIO . runMake $ P.make modulesDir options (psciLoadedModules st ++ [(Left P.RebuildAlways, m)]) []
370377 case e of
371378 Left err -> PSCI $ outputStrLn err
@@ -434,7 +441,7 @@ handleKindOf typ = do
434441-- |
435442-- Parses the input and returns either a Metacommand or an expression.
436443--
437−getCommand :: Bool -> InputT (StateT PSCiState IO) (Either ParseError (Maybe Command))
444+getCommand :: Bool -> InputT (StateT PSCiState IO) (Either Par.ParseError (Maybe Command))
438445getCommand singleLineMode = do
439446 firstLine <- getInputLine "> "
440447 case firstLine of
@@ -478,17 +485,6 @@ handleCommand (Show "loaded") = handleShowLoadedModules
478485handleCommand (Show "import") = handleShowImportedModules
479486handleCommand _ = PSCI $ outputStrLn "Unknown command"
480487
481−singleLineFlag :: Cmd.Term Bool
482−singleLineFlag = Cmd.value $ Cmd.flag $ (Cmd.optInfo ["single-line-mode"])
483− { Cmd.optName = "Single-line mode"
484− , Cmd.optDoc = "Run in single-line mode"
485− }
486−
487−inputFiles :: Cmd.Term [FilePath]
488−inputFiles = Cmd.value $ Cmd.posAny [] $ Cmd.posInfo { Cmd.posName = "file(s)"
489− , Cmd.posDoc = "Optional .purs files to load on start"
490− }
491−
492488loadUserConfig :: IO (Maybe [Command])
493489loadUserConfig = do
494490 configFile <- (</> ".psci") <$> getCurrentDirectory
@@ -505,8 +501,8 @@ loadUserConfig = do
505501-- |
506502-- The PSCI main loop.
507503--
508−loop :: Bool -> [FilePath] -> IO ()
509−loop singleLineMode files = do
504+loop :: PSCiOptions -> IO ()
505+loop (PSCiOptions singleLineMode files) = do
510506 config <- loadUserConfig
511507 modulesOrFirstError <- loadAllModules files
512508 case modulesOrFirstError of
@@ -528,15 +524,25 @@ loop singleLineMode files = do
528524 Right (Just Quit) -> outputStrLn quitMessage
529525 Right (Just c') -> runPSCI (handleCommand c') >> go
530526
531−term :: Cmd.Term (IO ())
532−term = loop <$> singleLineFlag <*> inputFiles
527+singleLineFlag :: Parser Bool
528+singleLineFlag = switch $
529+ long "single-line-mode"
530+ <> Opts.help "Run in single-line mode"
533531
534−termInfo :: Cmd.TermInfo
535−termInfo = Cmd.defTI
536− { Cmd.termName = "psci"
537− , Cmd.version = showVersion Paths.version
538− , Cmd.termDoc = "Interactive mode for PureScript"
539− }
532+inputFile :: Parser FilePath
533+inputFile = strArgument $
534+ metavar "FILE"
535+ <> Opts.help "Optional .purs files to load on start"
536+
537+psciOptions :: Parser PSCiOptions
538+psciOptions = PSCiOptions <$> singleLineFlag
539+ <*> many inputFile
540540
541541main :: IO ()
542−main = Cmd.run (term, termInfo)
542+main = execParser opts >>= loop
543+ where
544+ opts = info (helper <*> psciOptions) infoModList
545+ infoModList = fullDesc <> headerInfo <> footerInfo
546+ headerInfo = header "psci - Interactive mode for PureScript"
547+ footerInfo = footer $ "psci " ++ showVersion Paths.version
548+