Enhance your Neovim with Fennel
Last update: 07/31/2023
Back to home
Back to Posts
This is a report about my experience using the
nfnl plugin by Oliver Caldwell to
create a plugin for Neovim. nfnl
allows me to use Fennel instead of
Vimscript (VimL). Many thanks, Oliver!
Of course, this won't work with Vim because we're using Fennel compiled to Lua to make Neovim behave the way we want it to. Neovim understands both VimL and Lua. Nice!
Truth in advertising:
You will need to learn some Vimscript and Lua and how to script Vim when you venture into writing plugins or setting up configurations. So many ways of doing things. It hard to keep things straight and know when to use what for the problem you're trying to solve.
Set Up For A Plugin
For this example, we'll use my-plugin
as the plugin name.
Install the nfnl plugin and restart Neovim.
Create project directory and switch to it.
$ mkdir my-plugin $ cd my-plugin
Add these subdirectories:
- fnl/my-plugin/
- lua/my-plugin/
- plugin/
$ mkdir -p lua/my-plugin fnl/my-plugin plugin
Add this configuration to
.nfnl.fnl
at the top of the project directory.{:source-file-patterns ["fnl/**/*.fnl"]}
This configuration will keep the .fnl and .lua files in separate directories using a parallel directory structure. If you don't mind them being in the same directory, then don't use separate directories and just put
{}
in your.nfnl.fnl
file.
Add The Code
For this example, we'll assume all the hard work of figuring out what to implement in code is done.
Create
plugin/my-plugin.vim
with this inside:if has("nvim") lua require("my-plugin.main").init() endif
When this plugin loads, it will cause the
init
function in main.lua to be run. A deeper explanation of this is beyond this report. See:he write-plugin
for more about writing plugins.Create
fnl/my-plugin/main.fnl
with this inside:(local {: autoload} (require :nfnl.module)) (local core (autoload :nfnl.core)) (local mod {}) (local msg "Tears began to fall from my-plugin! -- Frank Z made me do it.") (fn mod.init [] (print "This is msg:" msg) (print " Now just a part of it: >" (string.sub msg 5) "<")) mod
Alternative to using a local mod variable:
(local {: autoload} (require :nfnl.module)) (local core (autoload :nfnl.core)) (local msg "Tears began to fall from my-plugin! -- Frank Z made me do it.") (fn init [] (print "This is msg:" msg) (print " Now just a part of it: >" (string.sub msg 5) "<")) {: init} ;; Export only these functions. The rest are "local".
Compile The Fennel Code
Just save your Fennel file. That's it!
nfnl
will recognize your .nfnl.fnl
file and take it from there.
The first time that you save the first Fennel file, nfnl
will
prompt you to confirm that it is OK to proceed. You'll see something like this in
the command output area.
.../my-plugin/.nfnl.fnl is not trusted.
[i]gnore, (v)iew, (d)eny, (a)llow: a
You will only need to have the nfnl.fnl
file in the top level directory of
your project. The confirmation question will only be asked the first time that
you save a Fennel file anywhere under your project directory.
The project directory structure looks like this:
├── .nfnl.fnl
├── fnl
│ └── my-plugin
│ └── main.fnl
├── lua
│ └── my-plugin
│ └── main.lua
└── plugin
└── my-plugin.vim
Install Your Plugin
So now that everything is working, we add the my-plugin
plugin to our Neovim
configuration. This will depend on which plugin manager you use.
Testing The Plugin
When you start Neovim without any arguments, you should see this message appear below the status line:
This is msg: Tears began to fall from my-plugin! -- Frank Z made me do it.
Now just a part of it: > s began to fall from my-plugin! -- Frank Z made me do it. <
This is confirmation that the plugin is being loaded and called successfully. Hello, world!
Retrospective
It was much easier to create the plugin using nfnl
compared to Aniseed
.
There's less setup and things to do to get things to work.
I recommend using this as just one way to start to create plugins.
It all appears so easy now but the truth is I fumbled around a lot before things came together. I tried setting up a plugin using Oliver's Aniseed. That experience of getting the equivalent of a Hello, world! program running was used here.
The Good News :-)
The plugin's author quickly responded to my problem with the plugin not
automatically compiling a Fennel file. I was using
Packer and some unknown reason
(probably my unfamiliarity with Fennel, Lua, and Aniseed) the FileType
autocmd wasn't created for nfnl
. That's not a problem any more and things
just work.