Skip to content

Commit 9de00b7

Browse files
committed
Remove StateT from Neovim
1 parent 032f702 commit 9de00b7

File tree

22 files changed

+228
-221
lines changed

22 files changed

+228
-221
lines changed

library/Neovim/API/Parser.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ module Neovim.API.Parser
1919
import Neovim.Classes
2020

2121
import Control.Applicative
22-
import Control.Exception.Lifted
2322
import Control.Monad.Except
2423
import qualified Data.ByteString as B
2524
import Data.Map (Map)
@@ -32,6 +31,8 @@ import System.Process
3231
import Neovim.Compat.Megaparsec as P
3332
import Text.PrettyPrint.ANSI.Leijen (Doc)
3433
import qualified Text.PrettyPrint.ANSI.Leijen as P
34+
import UnliftIO.Exception (SomeException,
35+
bracket, catch)
3536

3637
import Prelude
3738

library/Neovim/API/TH.hs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ module Neovim.API.TH
2121
, autocmd
2222
, defaultAPITypeToHaskellTypeMap
2323

24-
, module Control.Exception.Lifted
24+
, module UnliftIO.Exception
2525
, module Neovim.Classes
2626
, module Data.Data
2727
, module Data.MessagePack
@@ -44,7 +44,6 @@ import Control.Applicative
4444
import Control.Arrow (first)
4545
import Control.Concurrent.STM (STM)
4646
import Control.Exception
47-
import Control.Exception.Lifted
4847
import Control.Monad
4948
import Data.ByteString (ByteString)
5049
import Data.ByteString.UTF8 (fromString)
@@ -58,6 +57,7 @@ import Data.Monoid
5857
import qualified Data.Set as Set
5958
import Data.Text (Text)
6059
import Text.PrettyPrint.ANSI.Leijen (text, (<+>), Doc)
60+
import UnliftIO.Exception
6161

6262
import Prelude
6363

@@ -148,8 +148,8 @@ createFunction typeMap nf = do
148148
let withDeferred | async nf = appT [t|STM|]
149149
| otherwise = id
150150

151-
withException | canFail nf = appT [t|Either NeovimException|]
152-
| otherwise = id
151+
withException' | canFail nf = appT [t|Either NeovimException|]
152+
| otherwise = id
153153

154154
callFns | async nf && canFail nf = [ [|acall|] ]
155155
| async nf = [ [|acall'|] ]
@@ -160,13 +160,13 @@ createFunction typeMap nf = do
160160
toObjVar v = [|toObject $(varE v)|]
161161

162162

163-
retTypes <- let (r,st) = (mkName "r", mkName "st")
163+
retTypes <- let env = (mkName "env")
164164
createSig retTypeFun =
165-
forallT [PlainTV r, PlainTV st] (return [])
166-
. appT ([t|Neovim $(varT r) $(varT st) |])
165+
forallT [PlainTV env] (return [])
166+
. appT ([t|Neovim $(varT env) |])
167167
. withDeferred . retTypeFun
168168
. apiTypeToHaskellType typeMap $ returnType nf
169-
in mapM createSig [ withException, id ]
169+
in mapM createSig [ withException', id ]
170170

171171
vars <- mapM (\(t,n) -> (,) <$> apiTypeToHaskellType typeMap t
172172
<*> newName n)

library/Neovim/Classes.hs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@ import Neovim.Exceptions (NeovimException(..))
3636
import Control.Applicative
3737
import Control.Arrow
3838
import Control.DeepSeq
39-
import Control.Exception.Lifted (throwIO)
4039
import Control.Monad.Except
41-
import Control.Monad.Base (MonadBase(..))
4240
import Data.ByteString (ByteString)
4341
import Data.Int (Int16, Int32, Int64, Int8)
4442
import qualified Data.Map.Strict as SMap
@@ -55,6 +53,7 @@ import qualified Text.PrettyPrint.ANSI.Leijen as P
5553

5654
import qualified Data.ByteString.UTF8 as UTF8 (fromString, toString)
5755
import Data.Text.Encoding (decodeUtf8, encodeUtf8)
56+
import UnliftIO.Exception (throwIO)
5857

5958
import Prelude
6059

@@ -101,7 +100,7 @@ class NFData o => NvimObject o where
101100
fromObject :: Object -> Either Doc o
102101
fromObject = return . fromObjectUnsafe
103102

104-
fromObject' :: (MonadBase IO io) => Object -> io o
103+
fromObject' :: (MonadIO io) => Object -> io o
105104
fromObject' = either (throwIO . ErrorMessage) return . fromObject
106105

107106

library/Neovim/Config.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import System.Log (Priority (..))
2323
-- the fields' documentation for what you possibly want to change. Also, the
2424
-- tutorial in the "Neovim" module should get you started.
2525
data NeovimConfig = Config
26-
{ plugins :: [Neovim (StartupConfig NeovimConfig) () NeovimPlugin]
26+
{ plugins :: [Neovim (StartupConfig NeovimConfig) NeovimPlugin]
2727
-- ^ The list of plugins. The IO type inside the list allows the plugin
2828
-- author to run some arbitrary startup code before creating a value of
2929
-- type 'NeovimPlugin'.

library/Neovim/Context.hs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,13 @@ import Text.PrettyPrint.ANSI.Leijen (Pretty (..))
6565

6666

6767
-- | @'throw'@ specialized to a 'Pretty' value.
68-
err :: Pretty err => err -> Neovim r st a
68+
err :: Pretty err => err -> Neovim env a
6969
err = throw . ErrorMessage . pretty
7070

7171

7272
errOnInvalidResult :: (NvimObject o)
73-
=> Neovim r st (Either NeovimException Object)
74-
-> Neovim r st o
73+
=> Neovim env (Either NeovimException Object)
74+
-> Neovim env o
7575
errOnInvalidResult a = a >>= \case
7676
Left o ->
7777
(err . show) o
@@ -85,11 +85,11 @@ errOnInvalidResult a = a >>= \case
8585

8686

8787
-- | Initiate a restart of the plugin provider.
88-
restart :: Neovim r st ()
88+
restart :: Neovim env ()
8989
restart = liftIO . flip putMVar Internal.Restart =<< Internal.asks' Internal.transitionTo
9090

9191

9292
-- | Initiate the termination of the plugin provider.
93-
quit :: Neovim r st ()
93+
quit :: Neovim env ()
9494
quit = liftIO . flip putMVar Internal.Quit =<< Internal.asks' Internal.transitionTo
9595

library/Neovim/Context/Internal.hs

Lines changed: 48 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -26,23 +26,19 @@ import Neovim.Plugin.Classes
2626
import Neovim.Plugin.IPC (SomeMessage)
2727

2828
import Control.Applicative
29-
import Control.Concurrent (ThreadId, forkIO)
30-
import Control.Concurrent (MVar, newEmptyMVar)
31-
import Control.Concurrent.STM
29+
import Control.Concurrent (MVar, ThreadId, forkIO)
3230
import Control.Exception (ArithException, ArrayException,
3331
ErrorCall, PatternMatchFail)
34-
import Control.Monad.Base
35-
import Control.Monad.Catch
3632
import Control.Monad.Except
3733
import Control.Monad.Reader
38-
import Control.Monad.State
3934
import Control.Monad.Trans.Resource
4035
import qualified Data.ByteString.UTF8 as U (fromString)
4136
import Data.Map (Map)
4237
import qualified Data.Map as Map
4338
import Data.MessagePack (Object)
4439
import System.Log.Logger
4540
import Text.PrettyPrint.ANSI.Leijen hiding ((<$>))
41+
import UnliftIO
4642

4743
import Prelude
4844

@@ -56,38 +52,40 @@ import Prelude
5652
-- good practice to factor them out. This allows you to write tests and spot
5753
-- errors easier. Essentially, you should treat this similar to 'IO' in general
5854
-- haskell programs.
59-
newtype Neovim r st a = Neovim
60-
{ unNeovim :: ResourceT (StateT st (ReaderT (Config r st) IO)) a }
55+
newtype Neovim env a = Neovim
56+
{ unNeovim :: ResourceT (ReaderT (Config env) IO) a }
6157

62-
deriving (Functor, Applicative, Monad, MonadIO, MonadState st
63-
, MonadThrow, MonadCatch, MonadMask, MonadResource)
64-
65-
66-
instance MonadBase IO (Neovim r st) where
67-
liftBase = liftIO
58+
deriving (Functor, Applicative, Monad, MonadIO
59+
, MonadThrow, MonadResource)
6860

6961

7062
-- | User facing instance declaration for the reader state.
71-
instance MonadReader r (Neovim r st) where
63+
instance MonadReader env (Neovim env) where
7264
ask = Neovim $ asks customConfig
7365
local f (Neovim a) = do
74-
r <- Neovim $ ask
75-
s <- get
76-
fmap fst . liftIO $ runReaderT (runStateT (runResourceT a) s)
66+
r <- Neovim ask
67+
liftIO $ runReaderT (runResourceT a)
7768
(r { customConfig = f (customConfig r)})
7869

7970

71+
72+
-- newtype UnliftIO m = UnliftIO { unliftIO :: forall a. m a -> IO a }
73+
74+
instance MonadUnliftIO (Neovim env) where
75+
askUnliftIO = Neovim . withUnliftIO $ \x ->
76+
return (UnliftIO (unliftIO x . unNeovim))
77+
8078
-- | Same as 'ask' for the 'InternalConfig'.
81-
ask' :: Neovim r st (Config r st)
82-
ask' = Neovim $ ask
79+
ask' :: Neovim env (Config env)
80+
ask' = Neovim ask
8381

8482

8583
-- | Same as 'asks' for the 'InternalConfig'.
86-
asks' :: (Config r st -> a) -> Neovim r st a
84+
asks' :: (Config env -> a) -> Neovim env a
8785
asks' = Neovim . asks
8886

8987
-- | Convenience alias for @'Neovim' () ()@.
90-
type Neovim' = Neovim () ()
88+
type Neovim' = Neovim ()
9189

9290
exceptionHandlers :: [Handler IO (Either Doc a)]
9391
exceptionHandlers =
@@ -102,19 +100,17 @@ exceptionHandlers =
102100

103101
-- | Initialize a 'Neovim' context by supplying an 'InternalEnvironment'.
104102
runNeovim :: NFData a
105-
=> Config r st
106-
-> st
107-
-> Neovim r st a
108-
-> IO (Either Doc (a, st))
109-
runNeovim = runNeovimInternal (\(a,st) -> a `deepseq` return (a, st))
110-
111-
runNeovimInternal :: ((a, st) -> IO (a, st))
112-
-> Config r st
113-
-> st
114-
-> Neovim r st a
115-
-> IO (Either Doc (a, st))
116-
runNeovimInternal f r st (Neovim a) =
117-
(try . runReaderT (runStateT (runResourceT a) st)) r >>= \case
103+
=> Config env
104+
-> Neovim env a
105+
-> IO (Either Doc a)
106+
runNeovim = runNeovimInternal (\a -> a `deepseq` return a)
107+
108+
runNeovimInternal :: (a -> IO a)
109+
-> Config env
110+
-> Neovim env a
111+
-> IO (Either Doc a)
112+
runNeovimInternal f r (Neovim a) =
113+
(try . runReaderT (runResourceT a)) r >>= \case
118114
Left e -> case fromException e of
119115
Just e' ->
120116
return . Left . pretty $ (e' :: NeovimException)
@@ -131,19 +127,19 @@ runNeovimInternal f r st (Neovim a) =
131127
-- returend immediately.
132128
-- FIXME This function is pretty much unused and mayhave undesired effects,
133129
-- namely that you cannot register autocmds in the forked thread.
134-
forkNeovim :: NFData a => ir -> ist -> Neovim ir ist a -> Neovim r st ThreadId
135-
forkNeovim r st a = do
130+
forkNeovim :: NFData a => iEnv -> Neovim iEnv a -> Neovim env ThreadId
131+
forkNeovim r a = do
136132
cfg <- ask'
137133
let threadConfig = cfg
138134
{ pluginSettings = Nothing -- <- slightly problematic
139135
, customConfig = r
140136
}
141-
liftIO . forkIO . void $ runNeovim threadConfig st a
137+
liftIO . forkIO . void $ runNeovim threadConfig a
142138

143139

144140
-- | Create a new unique function name. To prevent possible name clashes, digits
145141
-- are stripped from the given suffix.
146-
newUniqueFunctionName :: Neovim r st FunctionName
142+
newUniqueFunctionName :: Neovim env FunctionName
147143
newUniqueFunctionName = do
148144
tu <- asks' uniqueCounter
149145
-- reverseing the integer string should distribute the first character more
@@ -200,7 +196,7 @@ mkFunctionMap = Map.fromList . map (\e -> (name (fst e), e))
200196
--
201197
-- Note that you most probably do not want to change the fields prefixed with an
202198
-- underscore.
203-
data Config r st = Config
199+
data Config env = Config
204200
-- Global settings; initialized once
205201
{ eventQueue :: TQueue SomeMessage
206202
-- ^ A queue of messages that the event handler will propagate to
@@ -229,11 +225,11 @@ data Config r st = Config
229225
-- it's appropriate targets.
230226

231227
-- Local settings; intialized for each stateful component
232-
, pluginSettings :: Maybe (PluginSettings r st)
228+
, pluginSettings :: Maybe (PluginSettings env)
233229
-- ^ In a registered functionality this field contains a function (and
234230
-- possibly some context dependent values) to register new functionality.
235231

236-
, customConfig :: r
232+
, customConfig :: env
237233
-- ^ Plugin author supplyable custom configuration. Queried on the
238234
-- user-facing side with 'ask' or 'asks'.
239235
}
@@ -243,38 +239,38 @@ data Config r st = Config
243239
-- config.
244240
--
245241
-- Sets the 'pluginSettings' field to 'Nothing'.
246-
retypeConfig :: r -> st -> Config anotherR anotherSt -> Config r st
247-
retypeConfig r _ cfg = cfg { pluginSettings = Nothing, customConfig = r }
242+
retypeConfig :: env -> Config anotherEnv -> Config env
243+
retypeConfig r cfg = cfg { pluginSettings = Nothing, customConfig = r }
248244

249245

250246
-- | This GADT is used to share information between stateless and stateful
251247
-- plugin threads since they work fundamentally in the same way. They both
252248
-- contain a function to register some functionality in the plugin provider
253249
-- as well as some values which are specific to the one or the other context.
254-
data PluginSettings r st where
250+
data PluginSettings env where
255251
StatelessSettings
256252
:: (FunctionalityDescription
257253
-> ([Object] -> Neovim' Object)
258254
-> Neovim' (Maybe FunctionMapEntry))
259-
-> PluginSettings () ()
255+
-> PluginSettings ()
260256

261257
StatefulSettings
262258
:: (FunctionalityDescription
263-
-> ([Object] -> Neovim r st Object)
259+
-> ([Object] -> Neovim env Object)
264260
-> TQueue SomeMessage
265-
-> TVar (Map FunctionName ([Object] -> Neovim r st Object))
266-
-> Neovim r st (Maybe FunctionMapEntry))
261+
-> TVar (Map FunctionName ([Object] -> Neovim env Object))
262+
-> Neovim env (Maybe FunctionMapEntry))
267263
-> TQueue SomeMessage
268-
-> TVar (Map FunctionName ([Object] -> Neovim r st Object))
269-
-> PluginSettings r st
264+
-> TVar (Map FunctionName ([Object] -> Neovim env Object))
265+
-> PluginSettings env
270266

271267

272268
-- | Create a new 'InternalConfig' object by providing the minimal amount of
273269
-- necessary information.
274270
--
275271
-- This function should only be called once per /nvim-hs/ session since the
276272
-- arguments are shared across processes.
277-
newConfig :: IO (Maybe String) -> IO r -> IO (Config r context)
273+
newConfig :: IO (Maybe String) -> IO env -> IO (Config env)
278274
newConfig ioProviderName r = Config
279275
<$> newTQueueIO
280276
<*> newEmptyMVar

0 commit comments

Comments
 (0)