1{-# LANGUAGE DoAndIfThenElse #-}
2{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE MultiParamTypeClasses #-}
4{-# LANGUAGE TupleSections #-}
5{-# LANGUAGE DataKinds #-}
7module Language.PureScript.Interactive
11 -- TODO: remove these exports
19import Data.List (nub, sort, find, foldl')
20import Data.Maybe (mapMaybe)
21import qualified Data.Map as M
22import Data.Monoid ((<>))
23import Data.Text (Text)
24import qualified Data.Text as T
26import Control.Monad.IO.Class (MonadIO, liftIO)
27import Control.Monad.State.Class
28import Control.Monad.Reader.Class
29import Control.Monad.Trans.Except (ExceptT(..), runExceptT)
30import Control.Monad.Trans.State.Strict (StateT, runStateT)
31import Control.Monad.Writer.Strict (Writer(), runWriter)
33import qualified Language.PureScript as P
34import qualified Language.PureScript.Names as N
36import Language.PureScript.Interactive.Completion as Interactive
37import Language.PureScript.Interactive.IO as Interactive
38import Language.PureScript.Interactive.Message as Interactive
39import Language.PureScript.Interactive.Module as Interactive
40import Language.PureScript.Interactive.Parser as Interactive
41import Language.PureScript.Interactive.Printer as Interactive
42import Language.PureScript.Interactive.Types as Interactive
44import System.FilePath ((</>))
46-- | Pretty-print errors
47printErrors :: MonadIO m => P.MultipleErrors -> m ()
48printErrors = liftIO . putStrLn . P.prettyPrintMultipleErrors P.defaultPPEOptions
50-- | This is different than the runMake in 'Language.PureScript.Make' in that it specifies the
51-- options and ignores the warning messages.
52runMake :: P.Make a -> IO (Either P.MultipleErrors a)
53runMake mk = fst <$> P.runMake P.defaultOptions mk
55-- | Rebuild a module, using the cached externs data for dependencies.
59 -> P.Make (P.ExternsFile, P.Environment)
60rebuild loadedExterns m = do
61 externs <- P.rebuildModule buildActions loadedExterns m
62 return (externs, foldl' (flip P.applyExternsFileToEnvironment) P.initEnvironment (loadedExterns ++ [externs]))
64 buildActions :: P.MakeActions P.Make
66 (P.buildMakeActions modulesDir
69 False) { P.progress = const (return ()) }
71 filePathMap :: M.Map P.ModuleName (Either P.RebuildPolicy FilePath)
72 filePathMap = M.singleton (P.getModuleName m) (Left P.RebuildAlways)
74-- | Build the collection of modules from scratch. This is usually done on startup.
76 :: [(FilePath, P.Module)]
77 -> P.Make ([P.ExternsFile], P.Environment)
79 foreignFiles <- P.inferForeignModules filePathMap
80 externs <- P.make (buildActions foreignFiles) (map snd ms)
81 return (externs, foldl' (flip P.applyExternsFileToEnvironment) P.initEnvironment externs)
83 buildActions :: M.Map P.ModuleName FilePath -> P.MakeActions P.Make
84 buildActions foreignFiles =
85 P.buildMakeActions modulesDir
90 filePathMap :: M.Map P.ModuleName (Either P.RebuildPolicy FilePath)
91 filePathMap = M.fromList $ map (\(fp, m) -> (P.getModuleName m, Right fp)) ms
93-- | Performs a PSCi command
95 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
100handleCommand _ _ ShowHelp = liftIO $ putStrLn helpMessage
101handleCommand _ r ResetState = handleResetState r
102handleCommand c _ (Expression val) = handleExpression c val
103handleCommand _ _ (Import im) = handleImport im
104handleCommand _ _ (Decls l) = handleDecls l
105handleCommand _ _ (TypeOf val) = handleTypeOf val
106handleCommand _ _ (KindOf typ) = handleKindOf typ
107handleCommand _ _ (BrowseModule moduleName) = handleBrowse moduleName
108handleCommand _ _ (ShowInfo QueryLoaded) = handleShowLoadedModules
109handleCommand _ _ (ShowInfo QueryImport) = handleShowImportedModules
110handleCommand _ _ _ = P.internalError "handleCommand: unexpected command"
112-- | Reset the application state
114 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
117handleResetState reload = do
118 modify $ updateImportedModules (const [])
119 . updateLets (const [])
120 files <- asks psciLoadedFiles
122 modules <- ExceptT . liftIO $ loadAllModules files
123 (externs, _) <- ExceptT . liftIO . runMake . make $ modules
124 return (map snd modules, externs)
126 Left errs -> printErrors errs
127 Right (modules, externs) -> do
128 modify (updateLoadedExterns (const (zip modules externs)))
131-- | Takes a value expression and evaluates it with the current state.
133 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
137handleExpression evaluate val = do
139 let m = createTemporaryModule True st val
140 e <- liftIO . runMake $ rebuild (map snd (psciLoadedExterns st)) m
142 Left errs -> printErrors errs
144 js <- liftIO $ readFile (modulesDir </> "$PSCI" </> "index.js")
148-- Takes a list of declarations and updates the environment, then run a make. If the declaration fails,
149-- restore the original environment.
152 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
156 st <- gets (updateLets (++ ds))
157 let m = createTemporaryModule False st (P.Literal (P.ObjectLiteral []))
158 e <- liftIO . runMake $ rebuild (map snd (psciLoadedExterns st)) m
160 Left err -> printErrors err
163-- | Show actual loaded modules in psci.
164handleShowLoadedModules
165 :: (MonadState PSCiState m, MonadIO m)
167handleShowLoadedModules = do
168 loadedModules <- gets psciLoadedExterns
169 liftIO $ putStrLn (readModules loadedModules)
171 readModules = unlines . sort . nub . map (T.unpack . P.runModuleName . P.getModuleName . fst)
173-- | Show the imported modules in psci.
174handleShowImportedModules
175 :: (MonadState PSCiState m, MonadIO m)
177handleShowImportedModules = do
178 PSCiState { psciImportedModules = importedModules } <- get
179 liftIO $ showModules importedModules >>= putStrLn
182 showModules = return . unlines . sort . map (T.unpack . showModule)
183 showModule (mn, declType, asQ) =
184 "import " <> N.runModuleName mn <> showDeclType declType <>
185 foldMap (\mn' -> " as " <> N.runModuleName mn') asQ
187 showDeclType P.Implicit = ""
188 showDeclType (P.Explicit refs) = refsList refs
189 showDeclType (P.Hiding refs) = " hiding " <> refsList refs
190 refsList refs = " (" <> commaList (mapMaybe showRef refs) <> ")"
192 showRef :: P.DeclarationRef -> Maybe Text
193 showRef (P.TypeRef pn dctors) =
194 Just $ N.runProperName pn <> "(" <> maybe ".." (commaList . map N.runProperName) dctors <> ")"
195 showRef (P.TypeOpRef op) =
196 Just $ "type " <> N.showOp op
197 showRef (P.ValueRef ident) =
198 Just $ N.runIdent ident
199 showRef (P.ValueOpRef op) =
201 showRef (P.TypeClassRef pn) =
202 Just $ "class " <> N.runProperName pn
203 showRef (P.TypeInstanceRef ident) =
204 Just $ N.runIdent ident
205 showRef (P.ModuleRef name) =
206 Just $ "module " <> N.runModuleName name
207 showRef (P.ReExportRef _ _) =
209 showRef (P.PositionedDeclarationRef _ _ ref) =
212 commaList :: [Text] -> Text
213 commaList = T.intercalate ", "
215-- | Imports a module, preserving the initial state on failure.
217 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
221 st <- gets (updateImportedModules (im :))
222 let m = createTemporaryModuleForImports st
223 e <- liftIO . runMake $ rebuild (map snd (psciLoadedExterns st)) m
225 Left errs -> printErrors errs
228-- | Takes a value and prints its type
230 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
235 let m = createTemporaryModule False st val
236 e <- liftIO . runMake $ rebuild (map snd (psciLoadedExterns st)) m
238 Left errs -> printErrors errs
240 case M.lookup (P.mkQualified (P.Ident "it") (P.ModuleName [P.ProperName "$PSCI"])) (P.names env') of
241 Just (ty, _, _) -> liftIO . putStrLn . P.prettyPrintType $ ty
242 Nothing -> liftIO $ putStrLn "Could not find type"
244-- | Takes a type and prints its kind
246 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
251 let m = createTemporaryModuleForKind st typ
252 mName = P.ModuleName [P.ProperName "$PSCI"]
253 e <- liftIO . runMake $ rebuild (map snd (psciLoadedExterns st)) m
255 Left errs -> printErrors errs
257 case M.lookup (P.Qualified (Just mName) $ P.ProperName "IT") (P.typeSynonyms env') of
259 let chk = (P.emptyCheckState env') { P.checkCurrentModule = Just mName }
260 k = check (P.kindOf typ') chk
262 check :: StateT P.CheckState (ExceptT P.MultipleErrors (Writer P.MultipleErrors)) a -> P.CheckState -> Either P.MultipleErrors (a, P.CheckState)
263 check sew = fst . runWriter . runExceptT . runStateT sew
265 Left err -> printErrors err
266 Right (kind, _) -> liftIO . putStrLn . T.unpack . P.prettyPrintKind $ kind
267 Nothing -> liftIO $ putStrLn "Could not find kind"
269-- | Browse a module and displays its signature
271 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
274handleBrowse moduleName = do
276 env <- asks psciEnvironment
277 if isModInEnv moduleName st
278 then liftIO . putStrLn $ printModuleSignatures moduleName env
279 else case lookupUnQualifiedModName moduleName st of
280 Just unQualifiedName ->
281 if isModInEnv unQualifiedName st
282 then liftIO . putStrLn $ printModuleSignatures unQualifiedName env
283 else failNotInEnv moduleName
285 failNotInEnv moduleName
288 any ((== modName) . P.getModuleName . fst) . psciLoadedExterns
289 failNotInEnv modName =
290 liftIO $ putStrLn $ T.unpack $ "Module '" <> N.runModuleName modName <> "' is not valid."
291 lookupUnQualifiedModName quaModName st =
292 (\(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