The What
Recently, I was working on my competitive-coding skills to land a job. But like a developer I was pushing each and every program that I made to GitHub. I wanted a way to list down all the files I made in my README.md file in a readable format.
The tree command is a very useful utility to list out the hierarchy inside a project. My aim was to convert this hierarchial structure into a markdown list:
Before:
.
├── arrays
│ ├── k-smallest-fastest.cpp
│ ├── k-smallest-using-set.cpp
│ └── rotate.cpp
After:
* arrays
* k-smallest-fastest.cpp
* k-smallest-using-set.cpp
* rotate.cpp
To see what we are going to make in detail, check this video out:
{% youtube FY23ah7wukM %}
The How
Working with the hierarchy that we have, we need to perform a series of find and replace operations to get our output. The only challenge is that our symbols | |-- --
are not utf-8 encoded. Which means that we cannot type them using our standard keyboard. So to search for these tags, we need to copy paste them.
Removing the left-most pipe
Now let us perform our first operation:
:%s/│//
This will search for all │
(which are in the left side of the hierarchy) and delete them. Now to type this command, you can copy paste the │
character from your file, or you can directly go into the vim command line with │
in your cursor and press Ctrl + r + "
to paste it there, which is a more intuitive way of approaching the problem. We get this as our output:
.
|── arrays
├── k-smallest-fastest.cpp
├── k-smallest-using-set.cpp
└── rotate.cpp
Replacing the sub-element pipe with a star
To convert our hierarchy to a list, every sub-element needs to remain in the same position and have a * next to it. This can be achieved by replacing the ├──
character by a *
:
:%s/├──/*/
Our output now look like this:
.
* arrays
* k-smallest-fastest.cpp
* k-smallest-using-set.cpp
└── rotate.cpp
Replacing the last sub-element pipe with a star
Notice that the last sub-element still has the pipe character in front of it. It can be replaced by the following and subsequent output is given below:
:%s/└──/*/
.
* arrays
* k-smallest-fastest.cpp
* k-smallest-using-set.cpp
* rotate.cpp
Are we done? Not quite. If you look at the produced output in a markdown previewer, you will notice that it does not render properly. Why?
That is because there are hidden unicode characters in this file which we need to replace by a space character. To show all whitespaces, you can run the following commands:
:set listchars=eol:$,tab:>-,trail:~,extends:>,precedes:<,space:␣
:set list
" to see unicode characters in the statusline
:set statusline=%b\ %B
This will yield the following output:
Notice that in the statusline we can view the invisible character as A0
. We need to replace it by space, which can be easily done by:
:%s/\%u00a0/ /g
And voila, we have our output!
Combining everything
In vim, the pipe (|) character can be used to pipe multiple find and replace commands. So everything we did here can be condensed to the following command:
:%s/│//|%s/├──/*/|%s/└──/*/|%s/\%u00a0/ /g
What lies ahead
I have made a plugin called treemd which maps some very easy keybindings for converting your tree buffer to a markdown list. There is a bonus keybinding for running the tree command with a specified depth, in the current directory and using it as a markdown list:
{% github L04DB4L4NC3R/treemd.vim %}