I am a big user of Vim and Neovim. I probably don't know all the bindings and all the magic inside, but I use it daily and it has become one of my favorite app.
But today, we are going to take one step further: writing a plugin!
We use Splunk at work a data-driven cloud app which has its own query language. Writing queries for Splunk can get cumbersome especially when they are starting to become larger and larger and you get lost in the amount of parenthesizes.
The solution I found was to write a small python script that would indent and separate the different blocks allowing a more convenient way to read the queries.
What about making it a Neovim plugin? As Neovim has a python interface, it should work right? Spoiler: yes.
Let's dive in!
First, we need to set a couple of things up. Python binaries must be in your shell PATH (you can check that with
As you can see here, the python binaries are missing from the PATH and Neovim cannot run anything with it. So let's add those lines in our
let g:python3_host_prog = '/usr/bin/python3' let g:python_host_prog = '/usr/bin/python2'
Alternatively you could add the binaries to you path:
And check it with
Then check that you have both version of
pynvim, the python Neovim library:
python3 -m pip install pynvim python -m pip install pynvim
After that we can start setting up our repository and our folders:
# do your git magic here mkdir -p rplugin/python touch rplugin/python/nvim-test.py
According to the documentation, remote plugins are the new way to do things so we're going to follow that.
Let's look into
nvim-test.py and get some inspiration from this Jacob Simpson's example:
import pynvim @pynvim.plugin class TestPlugin(object): def _init__(self, nvim): self.nvim = nvim @pynvim.function("TestFunction") def testFunction(self, args): self.nvim.current.line = "Hello from your plugin!"
Breaking up the code:
- We initialize the class and the subclass
- We create a function that will overwrite the current line
To test this, you could update your plugin on a git instance and update the plugins form your
init.vim. But... you could also use a test
echo "let &runtimepath.=','.escape(expand('<sfile>:p:h'), '\,')" > testvimrc
nvim -u testvimrc and run
:UpdateRemotePlugins this will register you plugin as a remote plugin and generate the manifest. Check that with:
cat ~/.local/share/nvim/rplugin.vim, the file should not be empty and you should see your plugin there.
Now, running after reloading Neovim,
:call TestFunction() should normally work and you can test your work. I think that so far you need to reboot Neovim every time you update the remove plugins, but maybe there's a way to bypass that.
Now for the work I did:
import re import pynvim @pynvim.plugin class SplunkLinter(object): def __init__(self, nvim): self.nvim = nvim @pynvim.function("LintSplunk") def lintSplunk(self, args): current_line = self.nvim.current.line front = current_line.split("(") i = 0 j = 0 res = "" for line in front: p = "" if j != 0: p = "(" back = re.findall("\)", line) line = ((i) * "\t") + p + line self.nvim.current.buffer.append(line, -1) if len(back) == 0: i = i + 1 elif len(back) > 1: i = i - len(back) if i < 0: i = 0 j = j + 1 self.nvim.current.line = "" return
Before you say anything, I know this can be improved. Basically this code is going to indent a string based on the level of parenthesizes that it contains. It's basically what I need and it does the job!
test (on) (one) (one (two (three))) (one) ((two)) # to test (on) (one) (one (two (three))) (one) ( (two))
The Github repo is here: https://github.com/christalib/nvim-splunk-linter, feel free to open issues, PR's and such!
Have you already developed a plugin for Neovim or Vim? How did you do it?