packages feed

ribosome-0.9.9.9: lib/Ribosome/Plugin/Builtin.hs

-- |Interceptor that adds internal RPC handlers to the host.
module Ribosome.Plugin.Builtin where

import Exon (exon)
import Prelude hiding (group)

import Ribosome.Data.PluginName (PluginName (PluginName))
import Ribosome.Data.ScratchId (ScratchId)
import qualified Ribosome.Effect.Scratch as Scratch
import Ribosome.Effect.Scratch (Scratch)
import qualified Ribosome.Effect.VariableWatcher as VariableWatcher
import Ribosome.Effect.VariableWatcher (VariableWatcher)
import Ribosome.Host.Data.BootError (BootError)
import Ribosome.Host.Data.Execution (Execution (Async))
import Ribosome.Host.Data.Report (Report, resumeReport)
import Ribosome.Host.Data.RpcError (RpcError)
import Ribosome.Host.Data.RpcHandler (Handler, RpcHandler)
import Ribosome.Host.Data.RpcName (RpcName (RpcName))
import Ribosome.Host.Data.RpcType (AutocmdGroup (AutocmdGroup), AutocmdOptions (target), AutocmdPatterns, group)
import Ribosome.Host.Effect.Handlers (Handlers)
import Ribosome.Host.Effect.Rpc (Rpc)
import Ribosome.Host.Handler (rpcAutocmd, rpcFunction)
import Ribosome.Host.Interpreter.Handlers (withHandlers)
import Ribosome.Text (capitalize)

-- |The set of autocmds that should trigger an update in 'VariableWatcher'.
watcherEvents :: [(Text, AutocmdPatterns)]
watcherEvents =
  [
    ("CmdlineLeave", def),
    ("BufWinEnter", def),
    ("VimEnter", def),
    ("User", "RibosomeUpdateVariables")
  ]

-- |Run 'VariableWatcher.update' and restop errors.
updateVar ::
  Member (VariableWatcher !! Report) r =>
  Handler r ()
updateVar =
  restop VariableWatcher.update

-- |Declare an autocmd that triggers the variable watcher.
watcherRpc ::
  ∀ r .
  Member (VariableWatcher !! Report) r =>
  PluginName ->
  Text ->
  AutocmdPatterns ->
  RpcHandler r
watcherRpc (PluginName name) event pat =
  rpcAutocmd (RpcName method) Async (fromText event) def { target = Right pat, group = Just (AutocmdGroup name) } do
    updateVar
  where
    method =
      [exon|#{capitalize name}VariableChanged#{event}|]

-- |Delete a scratch buffer.
deleteScratch ::
  Member (Scratch !! RpcError) r =>
  ScratchId ->
  Handler r ()
deleteScratch =
  resumeReport . Scratch.delete

-- |The name for the handler that is triggered by a scratch buffer being deleted.
deleteName :: PluginName -> RpcName
deleteName (PluginName name) =
  RpcName [exon|#{capitalize name}DeleteScratch|]

-- |A set of 'RpcHandler's for internal tasks.
builtinHandlers ::
  ∀ r .
  Members [Scratch !! RpcError, VariableWatcher !! Report] r =>
  PluginName ->
  [RpcHandler r]
builtinHandlers name =
  rpcFunction (deleteName name) Async deleteScratch : (uncurry (watcherRpc name) <$> watcherEvents)

-- |The dependencies of the builtin handlers.
type BuiltinHandlersDeps =
  [
    VariableWatcher !! Report,
    Handlers !! Report,
    Scratch !! RpcError,
    Rpc !! RpcError,
    Reader PluginName,
    Error BootError,
    Log
  ]

-- |Add builtin handlers to 'Handlers' without removing the effect from the stack.
interceptHandlersBuiltin ::
  Members BuiltinHandlersDeps r =>
  Sem r a ->
  Sem r a
interceptHandlersBuiltin sem = do
  name <- ask
  withHandlers (builtinHandlers name) sem