{-# LANGUAGE TemplateHaskell, ScopedTypeVariables, TupleSections #-}
-- | Invoke the executable that calls cabal functions and communicate
-- with it via RPC.
module IdeSession.ExeCabalClient (
    invokeExeCabal
  ) where

import System.Exit (ExitCode)

import Distribution.Verbosity (normal)
import Distribution.Simple.Program.Find (
    ProgramSearchPath
  , findProgramOnSearchPath
  , ProgramSearchPathEntry(..)
  )

import IdeSession.Cabal
import IdeSession.Config
import IdeSession.GHC.API
import IdeSession.RPC.Client (RpcServer, RpcConversation(..), forkRpcServer, rpcConversation, shutdown)
import IdeSession.State
import IdeSession.Types.Progress
import IdeSession.Util

-- | Invoke the executable that processes our custom functions that use
-- the machinery of the cabal library.
invokeExeCabal :: IdeStaticInfo -> ExeCabalRequest -> (Progress -> IO ())
               -> IO ExitCode
invokeExeCabal IdeStaticInfo{..} args callback = do
  mLoc <- findProgramOnSearchPath normal searchPath "ide-backend-exe-cabal"
  case mLoc of
    Nothing ->
      fail $ "Could not find ide-backend-exe-cabal"
    Just prog -> do
      env <- envWithPathOverride configExtraPathDirs
      let cwd = case args of
            ReqExeDoc{} -> ideSessionDir
            _ -> ideSessionDataDir ideSessionDir
      server <- forkRpcServer prog [] (Just cwd) env
      exitCode <- rpcRunExeCabal server args callback
      shutdown server  -- not long-running
      return exitCode
  where
    searchPath :: ProgramSearchPath
    searchPath = ProgramSearchPathDefault
               : map ProgramSearchPathDir configExtraPathDirs

    SessionConfig{..} = ideConfig

rpcRunExeCabal :: RpcServer -> ExeCabalRequest -> (Progress -> IO ())
               -> IO ExitCode
rpcRunExeCabal server req callback =
  rpcConversation server $ \RpcConversation{..} -> do
    put req

    let go = do response <- get
                case response of
                  ExeCabalProgress pcounter -> callback pcounter >> go
                  ExeCabalDone exitCode     -> return exitCode

    go