Formatting tables in Vim/NeoVim
While writing some documentation this weekend, I saw a Markdown file with a table that looked like this:
| Foo | Bar | Detailed comment | Bla |
| --- | --- | -------- ------- | --- |
| First | Second | This is the first row of the table, ignoring the headers | % |
| O | O | Some very long sentence for this entry | :emoji: |
| Bla | bleeeeeeeeeeeeeeeeeeee | blii | x |
The columns are not aligned! This bothered me, although the rendered table looks fine.
We have one million ways to make this table look nice in the Markdown file. One of them, when using Vim/NeoVim is:
- select the table, including the header and footer lines (with
shift V
, for example). - Prettify the table with
:!column -t -s '|' -o '|'
It only takes these two steps to align the columns of the example table:
| Foo | Bar | Detailed comment | Bla |
| --- | --- | -------- ------- | --- |
| First | Second | This is the first row of the table, ignoring the headers | % |
| O | O | Some very long sentence for this entry | :emoji: |
| Bla | bleeeeeeeeeeeeeeeeeeee | blii | x |
No plugin needed 🎉
How the hell this works?
shift V
switches to Visual mode linewise. This is to select all the lines of the table. See:help visual-mode
for details.:
switches to Command line mode, to type commands. See:help Cmdline
for details.!
specifies a filter command. This means we will send data to a command to modify it (or to filter) and replace the original lines. In this case we are in Visual mode, we defined the input text (the selected lines) and we will use an external command to modify the data.column
is the filter command we are using, from theutil-linux
package.column
’s purpose is to “columnate”. The-t
flag tellscolumn
to use the Table mode. The-s
flag specifies the delimiters in the input data (the default is whitespace). And the-o
flag is to specify the output delimiter to use (we need that because the default is two whitespaces).
🎃 🧙
Edit
2024-04-07
There may be an issue with this filter: if there are consecutive spaces at the beginning or end of any element in the cell, the columns in the pretty table get too long. For example:
| Foo | Bar | Detailed comment | Bla |
| --- | --- | -------- ------- | --- |
| First | Second | This is the first row of the table, ignoring the headers | % |
| O | O | Some very long sentence for this entry | :emoji: |
| Bla | bleeeeeeeeeeeeeeeeeeee | blii | x |
Becomes:
| Foo | Bar | Detailed comment | Bla |
| --- | --- | -------- ------- | --- |
| First | Second | This is the first row of the table, ignoring the headers | % |
| O | O | Some very long sentence for this entry | :emoji: |
| Bla | bleeeeeeeeeeeeeeeeeeee | blii | x |
Thanks to Phil, I got the tip of first
filtering with tr -s ' '
. This neat command gets rid of all consecutive
spaces and replace with only one. Like this:
$ echo " a a !" | tr -s ' '
a a !
So, the neatest filter is actually :! tr -s " " | column -t -s '|' -o '|'
.
This way we first apply tr
to get rid of repeated spaces and pipe that to the
column
command.
But note: any internal sequence of spaces is replaced with only one. Careful if you need those spaces.
Danke schön, Phil!