Python f-strings syntax highlighting in Vim - Phelipe Teles

Python f-strings syntax highlighting in Vim

2 min.
View source code

Getting Python syntax highlighting to work in Vim requires very little code, to my surprise.

After
Before

Here is everything that you need and an explanation below.

vim
" in ~/.config/nvim/after/syntax or ~/.vim/after/syntaxsyn match pythonEscape +{{+ contained containedin=pythonfString,pythonfDocstringsyn match pythonEscape +}}+ contained containedin=pythonfString,pythonfDocstring syn region pythonfString matchgroup=pythonQuotes      \ start=+[fF]\@1<=\z(['"]\)+ end="\z1"      \ contains=@Spell,pythonEscape,pythonInterpolationsyn region pythonfDocstring matchgroup=pythonQuotes      \ start=+[fF]\@1<=\z('''\|"""\)+ end="\z1" keepend      \ contains=@Spell,pythonEscape,pythonSpaceError,pythonInterpolation,pythonDoctest syn region pythonInterpolation contained      \ matchgroup=SpecialChar      \ start=+{{\@!+ end=+}}\@!+ skip=+{{+ keepend      \ contains=ALLBUT,pythonDecoratorName,pythonDecorator,pythonFunction,pythonDoctestValue,pythonDoctest syn match pythonStringModifier /:\(.[<^=>]\)\?[-+ ]\?#\?0\?[0-9]*[_,]\?\(\.[0-9]*\)\?[bcdeEfFgGnosxX%]\?/ contained containedin=pythonInterpolationsyn match pythonStringModifier /![sra]/ contained containedin=pythonInterpolation hi link pythonfString Stringhi link pythonfDocstring Stringhi link pythonStringModifier PreProc

Declaring a syntax region for f-strings

The first two lines define a new syntax region (see :h syn-region) called pythonfString.

We then declare how it starts with the regex [fF]\@1<=\z(['"]\), which is equivalent to (?:<=[fF])(['"]) in Perl regular expressions (see :h \@<=). The second line just handles the case of a docstring.

The string will end how it starts, so we can just reference the captured group using \z1 (we need to prefix it with z because it is an external pattern, see :h \z().

The matchgroup argument tells Vim which highlight group it should use to highlight the start/end pattern. The group pythonQuotes come from the default syntax file.

Handling expressions inside f-strings

We also need to declare what this region contains.

For this we declare another region called pythonInterpolation, which starts with { (but not with {{, which will actually produce a literal {) and closes with }. With that in mind, we use the regex {{\@! because we don’t want a match if the preceding token is present (see :h \@!).

This region may contain only expressions, so stuff like a function declaration does not make sense (notice there is a syntax for that, :helpgrep ALLBUT)

Handling string modifiers

f-strings supports str.format syntax for formatting, for example:

Python
import mathprint(f"The value of pi is approximately {math.pi:.3f}.")

So I read the Python docs and wrote a regex based on it, but regexes are always easier to write than to read so I wouldn’t recommend you trying.

It’s also possible to convert a value as if wrapping them in functions such as ascii(), repr(), str() with !a, !r, !s respectively, so we need to handle this also.

For this, I declared a syntax group with :h syn-match and pass the regexes that should be used.

It should only be highlighted inside a pythonInterpolation so we take advantage of the containedin argument (see :h syn-containedin).

Highlighting declared groups

Finally, we link these new highlight groups with an appropriate/whichever you like highlight group (see :h hi-link and :h group-name). I chose String for f-strings and PreProc for modifiers. And it should work as expected.