module PureScript.Ide where
import Control.Monad.Except
import Control.Monad.State.Lazy (StateT (..), get, modify)
import Control.Monad.Trans.Either
import qualified Data.Map.Lazy as M
import Data.Maybe (mapMaybe)
import Data.Monoid
import qualified Data.Text as T
import PureScript.Ide.Completion
import PureScript.Ide.Externs
import PureScript.Ide.Pursuit
import PureScript.Ide.Error
import PureScript.Ide.Types
import System.FilePath
import System.Directory
type PscIde = StateT PscState IO
getAllDecls :: PscIde [ExternDecl]
getAllDecls = concat . pscStateModules <$> get
getAllModules :: PscIde [Module]
getAllModules = M.toList . pscStateModules <$> get
findCompletions :: [Filter] -> Matcher -> PscIde Success
findCompletions filters matcher =
CompletionResult <$> getCompletions filters matcher <$> getAllModules
findType :: DeclIdent -> [Filter] -> PscIde Success
findType search filters =
CompletionResult <$> getExactMatches search filters <$> getAllModules
findPursuitCompletions :: PursuitQuery -> PscIde Success
findPursuitCompletions (PursuitQuery q) =
PursuitResult <$> liftIO (searchPursuitForDeclarations q)
findPursuitPackages :: PursuitQuery -> PscIde Success
findPursuitPackages (PursuitQuery q) =
PursuitResult <$> liftIO (findPackagesForModuleIdent q)
loadExtern :: FilePath -> PscIde (Either Error ())
loadExtern fp = runEitherT $ do
decls <- EitherT . liftIO $ readExternFile fp
(name, decls') <- EitherT . return $ moduleFromDecls decls
modify (\x ->
x
{ pscStateModules = M.insert
name
decls'
(pscStateModules x)
})
getDependenciesForModule :: ModuleIdent -> PscIde (Maybe [ModuleIdent])
getDependenciesForModule m = do
mDecls <- M.lookup m . pscStateModules <$> get
return $ mapMaybe getDependencyName <$> mDecls
where getDependencyName (Dependency dependencyName _) = Just dependencyName
getDependencyName _ = Nothing
moduleFromDecls :: [ExternDecl] -> Either Error Module
moduleFromDecls decls@(ModuleDecl name _:_) = Right (name, decls)
moduleFromDecls _ = Left (GeneralError "An externs File didn't start with a module declaration")
stateFromDecls :: [[ExternDecl]] -> Either Error PscState
stateFromDecls externs= do
modules <- mapM moduleFromDecls externs
return $ PscState (M.fromList modules)
printModules :: PscIde Success
printModules =
TextResult . T.intercalate ", " . M.keys . pscStateModules <$> get
loadModulesAndDeps :: [ModuleIdent] -> [ModuleIdent] -> PscIde (Either Error Success)
loadModulesAndDeps mods deps = do
r1 <- mapM loadModule mods
r2 <- mapM loadModuleDependencies deps
return $
TextResult <$>
liftM2
(\x y -> x <> ", " <> y)
(T.concat <$> sequence r1)
(T.concat <$> sequence r2)
loadModuleDependencies :: ModuleIdent -> PscIde (Either Error T.Text)
loadModuleDependencies moduleName = do
_ <- loadModule moduleName
mDeps <- getDependenciesForModule moduleName
case mDeps of
Just deps -> do
mapM_ loadModule deps
return (Right ("Dependencies for " <> moduleName <> " loaded."))
Nothing -> return (Left (ModuleNotFound moduleName))
loadModule :: ModuleIdent -> PscIde (Either Error T.Text)
loadModule mn = do
path <- liftIO $ filePathFromModule mn
case path of
Right p -> loadExtern p >> return (Right $ "Loaded extern file at: " <> T.pack p)
Left err -> return (Left err)
filePathFromModule :: ModuleIdent -> IO (Either Error FilePath)
filePathFromModule moduleName = do
cwd <- getCurrentDirectory
let path = cwd </> "output" </> T.unpack moduleName </> "externs.purs"
ex <- doesFileExist path
return $
if ex
then Right path
else Left (ModuleFileNotFound moduleName)
maybeToEither :: MonadError e m =>
e
-> Maybe a
-> m a
maybeToEither errorval Nothing = throwError errorval
maybeToEither _ (Just normalval) = return normalval