Skip to content

Commit 71ced08

Browse files
committed
Update Documentation in Neovim module
1 parent eeca57f commit 71ced08

File tree

1 file changed

+63
-44
lines changed

1 file changed

+63
-44
lines changed

library/Neovim.hs

Lines changed: 63 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ of this package. It is also on the repositories front page.
146146
If you are proficient with Haskell, it may be sufficient to point you at some of the
147147
important data structures and functions. So, I will do it here. If you need more
148148
assistance, please skip to the next section and follow the links for functions or data
149-
types you do no understand how to use. If you think that the documentation is lacking,
149+
types you do not understand how to use. If you think that the documentation is lacking,
150150
please create an issue on github (or even better, a pull request with a fix @;-)@).
151151
The code sections that describe new functionality are followed by the source code
152152
documentation of the used functions (and possibly a few more).
@@ -249,7 +249,7 @@ module Fibonacci.Plugin (fibonacci) where
249249
import "Neovim"
250250
251251
\-\- \| Neovim is not really good with big numbers, so we return a 'String' here.
252-
fibonacci :: 'Int' -> 'Neovim'' 'String'
252+
fibonacci :: 'Int' -> 'Neovim' env 'String'
253253
fibonacci n = 'return' . 'show' \$ fibs !! n
254254
where
255255
fibs :: [Integer]
@@ -267,8 +267,8 @@ import Fibonacci.Plugin (fibonacci)
267267
268268
plugin :: 'Neovim' ('StartupConfig' 'NeovimConfig') () 'NeovimPlugin'
269269
plugin = 'wrapPlugin' Plugin
270-
{ 'exports' = [ $('function'' 'fibonacci) 'Sync' ]
271-
, 'statefulExports' = []
270+
{ 'environment' = ()
271+
, 'exports' = [ $('function'' 'fibonacci) 'Sync' ]
272272
}
273273
@
274274
@@ -289,35 +289,27 @@ Let's analyze how it works. The module @Fibonacci.Plugin@ simply defines a funct
289289
that takes the @n@th element of the infinite list of Fibonacci numbers. Even though
290290
the definition is very concise and asthetically pleasing, the important part is the
291291
type signature for @fibonacci@. Similarly how @main :: IO ()@ works in normal Haskell
292-
programs, 'Neovim'' is the environment we need for plugins. Internally, it stores a
292+
programs, 'Neovim' is the environment we need for plugins. Internally, it stores a
293293
few things that are needed to communicate with neovim, but that shouldn't bother you
294294
too much. Simply remember that every plugin function must have a function signature
295-
whose last element is of type @'Neovim' r st something@. The result of @fibonacci@
295+
whose last element is of type @'Neovim' env something@. The result of @fibonacci@
296296
is 'String' because neovim cannot handle big numbers so well. :-)
297297
You can use any argument or result type as long as it is an instance of 'NvimObject'.
298298
299299
The second part of of the puzzle, which is the definition of @plugin@
300-
in @~\/.config\/nvim\/lib\/Fibonacci.hs@, shows what a plugin is. It is essentially two
301-
lists of stateless and stateful functionality. A functionality can currently be one
302-
of three things: a function, a command and an autocmd in the context of vim
303-
terminology. In the end, all of those functionalities map to a function at the side
300+
in @~\/.config\/nvim\/lib\/Fibonacci.hs@, shows what a plugin is. It is essentially
301+
an environment that and a list of functions, commands or autocommands in the context of vim
302+
terminology. In the end, all of those things map to a function at the side
304303
of /nvim-hs/. If you really want to know what the distinction between those is, you
305304
have to consult the @:help@ pages of neovim (e.g. @:help :function@, @:help :command@
306-
and @:help :autocmd@). What's relevant from the side of /nvim-hs/ is the distinction
307-
between __stateful__ and __stateless__. A stateless function can be called at any
308-
time and it does not share any of its internals with other functions. A stateful
309-
function on the other hand can share a well-defined amount of state with other
310-
functions and in the next section I will show you a simple example for that.
311-
Anyhow, if you take a look at the type alias for 'Neovim', you notice the two
312-
type variables @r@ and @st@. These can be accessed with different semantics
313-
each. A value of type @r@ can only be read. It is more or less a static value
314-
you can query with 'ask' or 'asks' if you
315-
are inside a 'Neovim' environment. The value @st@ can be changed and those
316-
changes will be available to other functions which run in the same environment.
317-
You can get the current value with 'get', you can replace an existing value with
318-
'put' and you can also apply a function to the current state with 'modify'.
319-
Notice how 'Neovim'' is just a specialization of 'Neovim' with its @r@ and
320-
@st@ set to @()@.
305+
and @:help :autocmd@). What's relevant from the side of /nvim-hs/ is the environment.
306+
The environment is a data type that is avaiable to all exported functions of your
307+
plugin. This example does not make use of anything of that environment, so
308+
we used '()', also known as unit, as our environment. The definition of
309+
@fibonacci@ uses a type variable @env@ as it does not access the environment and
310+
can handly any environment. If you want to access the environment, you can call
311+
'ask' or 'asks' if you are inside a 'Neovim' environment. An example that shows
312+
you how to use it can be found in a later chapter.
321313
322314
Now to the magical part: @\$('function'' 'fibonacci)@. This is a so called
323315
Template Haskell splice and this is why you need
@@ -364,15 +356,47 @@ module Random.Plugin (nextRandom, setNextRandom) where
364356
365357
import "Neovim"
366358
367-
\-\- | Neovim isn't so good with big numbers here either.
368-
nextRandom :: 'Neovim' r ['Int16'] 'Int16'
359+
import System.Random (newStdGen, randoms)
360+
import UnliftIO.STM (TVar, atomically, readTVar, modifyTVar, newTVarIO)
361+
362+
-- You may want to define a type alias for your plugin, so that if you change
363+
-- your environment, you don't have to change all type signatures.
364+
--
365+
-- If I were to write a real plugin, I would probably also create a data type
366+
-- instead of directly using a TVar here.
367+
--
368+
type MyNeovim a = Neovim ('TVar' ['Int16']) a
369+
370+
-- This function will create an initial environment for our random number
371+
-- generator. Note that the return type is the type of our environment.
372+
randomNumbers :: Neovim startupEnv (TVar [Int16])
373+
randomNumbers = do
374+
g <- liftIO newStdGen -- Create a new seed for a pseudo random number generator
375+
newTVarIO (randoms g) -- Put an infinite list of random numbers into a TVar
376+
377+
-- | Get the next random number and update the state of the list.
378+
nextRandom :: MyNeovim 'Int16'
369379
nextRandom = do
370-
r <- 'gets' 'head' -- get the head of the infinite random number list
371-
'modify' 'tail' -- set the list to its tail
372-
'return' r
380+
tVarWithRandomNumbers <- 'ask'
381+
atomically $ do
382+
-- pick the head of our list of random numbers
383+
r <- 'head' <$> 'readTVar' tVarWithRandomNumbers
384+
385+
-- Since we do not want to return the same number all over the place
386+
-- remove the head of our list of random numbers
387+
modifyTVar tVarWithRandomNumbers 'tail'
388+
389+
'return' r
390+
391+
392+
-- | You probably don't want this in a random number generator, but this shows
393+
-- hoy you can edit the state of a stateful plugin.
394+
setNextRandom :: 'Int16' -> MyNeovim ()
395+
setNextRandom n = do
396+
tVarWithRandomNumbers <- 'ask'
373397
374-
setNextRandom :: 'Int16' -> 'Neovim' r ['Int16'] ()
375-
setNextRandom n = 'modify' (n:) -- cons to the front of the infinite list
398+
-- cons n to the front of the infinite list
399+
atomically $ modifyTVar tVarWithRandomNumbers (n:)
376400
@
377401
378402
File @~\/.config\/nvim\/lib\/Random.hs@:
@@ -387,18 +411,13 @@ import "System.Random" ('newStdGen', 'randoms')
387411
388412
plugin :: 'Neovim' ('StartupConfig' 'NeovimConfig') () 'NeovimPlugin'
389413
plugin = do
390-
g <- 'liftIO' 'newStdGen' -- initialize with a random seed
391-
let randomNumbers = 'randoms' g -- an infinite list of random numbers
414+
env <- randomNumbers
392415
'wrapPlugin' 'Plugin'
393-
{ 'exports' = []
394-
, 'statefulExports' = [ 'StatefulFunctionality'
395-
{ readOnly = ()
396-
, writable = randomNumbers
397-
, functionalities =
398-
[ $('function'' 'nextRandom) 'Sync'
399-
, $('function' \"SetNextRandom\" 'setNextRandom) 'Async'
400-
]
401-
}]
416+
{ environment = env
417+
, 'exports' =
418+
[ $('function'' 'nextRandom) 'Sync'
419+
, $('function' \"SetNextRandom\" 'setNextRandom) 'Async'
420+
]
402421
}
403422
@
404423
@@ -452,7 +471,7 @@ getting some abstract 'Buffer' object, test whether it is valid and then try
452471
to rename it.
453472
454473
@
455-
inspectBuffer :: 'Neovim' r st ()
474+
inspectBuffer :: 'Neovim' env ()
456475
inspectBuffer = do
457476
cb <- 'vim_get_current_buffer'
458477
isValid <- 'buffer_is_valid' cb

0 commit comments

Comments
 (0)