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.

Flow


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:

Alt Text

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 %}