content: module GhcMod.Exe.Info (
      info
    , types
    ) where
  
  import Data.Function (on)
  import Data.List (sortBy)
  import System.FilePath
  import Exception (ghandle, SomeException(..))
  import GHC (GhcMonad, SrcSpan)
  import Prelude
  import qualified GHC as G
  
  import qualified GhcMod.Gap as Gap
  import GhcMod.Convert
  import GhcMod.Doc
  import GhcMod.DynFlags
  import GhcMod.Gap
  import GhcMod.Logging
  import GhcMod.Monad
  import GhcMod.SrcUtils
  import GhcMod.Types
  import GhcMod.Utils (mkRevRedirMapFunc)
  import GhcMod.FileMapping (fileModSummaryWithMapping)
  
  ----------------------------------------------------------------
  
  -- | Obtaining information of a target expression. (GHCi's info:)
  info :: IOish m
       => FilePath     -- ^ A target file.
       -> Expression   -- ^ A Haskell expression.
       -> GhcModT m String
  info file expr =
    ghandle handler $
      runGmlT' [Left file] deferErrors $
        withInteractiveContext $ do
          convert' =<< body
    where
      handler (SomeException ex) = do
        gmLog GmException "info" $ text "" $$ nest 4 (showToDoc ex)
        convert' "Cannot show info"
  
      body :: (GhcMonad m, GmState m, GmEnv m) => m String
      body = do
        m <- mkRevRedirMapFunc
        sdoc  <- Gap.infoThing m expr
        st    <- getStyle
        dflag <- G.getSessionDynFlags
        return $ showPage dflag st sdoc
  
  ----------------------------------------------------------------
  
  -- | Obtaining type of a target expression. (GHCi's type:)
  types :: IOish m
        => Bool         -- ^ Include constraints into type signature
        -> FilePath     -- ^ A target file.
        -> Int          -- ^ Line number.
        -> Int          -- ^ Column number.
        -> GhcModT m String
  types withConstraints file lineNo colNo =
    ghandle handler $
      runGmlT' [Left file] deferErrors $
        withInteractiveContext $ do
          crdl         <- cradle
          modSum       <- fileModSummaryWithMapping (cradleCurrentDir crdl </> file)
          srcSpanTypes <- getSrcSpanType withConstraints modSum lineNo colNo
          dflag        <- G.getSessionDynFlags
          st           <- getStyle
          convert' $ map (toTup dflag st) $ sortBy (cmp `on` fst) srcSpanTypes
   where
     handler (SomeException ex) = do
       gmLog GmException "types" $ showToDoc ex
       return []
  
  getSrcSpanType :: (GhcMonad m) => Bool -> G.ModSummary -> Int -> Int -> m [(SrcSpan, G.Type)]
  getSrcSpanType withConstraints modSum lineNo colNo =
    G.parseModule modSum
    >>= G.typecheckModule
    >>= flip (collectSpansTypes withConstraints) (lineNo, colNo)
  