git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
[psc-ide] Multi phase load
commita07a71430adae0f7b3801b8ce3fea54bf5fccdbb authorChristoph Hegemann <christoph.hegemann1337@gmail.com> dateSun 5 Jun 2016, 19:02 (10 years ago) parent3629bd6
30 files changed+521−529
psc-ide-server/Main.hs+11−11 psc-ide-server/PROTOCOL.md+3−7 purescript.cabal+12−11 src/Language/PureScript/Ide.hs+78−128 src/Language/PureScript/Ide/CaseSplit.hs+13−10 src/Language/PureScript/Ide/Command.hs+5−10 src/Language/PureScript/Ide/Completion.hs+3−6 src/Language/PureScript/Ide/Conversions.hs+36 src/Language/PureScript/Ide/Externs.hs+25−11 src/Language/PureScript/Ide/Filter.hs+9−38 src/Language/PureScript/Ide/Imports.hs+17−17 src/Language/PureScript/Ide/Matcher.hs+2−2 src/Language/PureScript/Ide/Rebuild.hs+5−5 src/Language/PureScript/Ide/Reexports.hs+20−9 src/Language/PureScript/Ide/State.hs+131−78 src/Language/PureScript/Ide/Types.hs+57−27 src/Language/PureScript/Ide/Util.hs+35−42 src/Language/PureScript/Ide/Watcher.hs+4−4 src/Language/PureScript/Publish.hs+1 tests/Language/PureScript/Ide/FilterSpec.hs+9−22 tests/Language/PureScript/Ide/Imports/IntegrationSpec.hs+10−23 tests/Language/PureScript/Ide/ImportsSpec.hs+3−3 tests/Language/PureScript/Ide/Integration.hs+11−7 tests/Language/PureScript/Ide/MatcherSpec.hs+7−7 tests/Language/PureScript/Ide/RebuildSpec.hs+4−4 tests/Language/PureScript/Ide/ReexportsSpec.hs+7−7 tests/Language/PureScript/IdeSpec.hs−35 tests/support/pscide/src/ImportsSpec.purs+1−3 tests/support/pscide/src/Main.purs → tests/support/pscide/src/MatcherSpec.purs+1−1 tests/support/pscide/src/RebuildSpecSingleModule.purs+1−1
psc-ide-server/Main.hs+11−11
@@ -81,21 +81,21 @@ main = do
8181 Options dir outputPath port noWatch debug <- execParser opts
8282 maybe (pure ()) setCurrentDirectory dir
8383 serverState <- newTVarIO emptyPscIdeState
84+ ideState <- newTVarIO emptyIdeState
8485 cwd <- getCurrentDirectory
8586 let fullOutputPath = cwd </> outputPath
8687
87− doesDirectoryExist fullOutputPath
88− >>= flip unless
89− (do putStrLn ("Your output directory didn't exist. I'll create it at: " <> fullOutputPath)
90− createDirectory fullOutputPath
91− putStrLn "This usually means you didn't compile your project yet."
92− putStrLn "psc-ide needs you to compile your project (for example by running pulp build)")
88+ unlessM (doesDirectoryExist fullOutputPath) $ do
89+ putStrLn ("Your output directory didn't exist. I'll create it at: " <> fullOutputPath)
90+ createDirectory fullOutputPath
91+ putStrLn "This usually means you didn't compile your project yet."
92+ putStrLn "psc-ide needs you to compile your project (for example by running pulp build)"
9393
9494 unless noWatch $
95− void (forkFinally (watcher serverState fullOutputPath) print)
95+ void (forkFinally (watcher ideState fullOutputPath) print)
9696
9797 let conf = Configuration {confDebug = debug, confOutputPath = outputPath}
98− env = PscIdeEnvironment {envStateVar = serverState, envConfiguration = conf}
98+ env = IdeEnvironment {envStateVar = serverState, ideStateVar = ideState, ideConfiguration = conf}
9999 startServer port env
100100 where
101101 parser =
@@ -111,14 +111,14 @@ main = do
111111 (InfoMsg (showVersion Paths.version))
112112 (long "version" <> help "Show the version number")
113113
114−startServer :: PortID -> PscIdeEnvironment -> IO ()
114+startServer :: PortID -> IdeEnvironment -> IO ()
115115startServer port env = withSocketsDo $ do
116116 sock <- listenOnLocalhost port
117117 runLogger (runReaderT (forever (loop sock)) env)
118118 where
119− runLogger = runStdoutLoggingT . filterLogger (\_ _ -> confDebug (envConfiguration env))
119+ runLogger = runStdoutLoggingT . filterLogger (\_ _ -> confDebug (ideConfiguration env))
120120
121− loop :: (PscIde m, MonadLogger m) => Socket -> m ()
121+ loop :: (Ide m, MonadLogger m) => Socket -> m ()
122122 loop sock = do
123123 accepted <- runExceptT $ acceptCommand sock
124124 case accepted of
psc-ide-server/PROTOCOL.md+3−7
@@ -14,24 +14,20 @@ to detect all the compiled modules in your project and load them.
1414
1515**Params:**
1616 - `modules :: (optional) [ModuleName]`: A list of modules to load.
17− psc-ide-server will try to parse all the declarations in these modules
18− - `dependencies :: (optional) [ModuleName]`: A list of modules to load
19− including their dependencies. In contrast to the `module` field, all the
20− imports in these Modules will also be loaded.
17+ psc-ide-server will try to parse all the declarations in these modules
2118
2219```json
2320{
2421 "command": "load",
2522 "params": (optional) {
26− "modules": (optional)["Module.Name1", "Module.Name2"],
27− "dependencies": (optional)["Module.Name3"]
23+ "modules": (optional)["Module.Name1", "Module.Name2"]
2824 }
2925}
3026```
3127
3228**Result:**
3329
34−The Load Command returns a string.
30+The Load Command returns a string with a summary about the loading process.
3531
3632### Type
3733The `type` command looks up the type for a given identifier.
purescript.cabal+12−11
@@ -101,6 +101,7 @@ library
101101 aeson >= 0.8 && < 0.12,
102102 aeson-better-errors >= 0.8,
103103 ansi-terminal >= 0.6.2 && < 0.7,
104+ async,
104105 base-compat >=0.6.0,
105106 bower-json >= 0.8,
106107 boxes >= 0.1.4 && < 0.2.0,
@@ -251,22 +252,23 @@ library
251252 Language.PureScript.Publish.BoxesHelpers
252253
253254 Language.PureScript.Ide
255+ Language.PureScript.Ide.CaseSplit
254256 Language.PureScript.Ide.Command
257+ Language.PureScript.Ide.Completion
258+ Language.PureScript.Ide.Conversions
255259 Language.PureScript.Ide.Externs
256260 Language.PureScript.Ide.Error
257− Language.PureScript.Ide.Pursuit
258− Language.PureScript.Ide.Completion
259− Language.PureScript.Ide.Matcher
261+ Language.PureScript.Ide.Imports
260262 Language.PureScript.Ide.Filter
261− Language.PureScript.Ide.Types
262− Language.PureScript.Ide.State
263− Language.PureScript.Ide.CaseSplit
264− Language.PureScript.Ide.SourceFile
265− Language.PureScript.Ide.Watcher
263+ Language.PureScript.Ide.Matcher
264+ Language.PureScript.Ide.Pursuit
265+ Language.PureScript.Ide.Rebuild
266266 Language.PureScript.Ide.Reexports
267− Language.PureScript.Ide.Imports
267+ Language.PureScript.Ide.SourceFile
268+ Language.PureScript.Ide.State
269+ Language.PureScript.Ide.Types
268270 Language.PureScript.Ide.Util
269− Language.PureScript.Ide.Rebuild
271+ Language.PureScript.Ide.Watcher
270272
271273 Language.PureScript.Interactive
272274 Language.PureScript.Interactive.Types
@@ -498,6 +500,5 @@ test-suite tests
498500 Language.PureScript.Ide.MatcherSpec
499501 Language.PureScript.Ide.RebuildSpec
500502 Language.PureScript.Ide.ReexportsSpec
501− Language.PureScript.IdeSpec
502503 buildable: True
503504 hs-source-dirs: tests
src/Language/PureScript/Ide.hs+78−128
@@ -14,7 +14,6 @@
1414
1515{-# LANGUAGE OverloadedStrings #-}
1616{-# LANGUAGE PackageImports #-}
17−{-# LANGUAGE TemplateHaskell #-}
1817
1918module Language.PureScript.Ide
2019 ( handleCommand
@@ -25,14 +24,13 @@ module Language.PureScript.Ide
2524import Prelude ()
2625import Prelude.Compat
2726
28−import Control.Monad (unless)
27+import Control.Concurrent.Async
2928import Control.Monad.Error.Class
3029import Control.Monad.IO.Class
3130import "monad-logger" Control.Monad.Logger
32−import Control.Monad.Reader.Class
31+import Control.Monad.Reader
3332import Data.Foldable
34−import qualified Data.Map.Lazy as M
35−import Data.Maybe (catMaybes, mapMaybe)
33+import Data.Maybe (catMaybes)
3634import Data.Monoid
3735import Data.Text (Text)
3836import qualified Data.Text as T
@@ -47,7 +45,6 @@ import Language.PureScript.Ide.Imports hiding (Import)
4745import Language.PureScript.Ide.Matcher
4846import Language.PureScript.Ide.Pursuit
4947import Language.PureScript.Ide.Rebuild
50−import Language.PureScript.Ide.Reexports
5148import Language.PureScript.Ide.SourceFile
5249import Language.PureScript.Ide.State
5350import Language.PureScript.Ide.Types
@@ -56,11 +53,10 @@ import System.Directory
5653import System.Exit
5754import System.FilePath
5855
59−handleCommand :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
56+handleCommand :: (Ide m, MonadLogger m, MonadError PscIdeError m) =>
6057 Command -> m Success
61−handleCommand (Load [] []) = loadAllModules
62−handleCommand (Load modules deps) =
63− loadModulesAndDeps modules deps
58+handleCommand (Load []) = loadAllModules
59+handleCommand (Load modules) = loadModules modules
6460handleCommand (Type search filters currentModule) =
6561 findType search filters currentModule
6662handleCommand (Complete filters matcher currentModule) =
@@ -78,7 +74,7 @@ handleCommand (List (Imports fp)) =
7874handleCommand (CaseSplit l b e wca t) =
7975 caseSplit l b e wca t
8076handleCommand (AddClause l wca) =
81− pure $ addClause l wca
77+ addClause l wca
8278handleCommand (Import fp outfp _ (AddImplicitImport mn)) = do
8379 rs <- addImplicitImport fp mn
8480 answerRequest outfp rs
@@ -86,25 +82,25 @@ handleCommand (Import fp outfp filters (AddImportForIdentifier ident)) = do
8682 rs <- addImportForIdentifier fp ident filters
8783 case rs of
8884 Right rs' -> answerRequest outfp rs'
89− Left question -> pure $ CompletionResult (mapMaybe completionFromMatch question)
85+ Left question -> pure $ CompletionResult (map completionFromMatch question)
9086handleCommand (Rebuild file) =
9187 rebuildFile file
9288handleCommand Cwd =
9389 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.")
9591handleCommand Quit = liftIO exitSuccess
9692
97−findCompletions :: (PscIde m) =>
93+findCompletions :: (Ide m) =>
9894 [Filter] -> Matcher -> Maybe P.ModuleName -> m Success
9995findCompletions filters matcher currentModule = do
100− modules <- getAllModulesWithReexportsAndCache currentModule
101− pure . CompletionResult . mapMaybe completionFromMatch . getCompletions filters matcher $ modules
96+ modules <- getAllModules2 currentModule
97+ pure . CompletionResult . map completionFromMatch . getCompletions filters matcher $ modules
10298
103−findType :: (PscIde m) =>
104− DeclIdent -> [Filter] -> Maybe P.ModuleName -> m Success
99+findType :: (Ide m) =>
100+ Text -> [Filter] -> Maybe P.ModuleName -> m Success
105101findType search filters currentModule = do
106− modules <- getAllModulesWithReexportsAndCache currentModule
107− pure . CompletionResult . mapMaybe completionFromMatch . getExactMatches search filters $ modules
102+ modules <- getAllModules2 currentModule
103+ pure . CompletionResult . map completionFromMatch . getExactMatches search filters $ modules
108104
109105findPursuitCompletions :: (MonadIO m) =>
110106 PursuitQuery -> m Success
@@ -116,39 +112,35 @@ findPursuitPackages :: (MonadIO m) =>
116112findPursuitPackages (PursuitQuery q) =
117113 PursuitResult <$> liftIO (findPackagesForModuleIdent q)
118114
119−loadExtern :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
120− FilePath -> m ()
121−loadExtern fp = do
122− m <- readExternFile fp
123− insertModule m
115+printModules :: (Ide m) => m Success
116+printModules = ModuleList . map runModuleNameT <$> getLoadedModulenames
124117
125−printModules :: (PscIde m) => m Success
126−printModules = printModules' . pscIdeStateModules <$> getPscIdeState
127−
128−printModules' :: M.Map ModuleIdent [ExternDecl] -> Success
129−printModules' = ModuleList . M.keys
118+outputDirectory :: Ide m => m FilePath
119+outputDirectory = do
120+ outputPath <- confOutputPath . ideConfiguration <$> ask
121+ cwd <- liftIO getCurrentDirectory
122+ pure (cwd </> outputPath)
130123
131−listAvailableModules :: PscIde m => m Success
124+listAvailableModules :: Ide m => m Success
132125listAvailableModules = do
133− outputPath <- confOutputPath . envConfiguration <$> ask
126+ oDir <- outputDirectory
134127 liftIO $ do
135− cwd <- getCurrentDirectory
136− dirs <- getDirectoryContents (cwd </> outputPath)
137− return (ModuleList (listAvailableModules' dirs))
138−
139−listAvailableModules' :: [FilePath] -> [Text]
140−listAvailableModules' dirs =
141− let cleanedModules = filter (`notElem` [".", ".."]) dirs
142− in map T.pack cleanedModules
128+ contents <- getDirectoryContents oDir
129+ let cleaned = filter (`notElem` [".", ".."]) contents
130+ return (ModuleList (map T.pack cleaned))
143131
144−caseSplit :: (PscIde m, MonadError PscIdeError m) =>
132+caseSplit :: (Ide m, MonadError PscIdeError m) =>
145133 Text -> Int -> Int -> CS.WildcardAnnotations -> Text -> m Success
146134caseSplit l b e csa t = do
147135 patterns <- CS.makePattern l b e csa <$> CS.caseSplit t
148136 pure (MultilineTextResult patterns)
149137
150−addClause :: Text -> CS.WildcardAnnotations -> Success
151−addClause t wca = MultilineTextResult (CS.addClause t wca)
138+addClause
139+ :: (MonadError PscIdeError m)
140+ => Text
141+ -> CS.WildcardAnnotations
142+ -> m Success
143+addClause t wca = MultilineTextResult <$> CS.addClause t wca
152144
153145importsForFile :: (MonadIO m, MonadError PscIdeError m) =>
154146 FilePath -> m Success
@@ -156,90 +148,48 @@ importsForFile fp = do
156148 imports <- getImportsForFile fp
157149 pure (ImportList imports)
158150
159−-- | The first argument is a set of modules to load. The second argument
160−-- denotes modules for which to load dependencies
161−loadModulesAndDeps :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
162− [ModuleIdent] -> [ModuleIdent] -> m Success
163−loadModulesAndDeps mods deps = do
164− r1 <- mapM loadModule (mods ++ deps)
165− r2 <- mapM loadModuleDependencies deps
166− let moduleResults = T.concat r1
167− let dependencyResults = T.concat r2
168− pure (TextResult (moduleResults <> ", " <> dependencyResults))
169−
170−loadModuleDependencies ::(PscIde m, MonadLogger m, MonadError PscIdeError m) =>
171− ModuleIdent -> m Text
172−loadModuleDependencies moduleName = do
173− m <- getModule moduleName
174− case getDependenciesForModule <$> m of
175− Just deps -> do
176− mapM_ loadModule deps
177− -- We need to load the modules, that get reexported from the dependencies
178− depModules <- catMaybes <$> mapM getModule deps
179− -- What to do with errors here? This basically means a reexported dependency
180− -- doesn't exist in the output/ folder
181− traverse_ loadReexports depModules
182− pure ("Dependencies for " <> moduleName <> " loaded.")
183− Nothing -> throwError (ModuleNotFound moduleName)
184−
185−loadReexports :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
186− Module -> m [ModuleIdent]
187−loadReexports m = case getReexports m of
188− [] -> pure []
189− exportDeps -> do
190− -- I'm fine with this crashing on a failed pattern match.
191− -- If this ever fails I'll need to look at GADTs
192− let reexports = map (\(Export mn) -> mn) exportDeps
193− $(logDebug) ("Loading reexports for module: " <> fst m <>
194− " reexports: " <> T.intercalate ", " reexports)
195− traverse_ loadModule reexports
196− exportDepsModules <- catMaybes <$> traverse getModule reexports
197− exportDepDeps <- traverse loadReexports exportDepsModules
198− return $ concat exportDepDeps
199−
200−getDependenciesForModule :: Module -> [ModuleIdent]
201−getDependenciesForModule (_, decls) = mapMaybe getDependencyName decls
202− where getDependencyName (Dependency dependencyName _ _) = Just dependencyName
203− getDependencyName _ = Nothing
204−
205−loadModule :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
206− ModuleIdent -> m Text
207−loadModule "Prim" = pure "Prim won't be loaded"
208−loadModule mn = do
209− path <- filePathFromModule mn
210− loadExtern path
211− $(logDebug) ("Loaded extern file at: " <> T.pack path)
212− pure ("Loaded extern file at: " <> T.pack path)
213−
214−loadAllModules :: (PscIde m, MonadLogger m, MonadError PscIdeError m) => m Success
151+-- | Takes the output directory and a filepath like "Monad.Control.Eff" and
152+-- looks up, whether that folder contains an externs.json
153+checkExternsPath :: FilePath -> FilePath -> IO (Maybe FilePath)
154+checkExternsPath oDir d
155+ | d `elem` [".", ".."] = pure Nothing
156+ | otherwise = do
157+ let file = oDir </> d </> "externs.json"
158+ ex <- doesFileExist file
159+ if ex
160+ then pure (Just file)
161+ else pure Nothing
162+
163+findAllExterns :: (Ide m, MonadError PscIdeError m) => m [FilePath]
164+findAllExterns = do
165+ oDir <- outputDirectory
166+ unlessM (liftIO (doesDirectoryExist oDir))
167+ (throwError (GeneralError "Couldn't locate your output directory."))
168+ liftIO $ do
169+ dirs <- getDirectoryContents oDir
170+ externPaths <- traverse (checkExternsPath oDir) dirs
171+ pure (catMaybes externPaths)
172+
173+loadModules
174+ :: (Ide m, MonadError PscIdeError m, MonadLogger m)
175+ => [P.ModuleName]
176+ -> m Success
177+loadModules mns = do
178+ oDir <- outputDirectory
179+ let efPaths = map (\mn -> oDir </> P.runModuleName mn </> "externs.json") mns
180+ efiles <- traverse readExternFile efPaths
181+ traverse_ insertExterns efiles
182+ --TODO Get rid of this once ModuleOld is gone
183+ traverse_ insertModule efiles
184+ populateStage2
185+ pure (TextResult ("Loaded " <> foldMap runModuleNameT mns <> "."))
186+
187+loadAllModules :: (Ide m, MonadError PscIdeError m) => m Success
215188loadAllModules = do
216− outputPath <- confOutputPath . envConfiguration <$> ask
217− cwd <- liftIO getCurrentDirectory
218− let outputDirectory = cwd </> outputPath
219− liftIO (doesDirectoryExist outputDirectory)
220− >>= flip unless (throwError (GeneralError "Couldn't locate your output directory"))
221− liftIO (getDirectoryContents outputDirectory)
222− >>= liftIO . traverse (getExternsPath outputDirectory)
223− >>= traverse_ loadExtern . catMaybes
189+ exts <- traverse readExternFile =<< findAllExterns
190+ traverse_ insertExterns exts
191+ --TODO Get rid of this once ModuleOld is gone
192+ traverse_ insertModule exts
193+ env <- ask
194+ _ <- liftIO $ async (runStdoutLoggingT (runReaderT populateStage2 env))
224195 pure (TextResult "All modules loaded.")
225− where
226− getExternsPath :: FilePath -> FilePath -> IO (Maybe FilePath)
227− getExternsPath outputDirectory d
228− | d `elem` [".", ".."] = pure Nothing
229− | otherwise = do
230− let file = outputDirectory </> d </> "externs.json"
231− ex <- doesFileExist file
232− if ex
233− then pure (Just file)
234− else pure Nothing
235−
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
243− if ex
244− then pure path
245− else throwError (ModuleFileNotFound moduleName)
src/Language/PureScript/Ide/CaseSplit.hs+13−10
@@ -53,7 +53,7 @@ explicitAnnotations = WildcardAnnotations True
5353noAnnotations :: WildcardAnnotations
5454noAnnotations = WildcardAnnotations False
5555
56−caseSplit :: (PscIde m, MonadError PscIdeError m) =>
56+caseSplit :: (Ide m, MonadError PscIdeError m) =>
5757 Text -> m [Constructor]
5858caseSplit q = do
5959 type' <- parseType' (T.unpack q)
@@ -63,7 +63,7 @@ caseSplit q = do
6363 let appliedCtors = map (second (map applyTypeVars)) ctors
6464 pure appliedCtors
6565
66−findTypeDeclaration :: (PscIde m, MonadError PscIdeError m) =>
66+findTypeDeclaration :: (Ide m, MonadError PscIdeError m) =>
6767 P.ProperName 'P.TypeName -> m ExternsDeclaration
6868findTypeDeclaration q = do
6969 efs <- getExternFiles
@@ -113,14 +113,14 @@ makePattern t x y wsa = makePattern' (T.take x t) (T.drop y t)
113113 where
114114 makePattern' lhs rhs = map (\ctor -> lhs <> prettyCtor wsa ctor <> rhs)
115115
116−addClause :: Text -> WildcardAnnotations -> [Text]
117−addClause s wca =
118− let (fName, fType) = parseTypeDeclaration' (T.unpack s)
119− (args, _) = splitFunctionType fType
116+addClause :: (MonadError PscIdeError m) => Text -> WildcardAnnotations -> m [Text]
117+addClause s wca = do
118+ (fName, fType) <- parseTypeDeclaration' (T.unpack s)
119+ let (args, _) = splitFunctionType fType
120120 template = runIdentT fName <> " " <>
121121 T.unwords (map (prettyPrintWildcard wca) args) <>
122122 " = ?" <> (T.strip . runIdentT $ fName)
123− in [s, template]
123+ pure [s, template]
124124
125125parseType' :: (MonadError PscIdeError m) =>
126126 String -> m P.Type
@@ -131,15 +131,18 @@ parseType' s =
131131 throwError (GeneralError ("Parsing the splittype failed with:"
132132 ++ show err))
133133
134−parseTypeDeclaration' :: String -> (P.Ident, P.Type)
134+parseTypeDeclaration' :: (MonadError PscIdeError m) => String -> m (P.Ident, P.Type)
135135parseTypeDeclaration' s =
136136 let x = do
137137 ts <- P.lex "" s
138138 P.runTokenParser "" (P.parseDeclaration <* Parsec.eof) ts
139139 in
140140 case unwrapPositioned <$> x of
141− Right (P.TypeDeclaration i t) -> (i, t)
142− y -> error (show y)
141+ Right (P.TypeDeclaration i t) -> pure (i, t)
142+ Right _ -> throwError (GeneralError "Found a non-type-declaration")
143+ Left err ->
144+ throwError (GeneralError ("Parsing the typesignature failed with: "
145+ ++ show err))
143146
144147splitFunctionType :: P.Type -> ([P.Type], P.Type)
145148splitFunctionType t = (arguments, returns)
src/Language/PureScript/Ide/Command.hs+5−10
@@ -29,12 +29,9 @@ import Language.PureScript.Ide.Matcher
2929import Language.PureScript.Ide.Types
3030
3131data Command
32− = Load
33− { loadModules :: [ModuleIdent]
34− , loadDependencies :: [ModuleIdent]
35− }
32+ = Load [P.ModuleName]
3633 | Type
37− { typeSearch :: DeclIdent
34+ { typeSearch :: Text
3835 , typeFilters :: [Filter]
3936 , typeCurrentModule :: Maybe P.ModuleName
4037 }
@@ -68,7 +65,7 @@ data Command
6865
6966data ImportCommand
7067 = AddImplicitImport P.ModuleName
71− | AddImportForIdentifier DeclIdent
68+ | AddImportForIdentifier Text
7269 deriving (Show, Eq)
7370
7471instance FromJSON ImportCommand where
@@ -103,11 +100,9 @@ instance FromJSON Command where
103100 "load" -> do
104101 params' <- o .:? "params"
105102 case params' of
106− Nothing -> pure (Load [] [])
103+ Nothing -> pure (Load [])
107104 Just params ->
108− Load
109− <$> params .:? "modules" .!= []
110− <*> params .:? "dependencies" .!= []
105+ Load <$> (map P.moduleNameFromString <$> params .:? "modules" .!= [])
111106 "type" -> do
112107 params <- o .: "params"
113108 Type
src/Language/PureScript/Ide/Completion.hs+3−6
@@ -6,7 +6,7 @@ module Language.PureScript.Ide.Completion
66import Prelude ()
77import Prelude.Compat
88
9−import Data.Maybe (mapMaybe)
9+import Data.Text (Text)
1010import Language.PureScript.Ide.Filter
1111import Language.PureScript.Ide.Matcher
1212import Language.PureScript.Ide.Types
@@ -17,7 +17,7 @@ getCompletions :: [Filter] -> Matcher -> [Module] -> [Match]
1717getCompletions filters matcher modules =
1818 runMatcher matcher $ completionsFromModules (applyFilters filters modules)
1919
20−getExactMatches :: DeclIdent -> [Filter] -> [Module] -> [Match]
20+getExactMatches :: Text -> [Filter] -> [Module] -> [Match]
2121getExactMatches search filters modules =
2222 completionsFromModules $
2323 applyFilters (equalityFilter search : filters) modules
@@ -26,7 +26,4 @@ completionsFromModules :: [Module] -> [Match]
2626completionsFromModules = foldMap completionFromModule
2727 where
2828 completionFromModule :: Module -> [Match]
29− completionFromModule (moduleIdent, decls) = mapMaybe (matchFromDecl moduleIdent) decls
30−
31−matchFromDecl :: ModuleIdent -> ExternDecl -> Maybe Match
32−matchFromDecl mi = Just . Match mi
29+ completionFromModule (moduleName, decls) = map (Match moduleName) decls
src/Language/PureScript/Ide/Conversions.hsnew file+36
@@ -0,0 +1,36 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Ide.Conversions
4+-- Description : Conversions to Text for PureScript types
5+-- Copyright : Christoph Hegemann 2016
6+-- License : MIT (http://opensource.org/licenses/MIT)
7+--
8+-- Maintainer : Christoph Hegemann <christoph.hegemann1337@gmail.com>
9+-- Stability : experimental
10+--
11+-- |
12+-- Conversions to Text for PureScript types
13+-----------------------------------------------------------------------------
14+
15+module Language.PureScript.Ide.Conversions where
16+
17+import Prelude.Compat
18+import Data.Text (Text)
19+import qualified Data.Text as T
20+import qualified Language.PureScript as P
21+
22+runProperNameT :: P.ProperName a -> Text
23+runProperNameT = T.pack . P.runProperName
24+
25+runIdentT :: P.Ident -> Text
26+runIdentT = T.pack . P.runIdent
27+
28+runOpNameT :: P.OpName a -> Text
29+runOpNameT = T.pack . P.runOpName
30+
31+runModuleNameT :: P.ModuleName -> Text
32+runModuleNameT = T.pack . P.runModuleName
33+
34+prettyTypeT :: P.Type -> Text
35+prettyTypeT = T.unwords . fmap T.strip . T.lines . T.pack . P.prettyPrintType
36+
src/Language/PureScript/Ide/Externs.hs+25−11
@@ -12,14 +12,16 @@
1212-- Handles externs files for psc-ide
1313-----------------------------------------------------------------------------
1414
15−{-# LANGUAGE OverloadedStrings #-}
15+{-# LANGUAGE OverloadedStrings #-}
16+{-# LANGUAGE RecordWildCards #-}
17+{-# LANGUAGE FlexibleContexts #-}
1618
1719module Language.PureScript.Ide.Externs
1820 ( ExternDecl(..),
1921 ModuleIdent,
20− DeclIdent,
2122 readExternFile,
2223 convertExterns,
24+ convertModule,
2325 unwrapPositioned,
2426 unwrapPositionedRef
2527 ) where
@@ -50,16 +52,13 @@ readExternFile fp = do
5052 Nothing -> throwError . GeneralError $ "Parsing the extern at: " ++ fp ++ " failed"
5153 Just externs -> pure externs
5254
53−moduleNameToText :: P.ModuleName -> Text
54−moduleNameToText = T.pack . P.runModuleName
55−
5655identToText :: P.Ident -> Text
5756identToText = T.pack . P.runIdent
5857
59−convertExterns :: P.ExternsFile -> Module
60−convertExterns ef = (moduleName, exportDecls ++ importDecls ++ decls ++ operatorDecls ++ tyOperatorDecls)
58+convertExterns :: P.ExternsFile -> ModuleOld
59+convertExterns ef = (runModuleNameT moduleName, exportDecls ++ importDecls ++ decls ++ operatorDecls ++ tyOperatorDecls)
6160 where
62− moduleName = moduleNameToText (P.efModuleName ef)
61+ moduleName = P.efModuleName ef
6362 importDecls = convertImport <$> P.efImports ef
6463 exportDecls = mapMaybe (convertExport . unwrapPositionedRef) (P.efExports ef)
6564 operatorDecls = convertOperator <$> P.efFixities ef
@@ -82,12 +81,12 @@ isTypeClassDeclaration _ = False
8281
8382convertImport :: P.ExternsImport -> ExternDecl
8483convertImport ei = Dependency
85− (moduleNameToText (P.eiModule ei))
84+ (runModuleNameT (P.eiModule ei))
8685 []
87− (moduleNameToText <$> P.eiImportedAs ei)
86+ (runModuleNameT <$> P.eiImportedAs ei)
8887
8988convertExport :: P.DeclarationRef -> Maybe ExternDecl
90−convertExport (P.ModuleRef mn) = Just (Export (moduleNameToText mn))
89+convertExport (P.ModuleRef mn) = Just (Export (runModuleNameT mn))
9190convertExport _ = Nothing
9291
9392convertDecl :: P.ExternsDeclaration -> Maybe ExternDecl
@@ -124,3 +123,18 @@ unwrapPositioned x = x
124123unwrapPositionedRef :: P.DeclarationRef -> P.DeclarationRef
125124unwrapPositionedRef (P.PositionedDeclarationRef _ _ x) = x
126125unwrapPositionedRef x = x
126+
127+convertModule :: ModuleOld -> Module
128+convertModule (mn, decls) = (P.moduleNameFromString (T.unpack mn), mapMaybe convertDeclaration decls)
129+ where convertDeclaration :: ExternDecl -> Maybe IdeDeclaration
130+ convertDeclaration d = case d of
131+ ValueDeclaration i t -> Just (IdeValue i t)
132+ TypeDeclaration i k -> Just (IdeType i k)
133+ TypeSynonymDeclaration i t -> Just (IdeTypeSynonym i t)
134+ DataConstructor i tn t -> Just (IdeDataConstructor i tn t)
135+ TypeClassDeclaration i -> Just (IdeTypeClass i)
136+ ValueOperator n i p a -> Just (IdeValueOperator n i p a)
137+ TypeOperator n i p a -> Just (IdeTypeOperator n i p a)
138+ Dependency{} -> Nothing
139+ ModuleDecl _ _ -> Nothing
140+ Export _ -> Nothing
src/Language/PureScript/Ide/Filter.hs+9−38
@@ -20,7 +20,6 @@ module Language.PureScript.Ide.Filter
2020 , moduleFilter
2121 , prefixFilter
2222 , equalityFilter
23− , dependencyFilter
2423 , runFilter
2524 , applyFilters
2625 ) where
@@ -31,11 +30,11 @@ import Prelude.Compat
3130import Control.Monad
3231import Data.Aeson
3332import Data.Foldable
34−import Data.Maybe (listToMaybe, mapMaybe)
3533import Data.Monoid
3634import Data.Text (Text, isPrefixOf)
3735import Language.PureScript.Ide.Types
3836import Language.PureScript.Ide.Util
37+import qualified Language.PureScript as P
3938
4039newtype Filter = Filter (Endo [Module]) deriving(Monoid)
4140
@@ -43,53 +42,29 @@ mkFilter :: ([Module] -> [Module]) -> Filter
4342mkFilter = Filter . Endo
4443
4544-- | Only keeps the given Modules
46−moduleFilter :: [ModuleIdent] -> Filter
45+moduleFilter :: [P.ModuleName] -> Filter
4746moduleFilter =
4847 mkFilter . moduleFilter'
4948
50−moduleFilter' :: [ModuleIdent] -> [Module] -> [Module]
49+moduleFilter' :: [P.ModuleName] -> [Module] -> [Module]
5150moduleFilter' moduleIdents = filter (flip elem moduleIdents . fst)
5251
53−-- | Only keeps the given Modules and all of their dependencies
54−dependencyFilter :: [ModuleIdent] -> Filter
55−dependencyFilter = mkFilter . dependencyFilter'
56−
57−dependencyFilter' :: [ModuleIdent] -> [Module] -> [Module]
58−dependencyFilter' moduleIdents mods =
59− moduleFilter' (concatMap (getDepForModule mods) moduleIdents) mods
60− where
61− getDepForModule :: [Module] -> ModuleIdent -> [ModuleIdent]
62− getDepForModule ms moduleIdent =
63− moduleIdent : maybe [] extractDeps (findModule moduleIdent ms)
64−
65− findModule :: ModuleIdent -> [Module] -> Maybe Module
66− findModule i ms = listToMaybe $ filter go ms
67− where go (mn, _) = i == mn
68−
69− extractDeps :: Module -> [ModuleIdent]
70− extractDeps = mapMaybe extractDep . snd
71− where extractDep (Dependency n _ _) = Just n
72− extractDep _ = Nothing
73−
7452-- | Only keeps Identifiers that start with the given prefix
7553prefixFilter :: Text -> Filter
7654prefixFilter "" = mkFilter id
7755prefixFilter t = mkFilter $ identFilter prefix t
7856 where
79− prefix :: ExternDecl -> Text -> Bool
80− prefix Export{} _ = False
81− prefix Dependency{} _ = False
82− prefix ed search = search `isPrefixOf` identifierFromExternDecl ed
83−
57+ prefix :: IdeDeclaration -> Text -> Bool
58+ prefix ed search = search `isPrefixOf` identifierFromIdeDeclaration ed
8459
8560-- | Only keeps Identifiers that are equal to the search string
8661equalityFilter :: Text -> Filter
8762equalityFilter = mkFilter . identFilter equality
8863 where
89− equality :: ExternDecl -> Text -> Bool
90− equality ed search = identifierFromExternDecl ed == search
64+ equality :: IdeDeclaration -> Text -> Bool
65+ equality ed search = identifierFromIdeDeclaration ed == search
9166
92−identFilter :: (ExternDecl -> Text -> Bool ) -> Text -> [Module] -> [Module]
67+identFilter :: (IdeDeclaration -> Text -> Bool) -> Text -> [Module] -> [Module]
9368identFilter predicate search =
9469 filter (not . null . snd) . fmap filterModuleDecls
9570 where
@@ -117,10 +92,6 @@ instance FromJSON Filter where
11792 return $ prefixFilter search
11893 "modules" -> do
11994 params <- o .: "params"
120− modules <- params .: "modules"
95+ modules <- map P.moduleNameFromString <$> params .: "modules"
12196 return $ moduleFilter modules
122− "dependencies" -> do
123− params <- o .: "params"
124− deps <- params .: "modules"
125− return $ dependencyFilter deps
12697 _ -> mzero
src/Language/PureScript/Ide/Imports.hs+17−17
@@ -181,7 +181,7 @@ addImplicitImport' imports mn =
181181-- @import Prelude (bind)@ in the file File.purs returns @["import Prelude
182182-- (bind, unit)"]@
183183addExplicitImport :: (MonadIO m, MonadError PscIdeError m) =>
184− FilePath -> ExternDecl -> P.ModuleName -> m [Text]
184+ FilePath -> IdeDeclaration -> P.ModuleName -> m [Text]
185185addExplicitImport fp decl moduleName = do
186186 (mn, pre, imports, post) <- parseImportsFromFile fp
187187 let newImportSection =
@@ -192,7 +192,7 @@ addExplicitImport fp decl moduleName = do
192192 else addExplicitImport' decl moduleName imports
193193 pure (pre ++ prettyPrintImportSection newImportSection ++ post)
194194
195−addExplicitImport' :: ExternDecl -> P.ModuleName -> [Import] -> [Import]
195+addExplicitImport' :: IdeDeclaration -> P.ModuleName -> [Import] -> [Import]
196196addExplicitImport' decl moduleName imports =
197197 let
198198 isImplicitlyImported =
@@ -207,28 +207,28 @@ addExplicitImport' decl moduleName imports =
207207 then imports
208208 else updateAtFirstOrPrepend matches (insertDeclIntoImport decl) freshImport imports
209209 where
210− refFromDeclaration (TypeClassDeclaration n) =
210+ refFromDeclaration (IdeTypeClass n) =
211211 P.TypeClassRef n
212− refFromDeclaration (DataConstructor n tn _) =
212+ refFromDeclaration (IdeDataConstructor n tn _) =
213213 P.TypeRef tn (Just [P.ProperName (T.unpack n)])
214− refFromDeclaration (TypeDeclaration n _) =
214+ refFromDeclaration (IdeType n _) =
215215 P.TypeRef n (Just [])
216− refFromDeclaration (ValueOperator op _ _ _) =
216+ refFromDeclaration (IdeValueOperator op _ _ _) =
217217 P.ValueOpRef op
218− refFromDeclaration (TypeOperator op _ _ _) =
218+ refFromDeclaration (IdeTypeOperator op _ _ _) =
219219 P.TypeOpRef op
220220 refFromDeclaration d =
221− P.ValueRef $ P.Ident $ T.unpack (identifierFromExternDecl d)
221+ P.ValueRef $ P.Ident $ T.unpack (identifierFromIdeDeclaration d)
222222
223223 -- | Adds a declaration to an import:
224224 -- TypeDeclaration "Maybe" + Data.Maybe (maybe) -> Data.Maybe(Maybe, maybe)
225− insertDeclIntoImport :: ExternDecl -> Import -> Import
225+ insertDeclIntoImport :: IdeDeclaration -> Import -> Import
226226 insertDeclIntoImport decl' (Import mn (P.Explicit refs) Nothing) =
227227 Import mn (P.Explicit (insertDeclIntoRefs decl' refs)) Nothing
228228 insertDeclIntoImport _ is = is
229229
230− insertDeclIntoRefs :: ExternDecl -> [P.DeclarationRef] -> [P.DeclarationRef]
231− insertDeclIntoRefs (DataConstructor dtor tn _) refs =
230+ insertDeclIntoRefs :: IdeDeclaration -> [P.DeclarationRef] -> [P.DeclarationRef]
231+ insertDeclIntoRefs (IdeDataConstructor dtor tn _) refs =
232232 let
233233 dtor' = P.ProperName (T.unpack dtor)
234234 in
@@ -263,14 +263,14 @@ updateAtFirstOrPrepend p t d l =
263263--
264264-- * If more than one possible imports are found, reports the possibilities as a
265265-- list of completions.
266−addImportForIdentifier :: (PscIde m, MonadError PscIdeError m)
266+addImportForIdentifier :: (Ide m, MonadError PscIdeError m)
267267 => FilePath -- ^ The Sourcefile to read from
268268 -> Text -- ^ The identifier to import
269269 -> [Filter] -- ^ Filters to apply before searching for
270270 -- the identifier
271271 -> m (Either [Match] [Text])
272272addImportForIdentifier fp ident filters = do
273− modules <- getAllModulesWithReexports
273+ modules <- getAllModules2 Nothing
274274 case getExactMatches ident filters modules of
275275 [] ->
276276 throwError (NotFound "Couldn't find the given identifier. \
@@ -279,7 +279,7 @@ addImportForIdentifier fp ident filters = do
279279 -- Only one match was found for the given identifier, so we can insert it
280280 -- right away
281281 [Match m decl] ->
282− Right <$> addExplicitImport fp decl (P.moduleNameFromString (T.unpack m))
282+ Right <$> addExplicitImport fp decl m
283283
284284 -- This case comes up for newtypes and dataconstructors. Because values and
285285 -- types don't share a namespace we can get multiple matches from the same
@@ -296,7 +296,7 @@ addImportForIdentifier fp ident filters = do
296296 -- dataconstructor as that will give us an unnecessary import warning at
297297 -- worst
298298 Just decl ->
299− Right <$> addExplicitImport fp decl (P.moduleNameFromString (T.unpack m1))
299+ Right <$> addExplicitImport fp decl m1
300300 -- Here we need the user to specify whether he wanted a dataconstructor
301301 -- or a type
302302 Nothing ->
@@ -307,9 +307,9 @@ addImportForIdentifier fp ident filters = do
307307 xs ->
308308 pure $ Left xs
309309 where
310− decideRedundantCase dtor@(DataConstructor _ t _) (TypeDeclaration t' _) =
310+ decideRedundantCase dtor@(IdeDataConstructor _ t _) (IdeType t' _) =
311311 if t == t' then Just dtor else Nothing
312− decideRedundantCase TypeDeclaration{} ts@TypeSynonymDeclaration{} =
312+ decideRedundantCase IdeType{} ts@IdeTypeSynonym{} =
313313 Just ts
314314 decideRedundantCase _ _ = Nothing
315315
src/Language/PureScript/Ide/Matcher.hs+2−2
@@ -41,7 +41,7 @@ import Text.Regex.TDFA ((=~))
4141
4242type ScoredMatch = (Match, Double)
4343
44−newtype Matcher = Matcher (Endo [Match]) deriving(Monoid)
44+newtype Matcher = Matcher (Endo [Match]) deriving (Monoid)
4545
4646instance FromJSON Matcher where
4747 parseJSON = withObject "matcher" $ \o -> do
@@ -105,7 +105,7 @@ flexRate p c = do
105105-- By string =~ pattern we'll get the start of the match and the length of
106106-- the matchas a (start, length) tuple if there's a match.
107107-- If match fails then it would be (-1,0)
108−flexScore :: Text -> DeclIdent -> Maybe Double
108+flexScore :: Text -> Text -> Maybe Double
109109flexScore pat str =
110110 case T.uncons pat of
111111 Nothing -> Nothing
src/Language/PureScript/Ide/Rebuild.hs+5−5
@@ -42,7 +42,7 @@ import System.IO.UTF8 (readUTF8File)
4242-- warnings, and if rebuilding fails, returns a @RebuildError@ with the
4343-- generated errors.
4444rebuildFile
45− :: (PscIde m, MonadLogger m, MonadError PscIdeError m)
45+ :: (Ide m, MonadLogger m, MonadError PscIdeError m)
4646 => FilePath
4747 -> m Success
4848rebuildFile path = do
@@ -60,7 +60,7 @@ rebuildFile path = do
6060 -- correctly to the 'Environment'.
6161 externs <- sortExterns m =<< getExternFiles
6262
63− outputDirectory <- confOutputPath . envConfiguration <$> ask
63+ outputDirectory <- confOutputPath . ideConfiguration <$> ask
6464
6565 -- For rebuilding, we want to 'RebuildAlways', but for inferring foreign
6666 -- modules using their file paths, we need to specify the path in the 'Map'.
@@ -82,7 +82,7 @@ rebuildFile path = do
8282-- | Rebuilds a module but opens up its export list first and stores the result
8383-- inside the rebuild cache
8484rebuildModuleOpen
85− :: (PscIde m, MonadLogger m, MonadError PscIdeError m)
85+ :: (Ide m, MonadLogger m, MonadError PscIdeError m)
8686 => MakeActionsEnv
8787 -> [P.ExternsFile]
8888 -> P.Module
@@ -100,7 +100,7 @@ rebuildModuleOpen makeEnv externs m = do
100100 Right result -> do
101101 $(logDebug)
102102 ("Setting Rebuild cache: " <> runModuleNameT (P.efModuleName result))
103− setCachedRebuild result
103+ cacheRebuild result
104104
105105-- | Parameters we can access while building our @MakeActions@
106106data MakeActionsEnv =
@@ -135,7 +135,7 @@ shushCodegen ma MakeActionsEnv{..} =
135135-- module. Throws an error if there is a cyclic dependency within the
136136-- ExternsFiles
137137sortExterns
138− :: (PscIde m, MonadError PscIdeError m)
138+ :: (Ide m, MonadError PscIdeError m)
139139 => P.Module
140140 -> M.Map P.ModuleName P.ExternsFile
141141 -> m [P.ExternsFile]
src/Language/PureScript/Ide/Reexports.hs+20−9
@@ -15,7 +15,13 @@
1515
1616{-# LANGUAGE OverloadedStrings #-}
1717
18−module Language.PureScript.Ide.Reexports where
18+module Language.PureScript.Ide.Reexports
19+ ( resolveReexports2
20+ -- for tests
21+ , getReexports
22+ , replaceReexport
23+ , replaceReexports
24+ ) where
1925
2026
2127import Prelude ()
@@ -25,9 +31,11 @@ import Data.List (union)
2531import Data.Map (Map)
2632import qualified Data.Map as Map
2733import Data.Maybe
34+import qualified Data.Text as T
2835import Language.PureScript.Ide.Types
36+import Language.PureScript.Ide.Externs
2937
30−getReexports :: Module -> [ExternDecl]
38+getReexports :: ModuleOld -> [ExternDecl]
3139getReexports (mn, decls)= concatMap getExport decls
3240 where getExport d
3341 | (Export mn') <- d
@@ -48,32 +56,32 @@ replaceExportWithAliases decls ident =
4856 , alias == ident = True
4957 | otherwise = False
5058
51−replaceReexport :: ExternDecl -> Module -> Module -> Module
59+replaceReexport :: ExternDecl -> ModuleOld -> ModuleOld -> ModuleOld
5260replaceReexport e@(Export _) (m, decls) (_, newDecls) =
5361 (m, filter (/= e) decls `union` newDecls)
5462replaceReexport _ _ _ = error "Should only get Exports here."
5563
56−emptyModule :: Module
64+emptyModule :: ModuleOld
5765emptyModule = ("Empty", [])
5866
5967isExport :: ExternDecl -> Bool
6068isExport (Export _) = True
6169isExport _ = False
6270
63−removeExportDecls :: Module -> Module
71+removeExportDecls :: ModuleOld -> ModuleOld
6472removeExportDecls = fmap (filter (not . isExport))
6573
66−replaceReexports :: Module -> Map ModuleIdent [ExternDecl] -> Module
74+replaceReexports :: ModuleOld -> Map ModuleIdent [ExternDecl] -> ModuleOld
6775replaceReexports m db = result
6876 where
6977 reexports = getReexports m
7078 result = foldl go (removeExportDecls m) reexports
7179
72− go :: Module -> ExternDecl -> Module
80+ go :: ModuleOld -> ExternDecl -> ModuleOld
7381 go m' re@(Export name) = replaceReexport re m' (getModule name)
7482 go _ _ = error "partiality! woohoo"
7583
76− getModule :: ModuleIdent -> Module
84+ getModule :: ModuleIdent -> ModuleOld
7785 getModule name = clean res
7886 where
7987 res = fromMaybe emptyModule $ (name , ) <$> Map.lookup name db
@@ -81,9 +89,12 @@ replaceReexports m db = result
8189 -- infinite loops
8290 clean (mn, decls) = (mn,) (filter (/= Export mn) decls)
8391
84−resolveReexports :: Map ModuleIdent [ExternDecl] -> Module -> Module
92+resolveReexports :: Map ModuleIdent [ExternDecl] -> ModuleOld -> ModuleOld
8593resolveReexports modules m =
8694 let replaced = replaceReexports m modules
8795 in if null (getReexports replaced)
8896 then replaced
8997 else resolveReexports modules replaced
98+
99+resolveReexports2 :: Map T.Text [ExternDecl] -> ModuleOld -> Module
100+resolveReexports2 decls = convertModule . resolveReexports decls
src/Language/PureScript/Ide/State.hs+131−78
@@ -17,17 +17,20 @@
1717{-# LANGUAGE TemplateHaskell #-}
1818
1919module Language.PureScript.Ide.State
20− ( getPscIdeState
20+ ( getLoadedModulenames
2121 , getExternFiles
22− , getModule
23− , getModuleWithReexports
24− , getAllModulesWithReexports
25− , getAllModulesWithReexportsAndCache
2622 , insertModule
27− , insertModuleSTM
28− , getCachedRebuild
29− , resetPscIdeState
30− , setCachedRebuild
23+ , resetIdeState
24+ , cacheRebuild
25+ , insertExterns
26+ , insertExternsSTM
27+ , getAllModules2
28+ , getStage1
29+ , setStage1
30+ , getStage2
31+ , setStage2
32+ , populateStage2
33+ , populateStage2STM
3134 ) where
3235
3336import Prelude ()
@@ -38,8 +41,9 @@ import Control.Monad.IO.Class
3841import "monad-logger" Control.Monad.Logger
3942import Control.Monad.Reader.Class
4043import qualified Data.Map.Lazy as M
41−import Data.Maybe (mapMaybe)
4244import Data.Monoid
45+import qualified Data.Text as T
46+import Data.Time (getCurrentTime, diffUTCTime)
4347import Language.PureScript.Externs
4448import Language.PureScript.Ide.Externs
4549import Language.PureScript.Ide.Reexports
@@ -47,74 +51,30 @@ import Language.PureScript.Ide.Types
4751import Language.PureScript.Ide.Util
4852import qualified Language.PureScript as P
4953
50−-- | Resets the PscIdeState to emptyPscIdeState
51−resetPscIdeState :: PscIde m => m ()
52−resetPscIdeState = do
54+-- | Resets all State inside psc-ide
55+resetIdeState :: Ide m => m ()
56+resetIdeState = do
5357 stateVar <- envStateVar <$> ask
54− liftIO $ atomically (writeTVar stateVar emptyPscIdeState)
58+ ideVar <- ideStateVar <$> ask
59+ liftIO . atomically $ do
60+ writeTVar stateVar emptyPscIdeState
61+ writeTVar ideVar emptyIdeState
62+ setStage2STM ideVar emptyStage2
5563
56−-- | Gets the entire PscIdeState
57−getPscIdeState :: PscIde m => m PscIdeState
58−getPscIdeState = do
59− stateVar <- envStateVar <$> ask
60− liftIO (readTVarIO stateVar)
64+-- | Gets the loaded Modulenames
65+getLoadedModulenames :: Ide m => m [P.ModuleName]
66+getLoadedModulenames = M.keys <$> getExternFiles
6167
6268-- | Gets all loaded ExternFiles
63−getExternFiles :: (PscIde m) => m (M.Map P.ModuleName ExternsFile)
64−getExternFiles = do
65− stateVar <- envStateVar <$> ask
66− liftIO (pscIdeStateExternsFiles <$> readTVarIO stateVar)
67−
68−-- | Gets all loaded Modules and resolves Reexports
69−getAllModulesWithReexports :: (PscIde m) => m [Module]
70−getAllModulesWithReexports = getAllModulesWithReexports' <$> getPscIdeState
71−
72−-- | Pure version of @getAllModulesWithReexports@
73−getAllModulesWithReexports' :: PscIdeState -> [Module]
74−getAllModulesWithReexports' state =
75− mapMaybe (getModuleWithReexports' state) (M.keys (pscIdeStateModules state))
76−
77−-- | Checks if the given ModuleName matches the last rebuild cache and if it
78−-- does, runs @getAllModulesWithReexports@ with the cached module replacing the
79−-- loaded module
80−getAllModulesWithReexportsAndCache
81− :: (PscIde m)
82− => Maybe P.ModuleName
83− -> m [Module]
84−getAllModulesWithReexportsAndCache Nothing = getAllModulesWithReexports
85−getAllModulesWithReexportsAndCache (Just mn) = do
86− state <- getPscIdeState
87− cachedRebuild <- getCachedRebuild
88− case cachedRebuild of
89− Just (cachedIdent, ef) | cachedIdent == mn ->
90− pure (getAllModulesWithReexports' (insertModule' ef state))
91− _ -> getAllModulesWithReexports
92−
93−-- | Looks up a single Module inside the loaded Modules
94−getModule :: (PscIde m) => ModuleIdent -> m (Maybe Module)
95−getModule m = getModule' <$> getPscIdeState <*> pure m
96−
97−-- | Pure version of @getModule@
98−getModule' :: PscIdeState -> ModuleIdent -> Maybe Module
99−getModule' ps mi = (mi,) <$> M.lookup mi (pscIdeStateModules ps)
100−
101−-- | Looks up a single Module and resolves its Reexports
102−getModuleWithReexports :: PscIde m => ModuleIdent -> m (Maybe Module)
103−getModuleWithReexports i = getModuleWithReexports' <$> getPscIdeState <*> pure i
104−
105−-- | Pure version of @getModuleWithReexports@
106−getModuleWithReexports' :: PscIdeState -> ModuleIdent -> Maybe Module
107−getModuleWithReexports' ps mi =
108− resolveReexports (pscIdeStateModules ps) <$> getModule' ps mi
69+getExternFiles :: Ide m => m (M.Map P.ModuleName ExternsFile)
70+getExternFiles = s1Externs <$> getStage1
10971
11072-- | Inserts an @ExternsFile@ into the PscIdeState. Also converts the
11173-- ExternsFile into psc-ide's internal Declaration format
112−insertModule :: (PscIde m, MonadLogger m) =>
113− ExternsFile -> m ()
74+-- TODO: should be removed when the "old" Declaration format gets removed
75+insertModule :: Ide m => ExternsFile -> m ()
11476insertModule externsFile = do
11577 stateVar <- envStateVar <$> ask
116− let moduleName = efModuleName externsFile
117− $(logDebug) $ "Inserting Module: " <> runModuleNameT moduleName
11878 liftIO . atomically $ insertModuleSTM stateVar externsFile
11979
12080-- | STM version of insertModule
@@ -125,19 +85,112 @@ insertModuleSTM st ef = modifyTVar st (insertModule' ef)
12585insertModule' :: ExternsFile -> PscIdeState -> PscIdeState
12686insertModule' ef state =
12787 state
128− { pscIdeStateExternsFiles =
129− M.insert (efModuleName ef) ef (pscIdeStateExternsFiles state)
130− , pscIdeStateModules = let (mn, decls) = convertExterns ef
88+ { pscIdeStateModules = let (mn, decls) = convertExterns ef
13189 in M.insert mn decls (pscIdeStateModules state)
13290 }
13391
92+-- | Retrieves Stage1 from the State.
93+-- This includes loaded Externfiles
94+-- (TODO: as soon as we actually parse the modules) aswell as the parsed modules
95+getStage1 :: Ide m => m Stage1
96+getStage1 = do
97+ st <- ideStateVar <$> ask
98+ fmap ideStage1 . liftIO . readTVarIO $ st
99+
100+-- | STM version of getStage1
101+getStage1STM :: TVar IdeState -> STM Stage1
102+getStage1STM ref = ideStage1 <$> readTVar ref
103+
104+-- | Sets Stage1 inside the compiler
105+setStage1 :: Ide m => Stage1 -> m ()
106+setStage1 s1 = do
107+ st <- ideStateVar <$> ask
108+ liftIO . atomically . modifyTVar st $ \x ->
109+ x {ideStage1 = s1}
110+ pure ()
111+
112+-- TODO: Soon to be Stage3
113+-- | Retrieves Stage2 from the State.
114+-- This includes the denormalized Declarations and cached rebuilds
115+getStage2 :: Ide m => m Stage2
116+getStage2 = do
117+ st <- ideStateVar <$> ask
118+ fmap ideStage2 . liftIO . readTVarIO $ st
119+
120+-- | Sets Stage2 inside the compiler
121+setStage2 :: Ide m => Stage2 -> m ()
122+setStage2 s2 = do
123+ st <- ideStateVar <$> ask
124+ liftIO . atomically $ setStage2STM st s2
125+
126+-- | STM version of setStage2
127+setStage2STM :: TVar IdeState -> Stage2 -> STM ()
128+setStage2STM ref s2 = do
129+ modifyTVar ref $ \x ->
130+ x {ideStage2 = s2}
131+ pure ()
132+
133+-- | Checks if the given ModuleName matches the last rebuild cache and if it
134+-- does returns all loaded definitions + the definitions inside the rebuild
135+-- cache
136+getAllModules2 :: Ide m => Maybe P.ModuleName -> m [(P.ModuleName, [IdeDeclaration])]
137+getAllModules2 mmoduleName = do
138+ modules <- s2Modules <$> getStage2
139+ rebuild <- cachedRebuild
140+ case mmoduleName of
141+ Nothing -> pure (M.toList modules)
142+ Just moduleName ->
143+ case rebuild of
144+ Just (cachedModulename, ef)
145+ | cachedModulename == moduleName ->
146+ pure . M.toList $
147+ M.insert moduleName (snd . convertModule . convertExterns $ ef) modules
148+ _ -> pure (M.toList modules)
149+
150+-- | Adds an ExternsFile into psc-ide's State Stage1. This does not populate the
151+-- following Stages, which needs to be done after all the necessary Exterms have
152+-- been loaded.
153+insertExterns :: Ide m => ExternsFile -> m ()
154+insertExterns ef = do
155+ st <- ideStateVar <$> ask
156+ liftIO (atomically (insertExternsSTM st ef))
157+
158+-- | STM version of insertExterns
159+insertExternsSTM :: TVar IdeState -> ExternsFile -> STM ()
160+insertExternsSTM ref ef =
161+ modifyTVar ref $ \x ->
162+ x { ideStage1 = (ideStage1 x) {
163+ s1Externs = M.insert (efModuleName ef) ef (s1Externs (ideStage1 x))}}
164+
134165-- | Sets rebuild cache to the given ExternsFile
135−setCachedRebuild :: PscIde m => ExternsFile -> m ()
136−setCachedRebuild ef = do
137− st <- envStateVar <$> ask
166+cacheRebuild :: Ide m => ExternsFile -> m ()
167+cacheRebuild ef = do
168+ st <- ideStateVar <$> ask
138169 liftIO . atomically . modifyTVar st $ \x ->
139− x { pscIdeStateCachedRebuild = Just (efModuleName ef, ef) }
170+ x { ideStage2 = (ideStage2 x) {
171+ s2CachedRebuild = Just (efModuleName ef, ef)}}
140172
141173-- | Retrieves the rebuild cache
142−getCachedRebuild :: PscIde m => m (Maybe (P.ModuleName, ExternsFile))
143−getCachedRebuild = pscIdeStateCachedRebuild <$> getPscIdeState
174+cachedRebuild :: Ide m => m (Maybe (P.ModuleName, ExternsFile))
175+cachedRebuild = s2CachedRebuild <$> getStage2
176+
177+-- | Resolves reexports and populates Stage2 with data to be used in queries.
178+populateStage2 :: (Ide m, MonadLogger m) => m ()
179+populateStage2 = do
180+ st <- ideStateVar <$> ask
181+ duration <- liftIO $ do
182+ start <- getCurrentTime
183+ atomically (populateStage2STM st)
184+ end <- getCurrentTime
185+ pure (diffUTCTime end start)
186+ $(logDebug) $ "Finished populating Stage2 in " <> T.pack (show duration)
187+
188+-- | STM version of populateStage2
189+populateStage2STM :: TVar IdeState -> STM ()
190+populateStage2STM ref = do
191+ externs <- s1Externs <$> getStage1STM ref
192+ -- Build the "old" ExternDecl format
193+ let modules = M.mapKeys runModuleNameT (M.map (snd . convertExterns) externs)
194+ -- Convert ExternDecl into IdeDeclaration
195+ declarations = resolveReexports2 modules <$> M.toList modules
196+ setStage2STM ref (Stage2 (M.fromList declarations) Nothing)
src/Language/PureScript/Ide/Types.hs+57−27
@@ -26,18 +26,15 @@ import Control.Monad.Trans
2626import Data.Aeson
2727import Data.Map.Lazy as M
2828import Data.Maybe (maybeToList)
29−import Data.Text (Text (), pack, unpack)
30−import qualified Language.PureScript.AST.Declarations as D
31−import Language.PureScript.Externs
29+import Data.Text (Text, pack, unpack)
3230import qualified Language.PureScript.Errors.JSON as P
33−import qualified Language.PureScript.Names as N
3431import qualified Language.PureScript as P
32+import Language.PureScript.Ide.Conversions
3533
3634import Text.Parsec
3735import Text.Parsec.Text
3836
3937type Ident = Text
40−type DeclIdent = Text
4138type ModuleIdent = Text
4239
4340data ExternDecl
@@ -53,10 +50,10 @@ data ExternDecl
5350 -- | A module declaration
5451 | ModuleDecl
5552 ModuleIdent -- The modules name
56− [DeclIdent] -- The exported identifiers
53+ [Ident] -- The exported identifiers
5754 -- | A data/newtype declaration
5855 | DataConstructor
59− DeclIdent -- The type name
56+ Ident -- The type name
6057 (P.ProperName 'P.TypeName)
6158 P.Type -- The "type"
6259 -- | An exported module
@@ -66,7 +63,18 @@ data ExternDecl
6663 | Export ModuleIdent -- The exported Modules name
6764 deriving (Show,Eq,Ord)
6865
69−type Module = (ModuleIdent, [ExternDecl])
66+data IdeDeclaration
67+ = IdeValue Ident P.Type
68+ | IdeType (P.ProperName 'P.TypeName) P.Kind
69+ | IdeTypeSynonym (P.ProperName 'P.TypeName) P.Type
70+ | IdeDataConstructor Ident (P.ProperName 'P.TypeName) P.Type
71+ | IdeTypeClass (P.ProperName 'P.ClassName)
72+ | IdeValueOperator (P.OpName 'P.ValueOpName) Ident P.Precedence P.Associativity
73+ | IdeTypeOperator (P.OpName 'P.TypeOpName) Ident P.Precedence P.Associativity
74+ deriving (Show, Eq, Ord)
75+
76+type Module = (P.ModuleName, [IdeDeclaration])
77+type ModuleOld = (Text, [ExternDecl])
7078
7179data Configuration =
7280 Configuration
@@ -74,29 +82,51 @@ data Configuration =
7482 , confDebug :: Bool
7583 }
7684
77−data PscIdeEnvironment =
78− PscIdeEnvironment
85+data IdeEnvironment =
86+ IdeEnvironment
7987 { envStateVar :: TVar PscIdeState
80− , envConfiguration :: Configuration
88+ , ideStateVar :: TVar IdeState
89+ , ideConfiguration :: Configuration
8190 }
8291
83−type PscIde m = (MonadIO m, MonadReader PscIdeEnvironment m)
92+type Ide m = (MonadIO m, MonadReader IdeEnvironment m)
8493
8594data PscIdeState =
8695 PscIdeState
8796 { pscIdeStateModules :: M.Map Text [ExternDecl]
88− , pscIdeStateExternsFiles :: M.Map P.ModuleName ExternsFile
89− , pscIdeStateCachedRebuild :: Maybe (P.ModuleName, ExternsFile)
9097 } deriving Show
9198
9299emptyPscIdeState :: PscIdeState
93−emptyPscIdeState = PscIdeState M.empty M.empty Nothing
100+emptyPscIdeState = PscIdeState M.empty
101+
102+data IdeState = IdeState
103+ { ideStage1 :: Stage1
104+ , ideStage2 :: Stage2
105+ }
106+
107+emptyIdeState :: IdeState
108+emptyIdeState = IdeState emptyStage1 emptyStage2
109+
110+emptyStage1 :: Stage1
111+emptyStage1 = Stage1 M.empty
112+
113+emptyStage2 :: Stage2
114+emptyStage2 = Stage2 M.empty Nothing
115+
116+data Stage1 = Stage1
117+ { s1Externs :: M.Map P.ModuleName P.ExternsFile
118+ }
119+
120+data Stage2 = Stage2
121+ { s2Modules :: M.Map P.ModuleName [IdeDeclaration]
122+ , s2CachedRebuild :: Maybe (P.ModuleName, P.ExternsFile)
123+ }
94124
95−data Match = Match ModuleIdent ExternDecl
96− deriving (Show, Eq)
125+data Match = Match P.ModuleName IdeDeclaration
126+ deriving (Show, Eq)
97127
98128newtype Completion =
99− Completion (ModuleIdent, DeclIdent, Text)
129+ Completion (ModuleIdent, Ident, Text)
100130 deriving (Show,Eq)
101131
102132instance ToJSON Completion where
@@ -106,7 +136,7 @@ instance ToJSON Completion where
106136data ModuleImport =
107137 ModuleImport
108138 { importModuleName :: ModuleIdent
109− , importType :: D.ImportDeclarationType
139+ , importType :: P.ImportDeclarationType
110140 , importQualifier :: Maybe Text
111141 } deriving(Show)
112142
@@ -116,25 +146,25 @@ instance Eq ModuleImport where
116146 && importQualifier mi1 == importQualifier mi2
117147
118148instance ToJSON ModuleImport where
119− toJSON (ModuleImport mn D.Implicit qualifier) =
149+ toJSON (ModuleImport mn P.Implicit qualifier) =
120150 object $ [ "module" .= mn
121151 , "importType" .= ("implicit" :: Text)
122152 ] ++ fmap (\x -> "qualifier" .= x) (maybeToList qualifier)
123− toJSON (ModuleImport mn (D.Explicit refs) _) =
153+ toJSON (ModuleImport mn (P.Explicit refs) _) =
124154 object [ "module" .= mn
125155 , "importType" .= ("explicit" :: Text)
126156 , "identifiers" .= (identifierFromDeclarationRef <$> refs)
127157 ]
128− toJSON (ModuleImport mn (D.Hiding refs) _) =
158+ toJSON (ModuleImport mn (P.Hiding refs) _) =
129159 object [ "module" .= mn
130160 , "importType" .= ("hiding" :: Text)
131161 , "identifiers" .= (identifierFromDeclarationRef <$> refs)
132162 ]
133163
134−identifierFromDeclarationRef :: D.DeclarationRef -> String
135−identifierFromDeclarationRef (D.TypeRef name _) = N.runProperName name
136−identifierFromDeclarationRef (D.ValueRef ident) = N.runIdent ident
137−identifierFromDeclarationRef (D.TypeClassRef name) = N.runProperName name
164+identifierFromDeclarationRef :: P.DeclarationRef -> Text
165+identifierFromDeclarationRef (P.TypeRef name _) = runProperNameT name
166+identifierFromDeclarationRef (P.ValueRef ident) = runIdentT ident
167+identifierFromDeclarationRef (P.TypeClassRef name) = runProperNameT name
138168identifierFromDeclarationRef _ = ""
139169
140170data Success =
@@ -182,7 +212,7 @@ data PursuitResponse =
182212 ModuleResponse ModuleIdent Text
183213 -- | A Pursuit Response for a declaration. Consist of the declarations type,
184214 -- module, name and package
185− | DeclarationResponse Text ModuleIdent DeclIdent Text
215+ | DeclarationResponse Text ModuleIdent Ident Text
186216 deriving (Show,Eq)
187217
188218instance FromJSON PursuitResponse where
src/Language/PureScript/Ide/Util.hs+35−42
@@ -9,14 +9,23 @@
99-- Stability : experimental
1010--
1111-- |
12−-- Generally useful functions and conversions
12+-- Generally useful functions
1313-----------------------------------------------------------------------------
1414
1515{-# LANGUAGE OverloadedStrings #-}
1616
17−module Language.PureScript.Ide.Util where
17+module Language.PureScript.Ide.Util
18+ ( identifierFromIdeDeclaration
19+ , identifierFromMatch
20+ , completionFromMatch
21+ , encodeT
22+ , decodeT
23+ , unlessM
24+ , module Language.PureScript.Ide.Conversions
25+ ) where
1826
1927import Prelude.Compat
28+import Control.Monad (unless)
2029import Data.Aeson
2130import Data.Text (Text)
2231import qualified Data.Text as T
@@ -24,50 +33,32 @@ import Data.Text.Lazy (fromStrict, toStrict)
2433import Data.Text.Lazy.Encoding (decodeUtf8, encodeUtf8)
2534import qualified Language.PureScript as P
2635import Language.PureScript.Ide.Types
36+import Language.PureScript.Ide.Conversions
2737
28−runProperNameT :: P.ProperName a -> Text
29−runProperNameT = T.pack . P.runProperName
30−
31−runIdentT :: P.Ident -> Text
32−runIdentT = T.pack . P.runIdent
33−
34−runOpNameT :: P.OpName a -> Text
35−runOpNameT = T.pack . P.runOpName
36−
37−runModuleNameT :: P.ModuleName -> Text
38−runModuleNameT = T.pack . P.runModuleName
39−
40−prettyTypeT :: P.Type -> Text
41−prettyTypeT = T.unwords . fmap T.strip . T.lines . T.pack . P.prettyPrintType
42−
43−identifierFromExternDecl :: ExternDecl -> Text
44−identifierFromExternDecl (ValueDeclaration name _) = name
45−identifierFromExternDecl (TypeDeclaration name _) = runProperNameT name
46−identifierFromExternDecl (TypeSynonymDeclaration name _) = runProperNameT name
47−identifierFromExternDecl (DataConstructor name _ _) = name
48−identifierFromExternDecl (TypeClassDeclaration name) = runProperNameT name
49−identifierFromExternDecl (ModuleDecl name _) = name
50−identifierFromExternDecl (ValueOperator op _ _ _) = runOpNameT op
51−identifierFromExternDecl (TypeOperator op _ _ _) = runOpNameT op
52−identifierFromExternDecl Dependency{} = "~Dependency~"
53−identifierFromExternDecl Export{} = "~Export~"
38+identifierFromIdeDeclaration :: IdeDeclaration -> Text
39+identifierFromIdeDeclaration d = case d of
40+ IdeValue name _ -> name
41+ IdeType name _ -> runProperNameT name
42+ IdeTypeSynonym name _ -> runProperNameT name
43+ IdeDataConstructor name _ _ -> name
44+ IdeTypeClass name -> runProperNameT name
45+ IdeValueOperator op _ _ _ -> runOpNameT op
46+ IdeTypeOperator op _ _ _ -> runOpNameT op
5447
5548identifierFromMatch :: Match -> Text
56−identifierFromMatch (Match _ ed) = identifierFromExternDecl ed
49+identifierFromMatch (Match _ ed) = identifierFromIdeDeclaration ed
5750
58−completionFromMatch :: Match -> Maybe Completion
59−completionFromMatch (Match m d) = case d of
60− ValueDeclaration name type' -> Just $ Completion (m, name, prettyTypeT type')
61− TypeDeclaration name kind -> Just $ Completion (m, runProperNameT name, T.pack $ P.prettyPrintKind kind)
62− TypeSynonymDeclaration name kind -> Just $ Completion (m, runProperNameT name, prettyTypeT kind)
63− DataConstructor name _ type' -> Just $ Completion (m, name, prettyTypeT type')
64− TypeClassDeclaration name -> Just $ Completion (m, runProperNameT name, "class")
65− ModuleDecl name _ -> Just $ Completion ("module", name, "module")
66− ValueOperator op ref precedence associativity -> Just $ Completion (m, runOpNameT op, showFixity precedence associativity ref op)
67− TypeOperator op ref precedence associativity -> Just $ Completion (m, runOpNameT op, showFixity precedence associativity ref op)
68− Dependency{} -> Nothing
69− Export{} -> Nothing
51+completionFromMatch :: Match -> Completion
52+completionFromMatch (Match m' d) = case d of
53+ IdeValue name type' -> Completion (m, name, prettyTypeT type')
54+ IdeType name kind -> Completion (m, runProperNameT name, T.pack $ P.prettyPrintKind kind)
55+ IdeTypeSynonym name kind -> Completion (m, runProperNameT name, prettyTypeT kind)
56+ IdeDataConstructor name _ type' -> Completion (m, name, prettyTypeT type')
57+ IdeTypeClass name -> Completion (m, runProperNameT name, "class")
58+ IdeValueOperator op ref precedence associativity -> Completion (m, runOpNameT op, showFixity precedence associativity ref op)
59+ IdeTypeOperator op ref precedence associativity -> Completion (m, runOpNameT op, showFixity precedence associativity ref op)
7060 where
61+ m = runModuleNameT m'
7162 showFixity p a r o =
7263 let asso = case a of
7364 P.Infix -> "infix"
@@ -75,9 +66,11 @@ completionFromMatch (Match m d) = case d of
7566 P.Infixr -> "infixr"
7667 in T.unwords [asso, T.pack (show p), r, "as", runOpNameT o]
7768
78−
7969encodeT :: (ToJSON a) => a -> Text
8070encodeT = toStrict . decodeUtf8 . encode
8171
8272decodeT :: (FromJSON a) => Text -> Maybe a
8373decodeT = decode . encodeUtf8 . fromStrict
74+
75+unlessM :: Monad m => m Bool -> m () -> m ()
76+unlessM cond act = cond >>= flip unless act
src/Language/PureScript/Ide/Watcher.hs+4−4
@@ -27,20 +27,20 @@ import System.FSNotify
2727
2828-- | Reloads an ExternsFile from Disc. If the Event indicates the ExternsFile
2929-- was deleted we don't do anything.
30−reloadFile :: TVar PscIdeState -> Event -> IO ()
30+reloadFile :: TVar IdeState -> Event -> IO ()
3131reloadFile _ Removed{} = pure ()
32−reloadFile stateVar ev = do
32+reloadFile ref ev = do
3333 let fp = eventPath ev
3434 ef' <- runExceptT (readExternFile fp)
3535 case ef' of
3636 Left _ -> pure ()
3737 Right ef -> do
38− atomically (insertModuleSTM stateVar ef)
38+ atomically (insertExternsSTM ref ef *> populateStage2STM ref)
3939 putStrLn ("Reloaded File at: " ++ fp)
4040
4141-- | Installs filewatchers for the given directory and reloads ExternsFiles when
4242-- they change on disc
43−watcher :: TVar PscIdeState -> FilePath -> IO ()
43+watcher :: TVar IdeState -> FilePath -> IO ()
4444watcher stateVar fp =
4545 withManagerConf (defaultConfig { confDebounce = NoDebounce }) $ \mgr -> do
4646 _ <- watchTree mgr fp
src/Language/PureScript/Publish.hs+1
@@ -21,6 +21,7 @@ module Language.PureScript.Publish
2121 , getResolvedDependencies
2222 ) where
2323
24+import Prelude ()
2425import Prelude.Compat hiding (userError)
2526
2627import Control.Arrow ((***))
tests/Language/PureScript/Ide/FilterSpec.hs+9−22
@@ -7,26 +7,23 @@ import Language.PureScript.Ide.Types
77import qualified Language.PureScript as P
88import Test.Hspec
99
10−value :: Text -> ExternDecl
11−value s = ValueDeclaration s $ P.TypeWildcard $ P.SourceSpan "" (P.SourcePos 0 0) (P.SourcePos 0 0)
10+value :: Text -> IdeDeclaration
11+value s = IdeValue s $ P.TypeWildcard $ P.SourceSpan "" (P.SourcePos 0 0) (P.SourcePos 0 0)
1212
1313modules :: [Module]
1414modules =
15− [
16− ("Module.A", [value "function1"]),
17− ("Module.B", [value "data1"]),
18− ("Module.C", [ModuleDecl "Module.C" []]),
19− ("Module.D", [Dependency "Module.C" [] Nothing, value "asd"])
15+ [ (P.moduleNameFromString "Module.A", [value "function1"])
16+ , (P.moduleNameFromString "Module.B", [value "data1"])
2017 ]
2118
2219runEq :: Text -> [Module]
2320runEq s = runFilter (equalityFilter s) modules
21+
2422runPrefix :: Text -> [Module]
2523runPrefix s = runFilter (prefixFilter s) modules
26−runModule :: [ModuleIdent] -> [Module]
24+
25+runModule :: [P.ModuleName] -> [Module]
2726runModule ms = runFilter (moduleFilter ms) modules
28−runDependency :: [ModuleIdent] -> [Module]
29−runDependency ms = runFilter (dependencyFilter ms) modules
3027
3128spec :: Spec
3229spec = do
@@ -35,7 +32,6 @@ spec = do
3532 runEq "test" `shouldBe` []
3633 it "keeps function declarations that are equal" $
3734 runEq "function1" `shouldBe` [head modules]
38− -- TODO: It would be more sensible to match Constructors
3935 it "keeps data declarations that are equal" $
4036 runEq "data1" `shouldBe` [modules !! 1]
4137 describe "prefixFilter" $ do
@@ -45,19 +41,10 @@ spec = do
4541 runPrefix "fun" `shouldBe` [head modules]
4642 it "keeps data decls prefix matches" $
4743 runPrefix "dat" `shouldBe` [modules !! 1]
48− it "keeps module decl prefix matches" $
49− runPrefix "Mod" `shouldBe` [modules !! 2]
5044 describe "moduleFilter" $ do
5145 it "removes everything on empty input" $
5246 runModule [] `shouldBe` []
5347 it "only keeps the specified modules" $
54− runModule ["Module.A", "Module.C"] `shouldBe` [head modules, modules !! 2]
48+ runModule [P.moduleNameFromString "Module.A"] `shouldBe` [head modules]
5549 it "ignores modules that are not in scope" $
56− runModule ["Module.A", "Module.C", "Unknown"] `shouldBe` [head modules, modules !! 2]
57− describe "dependencyFilter" $ do
58− it "removes everything on empty input" $
59− runDependency [] `shouldBe` []
60− it "only keeps the specified modules if they have no imports" $
61− runDependency ["Module.A", "Module.B"] `shouldBe` [head modules, modules !! 1]
62− it "keeps the specified modules and their imports" $
63− runDependency ["Module.A", "Module.D"] `shouldBe` [head modules, modules !! 2, modules !! 3]
50+ runModule (P.moduleNameFromString <$> ["Module.A", "Unknown"]) `shouldBe` [head modules]
tests/Language/PureScript/Ide/Imports/IntegrationSpec.hs+10−23
@@ -12,9 +12,7 @@ import System.Directory
1212import System.FilePath
1313
1414setup :: IO ()
15−setup = do
16− Integration.reset
17− mapM_ Integration.loadModuleWithDeps ["ImportsSpec", "ImportsSpec1"]
15+setup = void (Integration.reset *> Integration.loadAll)
1816
1917withSupportFiles :: (FilePath -> FilePath -> IO a) -> IO ()
2018withSupportFiles test = do
@@ -35,52 +33,41 @@ spec = beforeAll_ setup . describe "Adding imports" $ do
3533 let
3634 sourceFileSkeleton :: [Text] -> [Text]
3735 sourceFileSkeleton importSection =
38− [ "module ImportsSpec where" , ""] ++ importSection ++ [ "" , "myId = id"]
36+ [ "module ImportsSpec where" , ""] ++ importSection ++ [ "" , "myId x = x"]
3937 it "adds an implicit import" $ do
4038 withSupportFiles (Integration.addImplicitImport "ImportsSpec1")
4139 outputFileShouldBe (sourceFileSkeleton
4240 [ "import ImportsSpec1"
43− , "import Main (id)"
4441 ])
4542 it "adds an explicit unqualified import" $ do
4643 withSupportFiles (Integration.addImport "exportedFunction")
4744 outputFileShouldBe (sourceFileSkeleton
4845 [ "import ImportsSpec1 (exportedFunction)"
49− , "import Main (id)"
5046 ])
5147 it "adds an explicit unqualified import (type)" $ do
5248 withSupportFiles (Integration.addImport "MyType")
53− outputFileShouldBe (sourceFileSkeleton [ "import ImportsSpec1 (MyType)"
54− , "import Main (id)"
55− ])
49+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (MyType)"])
5650 it "adds an explicit unqualified import (parameterized type)" $ do
5751 withSupportFiles (Integration.addImport "MyParamType")
58− outputFileShouldBe (sourceFileSkeleton [ "import ImportsSpec1 (MyParamType)"
59− , "import Main (id)"
60− ])
52+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (MyParamType)"])
6153 it "adds an explicit unqualified import (typeclass)" $ do
6254 withSupportFiles (Integration.addImport "ATypeClass")
63− outputFileShouldBe (sourceFileSkeleton [ "import ImportsSpec1 (class ATypeClass)"
64− , "import Main (id)"])
55+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (class ATypeClass)"])
6556 it "adds an explicit unqualified import (dataconstructor)" $ do
6657 withSupportFiles (Integration.addImport "MyJust")
67− outputFileShouldBe (sourceFileSkeleton [ "import ImportsSpec1 (MyMaybe(MyJust))"
68− , "import Main (id)"])
58+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (MyMaybe(MyJust))"])
6959 it "adds an explicit unqualified import (newtype)" $ do
7060 withSupportFiles (Integration.addImport "MyNewtype")
71− outputFileShouldBe (sourceFileSkeleton [ "import ImportsSpec1 (MyNewtype(MyNewtype))"
72− , "import Main (id)"])
61+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (MyNewtype(MyNewtype))"])
7362 it "adds an explicit unqualified import (typeclass member function)" $ do
7463 withSupportFiles (Integration.addImport "typeClassFun")
75− outputFileShouldBe (sourceFileSkeleton [ "import ImportsSpec1 (typeClassFun)"
76− , "import Main (id)"])
64+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (typeClassFun)"])
7765 it "doesn't add a newtypes constructor if only the type is exported" $ do
7866 withSupportFiles (Integration.addImport "OnlyTypeExported")
79− outputFileShouldBe (sourceFileSkeleton [ "import ImportsSpec1 (OnlyTypeExported)"
80− , "import Main (id)"])
67+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (OnlyTypeExported)"])
8168 it "doesn't add an import if the identifier is defined in the module itself" $ do
8269 withSupportFiles (Integration.addImport "myId")
83− outputFileShouldBe (sourceFileSkeleton [ "import Main (id)"])
70+ outputFileShouldBe (sourceFileSkeleton [])
8471 it "responds with an error if it's undecidable whether we want a type or constructor" $
8572 withSupportFiles (\sourceFp outFp -> do
8673 r <- Integration.addImport "SpecialCase" sourceFp outFp
tests/Language/PureScript/Ide/ImportsSpec.hs+3−3
@@ -68,11 +68,11 @@ spec = do
6868 describe "import commands" $ do
6969 let simpleFileImports = let (_, _, i, _) = splitSimpleFile in i
7070 addValueImport i mn is =
71− prettyPrintImportSection (addExplicitImport' (ValueDeclaration i wildcard) mn is)
71+ prettyPrintImportSection (addExplicitImport' (IdeValue i wildcard) mn is)
7272 addOpImport op mn is =
73− prettyPrintImportSection (addExplicitImport' (ValueOperator op "" 2 P.Infix) mn is)
73+ prettyPrintImportSection (addExplicitImport' (IdeValueOperator op "" 2 P.Infix) mn is)
7474 addDtorImport i t mn is =
75− prettyPrintImportSection (addExplicitImport' (DataConstructor i t wildcard) mn is)
75+ prettyPrintImportSection (addExplicitImport' (IdeDataConstructor i t wildcard) mn is)
7676 it "adds an implicit unqualified import" $
7777 shouldBe
7878 (addImplicitImport' simpleFileImports (P.moduleNameFromString "Data.Map"))
tests/Language/PureScript/Ide/Integration.hs+11−7
@@ -29,8 +29,9 @@ module Language.PureScript.Ide.Integration
2929 -- sending commands
3030 , addImport
3131 , addImplicitImport
32+ , loadAll
3233 , loadModule
33− , loadModuleWithDeps
34+ , loadModules
3435 , getCwd
3536 , getFlexCompletions
3637 , getFlexCompletionsInModule
@@ -161,11 +162,14 @@ getCwd = do
161162 let cwdCommand = object ["command" .= ("cwd" :: String)]
162163 sendCommand cwdCommand
163164
164−loadModuleWithDeps :: String -> IO String
165−loadModuleWithDeps m = sendCommand $ load [] [m]
166−
167165loadModule :: String -> IO String
168−loadModule m = sendCommand $ load [m] []
166+loadModule m = loadModules [m]
167+
168+loadModules :: [String] -> IO String
169+loadModules = sendCommand . load
170+
171+loadAll :: IO String
172+loadAll = sendCommand (load [])
169173
170174getFlexCompletions :: String -> IO [(String, String, String)]
171175getFlexCompletions q = parseCompletions <$> sendCommand (completion [] (Just (flexMatcher q)) Nothing)
@@ -190,8 +194,8 @@ rebuildModule m = sendCommand (rebuildC m Nothing)
190194commandWrapper :: String -> Value -> Value
191195commandWrapper c p = object ["command" .= c, "params" .= p]
192196
193−load :: [String] -> [String] -> Value
194−load ms ds = commandWrapper "load" (object ["modules" .= ms, "dependencies" .= ds])
197+load :: [String] -> Value
198+load ms = commandWrapper "load" (object ["modules" .= ms])
195199
196200typeC :: String -> [Value] -> Value
197201typeC q filters = commandWrapper "type" (object ["search" .= q, "filters" .= filters])
tests/Language/PureScript/Ide/MatcherSpec.hs+7−7
@@ -10,14 +10,14 @@ import Language.PureScript.Ide.Matcher
1010import Language.PureScript.Ide.Types
1111import Test.Hspec
1212
13−value :: Text -> ExternDecl
14−value s = ValueDeclaration s $ P.TypeWildcard $ P.SourceSpan "" (P.SourcePos 0 0) (P.SourcePos 0 0)
13+value :: Text -> IdeDeclaration
14+value s = IdeValue s $ P.TypeWildcard $ P.SourceSpan "" (P.SourcePos 0 0) (P.SourcePos 0 0)
1515
1616completions :: [Match]
1717completions =
18− [ Match "" (value "firstResult")
19− , Match "" (value "secondResult")
20− , Match "" (value "fiult")
18+ [ Match (P.moduleNameFromString "Match") (value "firstResult")
19+ , Match (P.moduleNameFromString "Match") (value "secondResult")
20+ , Match (P.moduleNameFromString "Match") (value "fiult")
2121 ]
2222
2323mkResult :: [Int] -> [Match]
@@ -27,7 +27,7 @@ runFlex :: Text -> [Match]
2727runFlex s = runMatcher (flexMatcher s) completions
2828
2929setup :: IO ()
30−setup = reset *> void (loadModuleWithDeps "Main")
30+setup = reset *> void loadAll
3131
3232spec :: Spec
3333spec = do
@@ -45,4 +45,4 @@ spec = do
4545 cs `shouldBe` []
4646 it "matches on equality" $ do
4747 cs <- getFlexCompletions "const"
48− cs `shouldBe` [("Main", "const", "forall a b. a -> b -> a")]
48+ cs `shouldBe` [("MatcherSpec", "const", "forall a b. a -> b -> a")]
tests/Language/PureScript/Ide/RebuildSpec.hs+4−4
@@ -13,7 +13,7 @@ shouldBeFailure = shouldBe False . Integration.resultIsSuccess
1313spec :: Spec
1414spec = before_ Integration.reset . describe "Rebuilding single modules" $ do
1515 it "rebuilds a correct module without dependencies successfully" $ do
16− _ <- Integration.loadModuleWithDeps "RebuildSpecSingleModule"
16+ _ <- Integration.loadModule "RebuildSpecSingleModule"
1717 pdir <- Integration.projectDirectory
1818 let file = pdir </> "src" </> "RebuildSpecSingleModule.purs"
1919 Integration.rebuildModule file >>= shouldBeSuccess
@@ -22,12 +22,12 @@ spec = before_ Integration.reset . describe "Rebuilding single modules" $ do
2222 let file = pdir </> "src" </> "RebuildSpecSingleModule.fail"
2323 Integration.rebuildModule file >>= shouldBeFailure
2424 it "rebuilds a correct module with its dependencies successfully" $ do
25− _ <- Integration.loadModuleWithDeps "RebuildSpecWithDeps"
25+ _ <- Integration.loadModules ["RebuildSpecWithDeps", "RebuildSpecDep"]
2626 pdir <- Integration.projectDirectory
2727 let file = pdir </> "src" </> "RebuildSpecWithDeps.purs"
2828 Integration.rebuildModule file >>= shouldBeSuccess
2929 it "rebuilds a correct module that has reverse dependencies" $ do
30− _ <- Integration.loadModuleWithDeps "RebuildSpecWithDeps"
30+ _ <- Integration.loadModule "RebuildSpecWithDeps"
3131 pdir <- Integration.projectDirectory
3232 let file = pdir </> "src" </> "RebuildSpecDep.purs"
3333 Integration.rebuildModule file >>= shouldBeSuccess
@@ -37,7 +37,7 @@ spec = before_ Integration.reset . describe "Rebuilding single modules" $ do
3737 let file = pdir </> "src" </> "RebuildSpecWithDeps.purs"
3838 Integration.rebuildModule file >>= shouldBeFailure
3939 it "rebuilds a correct module with a foreign file" $ do
40− _ <- Integration.loadModuleWithDeps "RebuildSpecWithForeign"
40+ _ <- Integration.loadModule "RebuildSpecWithForeign"
4141 pdir <- Integration.projectDirectory
4242 let file = pdir </> "src" </> "RebuildSpecWithForeign.purs"
4343 Integration.rebuildModule file >>= shouldBeSuccess
tests/Language/PureScript/Ide/ReexportsSpec.hs+7−7
@@ -23,28 +23,28 @@ dep1 = Dependency "Test.Foo" [] (Just "T")
2323dep2 :: ExternDecl
2424dep2 = Dependency "Test.Bar" [] (Just "T")
2525
26−circularModule :: Module
26+circularModule :: ModuleOld
2727circularModule = ("Circular", [Export "Circular"])
2828
29−module1 :: Module
29+module1 :: ModuleOld
3030module1 = ("Module1", [Export "Module2", Export "Module3", decl1])
3131
32−module2 :: Module
32+module2 :: ModuleOld
3333module2 = ("Module2", [decl2])
3434
35−module3 :: Module
35+module3 :: ModuleOld
3636module3 = ("Module3", [decl3])
3737
38−module4 :: Module
38+module4 :: ModuleOld
3939module4 = ("Module4", [Export "T", decl1, dep1, dep2])
4040
41−result :: Module
41+result :: ModuleOld
4242result = ("Module1", [decl1, decl2, Export "Module3"])
4343
4444db :: Map.Map ModuleIdent [ExternDecl]
4545db = Map.fromList [module1, module2, module3]
4646
47−shouldBeEqualSorted :: Module -> Module -> Expectation
47+shouldBeEqualSorted :: ModuleOld -> ModuleOld -> Expectation
4848shouldBeEqualSorted (n1, d1) (n2, d2) = (n1, sort d1) `shouldBe` (n2, sort d2)
4949
5050spec :: Spec
tests/Language/PureScript/IdeSpec.hsdeleted−35
@@ -1,35 +0,0 @@
1−{-# LANGUAGE OverloadedStrings #-}
2−
3−module Language.PureScript.IdeSpec where
4−
5−import Control.Concurrent.STM
6−import Control.Monad.Reader
7−import Data.List
8−import qualified Data.Map as Map
9−import Language.PureScript.Ide
10−import Language.PureScript.Ide.Types
11−import Test.Hspec
12−
13−testState :: PscIdeState
14−testState = PscIdeState (Map.fromList [("Data.Array", []), ("Control.Monad.Eff", [])]) Map.empty Nothing
15−
16−defaultConfig :: Configuration
17−defaultConfig =
18− Configuration
19− {
20− confOutputPath = "output/"
21− , confDebug = False
22− }
23−
24−spec :: SpecWith ()
25−spec =
26− describe "list" $
27− describe "loadedModules" $ do
28− it "returns an empty list when no modules are loaded" $ do
29− st <- newTVarIO emptyPscIdeState
30− result <- runReaderT printModules (PscIdeEnvironment st defaultConfig)
31− result `shouldBe` ModuleList []
32− it "returns the list of loaded modules" $ do
33− st <- newTVarIO testState
34− ModuleList result <- runReaderT printModules (PscIdeEnvironment st defaultConfig)
35− sort result `shouldBe` sort ["Data.Array", "Control.Monad.Eff"]
tests/support/pscide/src/ImportsSpec.purs+1−3
@@ -1,5 +1,3 @@
11module ImportsSpec where
22
3−import Main (id)
4−
5−myId = id
3+myId x = x
tests/support/pscide/src/Main.purs → tests/support/pscide/src/MatcherSpec.pursrenamed+1−1
@@ -1,4 +1,4 @@
1−module Main where
1+module MatcherSpec where
22
33id :: forall a. a -> a
44id x = x
tests/support/pscide/src/RebuildSpecSingleModule.purs+1−1
@@ -1,4 +1,4 @@
11module RebuildSpecSingleModule where
22
33id x = x
4−const x y = x
4+lulz x y = x