ghc-mod/core/GhcMod/Types.hs

407 lines
12 KiB
Haskell
Raw Normal View History

{-# LANGUAGE CPP, DeriveDataTypeable, DeriveFunctor, DeriveGeneric, RankNTypes,
StandaloneDeriving, DefaultSignatures, FlexibleInstances, TemplateHaskell,
GeneralizedNewtypeDeriving #-}
2015-03-11 12:17:24 +00:00
{-# OPTIONS_GHC -fno-warn-orphans -fno-warn-deprecations #-}
module GhcMod.Types (
module GhcMod.Types
, ModuleName
, mkModuleName
, moduleNameString
) where
2010-04-30 09:36:31 +00:00
import Control.Monad.Trans.Control (MonadBaseControl)
import Control.Monad.Error (Error(..))
2015-04-02 23:15:12 +00:00
import qualified Control.Monad.IO.Class as MTL
import Control.Exception (Exception)
import Control.Applicative
import Control.Concurrent
import Control.Monad
import Control.DeepSeq
2015-11-26 14:23:32 +00:00
import Data.Binary
import Data.Binary.Generic
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Set (Set)
import qualified Data.Set as Set
import Data.Monoid
import Data.Maybe
import Data.Typeable (Typeable)
import Data.IORef
import Data.Label.Derive
import Distribution.Helper hiding (Programs(..))
import qualified Distribution.Helper as CabalHelper
import Exception (ExceptionMonad)
2015-04-02 23:15:12 +00:00
#if __GLASGOW_HASKELL__ < 708
import qualified MonadUtils as GHC (MonadIO(..))
#endif
import GHC (ModuleName, moduleNameString, mkModuleName)
import HscTypes (HscEnv)
import GHC.Generics
import Pretty (Doc)
2015-08-03 01:09:56 +00:00
import Prelude
import GhcMod.Caching.Types
-- | A constraint alias (-XConstraintKinds) to make functions dealing with
-- 'GhcModT' somewhat cleaner.
--
-- Basicially an @IOish m => m@ is a 'Monad' supporting arbitrary 'IO' and
-- exception handling. Usually this will simply be 'IO' but we parametrise it in
-- the exported API so users have the option to use a custom inner monad.
type IOish m = (Functor m, MonadIO m, MonadBaseControl IO m, ExceptionMonad m)
2014-08-12 16:08:28 +00:00
2015-04-02 23:15:12 +00:00
-- MonadUtils of GHC 7.6 or earlier defines its own MonadIO.
-- MonadUtils of GHC 7.8 or later imports MonadIO in Monad.Control.IO.Class.
#if __GLASGOW_HASKELL__ < 708
type MonadIOC m = (GHC.MonadIO m, MTL.MonadIO m)
#else
type MonadIOC m = (MTL.MonadIO m)
#endif
class MonadIOC m => MonadIO m where
2015-06-01 14:54:50 +00:00
liftIO :: IO a -> m a
2015-04-02 23:15:12 +00:00
2013-05-20 05:28:56 +00:00
-- | Output style.
2013-09-05 05:35:28 +00:00
data OutputStyle = LispStyle -- ^ S expression style.
| PlainStyle -- ^ Plain textstyle.
2014-10-22 22:53:41 +00:00
deriving (Show)
2012-02-14 01:21:48 +00:00
2013-09-05 05:35:28 +00:00
-- | The type for line separator. Historically, a Null string is used.
2014-10-22 22:53:41 +00:00
newtype LineSeparator = LineSeparator String deriving (Show)
2013-09-03 05:40:51 +00:00
data FileMapping = FileMapping {fmPath :: FilePath, fmTemp :: Bool}
2016-01-28 21:57:35 +00:00
deriving (Eq, Show)
type FileMappingMap = Map FilePath FileMapping
data ProgramSource = ProgramSourceUser | ProgramSourceStack
data Programs = Programs {
-- | @ghc@ program name.
ghcProgram :: FilePath
-- | @ghc-pkg@ program name.
, ghcPkgProgram :: FilePath
-- | @cabal@ program name.
, cabalProgram :: FilePath
-- | @stack@ program name.
, stackProgram :: FilePath
} deriving (Show)
data OutputOpts = OutputOpts {
-- | Verbosity
ooptLogLevel :: GmLogLevel
, ooptStyle :: OutputStyle
-- | Line separator string.
, ooptLineSeparator :: LineSeparator
-- | Stdout/err line multiplexing using prefix encoding. @fst@ is stdout,
-- @snd@ is stderr prefix.
, ooptLinePrefix :: Maybe (String, String)
} deriving (Show)
data Options = Options {
optOutput :: OutputOpts
, optPrograms :: Programs
2014-08-13 16:40:01 +00:00
-- | GHC command line options set on the @ghc-mod@ command line
, optGhcUserOptions :: [GHCOption]
, optFileMappings :: [(FilePath, Maybe FilePath)]
, optEncoding :: String
, optStackBuildDeps :: Bool
2014-10-22 22:53:41 +00:00
} deriving (Show)
2012-02-27 02:23:56 +00:00
2013-05-20 05:28:56 +00:00
-- | A default 'Options'.
2012-02-27 02:23:56 +00:00
defaultOptions :: Options
defaultOptions = Options {
optOutput = OutputOpts {
ooptLogLevel = GmWarning
, ooptStyle = PlainStyle
, ooptLineSeparator = LineSeparator "\0"
, ooptLinePrefix = Nothing
}
, optPrograms = Programs {
ghcProgram = "ghc"
, ghcPkgProgram = "ghc-pkg"
, cabalProgram = "cabal"
, stackProgram = "stack"
}
, optGhcUserOptions = []
, optFileMappings = []
, optEncoding = "UTF-8"
, optStackBuildDeps = False
2010-04-30 09:36:31 +00:00
}
2012-02-14 02:33:27 +00:00
----------------------------------------------------------------
2012-02-14 07:09:53 +00:00
data Project = CabalProject
| SandboxProject
| PlainProject
| StackProject StackEnv
2016-02-16 20:44:10 +00:00
deriving (Eq, Show, Ord)
isCabalHelperProject :: Project -> Bool
isCabalHelperProject StackProject {} = True
isCabalHelperProject CabalProject {} = True
isCabalHelperProject _ = False
data StackEnv = StackEnv {
seDistDir :: FilePath
, seBinPath :: [FilePath]
, seSnapshotPkgDb :: FilePath
, seLocalPkgDb :: FilePath
2016-02-16 20:44:10 +00:00
} deriving (Eq, Show, Ord)
2015-08-12 07:25:13 +00:00
2013-09-05 05:35:28 +00:00
-- | The environment where this library is used.
data Cradle = Cradle {
cradleProject :: Project
2013-09-05 05:35:28 +00:00
-- | The directory where this library is executed.
2015-08-12 07:25:13 +00:00
, cradleCurrentDir :: FilePath
-- | The project root directory.
, cradleRootDir :: FilePath
-- | Per-Project temporary directory
, cradleTempDir :: FilePath
2013-09-05 05:35:28 +00:00
-- | The file name of the found cabal file.
, cradleCabalFile :: Maybe FilePath
2015-08-18 09:41:14 +00:00
-- | The build info directory.
, cradleDistDir :: FilePath
2016-02-16 20:44:10 +00:00
} deriving (Eq, Show, Ord)
data GmStream = GmOutStream | GmErrStream
2015-08-13 07:01:58 +00:00
deriving (Show)
data GhcModEnv = GhcModEnv {
gmOptions :: Options
, gmCradle :: Cradle
}
data GhcModOut = GhcModOut {
gmoOptions :: OutputOpts
2015-09-16 03:08:16 +00:00
, gmoChan :: Chan (Either (MVar ()) (GmStream, String))
}
data GhcModLog = GhcModLog {
gmLogLevel :: Maybe GmLogLevel,
gmLogVomitDump :: Last Bool,
gmLogMessages :: [(GmLogLevel, String, Doc)]
} deriving (Show)
instance Monoid GhcModLog where
mempty = GhcModLog (Just GmPanic) (Last Nothing) mempty
GhcModLog ml vd ls `mappend` GhcModLog ml' vd' ls' =
GhcModLog (ml' `mplus` ml) (vd `mappend` vd') (ls `mappend` ls')
data GmGhcSession = GmGhcSession {
gmgsSession :: !(IORef HscEnv)
}
data GhcModCaches = GhcModCaches {
gmcPackageDbStack :: CacheContents ChCacheData [GhcPkgDb]
, gmcMergedPkgOptions :: CacheContents ChCacheData [GHCOption]
, gmcComponents :: CacheContents ChCacheData [GmComponent 'GMCRaw ChEntrypoint]
, gmcResolvedComponents :: CacheContents
[GmComponent 'GMCRaw (Set.Set ModulePath)]
(Map.Map ChComponentName (GmComponent 'GMCResolved (Set.Set ModulePath)))
}
data GhcModState = GhcModState {
gmGhcSession :: !(Maybe GmGhcSession)
, gmCaches :: !GhcModCaches
, gmMMappedFiles :: !FileMappingMap
}
defaultGhcModState :: GhcModState
defaultGhcModState =
2015-12-15 23:23:51 +00:00
GhcModState n (GhcModCaches n n n n) Map.empty
where n = Nothing
----------------------------------------------------------------
-- | GHC package database flags.
data GhcPkgDb = GlobalDb
| UserDb
| PackageDb String
deriving (Eq, Show, Generic)
instance Binary GhcPkgDb where
2015-11-26 14:23:32 +00:00
put = ggput . from
get = to `fmap` ggget
-- | A single GHC command line option.
2015-06-01 14:54:50 +00:00
type GHCOption = String
-- | An include directory for modules.
type IncludeDir = FilePath
-- | Haskell expression.
newtype Expression = Expression { getExpression :: String }
deriving (Show, Eq, Ord)
-- | Module name.
newtype ModuleString = ModuleString { getModuleString :: String }
deriving (Show, Eq, Ord, Binary, NFData)
2015-06-01 14:54:50 +00:00
data GmLogLevel =
GmSilent
| GmPanic
| GmException
| GmError
| GmWarning
| GmInfo
| GmDebug
| GmVomit
2015-06-01 14:54:50 +00:00
deriving (Eq, Ord, Enum, Bounded, Show, Read)
data GmModuleGraph = GmModuleGraph {
2015-06-01 14:54:50 +00:00
gmgGraph :: Map ModulePath (Set ModulePath)
} deriving (Eq, Ord, Show, Read, Generic, Typeable)
instance Binary GmModuleGraph where
2015-06-01 14:54:50 +00:00
put GmModuleGraph {..} = put (mpim, graph)
where
mpim :: Map ModulePath Integer
mpim = Map.fromList $ Map.keys gmgGraph `zip` [0..]
graph :: Map Integer (Set Integer)
graph = Map.map (Set.map mpToInt) $ Map.mapKeys mpToInt gmgGraph
mpToInt :: ModulePath -> Integer
mpToInt mp = fromJust $ Map.lookup mp mpim
get = do
(mpim :: Map ModulePath Integer, graph :: Map Integer (Set Integer)) <- get
let impm = swapMap mpim
intToMp i = fromJust $ Map.lookup i impm
mpGraph :: Map ModulePath (Set ModulePath)
mpGraph = Map.map (Set.map intToMp) $ Map.mapKeys intToMp graph
return $ GmModuleGraph mpGraph
where
swapMap :: Ord v => Map k v -> Map v k
2015-06-01 14:54:50 +00:00
swapMap = Map.fromList . map (\(x, y) -> (y, x)) . Map.toList
instance Monoid GmModuleGraph where
2015-06-01 14:54:50 +00:00
mempty = GmModuleGraph mempty
mappend (GmModuleGraph a) (GmModuleGraph a') =
GmModuleGraph (Map.unionWith Set.union a a')
data GmComponentType = GMCRaw
| GMCResolved
data GmComponent (t :: GmComponentType) eps = GmComponent {
2015-06-01 14:54:50 +00:00
gmcHomeModuleGraph :: GmModuleGraph
, gmcName :: ChComponentName
, gmcGhcOpts :: [GHCOption]
, gmcGhcPkgOpts :: [GHCOption]
, gmcGhcSrcOpts :: [GHCOption]
, gmcGhcLangOpts :: [GHCOption]
, gmcRawEntrypoints :: ChEntrypoint
, gmcEntrypoints :: eps
, gmcSourceDirs :: [FilePath]
} deriving (Eq, Ord, Show, Read, Generic, Functor)
instance Binary eps => Binary (GmComponent t eps) where
2015-11-26 14:23:32 +00:00
put = ggput . from
get = to `fmap` ggget
data ModulePath = ModulePath { mpModule :: ModuleName, mpPath :: FilePath }
2015-06-01 14:54:50 +00:00
deriving (Eq, Ord, Show, Read, Generic, Typeable)
instance Binary ModulePath where
2015-11-26 14:23:32 +00:00
put = ggput . from
get = to `fmap` ggget
instance Binary ModuleName where
2015-06-01 14:54:50 +00:00
get = mkModuleName <$> get
put mn = put (moduleNameString mn)
instance Show ModuleName where
2015-06-01 14:54:50 +00:00
show mn = "ModuleName " ++ show (moduleNameString mn)
instance Read ModuleName where
2015-06-01 14:54:50 +00:00
readsPrec d =
readParen
(d > app_prec)
(\r' -> [ (mkModuleName m, t)
| ("ModuleName", s) <- lex r'
, (m, t) <- readsPrec (app_prec + 1) s
])
where
app_prec = 10
data GhcModError
2015-06-01 14:54:50 +00:00
= GMENoMsg
-- ^ Unknown error
2015-06-01 14:54:50 +00:00
| GMEString String
-- ^ Some Error with a message. These are produced mostly by
-- 'fail' calls on GhcModT.
2015-06-01 14:54:50 +00:00
| GMECabalConfigure GhcModError
-- ^ Configuring a cabal project failed.
2015-09-15 03:25:29 +00:00
| GMEStackConfigure GhcModError
-- ^ Configuring a stack project failed.
2015-09-15 03:25:29 +00:00
| GMEStackBootstrap GhcModError
-- ^ Bootstrapping @stack@ environment failed (process exited with failure)
2015-06-01 14:54:50 +00:00
| GMECabalCompAssignment [(Either FilePath ModuleName, Set ChComponentName)]
-- ^ Could not find a consistent component assignment for modules
2015-08-31 06:55:49 +00:00
| GMEProcess String String [String] (Either Int GhcModError)
2015-06-01 14:54:50 +00:00
-- ^ Launching an operating system process failed. Fields in
2015-08-31 06:55:49 +00:00
-- order: function, command, arguments, (stdout, stderr, exitcode)
2015-06-01 14:54:50 +00:00
| GMENoCabalFile
-- ^ No cabal file found.
2015-06-01 14:54:50 +00:00
| GMETooManyCabalFiles [FilePath]
-- ^ Too many cabal files found.
2015-06-01 14:54:50 +00:00
deriving (Eq,Show,Typeable)
instance Error GhcModError where
2015-06-01 14:54:50 +00:00
noMsg = GMENoMsg
strMsg = GMEString
instance Exception GhcModError
instance Binary CabalHelper.Programs where
2015-11-26 14:23:32 +00:00
put = ggput . from
get = to `fmap` ggget
instance Binary ChModuleName where
2015-11-26 14:23:32 +00:00
put = ggput . from
get = to `fmap` ggget
instance Binary ChComponentName where
2015-11-26 14:23:32 +00:00
put = ggput . from
get = to `fmap` ggget
instance Binary ChEntrypoint where
2015-11-26 14:23:32 +00:00
put = ggput . from
get = to `fmap` ggget
2015-12-07 16:57:33 +00:00
-- | Options for "lintWith" function
data LintOpts = LintOpts {
optLintHlintOpts :: [String]
-- ^ options that will be passed to hlint executable
2015-12-20 12:02:31 +00:00
} deriving (Show)
2015-12-07 16:57:33 +00:00
-- | Default "LintOpts" instance
defaultLintOpts :: LintOpts
defaultLintOpts = LintOpts []
2015-12-07 16:57:33 +00:00
-- | Options for "browseWith" function
data BrowseOpts = BrowseOpts {
optBrowseOperators :: Bool
2015-12-07 16:57:33 +00:00
-- ^ If 'True', "browseWith" also returns operators.
, optBrowseDetailed :: Bool
2015-12-07 16:57:33 +00:00
-- ^ If 'True', "browseWith" also returns types.
, optBrowseParents :: Bool
-- ^ If 'True', "browseWith" also returns parents.
, optBrowseQualified :: Bool
2015-12-07 16:57:33 +00:00
-- ^ If 'True', "browseWith" will return fully qualified name
2015-12-20 12:02:31 +00:00
} deriving (Show)
2015-12-07 16:57:33 +00:00
-- | Default "BrowseOpts" instance
defaultBrowseOpts :: BrowseOpts
defaultBrowseOpts = BrowseOpts False False False False
mkLabel ''GhcModCaches
mkLabel ''GhcModState
mkLabel ''Options
mkLabel ''OutputOpts
mkLabel ''Programs