1   Some preliminaries

Reference documentation on Python scripting in Nvim can be displayed inside Nvim with this: :help python.

Because I use NeoVim/Nvim, I refer to Nvim in what follows. However, I suspect that the instructions and examples I give below will work in Vim as well as Nvim.

The power of Python in Nvim -- Because you run Python code from your Python installation, you can import and use any of the modules available there. I what follows, I use nltk (the natural language toolkit for Python), but almost any installed module could be employed.

I mostly use Python3 from an Anaconda distribution (see https://anaconda.org/). But, in the following I'm using a virtual environment created with virtualenv and virtualenvwrapper (see https://pypi.org/project/virtualenv/ and https://pypi.org/project/virtualenvwrapper/).

2   Some "how-to" instructions

2.1   Specify your Python installation

Specify which Python installation on your machine that you want to use inside Nvim and specify the location of that Python installation. Put the location of the Python3 executable that you want to use in the variable g:python3_host_prog. Suggestion: do this in your .vimrc. The following example points at the Python3 executable in one of my virtual environments created with virtualenv and virtualenvwrapper:

let g:python3_host_prog = '/home/dkuhlman/Python/Envs/Env02/bin/python'

2.2   Call a Python function in Nvim


:py3 my_python_function()

2.3   Write some Python code

Include some Python code in a Vim source code file. This enables you to define Python functions that can be called from within Nvim. Surround (bracket) the code with Example:

" mycode.vim
py3 << EOF
[some python code]

See :help python-commands.

2.4   Execute some Nvim "normal" commands


vim.command('normal mn`<v`>y`n')

2.5   Get the value of an Nvim register


content = vim.eval('@@')
content = vim.eval('@a')

Note that "@@" refers to the default/unnamed register.

2.6   Map a Python function to an Nvim key combination

For example, map the function my_python_function to the key combination ",u" (note: in my .vimrc, the leader character is defined as the comma):

map <leader>u :py3 my_python_function()<cr>

3   Examples using nltk and textstat

3.1   Categorize words in a sentence and display tags

nltk (natural language toolkit) is an extremely rich and powerful body of python code that helps perform processing of several natural languages.

You can learn about nltk here: http://www.nltk.org. The nltk book is a good resource: http://www.nltk.org/book/.

Here is a example that prints out the tags (parts of speech) for each of the words in a sentence containing the cursor:

py3 << EOF
import nltk
from nltk.app.chunkparser_app import RegexpChunkApp

def show_tags_sentence(tagset=None, verbose=False):
    """Show tokens and tags for sentence containing the cursor.

    - tagset -- "universal" or None
    - verbose -- also display tag descriptions if True (default=False)
    # yank the sentence containing the cursor into the default register.
    vim.command('normal mn(v)hy`n')
    # get the contents of the default register.
    content = vim.eval('@@')
    text = nltk.word_tokenize(content)
    tags = nltk.pos_tag(text, tagset=tagset)
    if tagset is None and verbose:
        tagsetdefs = RegexpChunkApp.TAGSET
        for word, tag in tags:
            desc = tagsetdefs.get(tag)
            print('word: "{}" -- tag: {} ({})'.format(word, tag, desc))
        for word, tag in tags:
            print('word: "{}" -- tag: {}'.format(word, tag))

map <leader>z :py3 show_tags_sentence(tagset=None, verbose=True)<cr>


  • This code is in a .vim file that we are going to load with the, for example, following Nvim command :source examples01.vim.

  • We tell Nvim which parts of that file are Python code by bracketing those lines with py3 << EOF and EOF.

  • In order to retrieve the sentence containing the cursor, we use the following:

    vim.command('normal mn(v)hy`n')    # line 1
    content = vim.eval('@@')           # line 2

    The first line executes Nvim normal commands, i.e. the commands that we use when we're in normal mode in Nvim. These commands (1) save the cursor position in mark "n" ("mn"); (2) go to the beginning of the sentence containing the cursor ("("); (3) start character-wise visual mode to select characters ("v"); (4) go to the end of the sentence (")"); (5) go left one character ("h"); and (6) yank the selected text ("y").

    The second line retrieves the value of the default (unnamed) register, which now contains our selected text (the sentence).

  • Next we use nltk to break the sentence into tokens and then turn the tokens into a list of 2-tuples, each tuple containing a token and a tag. The tokens, by the way, are often words, but sometimes punctuation. You can learn more about "Categorizing and Tagging Words" here: http://www.nltk.org/book/ch05.html.

  • And, finally, we use the Python print function to display the tokens, tags, and (optionally) tag descriptions.

  • RegexpChunkApp.TAGSET is a Python dictionary from nltk that enables us to provide a small bit of description for each tag.

  • For convenience, we map a call to this Python function to ,z (comma is my leader character in Nvim; see :help leader.) Note that this mapping is Vim script, and so it's outside of our "EOF" Python brackets.

Here is a sample of the output:

This is the cheese that lay in the house
that Jack built.
word: "This" -- tag: DT (Determiner)
word: "is" -- tag: VBZ (Verb,3rd ps. sing. present)
word: "the" -- tag: DT (Determiner)
word: "cheese" -- tag: NN (Noun, singular or masps)
word: "that" -- tag: WDT (wh-determiner)
word: "lay" -- tag: VBD (Verb, past tense)
word: "in" -- tag: IN (Preposition/subord. conjunction)
word: "the" -- tag: DT (Determiner)
word: "house" -- tag: NN (Noun, singular or masps)
word: "that" -- tag: WDT (wh-determiner)
word: "Jack" -- tag: NNP (Proper noun, singular)
word: "built" -- tag: NN (Noun, singular or masps)
word: "." -- tag: . (period)
Press ENTER or type command to continue

Wait. I think nltk made a mistake on the last tag "built". Should be a verb. What do you think?

3.2   Sentence complexity analysis with textstat

You can read about textstat here: https://pypi.org/project/textstat/.

Example code:

py3 << EOF
from textstat import flesch_reading_ease
def anal_complexity_sentence():
    # yank the sentence containing the cursor into the default register.
    vim.command('normal mn(v)hy`n')
    # get the contents of the default register.
    content = vim.eval('@@')
    complexity = flesch_reading_ease(content)
    print('content: {}'.format(content))
    print('complexity: {}'.format(complexity))

map <leader>u :py3 anal_complexity_sentence()<cr>

And, here are some samples of output. It shows the sentence being analyzed and the reading ease score. Bigger numbers are easier and smaller numbers indicate more difficulty.:

[Example 1]
The furry bunny hopped after the small, red squirrel.
Press ENTER or type command to continue

[Example 2]
This is the
house that Jack built.
Press ENTER or type command to continue

[Example 3]
This is the
dog that worried the cat that chased the rat that ate the cheese
that lay in the house that Jack built.
Press ENTER or type command to continue