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
(c
onceal
char
acter) 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.