hsdev 0.1.7.0 → 0.1.7.1
raw patch · 21 files changed
+292/−217 lines, 21 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- HsDev.Symbols: passImportList :: ImportList -> Text -> Bool
- HsDev.Symbols.Resolve: exported :: Declaration -> Export -> Maybe Declaration
- HsDev.Symbols.Resolve: instance Control.Monad.Reader.Class.MonadReader HsDev.Database.Database HsDev.Symbols.Resolve.ResolveM
- HsDev.Symbols.Types: ExportAll :: ExportPart
- HsDev.Symbols.Types: ExportNothing :: ExportPart
- HsDev.Symbols.Types: ExportWith :: [Text] -> ExportPart
- HsDev.Symbols.Types: [_importSpec] :: ImportList -> [Text]
- HsDev.Symbols.Types: data ExportPart
- HsDev.Symbols.Types: importSpec :: Lens' ImportList [Text]
- HsDev.Symbols.Types: instance Control.DeepSeq.NFData HsDev.Symbols.Types.ExportPart
- HsDev.Symbols.Types: instance Data.Aeson.Types.Class.FromJSON HsDev.Symbols.Types.ExportPart
- HsDev.Symbols.Types: instance Data.Aeson.Types.Class.ToJSON HsDev.Symbols.Types.ExportPart
- HsDev.Symbols.Types: instance GHC.Classes.Eq HsDev.Symbols.Types.ExportPart
- HsDev.Symbols.Types: instance GHC.Classes.Ord HsDev.Symbols.Types.ExportPart
- HsDev.Symbols.Types: instance GHC.Show.Show HsDev.Symbols.Types.ExportPart
- HsDev.Symbols.Util: imported :: ModuleId -> [Import] -> Bool
+ HsDev.Database.Update: liftExceptT_ :: CommandMonad m => ExceptT String IO a -> m a
+ HsDev.Server.Commands: [serverSilent] :: ServerOpts -> Bool
+ HsDev.Server.Types: [serverSilent] :: ServerOpts -> Bool
+ HsDev.Symbols: exported :: Declaration -> Export -> Bool
+ HsDev.Symbols: imported :: Declaration -> ImportList -> Bool
+ HsDev.Symbols: passImportSpec :: Declaration -> ImportSpec -> Bool
+ HsDev.Symbols: passThingSpec :: Text -> ThingPart -> Bool
+ HsDev.Symbols.Resolve: instance Control.Monad.Reader.Class.MonadReader (HsDev.Database.Database, HsDev.Symbols.Resolve.ModuleMap) HsDev.Symbols.Resolve.ResolveM
+ HsDev.Symbols.Resolve: resolveImports :: Module -> [Import] -> ResolveM [Declaration]
+ HsDev.Symbols.Types: ImportSpec :: Text -> ThingPart -> ImportSpec
+ HsDev.Symbols.Types: ThingAll :: ThingPart
+ HsDev.Symbols.Types: ThingNothing :: ThingPart
+ HsDev.Symbols.Types: ThingWith :: [Text] -> ThingPart
+ HsDev.Symbols.Types: [_importSpecName] :: ImportSpec -> Text
+ HsDev.Symbols.Types: [_importSpecPart] :: ImportSpec -> ThingPart
+ HsDev.Symbols.Types: [_importSpecs] :: ImportList -> [ImportSpec]
+ HsDev.Symbols.Types: data ImportSpec
+ HsDev.Symbols.Types: data ThingPart
+ HsDev.Symbols.Types: importSpecName :: Lens' ImportSpec Text
+ HsDev.Symbols.Types: importSpecPart :: Lens' ImportSpec ThingPart
+ HsDev.Symbols.Types: importSpecs :: Lens' ImportList [ImportSpec]
+ HsDev.Symbols.Types: instance Control.DeepSeq.NFData HsDev.Symbols.Types.ImportSpec
+ HsDev.Symbols.Types: instance Control.DeepSeq.NFData HsDev.Symbols.Types.ThingPart
+ HsDev.Symbols.Types: instance Data.Aeson.Types.Class.FromJSON HsDev.Symbols.Types.ImportSpec
+ HsDev.Symbols.Types: instance Data.Aeson.Types.Class.FromJSON HsDev.Symbols.Types.ThingPart
+ HsDev.Symbols.Types: instance Data.Aeson.Types.Class.ToJSON HsDev.Symbols.Types.ImportSpec
+ HsDev.Symbols.Types: instance Data.Aeson.Types.Class.ToJSON HsDev.Symbols.Types.ThingPart
+ HsDev.Symbols.Types: instance GHC.Classes.Eq HsDev.Symbols.Types.ImportSpec
+ HsDev.Symbols.Types: instance GHC.Classes.Eq HsDev.Symbols.Types.ThingPart
+ HsDev.Symbols.Types: instance GHC.Classes.Ord HsDev.Symbols.Types.ImportSpec
+ HsDev.Symbols.Types: instance GHC.Classes.Ord HsDev.Symbols.Types.ThingPart
+ HsDev.Symbols.Types: instance GHC.Show.Show HsDev.Symbols.Types.ImportSpec
+ HsDev.Symbols.Types: instance GHC.Show.Show HsDev.Symbols.Types.ThingPart
+ HsDev.Symbols.Util: moduleImported :: ModuleId -> [Import] -> Bool
+ HsDev.Tools.Ghc.Worker: logToChan :: Chan (Note OutputMessage) -> DynFlags -> Severity -> SrcSpan -> PprStyle -> SDoc -> IO ()
+ HsDev.Tools.Ghc.Worker: logToNull :: DynFlags -> Severity -> SrcSpan -> PprStyle -> SDoc -> IO ()
- HsDev.Database.Update: liftExceptT :: CommandMonad m => ExceptT String IO a -> m a
+ HsDev.Database.Update: liftExceptT :: CommandMonad m => Format -> ExceptT String IO a -> m a
- HsDev.Project: entity :: Lens (Extensions a_aZFP) (Extensions a_a11PZ) a_aZFP a_a11PZ
+ HsDev.Project: entity :: Lens (Extensions a_a11gl) (Extensions a_a13oA) a_a11gl a_a13oA
- HsDev.Project: extensions :: Lens' (Extensions a_aZFP) [Extension]
+ HsDev.Project: extensions :: Lens' (Extensions a_a11gl) [Extension]
- HsDev.Project: ghcOptions :: Lens' (Extensions a_aZFP) [String]
+ HsDev.Project: ghcOptions :: Lens' (Extensions a_a11gl) [String]
- HsDev.Server.Commands: ServerOpts :: ConnectionPort -> Int -> Maybe FilePath -> String -> Maybe FilePath -> Bool -> ServerOpts
+ HsDev.Server.Commands: ServerOpts :: ConnectionPort -> Int -> Maybe FilePath -> String -> Maybe FilePath -> Bool -> Bool -> ServerOpts
- HsDev.Server.Message: message :: Lens (Message a_aG5g) (Message a_aGg3) a_aG5g a_aGg3
+ HsDev.Server.Message: message :: Lens (Message a_aG5h) (Message a_aGg4) a_aG5h a_aGg4
- HsDev.Server.Message: messageId :: Lens' (Message a_aG5g) (Maybe String)
+ HsDev.Server.Message: messageId :: Lens' (Message a_aG5h) (Maybe String)
- HsDev.Server.Types: ServerOpts :: ConnectionPort -> Int -> Maybe FilePath -> String -> Maybe FilePath -> Bool -> ServerOpts
+ HsDev.Server.Types: ServerOpts :: ConnectionPort -> Int -> Maybe FilePath -> String -> Maybe FilePath -> Bool -> Bool -> ServerOpts
- HsDev.Symbols.Resolve: ResolveM :: ReaderT Database (State ResolvedTree) a -> ResolveM a
+ HsDev.Symbols.Resolve: ResolveM :: ReaderT (Database, ModuleMap) (State ResolvedTree) a -> ResolveM a
- HsDev.Symbols.Resolve: [runResolveM] :: ResolveM a -> ReaderT Database (State ResolvedTree) a
+ HsDev.Symbols.Resolve: [runResolveM] :: ResolveM a -> ReaderT (Database, ModuleMap) (State ResolvedTree) a
- HsDev.Symbols.Resolve: resolveImport :: Module -> Import -> ResolveM [Declaration]
+ HsDev.Symbols.Resolve: resolveImport :: Set String -> Module -> Import -> ResolveM [Declaration]
- HsDev.Symbols.Types: ExportName :: Maybe Text -> Text -> ExportPart -> Export
+ HsDev.Symbols.Types: ExportName :: Maybe Text -> Text -> ThingPart -> Export
- HsDev.Symbols.Types: ImportList :: Bool -> [Text] -> ImportList
+ HsDev.Symbols.Types: ImportList :: Bool -> [ImportSpec] -> ImportList
- HsDev.Symbols.Types: [_exportPart] :: Export -> ExportPart
+ HsDev.Symbols.Types: [_exportPart] :: Export -> ThingPart
- HsDev.Symbols.Types: exportPart :: Traversal' Export ExportPart
+ HsDev.Symbols.Types: exportPart :: Traversal' Export ThingPart
- HsDev.Symbols.Types: inspectedId :: Lens (Inspected i_a1mg4 a_a1mg5) (Inspected i_a1obD a_a1mg5) i_a1mg4 i_a1obD
+ HsDev.Symbols.Types: inspectedId :: Lens (Inspected i_a1mg9 a_a1mga) (Inspected i_a1ogw a_a1mga) i_a1mg9 i_a1ogw
- HsDev.Symbols.Types: inspection :: Lens' (Inspected i_a1mg4 a_a1mg5) Inspection
+ HsDev.Symbols.Types: inspection :: Lens' (Inspected i_a1mg9 a_a1mga) Inspection
- HsDev.Symbols.Types: inspectionResult :: Lens (Inspected i_a1mg4 a_a1mg5) (Inspected i_a1mg4 a_a1obE) (Either String a_a1mg5) (Either String a_a1obE)
+ HsDev.Symbols.Types: inspectionResult :: Lens (Inspected i_a1mg9 a_a1mga) (Inspected i_a1mg9 a_a1ogx) (Either String a_a1mga) (Either String a_a1ogx)
- HsDev.Tools.Types: note :: Lens (Note a_a1Ofd) (Note a_a1OoE) a_a1Ofd a_a1OoE
+ HsDev.Tools.Types: note :: Lens (Note a_a1MW9) (Note a_a1N5A) a_a1MW9 a_a1N5A
- HsDev.Tools.Types: noteLevel :: Lens' (Note a_a1Ofd) (Maybe Severity)
+ HsDev.Tools.Types: noteLevel :: Lens' (Note a_a1MW9) (Maybe Severity)
- HsDev.Tools.Types: noteRegion :: Lens' (Note a_a1Ofd) Region
+ HsDev.Tools.Types: noteRegion :: Lens' (Note a_a1MW9) Region
- HsDev.Tools.Types: noteSource :: Lens' (Note a_a1Ofd) ModuleLocation
+ HsDev.Tools.Types: noteSource :: Lens' (Note a_a1MW9) ModuleLocation
Files
- hsdev.cabal +4/−2
- src/HsDev/Cache.hs +1/−3
- src/HsDev/Client/Commands.hs +6/−10
- src/HsDev/Database/Update.hs +54/−29
- src/HsDev/Inspect.hs +9/−5
- src/HsDev/Project.hs +1/−1
- src/HsDev/Sandbox.hs +4/−7
- src/HsDev/Scan.hs +3/−5
- src/HsDev/Scan/Browse.hs +1/−2
- src/HsDev/Server/Base.hs +2/−3
- src/HsDev/Server/Types.hs +10/−5
- src/HsDev/Stack.hs +4/−5
- src/HsDev/Symbols.hs +32/−8
- src/HsDev/Symbols/Resolve.hs +42/−37
- src/HsDev/Symbols/Types.hs +56/−47
- src/HsDev/Symbols/Util.hs +4/−4
- src/HsDev/Tools/Ghc/Check.hs +4/−31
- src/HsDev/Tools/Ghc/Worker.hs +43/−5
- src/HsDev/Tools/GhcMod.hs +1/−1
- tests/Test.hs +8/−5
- tools/hsinspect.hs +3/−2
hsdev.cabal view
@@ -2,7 +2,7 @@ -- see http://haskell.org/cabal/users-guide/ name: hsdev -version: 0.1.7.0 +version: 0.1.7.1 synopsis: Haskell development library and tool with support of autocompletion, symbol info, go to declaration, find references etc. description: Haskell development library and tool with support of autocompletion, symbol info, go to declaration, find references, hayoo search etc. @@ -281,8 +281,10 @@ aeson-lens >= 0.5.0, async >= 2.0, data-default >= 0.5.0, - containers >= 0.5.0, deepseq >= 1.4.0, + directory >= 1.2.0, + filepath >= 1.4.0, + containers >= 0.5.0, hformat >= 0.1, hspec, lens >= 4.8,
src/HsDev/Cache.hs view
@@ -24,13 +24,11 @@ import Data.Char (isAlphaNum) import Data.List (intercalate) import System.FilePath -import Text.Read (readMaybe) import HsDev.PackageDb import HsDev.Project import HsDev.Database (Database) -import HsDev.Version -import HsDev.Util (split, version) +import HsDev.Util (version) -- | Escape path escapePath :: FilePath -> FilePath
src/HsDev/Client/Commands.hs view
@@ -39,7 +39,6 @@ import HsDev.Server.Types import HsDev.Sandbox hiding (findSandbox) import qualified HsDev.Sandbox as S (findSandbox) -import HsDev.Stack import HsDev.Symbols import HsDev.Symbols.Resolve (resolveOne, scopeModule, exportsModule) import HsDev.Symbols.Util @@ -55,7 +54,6 @@ import HsDev.Util import HsDev.Watcher -import qualified HsDev.Scan as Scan import qualified HsDev.Scan.Browse as Scan import qualified HsDev.Database.Update as Update @@ -87,7 +85,7 @@ map (Update.scanProject ghcs') projs, map (Update.scanFile ghcs') fs, map (Update.scanDirectory ghcs') paths', - if cabal then [Update.scanCabal ghcs'] else [], + [Update.scanCabal ghcs' | cabal], map (Update.scanSandbox ghcs') sboxes'] runCommand (RefineDocs projs fs ms) = toValue $ do projects <- traverse findProject projs @@ -164,7 +162,8 @@ runCommand (InfoSymbol sq fs locals') = toValue $ do dbval <- liftM (localsDatabase locals') $ getDb filter' <- targetFilters fs - return $ newestPackage $ filterMatch sq $ filter (checkModule filter') $ allDeclarations dbval + return $ newestPackage $ filterMatch sq $ + concatMap moduleModuleDeclarations $ filter (filter' . view moduleId) $ allModules dbval runCommand (InfoModule sq fs) = toValue $ do dbval <- getDb filter' <- targetFilters fs @@ -256,8 +255,8 @@ notes <- inWorkerWith (commandError_ . show) ghc (runExceptT $ Types.fileTypes ghcs' pdbs m msrc) either commandError_ return notes -runCommand (GhcMod GhcModLang) = toValue $ mapCommandIO $ GhcMod.langs -runCommand (GhcMod GhcModFlags) = toValue $ mapCommandIO $ GhcMod.flags +runCommand (GhcMod GhcModLang) = toValue $ mapCommandIO GhcMod.langs +runCommand (GhcMod GhcModFlags) = toValue $ mapCommandIO GhcMod.flags runCommand (GhcMod (GhcModType (Position line column) fpath ghcs')) = toValue $ do ghcmod <- askSession sessionGhcMod dbval <- getDb @@ -325,7 +324,7 @@ toValue' (Left (SomeException e)) = object ["fail" .= show e] toValue' (Right s) = toJSON s runCommand (Link hold) = toValue $ commandLink >> when hold commandHold -runCommand Exit = toValue $ serverExit +runCommand Exit = toValue serverExit targetFilters :: CommandMonad m => [TargetFilter] -> m (ModuleId -> Bool) targetFilters fs = do @@ -425,9 +424,6 @@ dbval <- getDb pdbs <- liftIO $ searchPackageDbStack fpath return $ filterDB (restrictPackageDbStack pdbs) (const True) dbval - -mapCommandErrorStr :: CommandMonad m => ExceptT String m a -> m a -mapCommandErrorStr act = runExceptT act >>= either commandError_ return mapCommandIO :: CommandMonad m => ExceptT String IO a -> m a mapCommandIO act = liftIO (runExceptT act) >>= either commandError_ return
src/HsDev/Database/Update.hs view
@@ -19,33 +19,32 @@ updateEvent, processEvent, -- * Helpers - liftExceptT, + liftExceptT, liftExceptT_, module HsDev.Watcher, module Control.Monad.Except ) where +import Control.Applicative ((<|>)) import Control.Arrow import Control.Concurrent.Lifted (fork) import Control.DeepSeq -import Control.Lens (preview, _Just, view, over, set, _1, mapMOf_, each, (^..), _head) +import Control.Lens (preview, _Just, view, over, set, _1, mapMOf_, each, (^..), _head, _Right) import Control.Monad.Except import Control.Monad.Reader import Control.Monad.Writer import Data.Aeson import Data.Aeson.Types -import Data.List ((\\)) import Data.Foldable (toList) import qualified Data.Map as M -import Data.Maybe (mapMaybe, isJust, fromMaybe, catMaybes) -import Data.Maybe.JustIf +import Data.Maybe (mapMaybe, isJust, fromMaybe) import qualified Data.Text as T (unpack) import System.Directory (canonicalizePath, doesFileExist) import System.FilePath import qualified System.Log.Simple as Log -import Control.Concurrent.Worker (inWorker) +import Control.Concurrent.Worker (inWorker, restartWorker) import qualified HsDev.Cache.Structured as Cache import HsDev.Database import HsDev.Database.Async hiding (Event) @@ -55,7 +54,7 @@ import HsDev.Sandbox import HsDev.Stack import HsDev.Symbols -import HsDev.Tools.Ghc.Worker (ghcWorker) +import HsDev.Tools.Ghc.Worker (setCmdOpts) import HsDev.Tools.Ghc.Types (inferTypes) import HsDev.Tools.HDocs import qualified HsDev.Scan as S @@ -112,13 +111,21 @@ return r scanDocs_ :: UpdateMonad m => InspectedModule -> m () scanDocs_ im = do - im' <- liftExceptT $ S.scanModify (\opts _ -> inspectDocs opts) im + im' <- + liftExceptT + ("Scanning docs for {} failed: {}" ~~ view inspectedId im) + (S.scanModify (\opts _ -> inspectDocs opts) im) + <|> return im updater $ return $ fromModule im' inferModTypes_ :: UpdateMonad m => InspectedModule -> m () inferModTypes_ im = do -- TODO: locate sandbox s <- getSession - im' <- liftExceptT $ S.scanModify (infer' s) im + im' <- + liftExceptT + ("Inferring types for {} failed: {}" ~~ view inspectedId im) + (S.scanModify (infer' s) im) + <|> return im updater $ return $ fromModule im' infer' :: Session -> [String] -> PackageDbStack -> Module -> ExceptT String IO Module infer' s opts pdbs m = case preview (moduleLocation . moduleFile) m of @@ -203,7 +210,7 @@ scanModule :: UpdateMonad m => [String] -> ModuleLocation -> Maybe String -> m () scanModule opts mloc mcts = runTask "scanning" mloc $ Log.scope "module" $ do defs <- askSession sessionDefines - im <- liftExceptT $ S.scanModule defs opts mloc mcts + im <- liftExceptT_ $ S.scanModule defs opts mloc mcts updater $ return $ fromModule im _ <- return $ view inspectionResult im return () @@ -255,8 +262,7 @@ scannedDbs = databasePackageDbs dbval unscannedDbs = filter ((`notElem` scannedDbs) . topPackageDb) $ reverse $ packageDbStacks userDb if null unscannedDbs - then do - Log.log Log.Trace $ "cabal (global-db and user-db) already scanned" + then Log.log Log.Trace $ "cabal (global-db and user-db) already scanned" else runTasks $ map (scanPackageDb opts) unscannedDbs -- | Prepare sandbox for scanning. This is used for stack project to build & configure. @@ -273,13 +279,12 @@ scanSandbox opts sbox = Log.scope "sandbox" $ do dbval <- readDB prepareSandbox sbox - pdbs <- liftExceptT $ sandboxPackageDbStack sbox + pdbs <- liftExceptT_ $ sandboxPackageDbStack sbox let scannedDbs = databasePackageDbs dbval unscannedDbs = filter ((`notElem` scannedDbs) . topPackageDb) $ reverse $ packageDbStacks pdbs if null unscannedDbs - then do - Log.log Log.Trace $ "sandbox already scanned" + then Log.log Log.Trace $ "sandbox already scanned" else runTasks $ map (scanPackageDb opts) unscannedDbs -- | Scan top of package-db stack, usable for rescan @@ -288,10 +293,10 @@ watch (\w -> watchPackageDb w pdbs opts) mlocs <- liftM (filter (\mloc -> preview modulePackageDb mloc == Just (topPackageDb pdbs))) $ - liftExceptT $ listModules opts pdbs + liftExceptT_ $ listModules opts pdbs scan (Cache.loadPackageDb (topPackageDb pdbs)) (packageDbDB (topPackageDb pdbs)) ((,,) <$> mlocs <*> pure [] <*> pure Nothing) opts $ \mlocs' -> do - ms <- liftExceptT $ browseModules opts pdbs (mlocs' ^.. each . _1) - docs <- liftExceptT $ hdocsCabal pdbs opts + ms <- liftExceptT_ $ browseModules opts pdbs (mlocs' ^.. each . _1) + docs <- liftExceptT_ $ hdocsCabal pdbs opts updater $ return $ mconcat $ map (fromModule . fmap (setDocs' docs)) ms where setDocs' :: Map String (Map String String) -> Module -> Module @@ -299,7 +304,7 @@ -- | Scan project file scanProjectFile :: UpdateMonad m => [String] -> FilePath -> m Project -scanProjectFile opts cabal = runTask "scanning" cabal $ liftExceptT $ S.scanProjectFile opts cabal +scanProjectFile opts cabal = runTask "scanning" cabal $ liftExceptT_ $ S.scanProjectFile opts cabal -- | Scan project and related package-db stack scanProjectStack :: UpdateMonad m => [String] -> FilePath -> m () @@ -314,7 +319,7 @@ scanProject opts cabal = runTask "scanning" (project cabal) $ Log.scope "project" $ do proj <- scanProjectFile opts cabal watch (\w -> watchProject w proj opts) - S.ScanContents _ [(_, sources)] _ <- liftExceptT $ S.enumProject proj + S.ScanContents _ [(_, sources)] _ <- liftExceptT_ $ S.enumProject proj scan (Cache.loadProject $ view projectCabal proj) (projectDB proj) sources opts $ \ms -> do scanModules opts ms updater $ return $ fromProject proj @@ -322,7 +327,7 @@ -- | Scan directory for source files and projects scanDirectory :: UpdateMonad m => [String] -> FilePath -> m () scanDirectory opts dir = runTask "scanning" dir $ Log.scope "directory" $ do - S.ScanContents standSrcs projSrcs pdbss <- liftExceptT $ S.enumDirectory dir + S.ScanContents standSrcs projSrcs pdbss <- liftExceptT_ $ S.enumDirectory dir runTasks [scanProject opts (view projectCabal p) | (p, _) <- projSrcs] runTasks $ map (scanPackageDb opts) pdbss -- TODO: Don't rescan mapMOf_ (each . _1) (watch . flip watchModule) standSrcs @@ -351,13 +356,23 @@ -- | Scan docs for inspected modules scanDocs :: UpdateMonad m => [InspectedModule] -> m () scanDocs ims = do - w <- liftIO $ ghcWorker ["-haddock"] (return ()) + -- w <- liftIO $ ghcWorker ["-haddock"] (return ()) + w <- askSession sessionGhc + liftIO $ do + restartWorker w + inWorker w $ setCmdOpts ["-haddock"] runTasks $ map (scanDocs' w) ims where scanDocs' w im = runTask "scanning docs" (view inspectedId im) $ Log.scope "docs" $ do Log.log Log.Trace $ "Scanning docs for {}" ~~ view inspectedId im - im' <- liftExceptT $ S.scanModify (\opts _ -> inWorkerT w . inspectDocsGhc opts) im - Log.log Log.Trace $ "Docs for {} updated" ~~ view inspectedId im + im' <- + liftExceptT + ("Scanning docs for {} failed: {}" ~~ view inspectedId im) + (S.scanModify (\opts _ -> inWorkerT w . inspectDocsGhc opts) im) + <|> return im + Log.log Log.Trace $ "Docs for {} updated: documented {} declarations" ~~ + view inspectedId im' ~~ + length (im' ^.. inspectionResult . _Right . moduleDeclarations . each . declarationDocs . _Just) updater $ return $ fromModule im' inWorkerT w = ExceptT . inWorker w . runExceptT @@ -366,7 +381,11 @@ inferModTypes' im = runTask "inferring types" (view inspectedId im) $ Log.scope "docs" $ do w <- askSession sessionGhc Log.log Log.Trace $ "Inferring types for {}" ~~ view inspectedId im - im' <- liftExceptT $ S.scanModify (\opts cabal m -> inWorkerT w (inferTypes opts cabal m Nothing)) im + im' <- + liftExceptT + ("Inferring types for {} failed: {}" ~~ view inspectedId im) + (S.scanModify (\opts cabal m -> inWorkerT w (inferTypes opts cabal m Nothing)) im) + <|> return im Log.log Log.Trace $ "Types for {} inferred" ~~ view inspectedId im updater $ return $ fromModule im' inWorkerT w = ExceptT . inWorker w . runExceptT @@ -388,7 +407,7 @@ dbval <- getCache cache' part' let obsolete = filterDB (\m -> view moduleIdLocation m `notElem` (mlocs ^.. each . _1)) (const False) dbval - changed <- liftExceptT $ S.changedModules dbval opts mlocs + changed <- liftExceptT "Getting changed modules failed: {}" $ S.changedModules dbval opts mlocs cleaner $ return obsolete act changed @@ -427,11 +446,17 @@ scanFile opts $ view eventPath e | otherwise = return () -liftExceptT :: CommandMonad m => ExceptT String IO a -> m a -liftExceptT act = liftIO (runExceptT act) >>= either commandError_ return +liftExceptT_ :: CommandMonad m => ExceptT String IO a -> m a +liftExceptT_ = liftExceptT "{}" +liftExceptT :: CommandMonad m => Format -> ExceptT String IO a -> m a +liftExceptT msg act = liftIO (runExceptT act) >>= either onError return where + onError e = do + Log.log Log.Error $ msg ~~ e + commandError_ $ msg ~~ e + liftCIO ::CommandMonad m => IO a -> m a -liftCIO = liftExceptT . liftE +liftCIO = liftExceptT "Exception during IO action: {}" . liftE processEvent :: UpdateOptions -> Watched -> Event -> ClientM IO () processEvent uopts w e = runUpdate uopts $ updateEvent w e
src/HsDev/Inspect.hs view
@@ -122,10 +122,10 @@ -- | Get exports getExports :: H.ExportSpec -> [Export] getExports (H.EModuleContents (H.ModuleName m)) = [ExportModule $ fromString m]-getExports (H.EVar n) = [uncurry ExportName (identOfQName n) ExportNothing]-getExports (H.EAbs _ n) = [uncurry ExportName (identOfQName n) ExportNothing]-getExports (H.EThingAll n) = [uncurry ExportName (identOfQName n) ExportAll]-getExports (H.EThingWith n ns) = [uncurry ExportName (identOfQName n) $ ExportWith (map toStr ns)] where+getExports (H.EVar n) = [uncurry ExportName (identOfQName n) ThingNothing]+getExports (H.EAbs _ n) = [uncurry ExportName (identOfQName n) ThingNothing]+getExports (H.EThingAll n) = [uncurry ExportName (identOfQName n) ThingAll]+getExports (H.EThingWith n ns) = [uncurry ExportName (identOfQName n) $ ThingWith (map toStr ns)] where toStr :: H.CName -> Text toStr (H.VarName cn) = identOfName cn toStr (H.ConName cn) = identOfName cn@@ -140,7 +140,11 @@ (Just $ toPosition $ H.importLoc d) where mname (H.ModuleName n) = fromString n- importLst (hiding, specs) = ImportList hiding $ map identOfName (concatMap childrenBi specs :: [H.Name])+ importLst (hiding, specs) = ImportList hiding $ map impSpec specs+ impSpec (H.IVar n) = ImportSpec (identOfName n) ThingNothing+ impSpec (H.IAbs _ n) = ImportSpec (identOfName n) ThingNothing+ impSpec (H.IThingAll n) = ImportSpec (identOfName n) ThingAll+ impSpec (H.IThingWith n ns) = ImportSpec (identOfName n) $ ThingWith $ map identOfName (concatMap childrenBi ns :: [H.Name]) -- | Decl declarations getDecls :: [H.Decl] -> [Declaration]
src/HsDev/Project.hs view
@@ -23,7 +23,7 @@ import Control.Arrow import Control.DeepSeq (NFData(..)) -import Control.Lens (makeLenses, Simple, Lens, view, lens, at) +import Control.Lens (makeLenses, Simple, Lens, view, lens) import Control.Exception import Control.Monad.Except import Data.Aeson
src/HsDev/Sandbox.hs view
@@ -11,11 +11,10 @@ ) where import Control.Arrow -import Control.Applicative import Control.DeepSeq (NFData(..)) import Control.Monad.Trans.Maybe import Control.Monad.Except -import Control.Lens (view, makeLenses, Lens', lens) +import Control.Lens (view, makeLenses) import Data.Aeson import Data.Maybe (isJust, fromMaybe) import Data.List ((\\)) @@ -85,9 +84,9 @@ else return Nothing where sandboxFromDir :: FilePath -> Maybe Sandbox - sandboxFromDir fpath - | takeFileName fpath == "stack.yaml" = sandboxFromPath (takeDirectory fpath </> ".stack-work") - | otherwise = sandboxFromPath fpath + sandboxFromDir fdir + | takeFileName fdir == "stack.yaml" = sandboxFromPath (takeDirectory fdir </> ".stack-work") + | otherwise = sandboxFromPath fdir -- | Search sandbox by parent directory searchSandbox :: FilePath -> IO (Maybe Sandbox) @@ -108,8 +107,6 @@ case mbox of Nothing -> return userDb Just sbox -> liftM (either (const userDb) id) $ runExceptT $ sandboxPackageDbStack sbox - where - userDb = PackageDbStack [UserDb] -- | Restore package-db stack by package-db restorePackageDbStack :: PackageDb -> IO PackageDbStack
src/HsDev/Scan.hs view
@@ -16,16 +16,14 @@ module Control.Monad.Except, ) where -import Control.Applicative ((<|>)) import Control.DeepSeq -import Control.Lens (view, preview, set, over, each, _Right, _1, _2, _3, (^.), (^..), at) +import Control.Lens (view, preview, set, over, each, _Right, _1, _2, _3, (^.), (^..)) import Control.Monad.Except import Data.Maybe (catMaybes, fromMaybe, isJust) import Data.List (intercalate) import System.Directory import Text.Format -import Data.Deps import HsDev.Scan.Browse (browsePackages) import HsDev.Server.Types (FileContents(..)) import HsDev.Sandbox @@ -176,9 +174,9 @@ getDbs = maybe (return userDb) searchPackageDbStack . preview packageDb scanModule _ _ (ModuleSource _) _ = throwError "Can inspect only modules in file or cabal" --- | Scan additional info and modify scanned module. Dones't fail on error, just left module unchanged +-- | Scan additional info and modify scanned module scanModify :: ([String] -> PackageDbStack -> Module -> ExceptT String IO Module) -> InspectedModule -> ExceptT String IO InspectedModule -scanModify f im = traverse f' im <|> return im where +scanModify f im = traverse f' im where f' m = do pdbs <- liftIO $ case view moduleLocation m of -- TODO: Get actual sandbox stack
src/HsDev/Scan/Browse.hs view
@@ -21,7 +21,6 @@ import Data.Version import System.Directory import System.FilePath -import Text.Read (readMaybe) import Data.Deps import HsDev.PackageDb @@ -93,7 +92,7 @@ _moduleName = fromString thisModule, _moduleDocs = Nothing, _moduleLocation = thisLoc, - _moduleExports = Just [ExportName Nothing (view declarationName d) ExportNothing | d <- ds], + _moduleExports = Just [ExportName Nothing (view declarationName d) ThingNothing | d <- ds], _moduleImports = [import_ iname | iname <- ordNub (mapMaybe (preview definedModule) ds), iname /= fromString thisModule], _moduleDeclarations = sortDeclarations ds } where
src/HsDev/Server/Base.hs view
@@ -16,7 +16,6 @@ import Control.Monad.Except import Control.Monad.Reader import Data.Default -import Data.List (intercalate) import qualified Data.Map as M import Data.Maybe import Data.String @@ -55,7 +54,7 @@ initLog sopts = do msgs <- F.newChan l <- newLog (constant [rule']) $ concat [ - [logger text console], + [logger text console | not $ serverSilent sopts], [logger text (chaner msgs)], maybeToList $ (logger text . file) <$> serverLog sopts] Log.writeLog l Log.Info ("Log politics: low = {}, high = {}" ~~ logLow ~~ logHigh) @@ -78,7 +77,7 @@ outputStr Log.Trace $ "Checking cache version in {}" ~~ cdir ver <- Cache.readVersion $ cdir </> Cache.versionCache outputStr Log.Debug $ "Cache version: {}" ~~ strVersion ver - when (not $ sameVersion (cutVersion version) (cutVersion ver)) $ ignoreIO $ do + unless (sameVersion (cutVersion version) (cutVersion ver)) $ ignoreIO $ do outputStr Log.Info $ "Cache version ({cache}) is incompatible with hsdev version ({hsdev}), removing cache ({dir})" ~~ ("cache" %= strVersion ver) ~~ ("hsdev" %= strVersion version) ~~
src/HsDev/Server/Types.hs view
@@ -37,7 +37,6 @@ import HsDev.Database import qualified HsDev.Database.Async as DB import HsDev.Project -import HsDev.Sandbox import HsDev.Symbols import HsDev.Server.Message import HsDev.Watcher.Types (Watcher) @@ -234,11 +233,12 @@ serverLog :: Maybe FilePath, serverLogConfig :: String, serverCache :: Maybe FilePath, - serverLoad :: Bool } + serverLoad :: Bool, + serverSilent :: Bool } deriving (Show) instance Default ServerOpts where - def = ServerOpts def 0 Nothing "use default" Nothing False + def = ServerOpts def 0 Nothing "use default" Nothing False False -- | Client options data ClientOpts = ClientOpts { @@ -269,7 +269,8 @@ optional logArg <*> (logConfigArg <|> pure (serverLogConfig def)) <*> optional cacheArg <*> - loadFlag + loadFlag <*> + serverSilentFlag instance FromCmd ClientOpts where cmdP = ClientOpts <$> @@ -288,6 +289,7 @@ noFileFlag :: Parser Bool loadFlag :: Parser Bool prettyFlag :: Parser Bool +serverSilentFlag :: Parser Bool stdinFlag :: Parser Bool silentFlag :: Parser Bool @@ -306,6 +308,7 @@ noFileFlag = switch (long "no-file" <> help "don't use mmap files") loadFlag = switch (long "load" <> help "force load all data from cache on startup") prettyFlag = switch (long "pretty" <> help "pretty json output") +serverSilentFlag = switch (long "silent" <> help "no stdout/stderr") stdinFlag = switch (long "stdin" <> help "pass data to stdin") silentFlag = switch (long "silent" <> help "supress notifications") @@ -316,7 +319,8 @@ marg "--log" (serverLog sopts), ["--log-config", serverLogConfig sopts], marg "--cache" (serverCache sopts), - ["--load" | serverLoad sopts]] + ["--load" | serverLoad sopts], + ["--silent" | serverSilent sopts]] where marg :: String -> Maybe String -> [String] marg n (Just v) = [n, v] @@ -613,6 +617,7 @@ inferFlag :: Parser Bool localsFlag :: Parser Bool moduleArg :: Parser String +packageDbArg :: Parser PackageDb packageArg :: Parser String pathArg :: Mod OptionFields String -> Parser FilePath projectArg :: Parser String
src/HsDev/Stack.hs view
@@ -12,7 +12,7 @@ ) where import Control.Arrow -import Control.Lens (makeLenses, Lens', at, ix, lens, (^?), (^.), view) +import Control.Lens (makeLenses, Lens', at, ix, lens, (^?), (^.)) import Control.Monad import Control.Monad.Trans.Maybe import Control.Monad.IO.Class @@ -26,7 +26,6 @@ import System.Process import HsDev.PackageDb -import HsDev.Project import HsDev.Util (withCurrentDirectory) -- | Invoke stack command, we are trying to get actual stack near current hsdev executable @@ -88,12 +87,12 @@ -- | Projects paths projectEnv :: FilePath -> MaybeT IO StackEnv projectEnv p = do - hasConfig <- liftIO $ doesFileExist yaml + hasConfig <- liftIO $ doesFileExist yaml' guard hasConfig - paths' <- path (Just yaml) + paths' <- path (Just yaml') MaybeT $ return $ getStackEnv paths' where - yaml = p </> "stack.yaml" + yaml' = p </> "stack.yaml" -- | Get package-db stack for stack environment stackPackageDbStack :: Lens' StackEnv PackageDbStack
src/HsDev/Symbols.hs view
@@ -4,7 +4,7 @@ module HsDev.Symbols ( -- * Information export, - passImportList, + passThingSpec, passImportSpec, imported, exported, importNames, import_, Symbol(..), unnamedModuleId, @@ -43,14 +43,12 @@ import Data.Function (on) import Data.List import Data.Maybe (fromMaybe) -import qualified Data.Map as M import Data.Ord (comparing) import Data.Text (Text) import qualified Data.Text as T (concat) import System.Directory import System.FilePath -import Data.Deps import System.Directory.Paths import HsDev.Symbols.Types @@ -64,11 +62,37 @@ export (ExportName (Just q) n _) = T.concat [q, ".", n] export (ExportModule m) = m --- | Check whether name pass import list -passImportList :: ImportList -> Text -> Bool -passImportList (ImportList hiding names) n - | hiding = n `notElem` names - | otherwise = n `elem` names +-- | Does name pass thing spec +passThingSpec :: Text -> ThingPart -> Bool +passThingSpec _ ThingNothing = False +passThingSpec _ ThingAll = True +passThingSpec n (ThingWith ns) = n `elem` ns + +-- | Does declaration pass import-list spec +passImportSpec :: Declaration -> ImportSpec -> Bool +passImportSpec decl' (ImportSpec n p) + | view declarationName decl' == n = True + | preview (declaration . related . _Just) decl' == Just n = view declarationName decl' `passThingSpec` p + | otherwise = False + +-- | Check whether declaration passes import list +imported :: Declaration -> ImportList -> Bool +imported decl' (ImportList hiding specs) = invert $ any (decl' `passImportSpec`) specs where + invert = if hiding then not else id + +-- | Check whether declaration passes export +exported :: Declaration -> Export -> Bool +exported decl' (ExportName q n p) + | view declarationName decl' == n = checkImport + | preview (declaration . related . _Just) decl' == Just n = view declarationName decl' `passThingSpec` p + | otherwise = False + where + checkImport = case q of + Nothing -> any (not . view importIsQualified) $ fromMaybe [] $ view declarationImported decl' + Just q' -> any ((q' `elem`) . importNames) $ fromMaybe [] $ view declarationImported decl' +exported decl' (ExportModule m) = any (unqualBy m) . fromMaybe [] . view declarationImported $ decl' where + unqualBy :: Text -> Import -> Bool + unqualBy m' i = m' `elem` importNames i && not (view importIsQualified i) -- | Get import module names - full and synonym importNames :: Import -> [Text]
src/HsDev/Symbols/Resolve.hs view
@@ -3,7 +3,7 @@ module HsDev.Symbols.Resolve ( ResolveM(..),ResolvedTree, ResolvedModule(..), resolvedModule, resolvedScope, resolvedExports, scopeModule, exportsModule, resolvedTopScope, - resolve, resolveOne, resolveModule, exported, resolveImport, + resolve, resolveOne, resolveModule, resolveImports, resolveImport, mergeImported ) where @@ -12,21 +12,26 @@ import Control.Monad.Reader import Control.Monad.State import Data.Function (on) -import Data.List (sortBy, groupBy, delete, nubBy) +import Data.List (sortBy, groupBy, delete) import qualified Data.Map as M import Data.Maybe (fromMaybe, listToMaybe, catMaybes) import Data.Maybe.JustIf import Data.Ord (comparing) +import qualified Data.Set as S import Data.String (fromString) import Data.Text (Text) import HsDev.Database import HsDev.Symbols import HsDev.Symbols.Util +import HsDev.Util (uniqueBy) +-- | Map from name to modules +type ModuleMap = M.Map Text [Module] + -- | Resolve monad uses existing @Database@ and @ResolvedTree@ as state. -newtype ResolveM a = ResolveM { runResolveM :: ReaderT Database (State ResolvedTree) a } - deriving (Functor, Applicative, Monad, MonadState ResolvedTree, MonadReader Database) +newtype ResolveM a = ResolveM { runResolveM :: ReaderT (Database, ModuleMap) (State ResolvedTree) a } + deriving (Functor, Applicative, Monad, MonadState ResolvedTree, MonadReader (Database, ModuleMap)) -- | Tree of resolved modules type ResolvedTree = Map ModuleId ResolvedModule @@ -55,7 +60,11 @@ -- | Resolve modules, function is not IO, so all file names must be canonicalized resolve :: (Traversable t, Foldable t) => Database -> t Module -> t ResolvedModule -resolve db = flip evalState M.empty . flip runReaderT db . runResolveM . traverse resolveModule +resolve db = flip evalState M.empty . flip runReaderT (db, m) . runResolveM . traverse resolveModule where + m :: ModuleMap + m = M.fromList $ map ((view moduleName . head) &&& id) $ + groupBy ((==) `on` view moduleName) $ + sortBy (comparing (view moduleName)) $ allModules db -- | Resolve one module resolveOne :: Database -> Module -> ResolvedModule @@ -71,14 +80,14 @@ _resolvedExports = view moduleDeclarations m } _ -> do scope' <- - liftM ((thisDecls ++) . mergeImported . concat) . - mapM (resolveImport m) . + liftM (thisDecls ++) . + resolveImports m . (import_ (fromString "Prelude") :) . view moduleImports $ m let exported' = case view moduleExports m of Nothing -> thisDecls - Just exports' -> unique $ catMaybes $ exported <$> scope' <*> exports' + Just exports' -> unique $ catMaybes $ mexported <$> scope' <*> exports' return $ ResolvedModule m (sortDeclarations scope') (sortDeclarations exported') thisDecls :: [Declaration] thisDecls = map (selfDefined . selfImport) $ view moduleDeclarations m @@ -92,34 +101,31 @@ modify $ M.insert (view (resolvedModule . moduleId) rm) rm return rm unique :: [Declaration] -> [Declaration] - unique = nubBy ((==) `on` declId) . sortBy (comparing declId) + unique = uniqueBy declId declId :: Declaration -> (Text, Maybe ModuleId) declId = view declarationName &&& view declarationDefined + mexported decl' e' = decl' `justIf` exported decl' e' -exported :: Declaration -> Export -> Maybe Declaration -exported decl' (ExportName q n p) - | view declarationName decl' == n = decl' `justIf` checkImport - | preview (declaration . related . _Just) decl' == Just n = case p of - ExportNothing -> Nothing - ExportAll -> Just decl' - ExportWith ns -> decl' `justIf` (view declarationName decl' `elem` ns) - | otherwise = Nothing - where - checkImport = case q of - Nothing -> any (not . view importIsQualified) $ fromMaybe [] $ view declarationImported decl' - Just q' -> any ((q' `elem`) . importNames) $ fromMaybe [] $ view declarationImported decl' -exported decl' (ExportModule m) = decl' `justWhen` (any (unqualBy m) . fromMaybe [] . view declarationImported) where - unqualBy :: Text -> Import -> Bool - unqualBy m' i = m' `elem` importNames i && not (view importIsQualified i) +-- | Bring declarations into scope by imports +resolveImports :: Module -> [Import] -> ResolveM [Declaration] +resolveImports m is = do + db <- asks fst + let + deps = maybe S.empty S.fromList $ do + f <- preview (moduleLocation . moduleFile) m + p <- preview (moduleLocation . moduleProject . _Just) m + p' <- refineProject db p + return $ delete (view projectName p') $ concatMap (view infoDepends) $ fileTargets p' f + liftM (mergeImported . concat) $ mapM (resolveImport deps m) is --- | Bring declarations into scope -resolveImport :: Module -> Import -> ResolveM [Declaration] -resolveImport m i = liftM (map $ setImport i) resolveImport' where +-- | Bring declarations into scope, first parameter is set of visible packages +resolveImport :: S.Set String -> Module -> Import -> ResolveM [Declaration] +resolveImport deps m i = liftM (map $ setImport i) resolveImport' where resolveImport' :: ResolveM [Declaration] resolveImport' = do ms <- case view moduleLocation m of FileModule file proj -> do - db <- ask + db <- asks fst let proj' = proj >>= refineProject db case proj' of @@ -128,29 +134,28 @@ installed] Just p -> selectImport i [ inProject p, - inDepsOf' file p] - InstalledModule cabal _ _ -> selectImport i [inPackageDb cabal] + inDeps] + InstalledModule pdb _ _ -> selectImport i [inPackageDb pdb] ModuleSource _ -> selectImport i [installed] fromMaybe [] <$> traverse (liftM (filterImportList . view resolvedExports) . resolveModule) ms setImport :: Import -> Declaration -> Declaration setImport i' = set declarationImported (Just [i']) selectImport :: Import -> [ModuleId -> Bool] -> ResolveM (Maybe Module) selectImport i' fs = do - db <- ask + modsMap <- asks snd + let + mods = fromMaybe [] $ M.lookup (view importModuleName i') modsMap return $ listToMaybe $ newestPackage $ fromMaybe [] $ listToMaybe $ dropWhile null - [selectModules (select' f) db | f <- fs] - where - select' f md = view moduleName md == view importModuleName i' && f (view moduleId md) + [filter (f . view moduleId) mods | f <- fs] filterImportList :: [Declaration] -> [Declaration] filterImportList = case view importList i of Nothing -> id - Just il -> filter (passImportList il . view declarationName) - deps f p = delete (view projectName p) $ concatMap (view infoDepends) $ fileTargets p f - inDepsOf' f p m' = any (`inPackage` m') (deps f p) + Just il -> filter (`imported` il) + inDeps = maybe False (`S.member` deps) . preview (moduleIdLocation . modulePackage . _Just . packageName) -- | Merge imported declarations mergeImported :: [Declaration] -> [Declaration]
src/HsDev/Symbols/Types.hs view
@@ -2,32 +2,22 @@ {-# OPTIONS_GHC -fno-warn-orphans #-} module HsDev.Symbols.Types ( - ExportPart(..), - Export(..), - ImportList(..), - Import(..), - ModuleId(..), - Module(..), moduleContents, moduleId, - Declaration(..), minimalDecl, - TypeInfo(..), showTypeInfo, - DeclarationInfo(..), declarationInfo, declarationTypeCtor, declarationTypeName, - ModuleDeclaration(..), - ExportedDeclaration(..), - Inspection(..), - Inspected(..), + ThingPart(..), + Export(..), exportQualified, exportName, exportPart, exportModule, + ImportSpec(..), importSpecName, importSpecPart, + ImportList(..), hidingList, importSpecs, + Import(..), importModuleName, importIsQualified, importAs, importList, importPosition, + ModuleId(..), moduleIdName, moduleIdLocation, + Module(..), moduleName, moduleDocs, moduleLocation, moduleExports, moduleImports, moduleDeclarations, moduleContents, moduleId, + Declaration(..), declarationName, declarationDefined, declarationImported, declarationDocs, declarationPosition, declaration, minimalDecl, + TypeInfo(..), typeInfoContext, typeInfoArgs, typeInfoDefinition, typeInfoFunctions, showTypeInfo, + DeclarationInfo(..), functionType, localDeclarations, related, typeInfo, declarationInfo, declarationTypeCtor, declarationTypeName, + ModuleDeclaration(..), declarationModuleId, moduleDeclaration, + ExportedDeclaration(..), exportedBy, exportedDeclaration, + Inspection(..), inspectionAt, inspectionOpts, + Inspected(..), inspection, inspectedId, inspectionResult, InspectedModule, - exportQualified, exportName, exportPart, exportModule, - hidingList, importSpec, importModuleName, importIsQualified, importAs, importList, importPosition, - moduleIdName, moduleIdLocation, - moduleName, moduleDocs, moduleLocation, moduleExports, moduleImports, moduleDeclarations, - declarationName, declarationDefined, declarationImported, declarationDocs, declarationPosition, declaration, - typeInfoContext, typeInfoArgs, typeInfoDefinition, typeInfoFunctions, - functionType, localDeclarations, related, typeInfo, - declarationModuleId, moduleDeclaration, - exportedBy, exportedDeclaration, - inspectionAt, inspectionOpts, inspection, inspectedId, inspectionResult, - module HsDev.PackageDb, module HsDev.Project, module HsDev.Symbols.Class, @@ -52,40 +42,40 @@ import HsDev.Symbols.Documented import HsDev.Util (tab, tabs, (.::), (.::?), (.::?!), noNulls) --- | What to export for data/class etc -data ExportPart = ExportNothing | ExportAll | ExportWith [Text] deriving (Eq, Ord) +-- | What to export/import for data/class etc +data ThingPart = ThingNothing | ThingAll | ThingWith [Text] deriving (Eq, Ord) -instance NFData ExportPart where - rnf ExportNothing = () - rnf ExportAll = () - rnf (ExportWith ns) = rnf ns +instance NFData ThingPart where + rnf ThingNothing = () + rnf ThingAll = () + rnf (ThingWith ns) = rnf ns -instance Show ExportPart where - show ExportNothing = "" - show ExportAll = "(..)" - show (ExportWith ns) = "(" ++ intercalate ", " (map unpack ns) ++ ")" +instance Show ThingPart where + show ThingNothing = "" + show ThingAll = "(..)" + show (ThingWith ns) = "(" ++ intercalate ", " (map unpack ns) ++ ")" -instance ToJSON ExportPart where - toJSON ExportNothing = toJSON ("nothing" :: String) - toJSON ExportAll = toJSON ("all" :: String) - toJSON (ExportWith ns) = object [ +instance ToJSON ThingPart where + toJSON ThingNothing = toJSON ("nothing" :: String) + toJSON ThingAll = toJSON ("all" :: String) + toJSON (ThingWith ns) = object [ "with" .= ns] -instance FromJSON ExportPart where +instance FromJSON ThingPart where parseJSON v = parse' <|> parseWith v where parse' = do s <- parseJSON v mplus - (guard (s == ("nothing" :: String)) >> return ExportNothing) - (guard (s == ("all" :: String)) >> return ExportAll) - parseWith = withObject "export part" $ \v' -> ExportWith <$> v' .:: "with" + (guard (s == ("nothing" :: String)) >> return ThingNothing) + (guard (s == ("all" :: String)) >> return ThingAll) + parseWith = withObject "export part" $ \v' -> ThingWith <$> v' .:: "with" -- | Module export data Export = ExportName { _exportQualified :: Maybe Text, _exportName :: Text, - _exportPart :: ExportPart } | + _exportPart :: ThingPart } | ExportModule { _exportModule :: Text } deriving (Eq, Ord) @@ -107,27 +97,45 @@ (ExportName <$> (v .:: "module") <*> (v .:: "name") <*> (v .:: "part")) <|> (ExportModule <$> (v .:: "module")) +-- | Import spec +data ImportSpec = ImportSpec { + _importSpecName :: Text, + _importSpecPart :: ThingPart } + deriving (Eq, Ord) + +instance NFData ImportSpec where + rnf (ImportSpec n p) = rnf n `seq` rnf p + +instance Show ImportSpec where + show (ImportSpec n p) = unpack n ++ show p + +instance ToJSON ImportSpec where + toJSON (ImportSpec n p) = object ["name" .= n, "part" .= p] + +instance FromJSON ImportSpec where + parseJSON = withObject "import-spec" $ \v -> ImportSpec <$> (v .:: "name") <*> (v .:: "part") + -- | Import list data ImportList = ImportList { _hidingList :: Bool, - _importSpec :: [Text] } + _importSpecs :: [ImportSpec] } deriving (Eq, Ord) instance NFData ImportList where rnf (ImportList h ls) = rnf h `seq` rnf ls instance Show ImportList where - show (ImportList h ls) = (if h then ("hiding " ++) else id) $ "(" ++ intercalate ", " (map unpack ls) ++ ")" + show (ImportList h ls) = (if h then ("hiding " ++) else id) $ "(" ++ intercalate ", " (map show ls) ++ ")" instance ToJSON ImportList where toJSON (ImportList h ls) = object [ "hiding" .= h, - "spec" .= ls] + "specs" .= ls] instance FromJSON ImportList where parseJSON = withObject "import-list" $ \v -> ImportList <$> v .:: "hiding" <*> - v .:: "spec" + v .:: "specs" -- | Module import data Import = Import { @@ -551,6 +559,7 @@ brief = brief . _moduleDeclaration makeLenses ''Export +makeLenses ''ImportSpec makeLenses ''ImportList makeLenses ''Import makeLenses ''ModuleId
src/HsDev/Symbols/Util.hs view
@@ -1,7 +1,7 @@ module HsDev.Symbols.Util ( projectOf, packageDbOf, packageOf, inProject, inDepsOfTarget, inDepsOfFile, inDepsOfProject, inPackageDb, inPackageDbStack, inPackage, inVersion, inFile, inModuleSource, inModule, byFile, installed, standalone, - imports, qualifier, imported, visible, inScope, + imports, qualifier, moduleImported, visible, inScope, newestPackage, sourceModule, visibleModule, preferredModule, uniqueModules, allOf, anyOf @@ -125,8 +125,8 @@ imports m -- | Check if module imported via imports specified -imported :: ModuleId -> [Import] -> Bool -imported m = any (\i -> view moduleIdName m == view importModuleName i) +moduleImported :: ModuleId -> [Import] -> Bool +moduleImported m = any (\i -> view moduleIdName m == view importModuleName i) -- | Check if module visible from this module within this project visible :: Project -> ModuleId -> ModuleId -> Bool @@ -138,7 +138,7 @@ -- | Check if module is in scope with qualifier inScope :: Module -> Maybe String -> ModuleId -> Bool -inScope this q m = m `imported` qualifier this q +inScope this q m = m `moduleImported` qualifier this q -- | Select symbols with last package version newestPackage :: Symbol a => [a] -> [a]
src/HsDev/Tools/Ghc/Check.hs view
@@ -15,24 +15,20 @@ import Control.Lens (preview, view, each, _Just, (^..)) import Control.Monad.Except -import Control.Concurrent.FiniteChan import Data.Maybe (fromMaybe) -import HsDev.Tools.Ghc.Worker import System.FilePath (makeRelative) import System.Directory (doesDirectoryExist) import GHC hiding (Warning, Module, moduleName) -import Outputable -import FastString (unpackFS) -import qualified ErrUtils as E -import System.Directory.Paths +import Control.Concurrent.FiniteChan import HsDev.PackageDb import HsDev.Scan.Browse (browsePackages) import HsDev.Symbols (moduleOpts) import HsDev.Symbols.Location import HsDev.Symbols.Types import HsDev.Tools.Base +import HsDev.Tools.Ghc.Worker import HsDev.Tools.Types import HsDev.Util (readFileUtf8, ordNub) @@ -41,7 +37,7 @@ checkFiles opts pdbs files _ = do ch <- liftIO newChan withFlags $ do - modifyFlags (\fs -> fs { log_action = logAction ch }) + modifyFlags (\fs -> fs { log_action = logToChan ch }) _ <- setCmdOpts ("-Wall" : (packageDbStackOpts pdbs ++ opts)) clearTargets mapM (`makeTarget` Nothing) files >>= loadTargets @@ -65,7 +61,7 @@ packageDbStackOpts pdbs, moduleOpts pkgs m, opts] - modifyFlags (\fs -> fs { log_action = logAction ch }) + modifyFlags (\fs -> fs { log_action = logToChan ch }) clearTargets target <- makeTarget (makeRelative dir file) msrc loadTargets [target] @@ -80,29 +76,6 @@ -- | Check module and collect warnings and errors checkSource :: [String] -> PackageDbStack -> Module -> String -> ExceptT String Ghc [Note OutputMessage] checkSource opts pdbs m src = check opts pdbs m (Just src) - --- | Log ghc warnings and errors as to chan --- You may have to apply recalcTabs on result notes -logAction :: Chan (Note OutputMessage) -> DynFlags -> E.Severity -> SrcSpan -> PprStyle -> SDoc -> IO () -logAction ch fs sev src _ msg - | Just sev' <- checkSev sev = do - src' <- canonicalize srcMod - putChan ch $ Note { - _noteSource = src', - _noteRegion = spanRegion src, - _noteLevel = Just sev', - _note = OutputMessage { - _message = showSDoc fs msg, - _messageSuggestion = Nothing } } - | otherwise = return () - where - checkSev SevWarning = Just Warning - checkSev SevError = Just Error - checkSev SevFatal = Just Error - checkSev _ = Nothing - srcMod = case src of - RealSrcSpan s' -> FileModule (unpackFS $ srcSpanFile s') Nothing - _ -> ModuleSource Nothing -- Recalc tabs for notes recalcNotesTabs :: [Note OutputMessage] -> IO [Note OutputMessage]
src/HsDev/Tools/Ghc/Worker.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE PatternGuards #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module HsDev.Tools.Ghc.Worker ( @@ -12,6 +13,7 @@ -- * Utils listPackages, spanRegion, withCurrentDirectory, + logToChan, logToNull, Ghc, @@ -25,16 +27,22 @@ import Data.Maybe import Data.Time.Clock (getCurrentTime) import Data.Version (showVersion) -import GHC -import GHC.Paths import Packages import StringBuffer import System.Directory (getCurrentDirectory, setCurrentDirectory) import Text.Read -import Control.Concurrent.Worker +import GHC hiding (Warning, Module, moduleName) +import GHC.Paths +import Outputable +import qualified ErrUtils as E +import FastString (unpackFS) -import HsDev.Symbols.Location (Position(..), Region(..), region, ModulePackage) +import Control.Concurrent.FiniteChan +import Control.Concurrent.Worker +import System.Directory.Paths +import HsDev.Symbols.Location (Position(..), Region(..), region, ModulePackage, ModuleLocation(..)) +import HsDev.Tools.Types -- | Ghc worker. Pass options and initializer action ghcWorker :: [String] -> Ghc () -> IO (Worker Ghc) @@ -87,7 +95,10 @@ -- | Set options after session reinit setCmdOpts :: [String] -> Ghc () -setCmdOpts opts = initGhcMonad (Just libdir) >> addCmdOpts opts +setCmdOpts opts = do + initGhcMonad (Just libdir) + addCmdOpts opts + modifyFlags (\fs -> fs { log_action = logToNull }) -- | Import some modules importModules :: [String] -> Ghc () @@ -134,6 +145,33 @@ withCurrentDirectory :: FilePath -> Ghc a -> Ghc a withCurrentDirectory dir act = gbracket (liftIO getCurrentDirectory) (liftIO . setCurrentDirectory) $ const (liftIO (setCurrentDirectory dir) >> act) + +-- | Log ghc warnings and errors as to chan +-- You may have to apply recalcTabs on result notes +logToChan :: Chan (Note OutputMessage) -> DynFlags -> E.Severity -> SrcSpan -> PprStyle -> SDoc -> IO () +logToChan ch fs sev src _ msg + | Just sev' <- checkSev sev = do + src' <- canonicalize srcMod + putChan ch $ Note { + _noteSource = src', + _noteRegion = spanRegion src, + _noteLevel = Just sev', + _note = OutputMessage { + _message = showSDoc fs msg, + _messageSuggestion = Nothing } } + | otherwise = return () + where + checkSev SevWarning = Just Warning + checkSev SevError = Just Error + checkSev SevFatal = Just Error + checkSev _ = Nothing + srcMod = case src of + RealSrcSpan s' -> FileModule (unpackFS $ srcSpanFile s') Nothing + _ -> ModuleSource Nothing + +-- | Don't log ghc warnings and errors +logToNull :: DynFlags -> E.Severity -> SrcSpan -> PprStyle -> SDoc -> IO () +logToNull _ _ _ _ _ = return () -- TODO: Load target by @ModuleLocation@, which may cause updating @DynFlags@
src/HsDev/Tools/GhcMod.hs view
@@ -84,7 +84,7 @@ _moduleName = fromString mname, _moduleDocs = Nothing, _moduleLocation = thisLoc, - _moduleExports = Just [ExportName Nothing (view declarationName d) ExportNothing | d <- ds], + _moduleExports = Just [ExportName Nothing (view declarationName d) ThingNothing | d <- ds], _moduleImports = [import_ iname | iname <- ordNub (mapMaybe (preview definedModule) ds), iname /= fromString mname],
tests/Test.hs view
@@ -10,10 +10,12 @@ import Data.Default import HsDev import Test.Hspec +import System.FilePath +import System.Directory call :: Server -> Command -> IO (Maybe Value) call srv c = do - r <- inServer srv c + r <- inServer srv def c case r of Result v -> return $ Just v Error e _ -> do @@ -27,12 +29,13 @@ main = hspec $ do describe "scan project" $ do it "should scan project" $ do - s <- startServer def - _ <- call s $ Scan ["tests\\test-package"] [] [] [] [] [] False False - one <- call s $ InfoResolve "tests\\test-package\\ModuleOne.hs" True + dir <- getCurrentDirectory + s <- startServer (def { serverSilent = True }) + _ <- call s $ Scan [dir </> "tests/test-package"] False [] [] [] [] [] False False + one <- call s $ InfoResolve (dir </> "tests/test-package/ModuleOne.hs") True when (["test", "forkIO", "f"] /= exports one) $ expectationFailure "invalid exports of ModuleOne.hs" - two <- call s $ InfoResolve "tests\\test-package\\ModuleTwo.hs" True + two <- call s $ InfoResolve (dir </> "tests/test-package/ModuleTwo.hs") True when (["f", "twice"] /= exports two) $ expectationFailure "invalid exports of ModuleTwo.hs" _ <- call s Exit
tools/hsinspect.hs view
@@ -41,10 +41,11 @@ ghc <- liftIO $ ghcWorker ghcs (return ()) let scanAdditional = - scanModify (\opts' _ -> inspectDocs opts') >=> - scanModify (\opts' pdbs m -> ExceptT (inWorker ghc (runExceptT $ inferTypes opts' pdbs m Nothing))) + scanModify' (\opts' _ -> inspectDocs opts') >=> + scanModify' (\opts' pdbs m -> ExceptT (inWorker ghc (runExceptT $ inferTypes opts' pdbs m Nothing))) toJSON <$> scanAdditional im inspect' (Opts (Just fcabal@(takeExtension -> ".cabal")) _) = do fcabal' <- liftIO $ canonicalizePath fcabal toJSON <$> readProject fcabal' inspect' (Opts (Just mname) ghcs) = toJSON <$> scanModule [] ghcs (InstalledModule UserDb Nothing mname) Nothing + scanModify' f im = scanModify f im <|> return im