packages feed

nvim-hs-2.3.2.1: src/Neovim/RPC/Classes.hs

{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}

{- |
Module      :  Neovim.RPC.Classes
Description :  Data types and classes for the RPC components
Copyright   :  (c) Sebastian Witte
License     :  Apache-2.0

Maintainer  :  woozletoff@gmail.com
Stability   :  experimental
Portability :  GHC

Import this module qualified as @MsgpackRPC@
-}
module Neovim.RPC.Classes (
    Message (..),
) where

import Neovim.Classes
import Neovim.Plugin.Classes (FunctionName (..), NeovimEventId (..))
import qualified Neovim.Plugin.IPC.Classes as IPC

import Control.Applicative
import Control.Monad.Error.Class
import Data.Data (Typeable)
import Data.MessagePack (Object (..))
import Prettyprinter (hardline, nest, viaShow)

import Prelude

{- | See https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md for
 details about the msgpack rpc specification.
-}
data Message
    = -- | Request in the sense of the msgpack rpc specification
      --
      -- Parameters
      -- * Message identifier that has to be put in the response to this request
      -- * Function name
      -- * Function arguments
      Request IPC.Request
    | -- | Response in the sense of the msgpack rpc specifcation
      --
      -- Parameters
      -- * Mesage identifier which matches a request
      -- * 'Either' an error 'Object' or a result 'Object'
      Response !Int64 (Either Object Object)
    | -- | Notification in the sense of the msgpack rpc specification
      Notification IPC.Notification
    deriving (Eq, Ord, Show, Typeable, Generic)

instance NFData Message

instance IPC.Message Message

instance NvimObject Message where
    toObject = \case
        Request (IPC.Request (F m) i ps) ->
            ObjectArray $ (0 :: Int64) +: i +: m +: ps +: []
        Response i (Left e) ->
            ObjectArray $ (1 :: Int64) +: i +: e +: () +: []
        Response i (Right r) ->
            ObjectArray $ (1 :: Int64) +: i +: () +: r +: []
        Notification (IPC.Notification (NeovimEventId eventId) ps) ->
            ObjectArray $ (2 :: Int64) +: eventId +: ps +: []

    fromObject = \case
        ObjectArray [ObjectInt 0, i, m, ps] -> do
            r <-
                IPC.Request
                    <$> fmap F (fromObject m)
                    <*> fromObject i
                    <*> fromObject ps
            return $ Request r
        ObjectArray [ObjectInt 1, i, e, r] ->
            let eer = case e of
                    ObjectNil -> Right r
                    _ -> Left e
             in Response <$> fromObject i
                    <*> pure eer
        ObjectArray [ObjectInt 2, m, ps] -> do
            n <-
                IPC.Notification
                    <$> fmap NeovimEventId (fromObject m)
                    <*> fromObject ps
            return $ Notification n
        o ->
            throwError $ "Not a known/valid msgpack-rpc message:" <+> viaShow o

instance Pretty Message where
    pretty = \case
        Request request ->
            pretty request
        Response i ret ->
            nest 2 $
                "Response" <+> "#" <> pretty i
                    <> hardline
                    <> either viaShow viaShow ret
        Notification notification ->
            pretty notification