@@ -22,9 +22,10 @@ executable my-nvim-hs
2222 , Neovim.Example.Plugin.Fibonacci
2323 , Neovim.Example.Plugin.Random
2424 build-depends: base >= 4.7 && < 5
25- , nvim-hs >= 0.2.5 && < 1.0.0
26- -- The dependency below is only needed for the example plugin
25+ , nvim-hs >= 1 && < 2
26+ -- The dependencies below are only needed for the example plugin
2727 , random
28+ , unliftio
2829 default-language: Haskell2010
2930
3031{-# START_FILE lib/Neovim/Example/Plugin.hs #-}
@@ -40,29 +41,24 @@ import Neovim
4041import Neovim.Example.Plugin.Random (nextRandom, setNextRandom, randomNumbers)
4142import Neovim.Example.Plugin.Fibonacci (fibonacci)
4243
43- plugin :: Neovim (StartupConfig NeovimConfig) () NeovimPlugin
44+ plugin :: Neovim (StartupConfig NeovimConfig) NeovimPlugin
4445plugin = do
4546 randomPluginState <- randomNumbers
4647 wrapPlugin Plugin
47- { exports =
48+ { environment = randomPluginState
49+ , exports =
4850 [ $(function' 'fibonacci) Sync
4951 -- Notice the quotation mark before the functin name, this is
5052 -- important!
51- ]
52- , statefulExports =
53- [ StatefulFunctionality
54- { readOnly = ()
55- , writable = randomPluginState
56- , functionalities =
57- [ $(function' 'nextRandom) Sync
58- , $(function "SetNextRandom" 'setNextRandom) Async
59- ]
60- }
53+
54+ , $(function' 'nextRandom) Sync
55+ , $(function "SetNextRandom" 'setNextRandom) Async
6156 ]
6257 }
6358
6459{-# START_FILE lib/Neovim/Example/Plugin/Random.hs #-}
6560{-# LANGUAGE TemplateHaskell #-}
61+ {-# LANGUAGE TemplateHaskell #-}
6662module Neovim.Example.Plugin.Random
6763 ( nextRandom
6864 , setNextRandom
@@ -71,45 +67,50 @@ module Neovim.Example.Plugin.Random
7167
7268import Neovim
7369import System.Random (newStdGen, randoms)
70+ import UnliftIO.STM (TVar, atomically, readTVar, modifyTVar, newTVarIO)
7471
75- -- | This is the start up code. It initializes the random number generator and
76- -- returns a convenient list of random numbers.
77- --
78- -- Except for the last @[Int16]@ return values, this type signature is mandatory
79- -- for your startup code. The internals of the plugin recompilation leak here a
80- -- bit, it might be changed in the future. If you don't mind warnings, you can
81- -- leave the signature undefined, but then you would have to add a type
82- -- signature to the value of @randoms g@.
72+ -- | This type alias encodes the type of your plugin's environment, namely
73+ -- '(TVar [Int16)' in this case.
8374--
84- -- See <https://github.com/neovimhaskell/nvim-hs/issues/13> for details.
75+ -- Since this plugin needs to store some state, we have to put it in a mutable
76+ -- variable. I chose TVar here because I like the Software Transactional Memory
77+ -- library.
78+ type MyNeovim a = Neovim (TVar [Int16]) a
79+
80+ -- | This is the start up code. It initializes the random number generator and
81+ -- returns a convenient list of random numbers. It returns the environment and
82+ -- is executed in the startup code, so this is the only place where you can't
83+ -- use the type alias defined above.
8584--
8685-- Neovim isn't so good with big numbers, so limit to 16 bits.
87- randomNumbers :: Neovim (StartupConfig NeovimConfig) () [Int16]
86+ randomNumbers :: Neovim startupEnv (TVar [Int16])
8887randomNumbers = do
8988 g <- liftIO newStdGen -- Create a new seed for a pseudo random number generator
90- return (randoms g) -- Return an infinite list of random numbers
91-
92- -- You could write this shorter in more idiomatic Haskell:
93- -- randomNumbers = randoms <$> liftIO newStdGen
89+ newTVarIO (randoms g) -- Put an infinite list of random numbers into a TVar
9490
9591-- | Get the next random number and update the state of the list.
96- nextRandom :: Neovim r [Int16] Int16
92+ nextRandom :: MyNeovim Int16
9793nextRandom = do
98- r <- gets head -- get the head of the infinite random number list
99- modify tail -- set the list to its tail
100- return r
94+ tVarWithRandomNumbers <- ask
95+ atomically $ do
96+ -- pick the head of our list of random numbers
97+ r <- head <$> readTVar tVarWithRandomNumbers
98+
99+ -- Since we do not want to return the same number all over the place
100+ -- remove the head of our list of random numbers
101+ modifyTVar tVarWithRandomNumbers tail
102+
103+ return r
101104
102- -- An alternative equivalent implementation with pattern matching on the list
103- -- nextRandom :: Neovim r [Int16] Int16
104- -- nextRandom = do
105- -- (r:rs) <- get
106- -- put rs
107- -- return r
108105
109106-- | You probably don't want this in a random number generator, but this shows
110107-- hoy you can edit the state of a stateful plugin.
111- setNextRandom :: Int16 -> Neovim r [Int16] ()
112- setNextRandom n = modify (n:) -- cons n to the front of the infinite list
108+ setNextRandom :: Int16 -> MyNeovim ()
109+ setNextRandom n = do
110+ tVarWithRandomNumbers <- ask
111+
112+ -- cons n to the front of the infinite list
113+ atomically $ modifyTVar tVarWithRandomNumbers (n:)
113114
114115{-# START_FILE lib/Neovim/Example/Plugin/Fibonacci.hs #-}
115116module Neovim.Example.Plugin.Fibonacci
@@ -124,7 +125,7 @@ fibonacciNumbers = 0:fibs -- Since were using !! to index an element in a list,
124125 where fibs = 1:scanl1 (+) fibs
125126
126127-- | Neovim is not really good with big numbers, so we return a 'String' here.
127- fibonacci :: Int -> Neovim' String
128+ fibonacci :: Int -> Neovim env String
128129fibonacci n = return . show $ fibonacciNumbers !! n
129130
130131{-# START_FILE nvim.hs #-}
0 commit comments