How I Align Contents in Neovim
Background
When writing documentation in plain text, I struggled to make the text look better, including Markdown tables, key-value pairs with different lengths, etc.
Who doesn’t want to make a table like this look better?
| header 1 | header 2 | header 3 |
|-|-|-|
| long content 1 | long content 2 | long content 3 |
| 4 | 5 | 6 |
Then I found this plugin. It is quite straightforward to use after understanding how it works. Let’s see how it helps.
mini.align
to the Rescue
mini.align is one of the powerful Neovim plugins collected in mini.nvim.
Basically, it aligns contents in 3 steps:
- Split the content into columns with a pattern. Note that the delimiters are preserved.
- Justify the columns, align the contents of each column with paddings.
- Merge the columns back into rows.
Installation
I installed mini.nvim
with lazy.nvim:
return {
{
"echasnovski/mini.nvim",
version = "*",
event = 'VeryLazy',
config = function()
require('mini.align').setup { mappings = { start = '', start_with_preview = 'g=' } }
end,
},
}
Note that I set a keymap of g=
to start alignment with preview.
Examples
Space Separated Columns
Let’s take an example, to format a crontab
file like this:
*/3 * * * * echo 1
* */3 * * * echo 2
* 1,3,5 * * * echo 3
I really hope to see the columns aligned so I can easily tell which time unit each column belongs to and how the command works.
I select the content to be aligned in visual mode, and press g=
to start alignment.
If everything goes well, I enter the alignment process and see the prompt in the status bar:
(mini.align) Split: "" | Justify: "left" | Merge: "" | Enter modifier
Now I go through the 3 steps mentioned above.
- Firstly, press
s
for Split, enter the delimiter:%s+
, meaning one or more whitespaces. I will see all the whitespaces disappear and everything collapses. - Press
t
to trim the columns to remove extra whitespaces before merging. Justify ofleft
looks good to me, so I won’t change it. - Finally press
m
and set Merge delimiter as
Now the content should look like this:
*/3 * * * * echo 1
* */3 * * * echo 2
* 1,3,5 * * * echo 3
Each column is aligned to the left, and separated with exactly one whitespace.
A Markdown Table
Another example is to format Markdown tables, for example:
| header 1 | header 2 | header 3 |
|-|-|-|
| long content 1 | long content 2 | long content 3 |
| 4 | 5 | 6 |
This is a valid Markdown table but it really looks bad in the source. So I am going to format it with mini.align
. To demonstrate some advanced features, I am going to align the first column to the left, the second in the center, and the third column to the right.
To make it clear, I will get the following structure after splitting (pseudo-code for better understanding):
[
['|', ' header 1 ', '|', ' header 2 ', '|', ' header 3 ', '|'],
['|', '-', '|', '-', '|', '-', '|'],
['|', ' long content 1 ', '|', ' long content 2 ', '|', ' long content 3 ', '|'],
['|', ' 4 ', '|', ' 5 ', '|', ' 6 ', '|'],
]
Note that the delimiters (|
) and whitespaces are all preserved.
Now I will align the first column to the left, using the filter feature.
- Select the table, press
g=
to start alignment, presss
to set the delimiter to|
. - Press
f
for filter, set the expression tocol<4
so we only modify the first column, taking the delimiters into account. - Press
t
to trim the filtered columns, thenjl
to justify the contents to the left. - Press
m
and merge the columns with a whitespace
Then the second column:
- Select the table, press
g=
to start alignment, presss
to set the delimiter to|
. - Press
f
for filter, set the expression tocol>=4 and col<6
so we only modify the second column and the following delimiter. - Press
t
to trim the filtered columns, thenjc
to justify the contents in the center. - Press
m
and merge the columns with a whitespace
Then the third column:
- Select the table, press
g=
to start alignment, presss
to set the delimiter to|
. - Press
f
for filter, set the expression tocol>=6
so we only modify the third column and the following delimiter. - Press
t
to trim the filtered columns, thenjr
to justify the contents to the right. - Press
m
and merge the columns with a whitespace
Here is what I get:
| header 1 | header 2 | header 3 |
| - | - | - |
| long content 1 | long content 2 | long content 3 |
| 4 | 5 | 6 |
Limitations
- The
filter
is global. All changes apply to thefilter
ed columns no matter when thefilter
is applied. So if we want to align the columns in 3 ways, we have to go through the process 3 times. - It is not perfect for Markdown table formatting. Here I just use it to demonstrate what we can do. Consider using marksman for better Markdown formatting.