packages feed

ribosome-host-0.9.9.9: lib/Ribosome/Host/Data/Range.hs

{-# options_haddock prune #-}

-- |Special command parameter that governs the range modifier.
module Ribosome.Host.Data.Range where

import Data.MessagePack (Object (ObjectArray))
import Exon (exon)

import Ribosome.Host.Class.Msgpack.Decode (pattern Msgpack, MsgpackDecode (fromMsgpack))
import Ribosome.Host.Class.Msgpack.Encode (toMsgpack)

-- |Neovim offers different semantics for the command range (see @:help :command-range@).
--
-- This type determines the position (prefix line number/postfix count) and default values.
data RangeStyle =
  -- |Prefix line range, defaulting to the entire file (@-range=%@).
  RangeFile
  |
  -- |'Nothing': Prefix line range defaulting to the current line (@-range@).
  -- |@'Just' N@: Prefix count defaulting to @N@ (@-range=N@).
  RangeLine (Maybe Nat)
  |
  -- |@'Just' N@: Prefix or postfix count defaulting to @N@ (@-count=N@).
  -- |'Nothing': Same as @'Just' 0@ (@-count@).
  RangeCount (Maybe Nat)

-- |When this type is used as a parameter of a command handler function, the command is declared with the @-range@
-- option, and when invoked, the argument passed to the handler contains the line range specified by the user, as in:
--
-- > :5Reverse
-- > :5,20Reverse
--
-- In the first case, the field 'high' is 'Nothing'.
--
-- The type has a phantom parameter of kind 'RangeStyle' that configures the semantics of the range, as defined by
-- Neovim (see @:help :command-range@).
data Range (style :: RangeStyle) =
  Range {
    low :: Int64,
    high :: Maybe Int64
  }
  deriving stock (Eq, Show)

instance MsgpackDecode (Range style) where
  fromMsgpack = \case
    ObjectArray [Msgpack low, Msgpack high] ->
      Right (Range low (Just high))
    ObjectArray [Msgpack low] ->
      Right (Range low Nothing)
    o ->
      Left [exon|Range must be an array with one or two elements: #{show o}|]

class RangeStyleOpt (s :: RangeStyle) where
  rangeStyleOpt :: Map Text Object

  rangeStyleArg :: Text
  rangeStyleArg =
    "[<line1>, <line2>]"

instance RangeStyleOpt ('RangeLine 'Nothing) where
  rangeStyleOpt =
    [("range", toMsgpack True)]

instance RangeStyleOpt 'RangeFile where
  rangeStyleOpt =
    [("range", toMsgpack @Text "%")]

instance (
    KnownNat n
  ) => RangeStyleOpt ('RangeLine ('Just n)) where
  rangeStyleOpt =
    [("range", toMsgpack (natVal (Proxy @n)))]

  rangeStyleArg =
    "[<count>]"

instance RangeStyleOpt ('RangeCount 'Nothing) where
  rangeStyleOpt =
    [("count", toMsgpack True)]

  rangeStyleArg =
    "[<count>]"

instance (
    KnownNat n
  ) => RangeStyleOpt ('RangeCount ('Just n)) where
  rangeStyleOpt =
    [("count", toMsgpack (natVal (Proxy @n)))]

  rangeStyleArg =
    "[<count>]"