More About Conceal


In my last post, I talked about using Vim conceal to create my own little syntax.

A couple of days ago, I came up with a way to make scientific programming easier to read.

In scientific programming, subscripts and superscripts are in every function. But since this is a computer and not a sheet of paper, you’re reduced to writing x0 instead of x₀, .

x0 is not generally a good variable name. But in something like an SVD, I think x0, x1, etc. can be fine if not abused. You shouldn’t have x1 all the way through x9.

It makes reading snippets like the following much nicer (taken from Ben Recht’s code on LQR):

# initial condition for system
z0 = -1 # initial position
v0 = 0  # initial velocity
x0 = np.vstack((z0,v0))

This looks nicer to my eyes as

# initial condition for system
z₀ = -1 # initial position
v₀ = 0  # initial velocity
x₀ = np.vstack((z₀,v₀))

In reinforcement learning, code like the following is common to compute discounted rewards:

sum(r * gamma**t for t,r in enumerate(rewards))

Conceal turns it into

sum(r ∙ γᵗ for t, r in enumerate(rewards))

You can see my Python conceal code here.

How To Write Your Own Conceal

Someone wrote this on my feedback form:

After reading your piece, I really wanted to use a subset of it myself but cannot figure out how to do so! It’d be nice if you explained what I need to add to my .vimrc etc. to make this work.

This is for you, 5/8/2018 6:39:53.


The basic syntax is:

syntax match [Group] [regex]{ms=int,me=int} conceal cchar=[single char]

Where the square brackets are required arguments and the curly braces are optional.

Let’s go over them in order.

Use :help

Before getting into anything, you should know that Vim’s documentation is really good. I know, I was surprised too.

The syntax to get help is :help x where x is your search term. You can also use :h instead of :help as an alias.

Syntax Groups

See :h group-name. No, really. I’m not going to repeat everything in there.

You can use one of the builtin group names, but I prefer to use highlight linking to establish a namespace in case I ever want to color one language differently.

It’s easy to create your own group. Just think of a name and write it in one of the syntax match ... lines. Then put highlight! link GroupName OtherGroupName somewhere. You can link a custom group to another custom group, then link that other group to a builtin one. It’ll transitively pick up its color.

For example:

highlight! link pyBuiltin pyOperator
highlight! link pyOperator Operator

Now python builtins are colored the same as python operators, which are colored as regular operators (green, for me).

Keep in mind that you don’t have to conceal the text. This is really just an extension to the syntax highlighting. By just specifying syntax match [Group] [regex], you get syntax highlighting without conceal.

Regex

This is the regex to match (and conceal). See :h regex and this.

I’m not gonna go over this too much. Just read the above and the section “Highlighting Operators” here.

Keep in mind that Vim regex is not the same as most other programming languages. To get a form of regex you recognize, preface every regex with \v. The regex itself should be in quotes or slashes or some other non-alphanumeric character. I use single quotes.

Here’s an example that matches terms like x0 and log_std0 and turns them into x₀,log_std₀.

syntax match Normal '\v<[[:alpha:]_]+[^_[:digit:]]*0>'ms=e conceal cchar=₀

Start And End

The ms,me is optional, but it specifies where a match starts/ends. You can use this to match a word like x_0 but only conceal the _0 by specifying ms=s+1 (start 1 char to the right of the beginning of the match). See my Python conceal for more

It has to be right after the regex, and must have no space between.

See :h syn-pattern-offset.

Conceal

Now for the good bit.

If you leave off the cchar=... but keep the conceal keyword, then the matched text will just be hidden. The cchar (conceal character) specifies what text to replace it with, if any. It has to be a single character. So get creative.

See :h conceal and :h syn-cchar.

Keyword

For simple terms, you don’t need a regex. You can use syntax keyword instead of syntax match, and it’ll work fine for terms like the ones below.

syntax keyword pyKeyword alpha conceal cchar=α
syntax keyword pyKeyword ALPHA conceal cchar=α
syntax keyword pyKeyword Gamma conceal cchar=Γ
syntax keyword pyConstant None conceal cchar=∅

Testing out conceal

Write your conceal code in some file. Then open a file that you want to conceal. Source the conceal code file, and see if it did what you wanted. If not, run :syntax clear and source the Vim code again. Repeat until satisfied. Exit Vim and stick the concealed code in your vimrc.

More concretely, say I have files p.py and v.vim. While editing p.py, I can run source (path to v.vim) and it’ll run the Vim code in v.vim. syntax clear wipes all syntax, including existing highlights, from the buffer you were in when you ran it. It persists till you close and reopen Vim.

Thanks

In writing this, I learned a few things too.

Related Posts

Handy command line benchmarking tool

Stan Rogers

Ultimate Hot Couch Guy

Quote on Java Generics

The Programmer Tendency

Figure out undocumented JSON with gron

Mental Model of Dental Hygiene

Book Review: Swastika Night

Is there a name for this construction?

Fun with negation and idioms