packages feed

emacs-module 0.3 → 0.4

raw patch · 15 files changed

+213/−97 lines, 15 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Data.Emacs.Module.SymbolName.Predefined.Funcall: funcall :: SymbolName
+ Data.Emacs.Module.SymbolName.Predefined: intern :: SymbolName
+ Data.Emacs.Module.SymbolName.Predefined.Intern: intern :: SymbolName
- Data.Emacs.Module.SymbolName.TH: cacheSym :: String -> Maybe String -> Q [Dec]
+ Data.Emacs.Module.SymbolName.TH: cacheSym :: String -> String -> Q [Dec]

Files

Changelog.md view
@@ -1,3 +1,10 @@+# 0.4++- Breaking change: `Data.Emacs.Module.SymbolName.TH.cacheSym` second+  argument changed its type `Maybe String` -> `Maybe`, semantics stayed the same++- Fix interning of non-ASCII symbols+ # 0.3  - Add `extractByteString` function to the `EmacsMonad` class
emacs-module.cabal view
@@ -3,7 +3,7 @@ name:   emacs-module version:-  0.3+  0.4 category: Foreign, Foreign binding  synopsis:@@ -35,6 +35,7 @@   , GHC == 9.8   , GHC == 9.10   , GHC == 9.12+  , GHC == 9.14  extra-source-files:   cbits/emacs-module.h@@ -119,7 +120,7 @@     Data.Emacs.Module.Runtime     Data.Emacs.Module.SymbolName     Data.Emacs.Module.SymbolName.Predefined-    Data.Emacs.Module.SymbolName.Predefined.Funcall+    Data.Emacs.Module.SymbolName.Predefined.Intern     Data.Emacs.Module.SymbolName.TH     Data.Emacs.Module.Value     Emacs.Module@@ -136,6 +137,7 @@     Data.Emacs.Module.Raw.Value     Data.Emacs.Module.Raw.Value.Internal     Data.Emacs.Module.SymbolName.Internal+    Data.Emacs.Module.SymbolName.Internal.Type     Data.Emacs.Module.Value.Internal     Emacs.Module.Monad.Common     Foreign.Ptr.Builder
src/Data/Emacs/Module/Raw/Env/TH.hs view
@@ -30,7 +30,8 @@  #if MIN_VERSION_template_haskell(2, 17, 0) unwrapForall :: Type -> (Maybe ([TyVarBndr Specificity], Cxt), Type)-#else+#endif+#if !MIN_VERSION_template_haskell(2, 17, 0) unwrapForall :: Type -> (Maybe ([TyVarBndr], Cxt), Type) #endif unwrapForall (ForallT bs c t) = (Just (bs, c), t)@@ -38,7 +39,8 @@  #if MIN_VERSION_template_haskell(2, 17, 0) wrapForall :: Maybe ([TyVarBndr Specificity], Cxt) -> Type -> Type-#else+#endif+#if !MIN_VERSION_template_haskell(2, 17, 0) wrapForall :: Maybe ([TyVarBndr], Cxt) -> Type -> Type #endif wrapForall Nothing        = id
src/Data/Emacs/Module/Raw/Value/Internal.hs view
@@ -34,7 +34,7 @@ import Prettyprinter (Pretty(..))  data Pinning-  -- | Tag for global values are independent of environment ('Env') that produced it.+  -- | Tag for global values that are independent of environment ('Env') that produced it.   --   -- Can be used to e.g. cache values that are expensive to compute from scratch.   = Pinned
src/Data/Emacs/Module/SymbolName/Internal.hs view
@@ -13,6 +13,8 @@  {-# OPTIONS_HADDOCK not-home #-} +{-# OPTIONS_GHC -Wno-orphans #-}+ module Data.Emacs.Module.SymbolName.Internal   ( Static(..)   , Dynamic(..)@@ -53,7 +55,8 @@ import Data.Emacs.Module.Raw.Value import Emacs.Module.Assert -import Data.Emacs.Module.SymbolName.Predefined.Funcall+import Data.Emacs.Module.SymbolName.Internal.Type+import Data.Emacs.Module.SymbolName.Predefined.Intern qualified as Sym  -- | Symbols that are known at compile time. --@@ -65,12 +68,6 @@ newtype Dynamic = Dynamic { unDynamic :: Text }   deriving (Eq, Ord, Show, Pretty) -data SymbolName-  = StaticSymbol  {-# UNPACK #-} !(Ptr CChar)-  | DynamicSymbol {-# UNPACK #-} !Text-  | CachedSymbol  (IORef (Env -> IO (RawValue 'Pinned))) SymbolName-  deriving (Eq)- instance Show SymbolName where   show = \case     StaticSymbol (Ptr addr)@@ -90,7 +87,7 @@   where     go :: SymbolName -> IO (IORef (Env -> IO (RawValue 'Pinned)))     go !name =-      unsafeFixIO $ \ ref ->+      unsafeFixIO $ \ref ->         newIORef $ \env -> do           !global <- Raw.makeGlobalRef env =<< reifySymbolRaw env name           writeIORef ref $ \_env -> pure global@@ -157,15 +154,15 @@     -- If it's only ASCII then can run FFI intern, otherwise have to go via funcall     -- TODO: cache this check     | T.all (\c -> ord c < 128) str ->-      f <$> T.withCString str (Raw.intern env)+        f <$> T.withCString str (Raw.intern env)     | otherwise                    ->-      T.withCStringLen str $ \(ptr, len) -> do-        str' <- emacsAssert (len >= 0) "Symbol text length must be non-negative" $-          Raw.makeString env ptr (fromIntegral len)-        funcall' <- reifySymbolUnknown env funcall-        allocaNonNull $ \args -> do-          poke (unNonNullPtr args) str'-          f <$> Raw.funcallPrimitive env funcall' 1 args+        T.withCStringLen str $ \(ptr, len) -> do+          str' <- emacsAssert (len >= 0) "Symbol text length must be non-negative" $+            Raw.makeString env ptr (fromIntegral len)+          intern' <- reifySymbolUnknown env Sym.intern+          allocaNonNull $ \args -> do+            poke (unNonNullPtr args) str'+            f <$> Raw.funcallPrimitive env intern' 1 args    CachedSymbol ref _ ->     g <$> ((\k -> k env) =<< readIORef ref)
src/Data/Emacs/Module/SymbolName/Internal.hs-boot view
@@ -1,21 +1,26 @@ {-# LANGUAGE DataKinds #-}+{-# LANGUAGE MagicHash #-}  module Data.Emacs.Module.SymbolName.Internal   ( SymbolName   , mkSymbolNameCache   , mkCachedSymbolName   , mkSymbolNameString+  , mkSymbolNameUnsafe   ) where  import Data.IORef  import Data.Emacs.Module.Raw.Env.Internal import Data.Emacs.Module.Raw.Value+import GHC.Exts (Addr#) -data SymbolName+import Data.Emacs.Module.SymbolName.Internal.Type  mkSymbolNameCache :: SymbolName -> IO (IORef (Env -> IO (RawValue 'Pinned)))  mkCachedSymbolName :: IORef (Env -> IO (RawValue 'Pinned)) -> SymbolName -> SymbolName  mkSymbolNameString :: String -> SymbolName++mkSymbolNameUnsafe :: Addr# -> SymbolName
+ src/Data/Emacs/Module/SymbolName/Internal/Type.hs view
@@ -0,0 +1,26 @@+-- |+-- Module:     Data.Emacs.Module.SymbolName.Internal.Type+-- Copyright:  (c) Sergey Vinokurov 2026+-- License:    Apache-2.0 (see LICENSE)+-- Maintainer: serg.foo@gmail.com++{-# LANGUAGE DataKinds #-}++{-# OPTIONS_HADDOCK not-home #-}++module Data.Emacs.Module.SymbolName.Internal.Type (SymbolName(..)) where++import Data.IORef+import Data.Text (Text)+import Foreign.C.Types+import GHC.Ptr++import Data.Emacs.Module.Raw.Env.Internal+import Data.Emacs.Module.Raw.Value++data SymbolName+  = StaticSymbol  {-# UNPACK #-} !(Ptr CChar)+  | DynamicSymbol {-# UNPACK #-} !Text+  | CachedSymbol  (IORef (Env -> IO (RawValue 'Pinned))) SymbolName+  deriving (Eq)+
src/Data/Emacs/Module/SymbolName/Predefined.hs view
@@ -33,29 +33,109 @@   , symbolName   , prin1ToString   , funcall+  , intern   ) where  import Prelude hiding (error, concat)  import Data.Emacs.Module.SymbolName.TH -import Data.Emacs.Module.SymbolName.Predefined.Funcall+import Data.Emacs.Module.SymbolName.Internal.Type (SymbolName)+import Data.Emacs.Module.SymbolName.Predefined.Intern -cacheSym "error"           Nothing-cacheSym "list"            Nothing-cacheSym "cons"            Nothing-cacheSym "car"             Nothing-cacheSym "cdr"             Nothing-cacheSym "setcar"          Nothing-cacheSym "setcdr"          Nothing-cacheSym "nil"             Nothing-cacheSym "fset"            Nothing-cacheSym "provide"         Nothing-cacheSym "t"               Nothing-cacheSym "vector"          Nothing-cacheSym "vconcat"         Nothing-cacheSym "face"            Nothing-cacheSym "propertize"      Nothing-cacheSym "concat"          Nothing-cacheSym "symbol-name"     (Just "symbolName")-cacheSym "prin1-to-string" (Just "prin1ToString")+cacheSym "error"           "errorTH"+cacheSym "list"            "listTH"+cacheSym "cons"            "consTH"+cacheSym "car"             "carTH"+cacheSym "cdr"             "cdrTH"+cacheSym "setcar"          "setcarTH"+cacheSym "setcdr"          "setcdrTH"+cacheSym "nil"             "nilTH"+cacheSym "fset"            "fsetTH"+cacheSym "provide"         "provideTH"+cacheSym "t"               "tTH"+cacheSym "vector"          "vectorTH"+cacheSym "vconcat"         "vconcatTH"+cacheSym "face"            "faceTH"+cacheSym "propertize"      "propertizeTH"+cacheSym "concat"          "concatTH"+cacheSym "symbol-name"     "symbolNameTH"+cacheSym "prin1-to-string" "prin1ToStringTH"+cacheSym "funcall"         "funcallTH"++{-# INLINE error #-}+error :: SymbolName+error = errorTH++{-# INLINE list #-}+list :: SymbolName+list = listTH++{-# INLINE cons #-}+cons :: SymbolName+cons = consTH++{-# INLINE car #-}+car :: SymbolName+car = carTH++{-# INLINE cdr #-}+cdr :: SymbolName+cdr = cdrTH++{-# INLINE setcar #-}+setcar :: SymbolName+setcar = setcarTH++{-# INLINE setcdr #-}+setcdr :: SymbolName+setcdr = setcdrTH++{-# INLINE nil #-}+nil :: SymbolName+nil = nilTH++{-# INLINE fset #-}+fset :: SymbolName+fset = fsetTH++{-# INLINE provide #-}+provide :: SymbolName+provide = provideTH++{-# INLINE t #-}+t :: SymbolName+t = tTH++{-# INLINE vector #-}+vector :: SymbolName+vector = vectorTH++{-# INLINE vconcat #-}+vconcat :: SymbolName+vconcat = vconcatTH++{-# INLINE face #-}+face :: SymbolName+face = faceTH++{-# INLINE propertize #-}+propertize :: SymbolName+propertize = propertizeTH++{-# INLINE concat #-}+concat :: SymbolName+concat = concatTH++{-# INLINE symbolName #-}+symbolName :: SymbolName+symbolName = symbolNameTH++{-# INLINE prin1ToString #-}+prin1ToString :: SymbolName+prin1ToString = prin1ToStringTH++{-# INLINE funcall #-}+funcall :: SymbolName+funcall = funcallTH+
− src/Data/Emacs/Module/SymbolName/Predefined/Funcall.hs
@@ -1,32 +0,0 @@-------------------------------------------------------------------------------- |--- Module      :  Data.Emacs.Module.SymbolName.Predefined.Funcall--- Copyright   :  (c) Sergey Vinokurov 2022--- License     :  Apache-2.0 (see LICENSE)--- Maintainer  :  serg.foo@gmail.com-------------------------------------------------------------------------------{-# LANGUAGE DataKinds #-}--module Data.Emacs.Module.SymbolName.Predefined.Funcall-  ( funcall-  ) where--import Data.IORef-import System.IO.Unsafe--import Data.Emacs.Module.Raw.Env.Internal-import Data.Emacs.Module.Raw.Value--import {-# SOURCE #-} Data.Emacs.Module.SymbolName.Internal--funcallSym :: SymbolName-funcallSym = mkSymbolNameString "funcall"--{-# NOINLINE funcallCache #-}-funcallCache :: IORef (Env -> IO (RawValue 'Pinned))-funcallCache = unsafePerformIO $ mkSymbolNameCache funcallSym--funcall :: SymbolName-funcall = mkCachedSymbolName funcallCache funcallSym-
+ src/Data/Emacs/Module/SymbolName/Predefined/Intern.hs view
@@ -0,0 +1,33 @@+----------------------------------------------------------------------------+-- |+-- Module      :  Data.Emacs.Module.SymbolName.Predefined.Intern+-- Copyright   :  (c) Sergey Vinokurov 2026+-- License     :  Apache-2.0 (see LICENSE)+-- Maintainer  :  serg.foo@gmail.com+----------------------------------------------------------------------------++{-# LANGUAGE DataKinds #-}+{-# LANGUAGE MagicHash #-}++module Data.Emacs.Module.SymbolName.Predefined.Intern+  ( intern+  ) where++import Data.IORef+import System.IO.Unsafe++import Data.Emacs.Module.Raw.Env.Internal+import Data.Emacs.Module.Raw.Value++import {-# SOURCE #-} Data.Emacs.Module.SymbolName.Internal++internSym :: SymbolName+internSym = mkSymbolNameUnsafe "intern"#++{-# NOINLINE internCache #-}+internCache :: IORef (Env -> IO (RawValue 'Pinned))+internCache = unsafePerformIO $ mkSymbolNameCache internSym++intern :: SymbolName+intern = mkCachedSymbolName internCache internSym+
src/Data/Emacs/Module/SymbolName/TH.hs view
@@ -14,8 +14,10 @@   ( cacheSym   ) where +import Data.ByteString qualified as BS import Data.IORef-import Data.Maybe+import Data.Text qualified as T+import Data.Text.Encoding qualified as T import Language.Haskell.TH import System.IO.Unsafe @@ -23,16 +25,15 @@ import Data.Emacs.Module.Raw.Value import Data.Emacs.Module.SymbolName.Internal qualified as Sym -cacheSym :: String -> Maybe String -> Q [Dec]+cacheSym :: String -> String -> Q [Dec] cacheSym sym bindingName = do-  ref      <- newName ("ref_" ++ binding)+  ref      <- newName ("ref_" ++ bindingName)   noinline <- pragInlD ref NoInline FunLike AllPhases   refSig   <- sigD ref [t| IORef (Env -> IO (RawValue 'Pinned)) |]   refDecl  <- valD (varP ref) (normalB [e| unsafePerformIO (Sym.mkSymbolNameCache $sym') |]) []-  symSig   <- sigD (mkName binding) [t| Sym.SymbolName |]-  symDecl  <- valD (varP (mkName binding)) (normalB [e| Sym.CachedSymbol $(varE ref) $sym' |]) []+  symSig   <- sigD (mkName bindingName) [t| Sym.SymbolName |]+  symDecl  <- valD (varP (mkName bindingName)) (normalB [e| Sym.CachedSymbol $(varE ref) $sym' |]) []   pure [noinline, refSig, refDecl, symSig, symDecl]   where     sym' :: ExpQ-    sym' = [e| Sym.mkSymbolNameString $(litE (stringL sym)) |]-    binding = fromMaybe sym bindingName+    sym' = [e| Sym.mkSymbolNameUnsafe $(litE (StringPrimL (BS.unpack (T.encodeUtf8 (T.pack sym))))) |]
src/Emacs/Module.hs view
@@ -35,14 +35,15 @@ -- >   :: MonadEmacs m v -- >   => EmacsFunction ('S ('S ('S ('S 'Z)))) ('S ('S 'Z)) 'True m v s -- > 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+-- >   x'         <- extractInt x+-- >   y'         <- extractInt y+-- >   z'         <- extractInt z+-- >   w'         <- traverse extractInt w+-- >   t'         <- traverse extractInt t -- >--- >   tmp   <- makeInt (x' * y' * z')--- >   tmp'  <- extractInt =<< funcallSym "funcall" [f, tmp]+-- >   tmp        <- makeInt (x' * y' * z')+-- >   funcallSym <- intern "funcall"+-- >   tmp'       <- extractInt =<< funcall funcallSym [f, tmp] -- > -- >   produceRef =<< makeInt (tmp' + fromMaybe 1 w' * fromMaybe 2 t' + length quux) --
src/Emacs/Module/Errors.hs view
@@ -47,7 +47,6 @@ import Prettyprinter.Render.Text as PP  import Data.Emacs.Module.Env qualified as Raw-import Data.Emacs.Module.GetRawValue import Data.Emacs.Module.NonNullPtr import Data.Emacs.Module.Raw.Env.Internal (Env) import Data.Emacs.Module.Raw.Value@@ -238,10 +237,10 @@   -> IO a -- ^ Result to return on error.   -> IO a   -> IO a-reportAllErrorsToEmacs env resultOnErr x+reportAllErrorsToEmacs env resultOnErr   = Exception.handle (\e -> report formatSomeException env e *> resultOnErr)-  $ Exception.handle (\et -> reportEmacsThrowToEmacs' env et *> resultOnErr)-  $ Exception.handle (\et -> reportEmacsSignalToEmacs' env et *> resultOnErr) x+  . Exception.handle (\et -> reportEmacsThrowToEmacs' env et *> resultOnErr)+  . Exception.handle (\et -> reportEmacsSignalToEmacs' env et *> resultOnErr)  report :: (e -> Text) -> Env -> e -> IO () report format env err = do@@ -251,7 +250,7 @@     str' <- Raw.makeString env str (fromIntegral len)     alloca $ \argsPtr -> do       poke argsPtr str'-      errData <- Raw.funcallPrimitive env (getRawValue listSym) 1 (mkNonNullPtr argsPtr)+      errData <- Raw.funcallPrimitive env listSym 1 (mkNonNullPtr argsPtr)       -- The 'nonLocalExitSignal' function does not overwrite pending       -- signals, so it's ok to use it here without checking whether an       -- error is already going on.
src/Emacs/Module/Monad.hs view
@@ -245,7 +245,6 @@       =<< (withPtrLenNonNull (coerceBuilderCache eArgsCache) (foldMap (PtrBuilder.storable . getRawValue) args) $ \n args' ->              Env.funcall eEnv (getRawValue func) (fromIntegral n) args') -   {-# INLINE funcallPrimitive #-}   funcallPrimitive     :: (WithCallStack, Foldable f)
src/Emacs/Module/Monad/Class.hs view
@@ -50,10 +50,6 @@   , forall s. PrimMonad (m s)   ) => MonadEmacs (m :: k -> Type -> Type) (v :: k -> Type) | m -> v where -  -- -- | Emacs value that is managed by the 'm' monad. Will be cleaned up-  -- -- after 'm' finishes its execution.-  -- type EmacsRef m :: k -> Type-   -- | Make a global reference to a value so that it will persist   -- across different calls from Emacs into exposed functions.   makeGlobalRef :: WithCallStack => v s -> m s (RawValue 'Pinned)