1{-# LANGUAGE ConstraintKinds #-}
2{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE MultiParamTypeClasses #-}
4{-# LANGUAGE OverloadedStrings #-}
5{-# LANGUAGE PackageImports #-}
6{-# LANGUAGE TemplateHaskell #-}
7{-# LANGUAGE TupleSections #-}
9module Language.PureScript.Ide where
14import Control.Monad.Error.Class
15import Control.Monad.IO.Class
16import "monad-logger" Control.Monad.Logger
17import Control.Monad.Reader.Class
19import qualified Data.Map.Lazy as M
20import Data.Maybe (catMaybes, mapMaybe)
22import Data.Text (Text)
23import qualified Data.Text as T
24import qualified Language.PureScript.Ide.CaseSplit as CS
25import Language.PureScript.Ide.Command
26import Language.PureScript.Ide.Completion
27import Language.PureScript.Ide.Error
28import Language.PureScript.Ide.Externs
29import Language.PureScript.Ide.Filter
30import Language.PureScript.Ide.Matcher
31import Language.PureScript.Ide.Pursuit
32import Language.PureScript.Ide.Reexports
33import Language.PureScript.Ide.SourceFile
34import Language.PureScript.Ide.State
35import Language.PureScript.Ide.Types
36import System.Directory
41handleCommand :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
43handleCommand (Load modules deps) =
44 loadModulesAndDeps modules deps
45handleCommand (Type search filters) =
46 findType search filters
47handleCommand (Complete filters matcher) =
48 findCompletions filters matcher
49handleCommand (Pursuit query Package) =
50 findPursuitPackages query
51handleCommand (Pursuit query Identifier) =
52 findPursuitCompletions query
53handleCommand (List LoadedModules) =
55handleCommand (List AvailableModules) =
57handleCommand (List (Imports fp)) =
59handleCommand (CaseSplit l b e wca t) =
61handleCommand (AddClause l wca) =
62 pure $ addClause l wca
64 TextResult . T.pack <$> liftIO getCurrentDirectory
65handleCommand Quit = liftIO exitSuccess
67findCompletions :: (PscIde m, MonadLogger m) =>
68 [Filter] -> Matcher -> m Success
69findCompletions filters matcher =
70 CompletionResult . getCompletions filters matcher <$> getAllModulesWithReexports
72findType :: (PscIde m, MonadLogger m) =>
73 DeclIdent -> [Filter] -> m Success
74findType search filters =
75 CompletionResult . getExactMatches search filters <$> getAllModulesWithReexports
77findPursuitCompletions :: (MonadIO m, MonadLogger m) =>
78 PursuitQuery -> m Success
79findPursuitCompletions (PursuitQuery q) =
80 PursuitResult <$> liftIO (searchPursuitForDeclarations q)
82findPursuitPackages :: (MonadIO m, MonadLogger m) =>
83 PursuitQuery -> m Success
84findPursuitPackages (PursuitQuery q) =
85 PursuitResult <$> liftIO (findPackagesForModuleIdent q)
87loadExtern ::(PscIde m, MonadLogger m, MonadError PscIdeError m) =>
90 m <- readExternFile fp
93printModules :: (PscIde m) => m Success
94printModules = printModules' <$> getPscIdeState
96printModules' :: M.Map ModuleIdent [ExternDecl] -> Success
97printModules' = ModuleList . M.keys
99listAvailableModules :: PscIde m => m Success
100listAvailableModules = do
101 outputPath <- confOutputPath . envConfiguration <$> ask
103 cwd <- getCurrentDirectory
104 dirs <- getDirectoryContents (cwd </> outputPath)
105 return (ModuleList (listAvailableModules' dirs))
107listAvailableModules' :: [FilePath] -> [Text]
108listAvailableModules' dirs =
109 let cleanedModules = filter (`notElem` [".", ".."]) dirs
110 in map T.pack cleanedModules
112caseSplit :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
113 Text -> Int -> Int -> CS.WildcardAnnotations -> Text -> m Success
114caseSplit l b e csa t = do
115 patterns <- CS.makePattern l b e csa <$> CS.caseSplit t
116 pure (MultilineTextResult patterns)
118addClause :: Text -> CS.WildcardAnnotations -> Success
119addClause t wca = MultilineTextResult (CS.addClause t wca)
121importsForFile :: (MonadIO m, MonadLogger m, MonadError PscIdeError m) =>
122 FilePath -> m Success
123importsForFile fp = do
124 imports <- getImportsForFile fp
125 pure (ImportList imports)
127-- | The first argument is a set of modules to load. The second argument
128-- denotes modules for which to load dependencies
129loadModulesAndDeps :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
130 [ModuleIdent] -> [ModuleIdent] -> m Success
131loadModulesAndDeps mods deps = do
132 r1 <- mapM loadModule (mods ++ deps)
133 r2 <- mapM loadModuleDependencies deps
134 let moduleResults = T.concat r1
135 let dependencyResults = T.concat r2
136 pure (TextResult (moduleResults <> ", " <> dependencyResults))
138loadModuleDependencies ::(PscIde m, MonadLogger m, MonadError PscIdeError m) =>
139 ModuleIdent -> m Text
140loadModuleDependencies moduleName = do
141 m <- getModule moduleName
142 case getDependenciesForModule <$> m of
144 mapM_ loadModule deps
145 -- We need to load the modules, that get reexported from the dependencies
146 depModules <- catMaybes <$> mapM getModule deps
147 -- What to do with errors here? This basically means a reexported dependency
148 -- doesn't exist in the output/ folder
149 traverse_ loadReexports depModules
150 pure ("Dependencies for " <> moduleName <> " loaded.")
151 Nothing -> throwError (ModuleNotFound moduleName)
153loadReexports :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
154 Module -> m [ModuleIdent]
155loadReexports m = case getReexports m of
158 -- I'm fine with this crashing on a failed pattern match.
159 -- If this ever fails I'll need to look at GADTs
160 let reexports = map (\(Export mn) -> mn) exportDeps
161 $(logDebug) ("Loading reexports for module: " <> fst m <>
162 " reexports: " <> T.intercalate ", " reexports)
163 traverse_ loadModule reexports
164 exportDepsModules <- catMaybes <$> traverse getModule reexports
165 exportDepDeps <- traverse loadReexports exportDepsModules
166 return $ concat exportDepDeps
168getDependenciesForModule :: Module -> [ModuleIdent]
169getDependenciesForModule (_, decls) = mapMaybe getDependencyName decls
170 where getDependencyName (Dependency dependencyName _ _) = Just dependencyName
171 getDependencyName _ = Nothing
173loadModule :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
174 ModuleIdent -> m Text
175loadModule "Prim" = pure "Prim won't be loaded"
177 path <- filePathFromModule mn
179 $(logDebug) ("Loaded extern file at: " <> T.pack path)
180 pure ("Loaded extern file at: " <> T.pack path)
182filePathFromModule :: (PscIde m, MonadError PscIdeError m) =>
183 ModuleIdent -> m FilePath
184filePathFromModule moduleName = do
185 outputPath <- confOutputPath . envConfiguration <$> ask
186 cwd <- liftIO getCurrentDirectory
187 let path = cwd </> outputPath </> T.unpack moduleName </> "externs.json"
188 ex <- liftIO $ doesFileExist path
191 else throwError (ModuleFileNotFound moduleName)
193-- | Taken from Data.Either.Utils
194maybeToEither :: MonadError e m =>
195 e -- ^ (Left e) will be returned if the Maybe value is Nothing
196 -> Maybe a -- ^ (Right a) will be returned if this is (Just a)
198maybeToEither errorval Nothing = throwError errorval
199maybeToEither _ (Just normalval) = return normalval
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list