packages feed

tricorder-0.1.0.0: src/Tricorder/Effects/GhcPkg.hs

module Tricorder.Effects.GhcPkg
    ( GhcPkg
    , findModule
    , getHaddockHtml
    , runGhcPkgIO
    , runGhcPkgScripted
    , GhcPkgScript (..)
    ) where

import Atelier.Effects.Process (Process, readProcessSafe)
import Effectful (Effect)
import Effectful.Dispatch.Dynamic (interpret, reinterpret)
import Effectful.State.Static.Shared (evalState, get, put)
import Effectful.TH (makeEffect)

import Data.Text qualified as T

import Tricorder.GhcPkg.Types (ModuleName (..), PackageId (..))


data GhcPkg :: Effect where
    FindModule :: ModuleName -> GhcPkg m (Maybe PackageId)
    GetHaddockHtml :: PackageId -> GhcPkg m (Maybe FilePath)


makeEffect ''GhcPkg


runGhcPkgIO :: (Process :> es) => Eff (GhcPkg : es) a -> Eff es a
runGhcPkgIO = interpret \_ -> \case
    FindModule modName -> do
        out <- readProcessSafe "ghc-pkg" ["find-module", "--simple-output", toString (unModuleName modName)]
        pure $ out >>= fmap PackageId . listToMaybe . filter (not . T.null) . map T.strip . T.lines
    GetHaddockHtml pkgId -> do
        out <- readProcessSafe "ghc-pkg" ["field", toString (unPackageId pkgId), "haddock-html", "--simple-output"]
        pure $ out >>= listToMaybe . map toString . T.words


-- | Script element for the test interpreter.
data GhcPkgScript
    = -- | Return this value for the next 'findModule' call.
      NextFindModule (Maybe PackageId)
    | -- | Return this value for the next 'getHaddockHtml' call.
      NextGetHaddockHtml (Maybe FilePath)


-- | Scripted interpreter for testing. Does not require 'IOE'.
runGhcPkgScripted :: [GhcPkgScript] -> Eff (GhcPkg : es) a -> Eff es a
runGhcPkgScripted script = reinterpret (evalState script) \_ -> \case
    FindModule _ ->
        get >>= \case
            NextFindModule result : rest -> put rest >> pure result
            _ -> error "GhcPkgScripted: expected NextFindModule but queue was empty or mismatched"
    GetHaddockHtml _ ->
        get >>= \case
            NextGetHaddockHtml result : rest -> put rest >> pure result
            _ -> error "GhcPkgScripted: expected NextGetHaddockHtml but queue was empty or mismatched"