packages feed

emacs-module 0.1 → 0.1.1

raw patch · 6 files changed

+120/−44 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

emacs-module.cabal view
@@ -1,7 +1,7 @@ name:   emacs-module version:-  0.1+  0.1.1 category: Foreign, Foreign binding  synopsis:@@ -9,7 +9,12 @@  description:   This package provides a full set of bindings to emacs-module.h that-  allows to develop Emacs modules in Haskell.+  allows to develop Emacs modules in Haskell. Bindings are based on+  Emacs 25 version of the interface and thus should work in all+  subsequent versions of Emacs.++  For pointers on how to write minimal Emacs module, please refer+  to https://github.com/sergv/emacs-module/blob/master/test/src/Emacs/TestsInit.hs  license:   BSD3
src/Data/Emacs/Module/Args.hs view
@@ -6,11 +6,7 @@ -- Maintainer  :  serg.foo@gmail.com ---------------------------------------------------------------------------- -{-# LANGUAGE BangPatterns           #-} {-# LANGUAGE DataKinds              #-}-{-# LANGUAGE DeriveFoldable         #-}-{-# LANGUAGE DeriveFunctor          #-}-{-# LANGUAGE DeriveTraversable      #-} {-# LANGUAGE FlexibleContexts       #-} {-# LANGUAGE FlexibleInstances      #-} {-# LANGUAGE GADTs                  #-}@@ -19,7 +15,6 @@ {-# LANGUAGE MultiParamTypeClasses  #-} {-# LANGUAGE PolyKinds              #-} {-# LANGUAGE ScopedTypeVariables    #-}-{-# LANGUAGE StandaloneDeriving     #-} {-# LANGUAGE TypeApplications       #-} {-# LANGUAGE TypeFamilies           #-} {-# LANGUAGE TypeFamilyDependencies #-}@@ -48,6 +43,9 @@ import Data.Emacs.Module.Raw.Env (variadicFunctionArgs) import Data.Emacs.Module.Raw.Value +-- | Type-level Peano numbers.+--+-- Indented to be used with @DataKinds@ extension enabled. data Nat = Z | S Nat  class NatValue (n :: Nat) where@@ -61,43 +59,36 @@   {-# INLINE natValue #-}   natValue _ = 1 + natValue (Proxy @n) --- type family EmacsArgs' (req :: Nat) (m :: Type -> Type) (a :: Type) = (r :: Type) | r -> req m a where---   EmacsArgs' ('S n) m a = RawValue       -> EmacsArgs' n  m a---   -- EmacsArgs 'Z     m a = Maybe RawValue -> EmacsArgs' 'Z k   rest m a---   -- EmacsArgs 'Z     m a = [RawValue]     -> m a---   EmacsArgs' 'Z     m a = m a---- type family EmacsArgs' (req :: Nat) (a :: Type) = (r :: Type) | r -> req------ type instance EmacsArgs' ('S n) a = RawValue -> EmacsArgs' n a---   -- EmacsArgs 'Z     m a = Maybe RawValue -> EmacsArgs' 'Z k   rest m a---   -- EmacsArgs 'Z     m a = [RawValue]     -> m a--- type instance EmacsArgs' 'Z     a = IO a---- | Required argument.+-- | Required argument of an exported function. data R a b = R !a !b --- | Optional argument.+-- | Optional argument of an exported function. data O a b = O !(Maybe a) !b --- | All other arguments as a list.+-- | All other arguments of an exported function as a list. newtype Rest a = Rest [a] --- | No more arguments.+-- | End of argument list of an exported funciton. data Stop a = Stop +-- | Specification of the arguments that exposed functions can receive from Emacs.+--+-- This type family allows to declaratively specify how many required and+-- optional arguments a function can take and whether it accepts rest arguments.+-- It's a direct translation of argument lists in Emacs lisp, e.g.+--+-- > (defun foo (x y z &optional w t &rest quux)+-- >   (+ (* x y z) (* (or w 1) (or t 2)) (length quux)))+--+-- The function above has 3 required arguments, 2 optional and also has+-- rest arguments. The type family below has two 'Nat's and one 'Bool'+-- to provide that info. type family EmacsArgs (req :: Nat) (opt :: Nat) (rest :: Bool) (a :: Type) = (r :: Type) | r -> req opt rest a where   EmacsArgs ('S n) opt    rest   a = R a (EmacsArgs n  opt rest a)   EmacsArgs 'Z     ('S k) rest   a = O a (EmacsArgs 'Z k   rest a)   EmacsArgs 'Z     'Z     'True  a = Rest a   EmacsArgs 'Z     'Z     'False a = Stop a --- type family EmacsArgs (req :: Nat) (opt :: Nat) (rest :: Bool) (s :: Type) (a :: Type) = (r :: Type) | r -> req opt rest where---   EmacsArgs ('S n) opt    rest   s a = Value s         -> EmacsArgs n  opt rest s a---   EmacsArgs 'Z     ('S k) rest   s a = Maybe (Value s) -> EmacsArgs 'Z k   rest s a---   EmacsArgs 'Z     'Z     'True  s a = [Value s]       -> IO a---   EmacsArgs 'Z     'Z     'False s a = IO a- class EmacsInvocation req opt rest where   supplyEmacsArgs     :: MonadBase IO m@@ -164,6 +155,7 @@     supplyEmacsArgs (nargs - 1) (advanceEmacsValuePtr startPtr) mkArg (f . R arg)  +-- | Helper to retrieve number of arguments a function takes for Emacs. class GetArities (req :: Nat) (opt :: Nat) (rest :: Bool) where   arities :: Proxy req -> Proxy opt -> Proxy rest -> (CPtrdiff, CPtrdiff) 
src/Emacs/Module.hs view
@@ -4,33 +4,86 @@ -- Copyright   :  (c) Sergey Vinokurov 2018 -- License     :  BSD3-style (see LICENSE) -- Maintainer  :  serg.foo@gmail.com+--+-- This module is the entry point for writing Emacs extensions in+-- Haskell.+--+-- This package, though provides a lot of wrapping around Emacs's bare+-- C interface, still presumes some familiarity with said interface.+-- Thus, when developnig Emacs modules it's recommended to keep a+-- reference of the C interface around. One such reference is+-- <https://phst.github.io/emacs-modules.html>.+--+-- = Minimalistic example+--+-- Consider Emacs function+--+-- > (defun foo (f x y z &optional w t &rest quux)+-- >   (+ (funcall f (* x y z)) (* (or w 1) (or t 2)) (length quux)))+--+-- With help of this package, it may be defined as+--+-- @+-- {-# LANGUAGE DataKinds   #-}+-- {-# LANGUAGE QuasiQuotes #-}+--+-- import Data.Maybe+-- import Data.Emacs.Module.SymbolName.TH+-- import Emacs.Module+--+-- foo+--   :: (MonadEmacs m, Monad (m s))+--   => EmacsFunction ('S ('S ('S ('S 'Z)))) ('S ('S 'Z)) 'True s m+-- foo (R f (R x (R y (R z (O w (O t (Rest quux))))))) = do+--   x'    <- extractInt x+--   y'    <- extractInt y+--   z'    <- extractInt z+--   w'    <- traverse extractInt w+--   t'    <- traverse extractInt t+--+--   tmp   <- makeInt (x' * y' * z')+--   tmp'  <- extractInt =<< funcall [esym|funcall|] [f, tmp]+--+--   produceRef =<< makeInt (tmp' + fromMaybe 1 w' * fromMaybe 2 t' + length quux)+-- @+--+-- = Creating Emacs dynamic module+-- In order to make shared object or dll callable from Emacs,+-- a cabal project with foreign-library section has to be created.+-- Please refer to <https://github.com/sergv/emacs-module/tree/master/test>+-- for such a project.+--+-- Please note that this project will need a small C file for initialising+-- Haskell runtime. In the project mentioned before it's present as+-- <https://github.com/sergv/emacs-module/blob/master/test/cbits/emacs_wrapper.c> ----------------------------------------------------------------------------  module Emacs.Module-  ( -- * Generic interface-    MonadEmacs(..)+  (+    -- * EmacsM+    EmacsM+  , runEmacsM -    -- * Type synonyms+    -- * Basic bindings+  , MonadEmacs(..)++    -- ** Define functions callable by Emacs   , EmacsFunction   , EmacsFunctionExtra-  , Raw.UserPtrFinaliserType-  , Raw.UserPtrFinaliser--    -- * Types for defining functions   , Nat(..)   , R(..)   , O(..)   , Rest(..)   , Stop(..) -    -- * Errors+    -- ** Error types   , EmacsError(..)   , EmacsInternalError(..)   , reportAllErrorsToEmacs -    -- * EmacsM-  , EmacsM-  , runEmacsM+    -- ** Other types+  , Raw.UserPtrFinaliserType+  , Raw.UserPtrFinaliser      -- * Reexports   , module Emacs.Module.Functions
src/Emacs/Module/Assert.hs view
@@ -21,6 +21,9 @@ import GHC.Stack (HasCallStack) #endif +-- | Call stacks for all emacs-related functions in Haskell.+-- Will be disabled unless this package was build with 'assertions'+-- flag enabled. #ifdef ASSERTIONS type WithCallStack = (HasCallStack :: Constraint) #else
src/Emacs/Module/Monad.hs view
@@ -75,6 +75,17 @@   , eResourceState :: !Resource.InternalState   } +-- | Concrete monad for interacting with Emacs. It provides:+--+-- 1. Ability to call Emacs C functions and automatically rethrows any+--    errors (non-local exits) from elisp as Haskell exceptions.+-- 2. Tracks ownership of any produced Emacs values and communicates+--    that to Emacs, so that GC on Emacs side will not make any+--    values in Haskell invalid (funnily enough, this can happen!).+--+-- Parameter 's' serves to make ownership-tracking capabilities possible.+-- It's use is the same as in 'Control.Monad.ST' monad. That is, it creates+-- local threads so that no produced Emacs values can leave past 'runEmacsM'. newtype EmacsM s a = EmacsM { unEmacsM :: ReaderT Environment IO a }   deriving     ( Functor@@ -100,6 +111,7 @@   {-# INLINE restoreM #-}   restoreM x = EmacsM (restoreM x) +-- | Execute emacs interaction session using an environment supplied by Emacs. runEmacsM   :: Env   -> (forall s. EmacsM s a)
src/Emacs/Module/Monad/Class.hs view
@@ -34,14 +34,25 @@ import Emacs.Module.Assert import Emacs.Module.Errors +-- | Basic Haskell function that can be called by Emacs. type EmacsFunction req opt rest (s :: k) (m :: k -> Type -> Type)   = (Throws EmacsThrow, Throws EmacsError, Throws EmacsInternalError, Throws UserError)   => EmacsArgs req opt rest (EmacsRef m s) -> m s (EmacsReturn m s) +-- | A Haskell functions that is callable by Emacs.+--+-- This type differs from 'EmacsFunction' in that it has an extra+-- parameter which will result in an additional pointer being passed+-- to this function when it's called by Emacs. Contents of the pointer is+-- specified when function is exported to Emacs. type EmacsFunctionExtra req opt rest extra (s :: k) (m :: k -> Type -> Type)   = (Throws EmacsThrow, Throws EmacsError, Throws EmacsInternalError, Throws UserError)   => EmacsArgs req opt rest (EmacsRef m s) -> Ptr extra -> m s (EmacsReturn m s) +-- | A mtl-style typeclass for interacting with Emacs. Typeclass functions+-- are mostly direct translations of emacs interface provided by 'emacs-module.h'.+--+-- For more functions please refer to "Emacs.Module.Functions" module. class MonadEmacs (m :: k -> Type -> Type) where    -- | Emacs value that is managed by the 'm' monad. Will be cleaned up@@ -66,7 +77,7 @@   -- | Equivalent to Emacs's @signal@ function.   --   -- NB if a non-local exit is alredy pending, this function will not-  -- overwrite it. In order to do that, use nonLocalExitClear.+  -- overwrite it. In order to do that, use 'nonLocalExitClear'.   nonLocalExitSignal     :: WithCallStack     => EmacsRef m s   -- ^ Error symbol@@ -76,7 +87,7 @@   -- | Equivalent to Emacs's @throw@ function.   --   -- NB if a non-local exit is alredy pending, this function will not-  -- overwrite it. In order to do that, use nonLocalExitClear.+  -- overwrite it. In order to do that, use 'nonLocalExitClear'.   nonLocalExitThrow     :: WithCallStack     => EmacsRef m s -- ^ Tag@@ -147,7 +158,7 @@   -- characters are the equal, but not much more. For more complete   -- equality comparison do   ---  -- > funcall [esym|equal|] [x, y]+  -- > funcallPrimitive [esym|equal|] [x, y]   eq     :: WithCallStack     => EmacsRef m s -> EmacsRef m s -> m s Bool