content: {-# LANGUAGE ExistentialQuantification #-}
  
  {- |
  Module      :  Neovim.Plugin.Internal
  Description :  Split module that can import Neovim.Context without creating import circles
  Copyright   :  (c) Sebastian Witte
  License     :  Apache-2.0
  
  Maintainer  :  woozletoff@gmail.com
  Stability   :  experimental
  Portability :  GHC
  -}
  module Neovim.Plugin.Internal (
      ExportedFunctionality (..),
      getFunction,
      getDescription,
      NeovimPlugin (..),
      Plugin (..),
      wrapPlugin,
  ) where
  
  import Neovim.Context (Neovim)
  import Neovim.Plugin.Classes (
      FunctionalityDescription,
      HasFunctionName (..),
   )
  
  import Data.MessagePack (Object)
  
  {- | This data type is used in the plugin registration to properly register the
   functions.
  -}
  newtype ExportedFunctionality env
      = EF (FunctionalityDescription, [Object] -> Neovim env Object)
  
  -- | Extract the description of an 'ExportedFunctionality'.
  getDescription :: ExportedFunctionality env -> FunctionalityDescription
  getDescription (EF (d, _)) = d
  
  -- | Extract the function of an 'ExportedFunctionality'.
  getFunction :: ExportedFunctionality env -> [Object] -> Neovim env Object
  getFunction (EF (_, f)) = f
  
  instance HasFunctionName (ExportedFunctionality env) where
      name = name . getDescription
      nvimMethod = nvimMethod . getDescription
  
  -- | This data type contains meta information for the plugin manager.
  data Plugin env = Plugin
      { environment :: env
      , exports :: [ExportedFunctionality env]
      }
  
  {- | 'Plugin' values are wraped inside this data type via 'wrapPlugin' so that
   we can put plugins in an ordinary list.
  -}
  data NeovimPlugin = forall env. NeovimPlugin (Plugin env)
  
  {- | Wrap a 'Plugin' in some nice blankets, so that we can put them in a simple
   list.
  -}
  wrapPlugin :: Applicative m => Plugin env -> m NeovimPlugin
  wrapPlugin = pure . NeovimPlugin
  