1{-# LANGUAGE DoAndIfThenElse #-}
3module Language.PureScript.Interactive
7 -- TODO: remove these exports
15import Data.List (nub, sort, find, foldl')
16import Data.Maybe (mapMaybe)
17import qualified Data.Map as M
18import Data.Monoid ((<>))
19import Data.Text (Text)
20import qualified Data.Text as T
22import Control.Monad.IO.Class (MonadIO, liftIO)
23import Control.Monad.State.Class
24import Control.Monad.Reader.Class
25import Control.Monad.Trans.Except (ExceptT(..), runExceptT)
26import Control.Monad.Trans.State.Strict (StateT, runStateT)
27import Control.Monad.Writer.Strict (Writer(), runWriter)
29import qualified Language.PureScript as P
30import qualified Language.PureScript.Names as N
32import Language.PureScript.Interactive.Completion as Interactive
33import Language.PureScript.Interactive.IO as Interactive
34import Language.PureScript.Interactive.Message as Interactive
35import Language.PureScript.Interactive.Module as Interactive
36import Language.PureScript.Interactive.Parser as Interactive
37import Language.PureScript.Interactive.Printer as Interactive
38import Language.PureScript.Interactive.Types as Interactive
40import System.FilePath ((</>))
42-- | Pretty-print errors
43printErrors :: MonadIO m => P.MultipleErrors -> m ()
44printErrors = liftIO . putStrLn . P.prettyPrintMultipleErrors P.defaultPPEOptions
46-- | This is different than the runMake in 'Language.PureScript.Make' in that it specifies the
47-- options and ignores the warning messages.
48runMake :: P.Make a -> IO (Either P.MultipleErrors a)
49runMake mk = fst <$> P.runMake P.defaultOptions mk
51-- | Rebuild a module, using the cached externs data for dependencies.
55 -> P.Make (P.ExternsFile, P.Environment)
56rebuild loadedExterns m = do
57 externs <- P.rebuildModule buildActions loadedExterns m
58 return (externs, foldl' (flip P.applyExternsFileToEnvironment) P.initEnvironment (loadedExterns ++ [externs]))
60 buildActions :: P.MakeActions P.Make
62 (P.buildMakeActions modulesDir
65 False) { P.progress = const (return ()) }
67 filePathMap :: M.Map P.ModuleName (Either P.RebuildPolicy FilePath)
68 filePathMap = M.singleton (P.getModuleName m) (Left P.RebuildAlways)
70-- | Build the collection of modules from scratch. This is usually done on startup.
72 :: [(FilePath, P.Module)]
73 -> P.Make ([P.ExternsFile], P.Environment)
75 foreignFiles <- P.inferForeignModules filePathMap
76 externs <- P.make (buildActions foreignFiles) (map snd ms)
77 return (externs, foldl' (flip P.applyExternsFileToEnvironment) P.initEnvironment externs)
79 buildActions :: M.Map P.ModuleName FilePath -> P.MakeActions P.Make
80 buildActions foreignFiles =
81 P.buildMakeActions modulesDir
86 filePathMap :: M.Map P.ModuleName (Either P.RebuildPolicy FilePath)
87 filePathMap = M.fromList $ map (\(fp, m) -> (P.getModuleName m, Right fp)) ms
89-- | Performs a PSCi command
91 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
96handleCommand _ _ ShowHelp = liftIO $ putStrLn helpMessage
97handleCommand _ r ResetState = handleResetState r
98handleCommand c _ (Expression val) = handleExpression c val
99handleCommand _ _ (Import im) = handleImport im
100handleCommand _ _ (Decls l) = handleDecls l
101handleCommand _ _ (TypeOf val) = handleTypeOf val
102handleCommand _ _ (KindOf typ) = handleKindOf typ
103handleCommand _ _ (BrowseModule moduleName) = handleBrowse moduleName
104handleCommand _ _ (ShowInfo QueryLoaded) = handleShowLoadedModules
105handleCommand _ _ (ShowInfo QueryImport) = handleShowImportedModules
106handleCommand _ _ _ = P.internalError "handleCommand: unexpected command"
108-- | Reset the application state
110 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
113handleResetState reload = do
114 modify $ updateImportedModules (const [])
115 . updateLets (const [])
116 files <- asks psciLoadedFiles
118 modules <- ExceptT . liftIO $ loadAllModules files
119 (externs, _) <- ExceptT . liftIO . runMake . make $ modules
120 return (map snd modules, externs)
122 Left errs -> printErrors errs
123 Right (modules, externs) -> do
124 modify (updateLoadedExterns (const (zip modules externs)))
127-- | Takes a value expression and evaluates it with the current state.
129 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
133handleExpression evaluate val = do
135 let m = createTemporaryModule True st val
136 e <- liftIO . runMake $ rebuild (map snd (psciLoadedExterns st)) m
138 Left errs -> printErrors errs
140 js <- liftIO $ readFile (modulesDir </> "$PSCI" </> "index.js")
144-- Takes a list of declarations and updates the environment, then run a make. If the declaration fails,
145-- restore the original environment.
148 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
152 st <- gets (updateLets (++ ds))
153 let m = createTemporaryModule False st (P.Literal (P.ObjectLiteral []))
154 e <- liftIO . runMake $ rebuild (map snd (psciLoadedExterns st)) m
156 Left err -> printErrors err
159-- | Show actual loaded modules in psci.
160handleShowLoadedModules
161 :: (MonadState PSCiState m, MonadIO m)
163handleShowLoadedModules = do
164 loadedModules <- gets psciLoadedExterns
165 liftIO $ putStrLn (readModules loadedModules)
167 readModules = unlines . sort . nub . map (T.unpack . P.runModuleName . P.getModuleName . fst)
169-- | Show the imported modules in psci.
170handleShowImportedModules
171 :: (MonadState PSCiState m, MonadIO m)
173handleShowImportedModules = do
174 PSCiState { psciImportedModules = importedModules } <- get
175 liftIO $ showModules importedModules >>= putStrLn
178 showModules = return . unlines . sort . map (T.unpack . showModule)
179 showModule (mn, declType, asQ) =
180 "import " <> N.runModuleName mn <> showDeclType declType <>
181 foldMap (\mn' -> " as " <> N.runModuleName mn') asQ
183 showDeclType P.Implicit = ""
184 showDeclType (P.Explicit refs) = refsList refs
185 showDeclType (P.Hiding refs) = " hiding " <> refsList refs
186 refsList refs = " (" <> commaList (mapMaybe showRef refs) <> ")"
188 showRef :: P.DeclarationRef -> Maybe Text
189 showRef (P.TypeRef pn dctors) =
190 Just $ N.runProperName pn <> "(" <> maybe ".." (commaList . map N.runProperName) dctors <> ")"
191 showRef (P.TypeOpRef op) =
192 Just $ "type " <> N.showOp op
193 showRef (P.ValueRef ident) =
194 Just $ N.runIdent ident
195 showRef (P.ValueOpRef op) =
197 showRef (P.TypeClassRef pn) =
198 Just $ "class " <> N.runProperName pn
199 showRef (P.TypeInstanceRef ident) =
200 Just $ N.runIdent ident
201 showRef (P.ModuleRef name) =
202 Just $ "module " <> N.runModuleName name
203 showRef (P.KindRef pn) =
204 Just $ "kind " <> N.runProperName pn
205 showRef (P.ReExportRef _ _) =
207 showRef (P.PositionedDeclarationRef _ _ ref) =
210 commaList :: [Text] -> Text
211 commaList = T.intercalate ", "
213-- | Imports a module, preserving the initial state on failure.
215 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
219 st <- gets (updateImportedModules (im :))
220 let m = createTemporaryModuleForImports st
221 e <- liftIO . runMake $ rebuild (map snd (psciLoadedExterns st)) m
223 Left errs -> printErrors errs
226-- | Takes a value and prints its type
228 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
233 let m = createTemporaryModule False st val
234 e <- liftIO . runMake $ rebuild (map snd (psciLoadedExterns st)) m
236 Left errs -> printErrors errs
238 case M.lookup (P.mkQualified (P.Ident "it") (P.ModuleName [P.ProperName "$PSCI"])) (P.names env') of
239 Just (ty, _, _) -> liftIO . putStrLn . P.prettyPrintType $ ty
240 Nothing -> liftIO $ putStrLn "Could not find type"
242-- | Takes a type and prints its kind
244 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
249 let m = createTemporaryModuleForKind st typ
250 mName = P.ModuleName [P.ProperName "$PSCI"]
251 e <- liftIO . runMake $ rebuild (map snd (psciLoadedExterns st)) m
253 Left errs -> printErrors errs
255 case M.lookup (P.Qualified (Just mName) $ P.ProperName "IT") (P.typeSynonyms env') of
257 let chk = (P.emptyCheckState env') { P.checkCurrentModule = Just mName }
258 k = check (P.kindOf typ') chk
260 check :: StateT P.CheckState (ExceptT P.MultipleErrors (Writer P.MultipleErrors)) a -> P.CheckState -> Either P.MultipleErrors (a, P.CheckState)
261 check sew = fst . runWriter . runExceptT . runStateT sew
263 Left err -> printErrors err
264 Right (kind, _) -> liftIO . putStrLn . T.unpack . P.prettyPrintKind $ kind
265 Nothing -> liftIO $ putStrLn "Could not find kind"
267-- | Browse a module and displays its signature
269 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
272handleBrowse moduleName = do
274 env <- asks psciEnvironment
275 if isModInEnv moduleName st
276 then liftIO . putStrLn $ printModuleSignatures moduleName env
277 else case lookupUnQualifiedModName moduleName st of
278 Just unQualifiedName ->
279 if isModInEnv unQualifiedName st
280 then liftIO . putStrLn $ printModuleSignatures unQualifiedName env
281 else failNotInEnv moduleName
283 failNotInEnv moduleName
286 any ((== modName) . P.getModuleName . fst) . psciLoadedExterns
287 failNotInEnv modName =
288 liftIO $ putStrLn $ T.unpack $ "Module '" <> N.runModuleName modName <> "' is not valid."
289 lookupUnQualifiedModName quaModName st =
290 (\(modName,_,_) -> modName) <$> find ( \(_, _, mayQuaName) -> mayQuaName == Just quaModName) (psciImportedModules st)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list