nvim-hs
Haskell plugin backend for neovim
https://github.com/neovimhaskell/nvim-hs
LTS Haskell 23.1: | 2.3.2.3@rev:1 |
Stackage Nightly 2024-12-27: | 2.3.2.3@rev:1 |
Latest on Hackage: | 2.3.2.3@rev:1 |
nvim-hs-2.3.2.3@sha256:461af7e2a809eab28afdd3235006ec18f7c461a71b8117d078da10f460e1558c,6764
Module documentation for 2.3.2.3
- Neovim
- Neovim.API
- Neovim.Classes
- Neovim.Compat
- Neovim.Config
- Neovim.Context
- Neovim.Debug
- Neovim.Exceptions
- Neovim.Log
- Neovim.Main
- Neovim.OS
- Neovim.Plugin
- Neovim.Quickfix
- Neovim.RPC
- Neovim.Test
- Neovim.Util
nvim-hs
Neovim API for Haskell plugins as well as a plugin provider. This library and executable should provide a basis for developing plugins. This package should only contain broadly useful interfaces to write plugins for Neovim in haskell. The design goal is to create an easy to use API that avoids most of the boilerplate while still retaining some sense of reliability and type safety. Since Template Haskell is used to generate the neovim bindings and to avoid some of the boilerplate handy work, some exotic operating systems and architectures may not work.
What do I have to expect if I were to use it now?
Check the issue list here on github.
For Windows users
Named pipes are not supported at the momend #103. You therefore have to start
nvim-hs
instances by connecting to STDIN and STDOUT or TCP. By default nvim-hs
connects to the listen socket pointed to by the NVIM
environment variable and
the functions in the module Neovim.Debug
rely on that. If you want to be able to
run these functions, start Neovim with nvim --listen localhost:
or similar
(This example command starts neovim with a socket listening on localhost
and
random a random TCP port.)
How do I start using this?
You need to install nvim-hs.vim
, a plugin that manages starting of nvim-hs
plugins.
To do that, just follow the instructions outlined here.
Once you have installed nvim-hs.vim
, you can use nvim-hs
plugins as you would
normal vim plugins. Note that every plugin you install is started as a separate process,
which should be fine unless you have a lot of them.
Scripting with Haskell
The entry point for all Haskell-based scripts is a plugin.
An nvim-hs
plugin is a plain Haskell project with two conventions:
-
You need an executable that starts a
msgpack-rpc
compatible client. -
You need a tiny bit of
vimL
in your runtime path that starts the plugin.
The simplest way to get started is using the stack template from this
repository/package inside your Neovim configuration folder, but you can also
manually create a project by doing everything that is explained in :help nvim-hs.txt
(which should be available if you installed nvim-hs.vim
as mentioned in the previous section).
To use that template, you’ll first need to install stack
and have the Neovim executable on the path (the API code generation calls nvim --api-info
so it needs access to nvim
).
After you’ve done that, you can run these commands to setup the template (assuming your Neovim configuration folder
is in $XDG_CONFIG_HOME/nvim
):
$ cd $XDG_CONFIG_HOME/nvim
$ stack new my-nvim-hs \
https://raw.githubusercontent.com/neovimhaskell/nvim-hs/master/stack-template.hsfiles \
--bare --omit-packages --ignore-subdirs
If you start Neovim now, it will compile the example plugins which may take a
few minutes. Once it is started you can use the predefined functions from the
template, for example by running :echo NextRandom()
, which should print a random number.
To start writing your own functions and plugins, read through the files generated by the template and also check out the library documentation on hackage.
Contributing
Documentation, typo fixes, and the like will almost always be merged.
If you want to bring forward new features or convenience libraries
for interacting with Neovim, you should create an issue first. The features
of this (cabal) project should be kept small as this helps
reduce the development time. (For some tests it is
necessary to issue cabal install
, so any change to to a module can
significantly increase the compilation time.)
If your idea solves a general problem, feel free to open an issue in the
library project of nvim-hs
,
nvim-hs-contrib
.
Changes
2.3.1.0
- Add
subscribe
andunsubscribe
function. Neovim doesn’t automatically send event notifications to nvim-hs (or any other remote plugin) and for the callback of thesubscribe
funtion to trigger, you have to call a specific function before (e.g.nvim_buf_attach
). In any case, if you want to subscribe to a specific event, you have to read the documentation of the neovim documentation. Some events are still better handled with autocommands.
2.3.0.0
- Windows is now rudimentarily supported. Since I couldn’t find a library to
connect to named pipes on windows and I didn’t want to extend or write one,
you have to use TCP sockets or Standard in and out to communicate with
neovim. If you start neovim with
nvim --listen localhost:
, it will set theNVIM
environment variable, so that nvim-hs can automatically connect to the neovim instance without passing any arguments.
2.2.0.0
- NeovimException are now thrown from (synchronous) remote functions and are no
longer suppressed with an
error
call that also had a terrible error message. A functioncatchNeovimException
(specializedcatch
) has been added that catches these errors. - The return type of asynchronous functions is now alwas
STM (Either NeovimException result)
and errors have to be handled by the caller explicitly.
2.1.0.2
- Exported functions and commands now can have the same name.
2.1.0.0
- Autocommands now take an additional parameter of type
Synchronous
, allowing them to execute synchronous (previously hardcoded asAsync
). In order to adapt to this, change$(autocmd 'handler) opts
to$(autocmd 'handler) Async opts
.
2.0.0.0
-
Your configuration is now just a Haskell project. The dependency to Dyre has been removed and you are now forced to write a line of vimL and add a normal nvim-plugin to your setup. The template still does set everything up for you. The distinction between a plugin and a personal nvim-hs configuration is now gone and apart from settings things up, nothing has changed in this regard. The nvim-plugin contains the necessary documentation on what to do and should be available with
:help nvim-hs
when installed correctly. -
Since basically all generated functions were throwing exceptions anyway, the primed functions have become the default and if you want to explicitly handle error cases, you have to surround your code with
catch
or something more appropriate fromUnliftIO.Exception
. You have to remove'
from your API calls or you have to adjust your error handling. -
There are now three flavors of APIs and you have to import one additionally to importing the
Neovim
module:-
Neovim.API.Text: This uses strict
Text
for strings andVector
as lists. This is the recommended API to use. -
Neovim.API.String: This is the same as before. Strings are
String
and lists are[]
. This is for the lazy and backwards-ish compatiblity. -
Neovim.API.ByteString: This can be useful for really performance critical stuff or if you`re writing a plugin for binary files.
-
1.0.1.0
- The
Neovim.Debug
module is now more pleasant to use.
1.0.0.2
- With the api of neovim 0.3.0, a function was exposed that had a reserved haskell keyword as a parameter name. The code generation did not sanitize this. This bugfix releases resolves this.
1.0.0.0
-
Each plugin (type) now defines an environment which is similar to how stateful plugins have been declared in previous versions. If you need multiple different environments for different functions, you can make them fields of a bigger environment or define multiple plugin values.
The type
Neovim r st a
has becomeNeovim env a
whereenv
is technically equivalent to the previousr
. I was mainly motivated by this blog post:https://www.fpcomplete.com/blog/2017/06/readert-design-pattern
-
Only works with ghc >= 8. I removed some backwards compatibility. If you need older ghc versions, just use the previous version (0.2.5) as the feature set hasn’t really changed.
-
A different pretty printer library is now used and may surface at some places.
-
Functions do now time out after some time, 10 seconds for those that block neovim and 10 minutes for background functions.
-
A few types have been adjusted.
-
Some improvement in error reporting.
0.2.5
- Older versions of
nvim-hs
may not function if some versions of a dependency are used. This version has proper bounds for the dependency and should cause a compile time failure if an incompatible version of the dependency is used (see #61).
0.2.0
-
Replace error code of remote functions to return
Either NeovimException a
instead of a generic messagepackObject
-
Export API functions that throw a
NeovimException
instead of returningEither NeovimExeception a
. -
Replace three element tuple for stateful function declaration (#53)
-
Add a stack template for easier setup
-
Exceptions from pure code are now caught (#48)
0.1.0
-
Adjust parser for output of
nvim --api-info
-
Adjust parser of ConfigHelper plugin
0.0.7
- Adjust handling of string sent by neovim in API generation.
0.0.6
-
Noteworthy new API functions for the user’s convenience:
errOnInvalidResult
(:+)
-
ansi-wl-pprint is used for pretty printing of various things now. Most notably, the error type has been changed from
String
toDoc
. This is a breaking change, but it was kind of announced in the issues list. In any case, uses oferr
can be fixed by enabling theOverloadedStrings
extension. Other breakages have to be fixed by hand.
0.0.5
-
Documentation received some love.
-
A few renames of repurposed internals.
0.0.3
-
Debugging facilities for ghci have been added. Check out the
Neovim.Debug
module! These few functions are very valuable to debug your code or even the code of nvim-hs itself. -
Startup code now has a special
Neovim
environment which has access to some of the internals that may or may not be useful. This change allowed the ConfigHelper plugin to be included as a normal, separable plugin. Unfortunately, this potentially breaks the plugin startup code of some existing plugins. -
Neovim context is no longer a type synonym, but a newtype wrapper around the previous type synonym with an added
ResourceT
wrapper. The functions fromMonadReader
are now actually exported as those.As a consequence, some of your code may break if you lack some specific instances which were auto-derived before. Send a PR or open a ticket to resolve this.
-
Add handling for some kind of variadic arguments handling.
A command or function will be passed
Nothing
as it’s last arguments if the argument type is wrapped inMaybe
and the invocation on the side of neovim did not pass those arguments.
0.0.2
-
Add handling for special command options
This breaks code that used
command
orcommand'
to export functionality. You should replace the options with a list ofCommandOptions
.An export like
$(command' foo) def { cmdSync = Async }
must be redefined to$(command' foo) [CmdSync Async]
.
0.0.1
- Usable prototype implementation