module Language.Haskell.Refact.Utils.Monad
(
ParseResult
, VerboseLevel(..)
, RefactSettings(..)
, RefactState(..)
, RefactModule(..)
, RefacSource(..)
, TargetModule
, Targets
, CabalGraph
, RefactStashId(..)
, RefactFlags(..)
, StateStorage(..)
, RefactGhc(..)
, runRefactGhc
, getRefacSettings
, defaultSettings
, logSettings
, cabalModuleGraphs
, canonicalizeGraph
, canonicalizeModSummary
, logm
) where
import qualified DynFlags as GHC
import qualified GHC as GHC
import qualified HscTypes as GHC
import qualified Outputable as GHC
import Control.Applicative
import Control.Monad.State
import Distribution.Helper
import Exception
import qualified Language.Haskell.GhcMod as GM
import qualified Language.Haskell.GhcMod.Internal as GM
import qualified Language.Haskell.GhcMod.Monad.Types as GM
import Language.Haskell.Refact.Utils.Types
import Language.Haskell.GHC.ExactPrint
import Language.Haskell.GHC.ExactPrint.Utils
import System.Directory
import System.Log.Logger
import qualified Data.Map as Map
import qualified Data.Set as Set
import Control.Monad.Trans.Control ( control, liftBaseOp, liftBaseOp_)
data VerboseLevel = Debug | Normal | Off
deriving (Eq,Show)
data RefactSettings = RefSet
{
rsetVerboseLevel :: !VerboseLevel
, rsetEnabledTargets :: (Bool,Bool,Bool,Bool)
} deriving (Show)
defaultSettings :: RefactSettings
defaultSettings = RefSet
{
rsetVerboseLevel = Normal
, rsetEnabledTargets = (True,True,True,True)
}
logSettings :: RefactSettings
logSettings = defaultSettings { rsetVerboseLevel = Debug }
data RefactStashId = Stash !String deriving (Show,Eq,Ord)
data RefactModule = RefMod
{ rsTypecheckedMod :: !GHC.TypecheckedModule
, rsNameMap :: NameMap
, rsTokenCache :: !(TokenCache Anns)
, rsStreamModified :: !RefacResult
} deriving (Show)
instance Show GHC.Name where
show n = showGhc n
deriving instance Show (GHC.Located GHC.Token)
instance Show GHC.TypecheckedModule where
show t = showGhc (GHC.pm_parsed_source $ GHC.tm_parsed_module t)
data RefactFlags = RefFlags
{ rsDone :: !Bool
} deriving (Show)
data RefactState = RefSt
{ rsSettings :: !RefactSettings
, rsUniqState :: !Int
, rsSrcSpanCol :: !Int
, rsFlags :: !RefactFlags
, rsStorage :: !StateStorage
, rsCurrentTarget :: !(Maybe TargetModule)
, rsModule :: !(Maybe RefactModule)
} deriving (Show)
data RefacSource = RSFile FilePath
| RSTarget TargetModule
| RSMod GHC.ModSummary
| RSAlreadyLoaded
type TargetModule = GM.ModulePath
instance GHC.Outputable TargetModule where
ppr t = GHC.text (show t)
type CabalGraph = Map.Map ChComponentName (GM.GmComponent 'GM.GMCResolved (Set.Set GM.ModulePath))
type Targets = [Either FilePath GHC.ModuleName]
type ParseResult = GHC.TypecheckedModule
data StateStorage = StorageNone
| StorageBind (GHC.LHsBind GHC.Name)
| StorageSig (GHC.LSig GHC.Name)
| StorageBindRdr (GHC.LHsBind GHC.RdrName)
| StorageDeclRdr (GHC.LHsDecl GHC.RdrName)
| StorageSigRdr (GHC.LSig GHC.RdrName)
instance Show StateStorage where
show StorageNone = "StorageNone"
show (StorageBind _bind) = "(StorageBind " ++ ")"
show (StorageSig _sig) = "(StorageSig " ++ ")"
show (StorageDeclRdr _bind) = "(StorageDeclRdr " ++ ")"
show (StorageBindRdr _bind) = "(StorageBindRdr " ++ ")"
show (StorageSigRdr _sig) = "(StorageSigRdr " ++ ")"
newtype RefactGhc a = RefactGhc
{ unRefactGhc :: GM.GhcModT (StateT RefactState IO) a
} deriving ( Functor
, Applicative
, Alternative
, Monad
, MonadPlus
, MonadIO
, GM.GmEnv
, GM.GmOut
, GM.MonadIO
, ExceptionMonad
)
runRefactGhc ::
RefactGhc a -> RefactState -> GM.Options -> IO (a, RefactState)
runRefactGhc comp initState opt = do
((merr,_log),s) <- runStateT (GM.runGhcModT opt (unRefactGhc comp)) initState
case merr of
Left err -> error (show err)
Right a -> return (a,s)
instance GM.GmOut (StateT RefactState IO) where
instance GM.MonadIO (StateT RefactState IO) where
liftIO = liftIO
instance MonadState RefactState RefactGhc where
get = RefactGhc (lift $ lift get)
put s = RefactGhc (lift $ lift (put s))
instance GHC.GhcMonad RefactGhc where
getSession = RefactGhc $ GM.unGmlT GM.gmlGetSession
setSession env = RefactGhc $ GM.unGmlT (GM.gmlSetSession env)
instance GHC.HasDynFlags RefactGhc where
getDynFlags = GHC.hsc_dflags <$> GHC.getSession
instance ExceptionMonad (StateT RefactState IO) where
gcatch act handler = control $ \run ->
run act `gcatch` (run . handler)
gmask = liftBaseOp gmask . liftRestore
where liftRestore f r = f $ liftBaseOp_ r
cabalModuleGraphs :: RefactGhc [GM.GmModuleGraph]
cabalModuleGraphs = RefactGhc doCabalModuleGraphs
where
doCabalModuleGraphs :: (GM.IOish m) => GM.GhcModT m [GM.GmModuleGraph]
doCabalModuleGraphs = do
mcs <- GM.cabalResolvedComponents
let graph = map GM.gmcHomeModuleGraph $ Map.elems mcs
return $ graph
canonicalizeGraph ::
[GHC.ModSummary] -> RefactGhc [(Maybe FilePath, GHC.ModSummary)]
canonicalizeGraph graph = do
mm' <- mapM canonicalizeModSummary graph
return mm'
canonicalizeModSummary :: (MonadIO m) =>
GHC.ModSummary -> m (Maybe FilePath, GHC.ModSummary)
canonicalizeModSummary modSum = do
let modSum' = (\m -> (GHC.ml_hs_file $ GHC.ms_location m, m)) modSum
canon ((Just fp),m) = do
fp' <- canonicalizePath fp
return $ (Just fp',m)
canon (Nothing,m) = return (Nothing,m)
mm' <- liftIO $ canon modSum'
return mm'
getRefacSettings :: RefactGhc RefactSettings
getRefacSettings = do
s <- get
return (rsSettings s)
logm :: String -> RefactGhc ()
logm string = do
settings <- getRefacSettings
let loggingOn = (rsetVerboseLevel settings == Debug)
when loggingOn $ do
liftIO $ warningM "HaRe" (string)
return ()
instance Show GHC.ModSummary where
show m = show $ GHC.ms_mod m
instance Show GHC.Module where
show m = GHC.moduleNameString $ GHC.moduleName m