Introduction#
I have been using Vim-airline for a while to customize my statusline. We can change the theme used for statusline with the many themes available in vim-airline-themes. Not all these themes looks good since it depends on the background color you use for Neovim and certainly your aesthetics.
I only use a handful of themes myself and I change my themes when I feel bored with one theme. It occurs to me that I can write a simple script to randomly pick a theme from my favorite list1. It turns out writing such a script is not easy for Neovim newbies like me.
In this post, I would like to share how I end up achieving what I want by mixing Vim script and Python script.
Prerequisite#
This post is specifically targeted at Neovim users so that some of the settings may not apply if you use Vim.
First, you need to install Python and Python 3 is preferable since Python 2
support will stop in 2020. Make sure that you
can call python
from the command line. When you start Neovim and :echo has('python3')
will print 1
in the command line.
You should also install pynvim, which is the Python client and plugin host for Neovim. You can install it with pip:
pip install pynvim
Finally, you should set the variable g:python3_host_prog
to the location of
Python executable. If your Python executable path is ~/anaconda3/bin/python
,
you should add the following setting in your init.vim
:
let g:python3_host_prog=expand('~/anaconda3/bin/python')
After that, open Neovim and run :checkhealth provider
and make sure there is
no error in the part about Python 3. A sample output is shown below:
## Python 3 provider (optional)
- INFO: Using: g:python3_host_prog = "D:/Anaconda/python"
- INFO: Executable: D:\Anaconda\python
- INFO: Python version: 3.6.5
- INFO: pynvim version: 0.3.2
- OK: Latest pynvim is installed.
Pick a random airline theme#
Generate a random number in the given range#
To pick a random theme from my favorite themes, I need to create a function which return a random index of the theme given the lowest and highest index. First, I will show my final function and then I will explain it bit by bit.
Click to see the function.
" generate a random integer from range [Low, High] using Python
function! RandInt(Low, High) abort
" if you use Python 3, the python block should start with `python3` instead of
" `python`, see https://github.com/neovim/neovim/issues/9927
python3 << EOF
import vim
import random
# using vim.eval to import variable outside Python script to python
idx = random.randint(int(vim.eval('a:Low')), int(vim.eval('a:High')))
# using vim.command to export variable inside Python script to vim script so
# we can return its value in vim script
vim.command("let index = {}".format(idx))
EOF
return index
endfunction
In the above function RandInt()
, we define a function which accept two
parameter Low
and High
. We generate a random integer between in the range
$[Low, High]$ using the Python package
random
and return the index.
The format for Python script is as follows:
python[3] << MARKER
# python code here
MARKER
If you use Python 2, you should use python
keyword, otherwise use python3
,
which is explained here. To
manipulate Neovim inside Python script, we need to import package vim
.
To get the value of Vim variable Low
and High
inside Python script, we need
to import them. vim.eval()
2 is used to get their value, which is used to
evaluate the expression using built-in expression evaluator. According to
documentation, the return value is:
- a string if the Vim expression evaluates to a string or number
So we need to use int()
to convert the return value to integer.
After we get the value of idx
, how do we use it outside the Python script? We
can use vim.command()
to achieve that:
vim.command("let index = {}".format(idx))
vim.command(str)
will execute str
as Vim command, thus assigning the value
of idx
to Vim variable index
.
Pick a airline theme#
Now we can define a list of themes to pick and generate a random index and set the airline theme using the theme at the index. An example code is shown below:
let s:candidate_airlinetheme = ['alduin', 'ayu_mirage', 'base16_flat',
\ 'monochrome', 'base16_grayscale', 'lucius', 'base16_tomorrow',
\ 'base16color', 'biogoo', 'distinguished', 'gruvbox', 'jellybeans',
\ 'luna', 'raven', 'seagull', 'solarized_flood', 'term', 'vice', 'zenburn']
let s:idx = RandInt(0, len(s:candidate_airlinetheme)-1)
let s:theme = s:candidate_airlinetheme[s:idx]
let g:airline_theme=s:theme
In the above script, len()
is used to get the length of a list.
Conclusion#
In this post, I introduced how to mix Python script with Vim script.
Specifically, I write a simple function to generate a random index and then
pick a airline theme based on the index. I have just scratched the surface of
the powerful ability of Python programming inside Vim. For more information,
see :h python
.
References#
- Hack vim with Python.
- python or python3 in script.
- Export value from Python to Vim.
- Can I script vim using Python.
- Import vim variable to Python script.
Note that vim-airline provides a command
AirlineTheme random
to pick a random theme, but you cannot set the list of color themes you want to use. ↩︎See
:h python-eval
for detailed documentation. ↩︎