@@ -14,7 +14,6 @@
15{-# LANGUAGE OverloadedStrings #-}
15{-# LANGUAGE OverloadedStrings #-}
16{-# LANGUAGE PackageImports #-}
16{-# LANGUAGE PackageImports #-}
17−{-# LANGUAGE TemplateHaskell #-}
19module Language.PureScript.Ide
18module Language.PureScript.Ide
20 ( handleCommand
19 ( handleCommand
@@ -25,14 +24,13 @@ module Language.PureScript.Ide
25import Prelude ()
24import Prelude ()
26import Prelude.Compat
25import Prelude.Compat
28−import Control.Monad (unless)
27+import Control.Concurrent.Async
29import Control.Monad.Error.Class
28import Control.Monad.Error.Class
30import Control.Monad.IO.Class
29import Control.Monad.IO.Class
31import "monad-logger" Control.Monad.Logger
30import "monad-logger" Control.Monad.Logger
32−import Control.Monad.Reader.Class
31+import Control.Monad.Reader
33import Data.Foldable
32import Data.Foldable
34−import qualified Data.Map.Lazy as M
35−import Data.Maybe (catMaybes, mapMaybe)
33+import Data.Maybe (catMaybes)
36import Data.Monoid
34import Data.Monoid
37import Data.Text (Text)
35import Data.Text (Text)
38import qualified Data.Text as T
36import qualified Data.Text as T
@@ -47,7 +45,6 @@ import Language.PureScript.Ide.Imports hiding (Import)
47import Language.PureScript.Ide.Matcher
45import Language.PureScript.Ide.Matcher
48import Language.PureScript.Ide.Pursuit
46import Language.PureScript.Ide.Pursuit
49import Language.PureScript.Ide.Rebuild
47import Language.PureScript.Ide.Rebuild
50−import Language.PureScript.Ide.Reexports
51import Language.PureScript.Ide.SourceFile
48import Language.PureScript.Ide.SourceFile
52import Language.PureScript.Ide.State
49import Language.PureScript.Ide.State
53import Language.PureScript.Ide.Types
50import Language.PureScript.Ide.Types
@@ -56,11 +53,10 @@ import System.Directory
56import System.Exit
53import System.Exit
57import System.FilePath
54import System.FilePath
59−handleCommand :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
56+handleCommand :: (Ide m, MonadLogger m, MonadError PscIdeError m) =>
60 Command -> m Success
57 Command -> m Success
61−handleCommand (Load [] []) = loadAllModules
58+handleCommand (Load []) = loadAllModules
62−handleCommand (Load modules deps) =
59+handleCommand (Load modules) = loadModules modules
63− loadModulesAndDeps modules deps
64handleCommand (Type search filters currentModule) =
60handleCommand (Type search filters currentModule) =
65 findType search filters currentModule
61 findType search filters currentModule
66handleCommand (Complete filters matcher currentModule) =
62handleCommand (Complete filters matcher currentModule) =
@@ -78,7 +74,7 @@ handleCommand (List (Imports fp)) =
78handleCommand (CaseSplit l b e wca t) =
74handleCommand (CaseSplit l b e wca t) =
79 caseSplit l b e wca t
75 caseSplit l b e wca t
80handleCommand (AddClause l wca) =
76handleCommand (AddClause l wca) =
81− pure $ addClause l wca
77+ addClause l wca
82handleCommand (Import fp outfp _ (AddImplicitImport mn)) = do
78handleCommand (Import fp outfp _ (AddImplicitImport mn)) = do
83 rs <- addImplicitImport fp mn
79 rs <- addImplicitImport fp mn
84 answerRequest outfp rs
80 answerRequest outfp rs
@@ -86,25 +82,25 @@ handleCommand (Import fp outfp filters (AddImportForIdentifier ident)) = do
86 rs <- addImportForIdentifier fp ident filters
82 rs <- addImportForIdentifier fp ident filters
87 case rs of
83 case rs of
88 Right rs' -> answerRequest outfp rs'
84 Right rs' -> answerRequest outfp rs'
89− Left question -> pure $ CompletionResult (mapMaybe completionFromMatch question)
85+ Left question -> pure $ CompletionResult (map completionFromMatch question)
90handleCommand (Rebuild file) =
86handleCommand (Rebuild file) =
91 rebuildFile file
87 rebuildFile file
92handleCommand Cwd =
88handleCommand Cwd =
93 TextResult . T.pack <$> liftIO getCurrentDirectory
89 TextResult . T.pack <$> liftIO getCurrentDirectory
94−handleCommand Reset = resetPscIdeState *> pure (TextResult "State has been reset.")
90+handleCommand Reset = resetIdeState *> pure (TextResult "State has been reset.")
95handleCommand Quit = liftIO exitSuccess
91handleCommand Quit = liftIO exitSuccess
97−findCompletions :: (PscIde m) =>
93+findCompletions :: (Ide m) =>
98 [Filter] -> Matcher -> Maybe P.ModuleName -> m Success
94 [Filter] -> Matcher -> Maybe P.ModuleName -> m Success
99findCompletions filters matcher currentModule = do
95findCompletions filters matcher currentModule = do
100− modules <- getAllModulesWithReexportsAndCache currentModule
96+ modules <- getAllModules2 currentModule
101− pure . CompletionResult . mapMaybe completionFromMatch . getCompletions filters matcher $ modules
97+ pure . CompletionResult . map completionFromMatch . getCompletions filters matcher $ modules
103−findType :: (PscIde m) =>
99+findType :: (Ide m) =>
104− DeclIdent -> [Filter] -> Maybe P.ModuleName -> m Success
100+ Text -> [Filter] -> Maybe P.ModuleName -> m Success
105findType search filters currentModule = do
101findType search filters currentModule = do
106− modules <- getAllModulesWithReexportsAndCache currentModule
102+ modules <- getAllModules2 currentModule
107− pure . CompletionResult . mapMaybe completionFromMatch . getExactMatches search filters $ modules
103+ pure . CompletionResult . map completionFromMatch . getExactMatches search filters $ modules
109findPursuitCompletions :: (MonadIO m) =>
105findPursuitCompletions :: (MonadIO m) =>
110 PursuitQuery -> m Success
106 PursuitQuery -> m Success
@@ -116,39 +112,35 @@ findPursuitPackages :: (MonadIO m) =>
116findPursuitPackages (PursuitQuery q) =
112findPursuitPackages (PursuitQuery q) =
117 PursuitResult <$> liftIO (findPackagesForModuleIdent q)
113 PursuitResult <$> liftIO (findPackagesForModuleIdent q)
119−loadExtern :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
115+printModules :: (Ide m) => m Success
120− FilePath -> m ()
116+printModules = ModuleList . map runModuleNameT <$> getLoadedModulenames
122− m <- readExternFile fp
125−printModules :: (PscIde m) => m Success
118+outputDirectory :: Ide m => m FilePath
126−printModules = printModules' . pscIdeStateModules <$> getPscIdeState
119+outputDirectory = do
127−
120+ outputPath <- confOutputPath . ideConfiguration <$> ask
128−printModules' :: M.Map ModuleIdent [ExternDecl] -> Success
121+ cwd <- liftIO getCurrentDirectory
129−printModules' = ModuleList . M.keys
122+ pure (cwd </> outputPath)
131−listAvailableModules :: PscIde m => m Success
124+listAvailableModules :: Ide m => m Success
132listAvailableModules = do
125listAvailableModules = do
133− outputPath <- confOutputPath . envConfiguration <$> ask
126+ oDir <- outputDirectory
134 liftIO $ do
127 liftIO $ do
135− cwd <- getCurrentDirectory
136− dirs <- getDirectoryContents (cwd </> outputPath)
128+ contents <- getDirectoryContents oDir
137− return (ModuleList (listAvailableModules' dirs))
139−listAvailableModules' :: [FilePath] -> [Text]
140−listAvailableModules' dirs =
141− let cleanedModules = filter (`notElem` [".", ".."]) dirs
129+ let cleaned = filter (`notElem` [".", ".."]) contents
142− in map T.pack cleanedModules
130+ return (ModuleList (map T.pack cleaned))
144−caseSplit :: (PscIde m, MonadError PscIdeError m) =>
132+caseSplit :: (Ide m, MonadError PscIdeError m) =>
145 Text -> Int -> Int -> CS.WildcardAnnotations -> Text -> m Success
133 Text -> Int -> Int -> CS.WildcardAnnotations -> Text -> m Success
146caseSplit l b e csa t = do
134caseSplit l b e csa t = do
147 patterns <- CS.makePattern l b e csa <$> CS.caseSplit t
135 patterns <- CS.makePattern l b e csa <$> CS.caseSplit t
148 pure (MultilineTextResult patterns)
136 pure (MultilineTextResult patterns)
139+ :: (MonadError PscIdeError m)
150−addClause :: Text -> CS.WildcardAnnotations -> Success
141+ -> CS.WildcardAnnotations
151−addClause t wca = MultilineTextResult (CS.addClause t wca)
143+addClause t wca = MultilineTextResult <$> CS.addClause t wca
153importsForFile :: (MonadIO m, MonadError PscIdeError m) =>
145importsForFile :: (MonadIO m, MonadError PscIdeError m) =>
154 FilePath -> m Success
146 FilePath -> m Success
@@ -156,90 +148,48 @@ importsForFile fp = do
156 imports <- getImportsForFile fp
148 imports <- getImportsForFile fp
157 pure (ImportList imports)
149 pure (ImportList imports)
159−-- | The first argument is a set of modules to load. The second argument
151+-- | Takes the output directory and a filepath like "Monad.Control.Eff" and
160−-- denotes modules for which to load dependencies
152+-- looks up, whether that folder contains an externs.json
161−loadModulesAndDeps :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
153+checkExternsPath :: FilePath -> FilePath -> IO (Maybe FilePath)
162− [ModuleIdent] -> [ModuleIdent] -> m Success
154+checkExternsPath oDir d
163−loadModulesAndDeps mods deps = do
155+ | d `elem` [".", ".."] = pure Nothing
164− r1 <- mapM loadModule (mods ++ deps)
156+ | otherwise = do
165− r2 <- mapM loadModuleDependencies deps
157+ let file = oDir </> d </> "externs.json"
166− let moduleResults = T.concat r1
158+ ex <- doesFileExist file
167− let dependencyResults = T.concat r2
159+ if ex
168− pure (TextResult (moduleResults <> ", " <> dependencyResults))
160+ then pure (Just file)
169−
161+ else pure Nothing
170−loadModuleDependencies ::(PscIde m, MonadLogger m, MonadError PscIdeError m) =>
162+
171− ModuleIdent -> m Text
163+findAllExterns :: (Ide m, MonadError PscIdeError m) => m [FilePath]
172−loadModuleDependencies moduleName = do
164+findAllExterns = do
173− m <- getModule moduleName
165+ oDir <- outputDirectory
174− case getDependenciesForModule <$> m of
166+ unlessM (liftIO (doesDirectoryExist oDir))
175− Just deps -> do
167+ (throwError (GeneralError "Couldn't locate your output directory."))
176− mapM_ loadModule deps
168+ liftIO $ do
177− -- We need to load the modules, that get reexported from the dependencies
169+ dirs <- getDirectoryContents oDir
178− depModules <- catMaybes <$> mapM getModule deps
170+ externPaths <- traverse (checkExternsPath oDir) dirs
179− -- What to do with errors here? This basically means a reexported dependency
171+ pure (catMaybes externPaths)
180− -- doesn't exist in the output/ folder
172+
181− traverse_ loadReexports depModules
173+loadModules
182− pure ("Dependencies for " <> moduleName <> " loaded.")
174+ :: (Ide m, MonadError PscIdeError m, MonadLogger m)
183− Nothing -> throwError (ModuleNotFound moduleName)
175+ => [P.ModuleName]
185−loadReexports :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
177+loadModules mns = do
186− Module -> m [ModuleIdent]
178+ oDir <- outputDirectory
187−loadReexports m = case getReexports m of
179+ let efPaths = map (\mn -> oDir </> P.runModuleName mn </> "externs.json") mns
188− [] -> pure []
180+ efiles <- traverse readExternFile efPaths
189− exportDeps -> do
181+ traverse_ insertExterns efiles
190− -- I'm fine with this crashing on a failed pattern match.
182+ --TODO Get rid of this once ModuleOld is gone
191− -- If this ever fails I'll need to look at GADTs
183+ traverse_ insertModule efiles
192− let reexports = map (\(Export mn) -> mn) exportDeps
184+ populateStage2
193− $(logDebug) ("Loading reexports for module: " <> fst m <>
185+ pure (TextResult ("Loaded " <> foldMap runModuleNameT mns <> "."))
194− " reexports: " <> T.intercalate ", " reexports)
186+
195− traverse_ loadModule reexports
196− exportDepsModules <- catMaybes <$> traverse getModule reexports
197− exportDepDeps <- traverse loadReexports exportDepsModules
198− return $ concat exportDepDeps
200−getDependenciesForModule :: Module -> [ModuleIdent]
201−getDependenciesForModule (_, decls) = mapMaybe getDependencyName decls
202− where getDependencyName (Dependency dependencyName _ _) = Just dependencyName
203− getDependencyName _ = Nothing
205−loadModule :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
206− ModuleIdent -> m Text
207−loadModule "Prim" = pure "Prim won't be loaded"
209− path <- filePathFromModule mn
211− $(logDebug) ("Loaded extern file at: " <> T.pack path)
212− pure ("Loaded extern file at: " <> T.pack path)
214−loadAllModules :: (PscIde m, MonadLogger m, MonadError PscIdeError m) => m Success
187+loadAllModules :: (Ide m, MonadError PscIdeError m) => m Success
215loadAllModules = do
188loadAllModules = do
216− outputPath <- confOutputPath . envConfiguration <$> ask
189+ exts <- traverse readExternFile =<< findAllExterns
217− cwd <- liftIO getCurrentDirectory
190+ traverse_ insertExterns exts
218− let outputDirectory = cwd </> outputPath
191+ --TODO Get rid of this once ModuleOld is gone
219− liftIO (doesDirectoryExist outputDirectory)
192+ traverse_ insertModule exts
220− >>= flip unless (throwError (GeneralError "Couldn't locate your output directory"))
193+ env <- ask
221− liftIO (getDirectoryContents outputDirectory)
194+ _ <- liftIO $ async (runStdoutLoggingT (runReaderT populateStage2 env))
222− >>= liftIO . traverse (getExternsPath outputDirectory)
223− >>= traverse_ loadExtern . catMaybes
224 pure (TextResult "All modules loaded.")
195 pure (TextResult "All modules loaded.")
226− getExternsPath :: FilePath -> FilePath -> IO (Maybe FilePath)
227− getExternsPath outputDirectory d
228− | d `elem` [".", ".."] = pure Nothing
230− let file = outputDirectory </> d </> "externs.json"
231− ex <- doesFileExist file
233− then pure (Just file)
236−filePathFromModule :: (PscIde m, MonadError PscIdeError m) =>
237− ModuleIdent -> m FilePath
238−filePathFromModule moduleName = do
239− outputPath <- confOutputPath . envConfiguration <$> ask
240− cwd <- liftIO getCurrentDirectory
241− let path = cwd </> outputPath </> T.unpack moduleName </> "externs.json"
242− ex <- liftIO $ doesFileExist path
245− else throwError (ModuleFileNotFound moduleName)