packages feed

emacs-module-0.2: src/Data/Emacs/Module/Doc.hs

----------------------------------------------------------------------------
-- |
-- Module      :  Data.Emacs.Module.Doc
-- Copyright   :  (c) Sergey Vinokurov 2022
-- License     :  Apache-2.0 (see LICENSE)
-- Maintainer  :  serg.foo@gmail.com
--
-- Defines type that provides function's documentation that would be visible
-- in Emacs.
----------------------------------------------------------------------------

{-# LANGUAGE MagicHash #-}

module Data.Emacs.Module.Doc
  ( Doc
  , mkLiteralDoc
  , mkTextDoc
  , useDocAsCString
  ) where

import Data.String
import Data.Text (Text)
import Data.Text qualified as T
import Data.Text.Foreign qualified as T
import Foreign.C.String
import GHC.Exts

data Doc
  = StaticDoc Addr#
  | DynamicDoc !Text

instance Show Doc where
  show = \case
    DynamicDoc x   -> show x
    StaticDoc addr -> show (unpackCString# addr)

instance IsString Doc where
  {-# INLINE fromString #-}
  fromString = mkStringDoc

mkStringDoc :: String -> Doc
mkStringDoc = mkTextDoc . T.pack

{-# INLINE [0] mkStringDoc #-}

{-# RULES
"Doc string literal" forall s .
   mkStringDoc (unpackCString# s) = mkLiteralDoc s
 #-}

-- | Indended to be used with unboxed string literals like this
--
-- @
-- mkLiteralDoc "foo"#
-- @
{-# INLINE mkLiteralDoc #-}
mkLiteralDoc :: Addr# -> Doc
mkLiteralDoc = StaticDoc

-- | Turn abritrary bytestring into 'Doc'.
{-# INLINE mkTextDoc #-}
mkTextDoc :: Text -> Doc
mkTextDoc = DynamicDoc

{-# INLINE useDocAsCString #-}
useDocAsCString :: Doc -> (CString -> IO a) -> IO a
useDocAsCString doc f = case doc of
  StaticDoc addr -> f (Ptr addr)
  DynamicDoc str -> T.withCString str f