packages feed

ribosome-0.4.0.0: lib/Ribosome/Plugin/Watch.hs

module Ribosome.Plugin.Watch where

import Control.Lens (Lens')
import qualified Control.Lens as Lens (at)
import qualified Data.Map.Strict as Map (toList)
import Data.MessagePack (Object(ObjectNil))

import Ribosome.Control.Lock (lockOrSkip)
import Ribosome.Control.Monad.Ribo (MonadRibo, NvimE, pluginInternalL, pluginInternalModifyL)
import Ribosome.Control.Ribosome (RibosomeInternal)
import qualified Ribosome.Control.Ribosome as RibosomeInternal (watchedVariables)
import Ribosome.Nvim.Api.IO (vimGetVar)
import Ribosome.Nvim.Api.RpcCall (RpcError)

data WatchedVariable m =
  WatchedVariable {
    wvName :: Text,
    wvHandler :: Object -> m ()
  }

watchedVariables :: Map Text (Object -> m ()) -> [WatchedVariable m]
watchedVariables =
  fmap create . Map.toList
  where
    create (name, handler) = WatchedVariable name handler

storedVarLens :: Text -> Lens' RibosomeInternal (Maybe Object)
storedVarLens name =
  RibosomeInternal.watchedVariables . Lens.at name

runHandler ::
  MonadRibo m =>
  WatchedVariable m ->
  Object ->
  m ()
runHandler (WatchedVariable name handler) new = do
  pluginInternalModifyL (storedVarLens name) (const (Just new))
  handler new

compareVar ::
  MonadRibo m =>
  WatchedVariable m ->
  Maybe Object ->
  Object ->
  m ()
compareVar _ (Just old) new | old == new =
  return ()
compareVar wv _ new =
  runHandler wv new

checkVar ::
  MonadRibo m =>
  NvimE e m =>
  WatchedVariable m ->
  m ()
checkVar wv@(WatchedVariable name _) = do
  old <- pluginInternalL (storedVarLens name)
  new <- catchAt @RpcError recover (Right <$> vimGetVar name)
  traverse_ (compareVar wv old) new
  where
  recover _ = return (Left ())

handleWatcherRequest ::
  MonadRibo m =>
  NvimE e m =>
  [WatchedVariable m] ->
  [Object] ->
  m Object
handleWatcherRequest variables _ =
  ObjectNil <$ traverse_ checkVar variables

handleWatcherRequestSafe ::
  MonadBaseControl IO m =>
  MonadRibo m =>
  NvimE e m =>
  [WatchedVariable m] ->
  [Object] ->
  m Object
handleWatcherRequestSafe variables o =
  ObjectNil <$ lockOrSkip "variable-watcher" (void $ handleWatcherRequest variables o)