Building a Note-taking System with Vanilla Vim

This post is part of the Workflow series.

Vim is my preferred tool for making notes and organizing my thoughts. This posts explains how we can use Vim to build a personalized note taking ecosystem of interconnected notes, only using plain text. I have some requirements for such a system. I want:

  • everything in plain text: future proof, portable, searchable.
  • version control on my notes
  • to be able to smoothly find notes and navigate between them
  • a quick way of searching the contents of my notes
  • notes to behave like hypertext: they can directly link to other notes
  • to do everything within a single consistent context, i.e. never leave Vim to do basic actions.
  • my note taking workflow to be cross-platform (for me: work both on Linux and Windows)
  • to Keep It Simple Stupid (KISS)

This is my guide for achieving the above. This guide assumes you make notes in Markdown, but you can adapt everything to your needs.


The overall goal is to start building a personal plain text ecosystem where notes are linked together in such a way that they do not only help me remember things, but also positively stimulate the process of thinking and writing. If knowledge is your business (if you are a writer, academic, or something of the like) spending some time to optimize your note taking is worth it.

Ideas about how note taking structures your thinking are worked out by the Zettelkasten (indexing cards) system that I found while writing this article. See for example a quote from this post on the benefits of extending your mind and memory through note taking :

Some note archives never move beyond a storage of thoughts and stuff you need for reference. If you connect your notes heavily by creating links between them, though, eventually your Zettelkasten will do more than fill memory gaps. Instead, it will improve the depth of your understanding.

Note taking improves the depth of your understanding for various reasons, but the least superficial is that writing down thoughts forces you to think more coherently by requiring you to make thoughts explicit.

Similar to how your ability to teach is a good indication of whether you understand the essence of something, just so is note taking a way to see if you really get the main point of for example a paper that you are reading. There is a hermeneutical principle at work here. The philosopher Gadamer for example describes how understanding requires you to go into dialogue with whatever you are trying to understand. This implies that you make your pre-understanding or prejudice explicit so that it can can be challenged in dialogue with something other, whether that is another person with a different background in teaching or a book you are reading.

So ideally notes are really an ecosystem rather than just a storage container. Just collecting stuff is not the same as understanding it. I really like the idea of “communicating” with your notes in the creative process, also worked out on the Zettelkasten blog . As you write down more notes and keep connecting them, your notes will gain complexity up to the point where, let’s say a year later, you will find surprising connections between new thoughts and old notes. In this sense your notes can really become this other party that you enter into dialogue with and a stimulant for creative thinking.

N.B. this post thus does not focus on more dynamic plain text notes, such as todo lists or agenda’s. Vim doesn’t try to emulate the functionalities of other types of software, but tries to do one thing well and then integrate with other tools dedicated to other purposes. Having said that, doing everything in plain text is cool, but you should probably have a look at Emacs Evil Mode in combination with Org mode.

Step 1: Create a single repository for your notes

Because I want version control on my notes, it makes an awful lot of sense to organize all my notes in a single directory so that I can straightforwardly use Git. You could distribute your notes over your system and still have version control using a tool like GNU Stow, but this effort is not worth it for me. Keep It Simple.

Additionally, this way you can easily organize your notes with a meaningful folder structure that is easy to remember and efficient to navigate, assuming that you will have a folder structure at all.

Step 2: Think about a folder structure for your workflow

After setting up your note directory, it makes sense to give some thought to how you are going to organize your notes within that directory.

There are many systems for organizing your life that rely on various forms of note taking. This is not the main focus of this post, but here are some pointers to relevant methods:

These methods generally begin with decluttering your mind by writing things down. There are plenty of online tutorials on how to implement these methods with digital note taking systems and tools, e.g. with Emacs . We will do something similar in Vim.

Personally I have not (yet?) settled for a single note taking system. In the end it’s all about finding out what works for your specific interests and use cases.

The Zettelkasten system for example urges you to only express a single idea in each note (atomicity) and rely heavily on tagging these ideas and linking them together with other notes. This implies that it is futile to try to organize everything in folders. You instead rely on searching tags and following hyperlinks between notes. Below I’ll explain how I use Vim to follow those links.

I really do try to minimize sorting files, but in my case some folder structure is meaningful to me. Having done university courses of two curricula, philosophy and artificial intelligence, it makes sense for me to at least organize long form course notes per year, e.g. under /AI/Y3/ .

If you do project-based work, where projects last for example at least half a year, it would also make sense to me to organize those notes in a folder. I have a separate directory for more free form notes.

Let’s start with the implementation in Vim.

Step 3: Create an index page

Because we have all our notes organized in a single directory, we can make an index as an entry point into our note taking system.

In the root directory of your notes, make a file. We are going to use this index file to make links to other files and directories that we can follow using Vim’s awesome gf command.

The gf (go to file) command opens the filename, directory or url that is currently under the cursor. This means that we can populate our index files with relative paths to files that we often use.

Only use relative paths, because this makes our note system independent of any specific system.

For example, my index file contains a “quick start” menu for useful folders:

Quick start:

- Philosophy/Thesis

All directories:

- AI
- Philosophy
- Miscellaneous
- Workflow\ &\ Skills
- Epub\ Annotations

To to one of these directories all I have to do is place my cursor somewhere on the folder name and type gf to open the file in a new window (vertical split), or gF to open it in the same window, or <C-w>f to open the file in a horizontal split. By the way, run :help key-codes for an explanation of Vim’s notation for key sequences.

Paths with spaces in them can complicate matters. If you escape the spaces the gf command works just fine, the other commands not so much (in terminal Vim at least). What works in all cases is visually selecting the path before running gf.

Next to a quick start menu, I thought it was cool to include a full tree of all notes. By default the tree command only shows the file names at nodes, but for gf to work we need valid paths. Because all notes share the same root directory, we can save space by using valid relative paths. On a Linux system, you can achieve this as such:

tree -f -I "images*|*.pdf|*.py|*.html"

The -f option displays the full paths relative to the root of the notes directory, which is necessary for gf. The -I option excludes everything matching the given pattern. I have some stray pdf, python and html files in my notes directory, so I make sure to exclude them. I also have one directory purely for images I reference in my notes. All notes have the markdown extension (and an occasional Emacs .org file).

To insert the output of the command directly in our text buffer, prepend the command with the read command or its shorthand r, or even shorter (but this overrides the current line), with . (a dot). So you run:

:.!tree -f -I "images*|*.pdf|*.py|*.html"

The resulting tree looks something like this:

├── ./AI
│   ├── ./AI/Master
│   │   ├── ./AI/Master/
│   │   ├── ./AI/Master/
│   │   ├── ./AI/Master/
│   │   ├── ./AI/Master/
│   │   ├── ./AI/Master/
│   │   └── ./AI/Master/
│   ├── ./AI/Other
│   │   ├── ./AI/Other/
│   │   ├── ./AI/Other/
│   │   └── ./AI/Other/
│   ├── ./AI/TA
│   │   ├── ./AI/TA/
│   │   ├── ./AI/TA/
│   │   ├── ./AI/TA/
│   │   ├── ./AI/TA/
. . . . . . . . . . .. . . . .  etc.

│       ├── ./AI/Y3/
│       ├── ./AI/Y3/
│       └── ./AI/Y3/
└── ./Zettelkasten
    ├── ./Zettelkasten/
    ├── ./Zettelkasten/
    ├── ./Zettelkasten/
    └── ./Zettelkasten/

You can use this full tree for navigating to any note using Vim’s gf command. To quickly jump to a file name in the tree, just use Vim’s search / in the index file.

UPDATE 14/4/2020: I almost immediately moved away from using the tree. It just looked cool, but it quickly gets unmanageable. Relying on directory structure forces you to categorize notes rather than relying on search tools and direct interlinking. I’ve switched to a “Zettelkasten” approach. However, the idea of an index page is alive and kicking! You can always insert links to heavily used project notes. I currently use a page with all my tags as my index page (for tags, see the next post).

The last thing we need to do is make a fast way to access the index file from anywhere. We can make a mapping to 1) open the index file and 2) change the Vim working directory to our notes directory, so that we can use our relative paths.

One way to do that is to add the following mapping to your .vimrc:

" Go to index of notes
nnoremap <leader>ww :e $NOTES_DIR/<CR>cd $NOTES_DIR

UPDATE 19/12/2019: I now let all note related mappings start with <leader>n. This command is now mapped as <leader>ni for “note index.” This command also has a small mistake. This is the corrected version:

" Go to index of notes and set working directory to my notes
nnoremap <leader>ni :e $NOTES_DIR/<CR>:cd $NOTES_DIR<CR>

N.B. the default leader key is the backslash \ .

<CR> is a carriage return, or an “Enter” in common tongue. We need <CR> to also execute the command, but it is also a cheeky way to chain two commands together on a single line.

$NOTES_DIR is a bash variable that I set in my ~/.bashrc:

export NOTES_DIR=/home/edwin/Documents/Notes

You can of course hardcore that path into your .vimrc, but I preferred to use the bash variable because then I don’t have to change my .vimrc in case I migrate my notes directory for some reason. On Windows I do hardcore the path though. Vim allows you to ignore the Windows convention of using backslashes in paths, so you can use a backslash to escape whitespaces as usual. For example, my remap on Windows looks like this:

nnoremap <Leader>ww :e C:/Users/Edwin\ Wenink/Documents/Notes/<cr>

Whatever we are doing in Vim, our notes are now always reachable within a second.

Step 4: Methods for finding notes

We can now quickly find notes by jumping to our index file, using Vim’s search operator / and then running gf on the search result.

A more rhizomatic way of navigation is to create links within notes to other related notes and follow them with gf. This is our method for building up an ecosystem of interconnected notes.

Another option is to use the default find function, which offers you autocomplete on paths. This is a feasible approach because all our notes are organized in a single directory with a meaningful structure.

Alternatively, just use a fuzzy file finder to quickly find files based on partial matches. A well-known option is fzf. I opted for the Ctrl-P fuzzy finder because making that run on Windows as well was easy.

You can make Ctrl-P faster by letting it use the blazingly fast tool ripgrep, by adding the following to your .vimrc (after installing ripgrep of course):

" Make Ctrlp use ripgrep
if executable('rg')
    let g:ctrlp_user_command = 'rg %s --files --color=never --glob ""'
    let g:ctrlp_user_caching = 0

Another good argument for using ripgrep is that it runs both on Linux and Windows and thus fits my cross-platform requirement. Do note however that ripgrep is an external command line tool and does not ship with Vim, so you need to install it yourself. Have a look at the project page for clear installation instructions.

Something I have not done yet, is design an effective plain-text tagging system UPDATE 19/12/2019: see this post . This blog adds tags behind all files in the index, as a quick hack. This doesn’t fit with the above mentioned approach of automatically generating the navigation tree, as that would replace the tags. I also think a plain-text tagging system is ideally decentralized, i.e. tags are stored in the notes themselves. This is more robust but also tricker to implement efficiently.

Step 5: Navigating between opened files in your buffer

We covered how to find a file you want to read or edit. But how do you efficiently jump back and forth between files that you opened?

Using search functions to find a file each time I need it is superfluous. When I’m writing a paper I want to have various related notes open at the same time and ready for inspection. But you shouldn’t have multiple windows of tabs open for more than two files, first of all because they fill up your precious screen space and secondly because cycling through them is slow.

You should use buffers and the jumplist markers Vim sets for you.

Everytime you open a new file, Vim will open that file in a buffer. It is important to realize that a buffer does not need to have a window, i.e. it is not necessarily visible.

You can see the complete list of open buffers using the ls command, which is familiar to all Unix users. Alternative you can type out buffers. You will see that each buffer is numbered. You can open a buffer quickly either by referring to its number, like so to open the second buffer :b2.

A very nice feature is that the buffer command can expand partial matches with filenames opened in a buffer. If you for example have your .vimrc opened in a buffer, you can type b rc<TAB> to expand rc to the full path to your .vimrc.

You can also cycle through buffers as such (with alternative mappings from vimunimpaired):

  • :bprevious or [b
  • :bnext or ]b

And you can delete buffers from the buffer list with :bd The command without arguments deletes the current buffer.

I have to admit that I only realized I wasn’t using Vim’s buffers properly after making a field trip to Emacs. Sometimes it is good to explore a different workflow to re-evaluate your habits, and integrate improvements. What was also more prominent in Emacs were functions to quickly jump back and forth between the buffers you visited lasts. I wish I knew that Vim could do this as well from the moment I started using it.

Vim uses movements to navigate through a text. Before each movement Vim sets a marker of your current location and stores it in the jumplist. These markers also work across files.

  • With C-o you jump to the previously visited location.
  • With C-i you jump one place to the front of the jumplist.

This means that if I open a new file in a buffer for example after using gf, then I can quickly jump back to the previous file with C-o.

If you perform movements in the meanwhile, you’ll have to cycle back through those movements as well. You can also directly alternate between the current file and the last opened file with C-6. Somehow introductions to Vim rarely mention these commands, but they really were eye-openers for me. I do not leave Vim anymore for file navigation, and especially on Windows this makes the whole experience much closer to using the command line.

Proper buffer navigation satisfies my wish to do everything from within Vim. Without buffers, you’ll find yourself opening new Vim instances all the time, which requires your window manager to switch between those instances.

Step 6: Search contents of your notes

Additionally, in the case tag based search would not be enough (true in my case, because I did not implement it), we fall back on searching the contents of our notes.

The most straightforward tool to do this is grep, available on every Unix-like system. However, we wanted our solution to be cross-platform and Windows does not have grep.

A first good approach is to use Vim’s native grep called… vimgrep. Because this doesn’t require an external tool, any system using Vim can use this approach. There is an issue though. vimgrep and lvimgrep (a vimgrep that populates the locallist instead of the cross-file quicklist) are slooooooow.

Luckily, Vim also has a regular grep command that you can configure to use any searching tool. We just need that tool to be cross-platform. We already used ripgrep for Ctrl-P, so let’s use it for Vim’s grep command as well.

" Make :grep use ripgrep
if executable('rg')
    set grepprg=rg\ --color=never\ --vimgrep

Merge the new line with the code block for the Ctrl-P fuzzy finder we saw above. The --vimgrep option emulates vimgrep behavior, i.e. it now returns each match, irregardless whether it’s in the same file or sentence as another hit, as a single result.

The next step is to write a command with a handy shortcut to search our notes and only our notes.

I was inspired by a note searching function from this video of a doctor using Vim to make notes. He uses the slow vimgrep. This is his function:

command! -nargs=1 Ngrep vimgrep "<args>" $NOTES_DIR/**/*.txt
nnoremap <leader>[ :Ngrep

I introduced four changes. We do not use vimgrep anymore, but Vim’s grep command which we redirected to rg. But the syntax of ripgrep is different. It does not take Unix style wildcards, but requires you to explicitly define a glob for the search pattern using -g. I also changed the mapping slightly, using the “n” for “notes”. Instead of .txt files, we only search through .md files. Adjust the glob pattern if you want to include more. Remember that the <leader> is a backslash by default.

" My own version, only searches markdown as well using ripgrep
" Thus depends on grepprg being set to rg
command! -nargs=1 Ngrep grep "<args>" -g "*.md" $NOTES_DIR
nnoremap <leader>nn :Ngrep 

So if we press \nn in Vim, we can immediately type our search term and get all matches in our note directory.

The results of the search populate what is called the quickfix list in Vim. This is a list you can access from any context within Vim (as opposed to the locallist which is bound to the context of the current file).

You can use the following commands to navigate the items in the quickfix list:

  • :copen and :cclose for opening the list
  • :cnext and :cprev for jumping to next/previous list item
  • :cc {nr}: to jump to item number and echo it
  • :colder and :cnewer to also navigate older quickfix lists.

The vim-unimpaired plugin provides default mappings for the quickfix list:

  • ]q for :cnext
  • [q for :cprev
  • [Q for :cfirst
  • ]Q for :clast

For who is into more advanced stuff, you can run commands on each item in the quicklist with cdo {cmd}, which runs cmd on every list item.

I was also inspired by the Vimming doctor linked above in the creation of a navigation pane for browsing the search results in the quickfix list. The following function and mapping allows you to open a sidebar with the results from our custom “note grep” with \v:

command! Vlist botright vertical copen | vertical resize 50
nnoremap <leader>v :Vlist<CR>

Clicking on a option moves to exact line in file of the search hit.

Sometimes I leave “TODO” notes in notes. This is how the custom sidebar looks after searching my notes for “TODO”:

The sidebar shows the file a match was found in and a preview of the match itself. You can adjust the size of the bar with :vert resize {size}.

Conclusion and ideas for the future

The system described above only uses vanilla Vim functionality without the need for plugins.

I also deliberately do not use additional plugins for previewing my notes, because I write in Markdown and Markdown is designed to be readable in plain text. Instead I advice to explore the various Markdown plugins out there, for syntax highlighting and folding. I can really recommend vim-pandoc and the corresponding syntax plugin .

I’m interested in getting tips from you, especially about a potential implementation for “tags”.

This is my current TODO list:

  • Design a tagging system and related search functions
  • Think more about the best file naming convention
    • e.g. use timestaming and write a function to search timeframes
  • Write a function for quickly adding a new note
  • Think more about my folder organization
    • UPDATE 15/4/2020: I opted for a stricter Zettelkasten approach and now use a single directory. This forces you to rely on proper searching tools and manual interlinking, following the Zettelkasten principles. Additionally, this really simplifies writing your own tools, for example for managing backlinks, because you do not have to worry about paths but only about filenames. Additionally, not relying on paths in your links makes the link robuster, e.g. they do not break when you rename some directory. I do have to mention that this was never an issue with Vim alone, because Vim’s gF can move to parent en sibling directories as well. I would like my markdown links to be strictly correct though, so that they would also automatically work when I publish my notes as a website or preview them in Github (where I store them).

If I work any of these out you can expect a new blogpost about that.

Version control on notebooks using pre-commit and Jupytext <-- Latest

Custom Note Tagging System with Ctags and Vim <-- Next

On function creep, privacy and encryption <-- Previous

Object Orientation: Strategy Pattern <-- Random


Do you want to link a webmention to this page?
Provide the URL of your response for it to show up here.


Bronköl on Saturday, Dec 14, 2019:

Ha Edwin,

Another great post. I am slowly getting enthusiastic about VIM thanks to you. As much of the information here is new to me, I may have read over it in the text, but is there a way to see what other files link to a specific file? For example, if I were to implement your ideas here, could I get an overview of the files in which I make a reference to my notes on the ‘Human Condition’?


Edwin on Saturday, Dec 14, 2019
In reply to Bronköl

Thanks! You did not read over it. After writing this post, I actually implemented that feature :-)! It’s on the backlog for another post. What you are asking for is what is technically called a “reverse index” for hyperlinks. A regular index would be that for each document you save all files it links to, which is simple because you only need to look at the current file. A reverse index is a little bit trickier, because you want to look over all your other notes to see if they link to your current notes, in your case on Hannah Arendt. For now I wrote a quick Python script to do that. The cool thing about Vim is that you can quickly call that external script to make the index without leaving Vim. For now I let it output all backreferences in a JSON format and then have a function in Vim to find the references to the current file.

For example, if I’m currently checking out my notes on Stiegler’s introduction to Automatic Society 1, I run my function and Vim will show me a buffer with this:

    "Philosophy/": [

If you do gF on any of those filenames, you jump to the correct file :-)! They all contain a link to the file I was currently editing.

This was just a prototype. It works, but I want to get rid of the python dependency, ideally. I’ll keep you posted. If you can’t wait for the next post, you can always hit me up ;-)

Edwin on Saturday, Dec 14, 2019
In reply to Bronköl

Actually, if you do not use Vim but you do have all your notes in Markdown, my Python script would maybe be handy for you as a standalone. It currently makes an index of all tags, an index of all files belonging to each tag, and the reverse index that tells you which files link back to a given file. Tags are simply indicated like @philosophy, and I wrote code to recognize Markdown links in your notes (but not images etc.).

Brönkel on Saturday, Dec 28, 2019:

I am implementing your setup at the moment and as a beginner I have three questions:

  1. How did you create the initial index file, before you print the more elaborate tree structure? Did you just type this manually?
  2. I think the command has to be “:!.tree [etc]” instead of “:.!tree [etc]". Could that be true?
  3. Do you need to enter this command manually every time you open the index file or is there a way to automatize this?

Edwin on Saturday, Dec 28, 2019
In reply to Brönkel

Hi! It’s good that you ask these questions to help me understand where I could and should be more clear.

  1. Do you mean creating the actual index file or do you ask whether I manually typed everything before the tree in the index file? I did type the rest manually indeed. Apart from the full tree, the idea is to have some sort of a quickstart menu for projects you are currently working on in case you have separate folders for those. For example, you could type the name of a directory to link to all notes relating to your PhD work, or to things related to hobby writing etc. W.r.t. the former, to make a file from within Vim you can just type :e filename where ‘e’ is short for ‘edit’, and then just save with :w where ‘w’ is short for ‘write’.

  2. You are right that that command looks confusing and I would say it’s more advanced Vim stuff. I just included it in case someone wants to reproduce the tree. Everything after the ! is part of a Unix/Linux command, so you actually do not want the dot after the exclamation mark. In Vim commands the dot has the special meaning of referring to the current line. So what :.!tree [etc] says is: redirect the output of !tree [etc] to the current line. However, in hindsight the following command would have been more clear: :read !tree [etc] or shorter :r!tree [etc]. The read command is more clear about what it does: it reads the output from the command into the current file. The only difference with the more unclear command that I gave is that it pastes the output after the current line instead of on the line. But they essentially do the same.

  3. I did not automate the creation of the index file so far, so indeed you need to rerun the command manually. To be honest, I haven’t bothered doing that anymore. I thought the tree looks really cool, but in practice using a fuzzy finder such as CtrlP is just extremely efficient. The tree could be useful to visualize a complicated folder structure if you have one, but otherwise you could leave it out. The main purpose of the index file was to be a quickstart menu rather than a complete oversight anyways.

Having said that, if you do like it (I mean, it looks cool right?) you could automate it. What you usually do is make a bash script. I don’t mind making one for you. If you would be interested in that, let me know what’s the exact behavior you want :-)

Hope that helps, please feel free to ask further questions!

Edwin on Saturday, Dec 28, 2019
In reply to Brönkel

Oh by the way, to help you with manually typing paths it is good to realize that Vim has filepath completion by default. Just start typing a path to a file and then press Ctrl-X Ctrl-F (f for filename completion) to pop up an autocompletion menu. Vim basically allows you to choose the type of completion you want to use. Because you might want to focus on the basics for now, you can use the lightweight plugin called MUcomplete to automatically do that for you. This plugin just uses the default Vim completion mechanisms (so it’s fast) but automatically selects the appropriate type of completion. Works great for me.

Brönkel on Tuesday, Jan 7, 2020:

Hey Edwin!

Thanks for the responses. I almost have the set up running now, and I like it a lot. The buffer function is amazing.

There are two things that seem to go wrong in my case, both related to the ‘fuzzy finder’.

  1. Even though I can use CtrlP, I cannot use it to search in my files; it just searches the titles. Is it possible to change this?
  2. Whenever I press \n, I get the error: E486: Pattern not found: <Hadfdasdfadsfllo>. It would be nice to have this short-cut, but I cannot get it to work somehow!

Thanks a lot for all the information on this amazing blog already :-) You have really changed my workflow for the better.

Any clues on what I am doing wrong?

Edwin on Tuesday, Jan 7, 2020
In reply to Brönkel

Awesome, good to hear! Yeah working with buffers was an eye-opener for me. You can leave multiple files open and switch quickly between them, without the need to clutter your screen with many windows.

W.r.t. your first point: that’s correct, the point of CtrlP is only to easily find files and not to search the contents of those files. For searching through the content of the file you should use the “Ngrep” function. Grep is a standard UNIX tool for searching the contents of files line by line, and the only goal of the Ngrep command mentioned in this post is to specify that we only care about our notes directory.

Your second point is not about the fuzzy file finder CtrlP right? I assume you use \n for the Ngrep command, so to search the contents of your files, correct? (Btw. I updated that mapping so now I use \nn because I wanted to use n as a prefix for all other “notes” commands.)

My first reaction is that maybe there is nothing wrong and that you simply search for a pattern that does not exist. Is “Hadfdasdfadsfllo” what you typed in as a search pattern? Can you try if the command works when searching for a pattern that for sure exists in your notes?

If it doesn’t work, can you give an example of 1) the line in your .vimrc where you define the relevant command and then 2) what you type in when using the mapping? Then I can hopefully help you better :-)

Brönkel on Tuesday, Jan 7, 2020:

Thanks for your quick reply Edwin!

I had simply copied your code which included nn instead of n, so that explains why my mapping went wrong. I changed it to n.

Whenever I press \n, I now get the command :Ngrep. However, no matter what I type in, I get the following error code:

grep: invalid option – ‘g’ Usage: grep [OPTION]… PATTERN [FILE]… Try ‘grep –help’ for more information.

This is the code of my .vimrc file:

107 if executable('rg')
108     let g:ctrlp_user_command = 'rg %s --files --color=never --glob ""'
109     let g:ctrlp_user_caching = 0
110     set grepprg=rg\ --color=never\ --vimgrep
111 endif
113 " Create a shortcode for searching using ripgrep
114 command! -nargs=1 Ngrep grep "<args>" -g "*.md" $NOTES_DIR
115 nnoremap <leader>n :Ngrep

Any ideas?

Edwin on Wednesday, Jan 8, 2020
In reply to Brönkel

Your code looks good! The simplest explanation is that you do not have ripgrep installed on your system or, alternatively, that for some reason Vim cannot find it (but if you can find it from your terminal, Vim should find it). That would explain the error because the default grep command does not have the ‘-g’ option. I see that I did not make it clear enough that the rg command is something you should install separately on your system. I did not provide the installation step because it is slightly different for different Linux distributions. I would do sudo pacman -S ripgrep and you should probably type sudo apt-get install ripgrep.

  1. Can you check if you have ripgrep installed by opening a terminal and typing rg. Does it tell you something like “command not found”
  2. If not, can you type in Vim :set grepprg? ? This is the way you check how your variable is set in Vim. I suspect yours will now mention regular grep and not rg. This is because, if my hunch is correct, your grepprg is only set correctly when rg exists on your system, due to the if executable('rg') condition.

Hopefully that’s it, because that’s a 15 second fix. Your questions really show me where I could be more clear in the post, so I’ll update the post with a clear remark about installation of ripgrep.

Let me know if that works out!

Brönkel on Wednesday, Jan 8, 2020:

Works like a charm! Thanks Edwin.

I install ‘rg’ via:

sudo snap install rg

Now everything works fine. Thanks a million for all the support!

Edwin on Wednesday, Jan 8, 2020
In reply to Brönkel

Awesome! Now your CtrlP should also be way faster. Enjoy!

Otternaut on Friday, Mar 6, 2020:

Thanks for this really good overview! but I have one question: how do you make links to other files in your index page?

Greetings and thanks for your great work!

Edwin on Friday, Mar 6, 2020
In reply to Otternaut

Hey, thanks a lot! I’m assuming you are not asking about the big file tree (which I do not use anymore, even though it looked kind of cool), but about the links to some heavily used directories or files (a sort of “quick start” menu). There’s multiple ways to go about this and in both cases the solution is really simple, luckily! These are two “manual” methods:

  1. Just write the name in plain text (so no explicit hyperlinking needed). This works because Vim is smart. So if I have a directory called “Philosophy”, I can just manually type “Philosophy”, put my cursor on that word, and open the directory with gf or gF. Pay attention that your working directory is the root of your notes directory. You can check this with :pwd (path working directory) and use :cd to change the working directory.

  2. You could make the links explicit using the Markdown format. If you do this correctly, you could for example also navigate your notes on GitHub, so without Vim. Example: [ Philosophy ]( ./Philosophy ). You can still use Vim’s gF on both of these paths. Notice that I left spaces around the path. In my experience this is needed to not confuse Vim into thinking either ] or ) is part of the path.

For me managing these links manually is fine. I practically never have to update them. Moreover, because the notesystem does not rely on directory hierarchy but more on searchability with CtrlP or fzf, and custom tags (see the next post ), I do not actually use it.

But if you really want to automatically list all directories, you can always pipe the output of dir (Windows) or ls (UNIX etc.) back into Vim. (This will not be formatted as a markdown link, of course.)

  1. E.g. if you run .!ls you automatically get all your (top-level) folders. To get all subdirectories as well, try .!ls -R. I never use the dir command on Windows, but you hopefully get the general idea.

Hope that helps!

Otternaut on Friday, Mar 6, 2020
In reply to Otternaut

Ah thanks! So when I write a word in vim, hover over them and press gf I get a new .txt?

I want to build a Zettelkasten with heavy interlinking

Edwin on Friday, Mar 6, 2020
In reply to Otternaut

The file or directory does already need to exist for gf (go to file) to work in Vim. But making a new file is super easy. Assuming you are in the right directory where you want a new file, you type :edit test.txt which will open the new file (:e test.txt for short). To save, then “write” out the file with :w. In your index file, you can now just type “test.txt” and run gf on that to jump to it! If you master Vim, you’ll never have to leave Vim again ;-). By the way, I wrote a mapping to quickly add a new note to the Zettelkasten. Have a look here. Notice that Vim also has a file explorer built in, in case you want to use that. It’s called netrw. There’s plenty of info online and for further information you can always use Vim’s built in help function with :help netrw.

By the way, I strongly recommend having a look at Markdown (.md extension). You can easily convert from that plain text format to webpages or pdfs with this amazing tool called pandoc.

Otternaut on Friday, Mar 6, 2020
In reply to Otternaut

Thank you so much! One last question. :) Is there an option in vim to highlight this words connected with an .md in the text?

For example you have an with the text ‚abc is great and test2 is also great‘. How can I highlight test2 in vim so that I know I can follow test2 with a gf command to

I think it will be difficult to have a good overview when you have for example 1000 .md textfiles

Edwin on Friday, Mar 6, 2020
In reply to Otternaut

You wouldn’t want Vim to check for each word you type whether it corresponds to a filename somewhere on your computer, which would be required to highlight “test2” only if it links to a file. So when you write “test2” you basically need to know yourself that’s a file. If your issue is that you are concerned that you might forget that refers to a file, I would suggest either writing it as a relative path, so as “./”. Then you know for sure that it’s a path. If you use a markdown link, you’ll also know it’s a link. So like: [ ]( ./ ). N.B. “test” and “” do not refer to the same file!

If you are concerned that you have to remember filenames when linking to them, it’s good to know that Vim can autocomplete filenames for you with Ctrl-X Ctrl-F (in insert mode, so when you are typing). And there are also many plugins to take of that more automatically).

Roman on Tuesday, Mar 10, 2020:

Edwin, thanks a lot :) Could you please help me to find the best way to make links between separate notes? And how to move quickly between these files?

Edwin on Wednesday, Mar 11, 2020
In reply to Roman

My pleasure! Otternaut (directly above) asked practically the same question, so reading through my response to him should help you. In short: 1) type the name of the file you want to link to, 2) use gf and gF in Vim (normal mode) to open that file. The only assumption this makes is that your working directory is set up correctly. The easiest solution is to make sure that the working directory is the root directory of all your notes :-). Check with :pwd and use :cd to change the working directory. Feel free to let me know if you encounter issues ;-).

Peter on Monday, Apr 13, 2020:

Hi Edwin! Great article, just what I was searching over last couple of days. I love vim and will definitely try your system out :-)! Thumbs up! Thank you!

Peter on Monday, Apr 13, 2020:

What a wonderful idea notetaking with Vim. I will give your system definitely a try, because it’s something I always wanted to do. Thank you.

Edwin on Monday, Apr 13, 2020
In reply to Peter

Hi Peter, thanks for the kind comment and for dropping by. Let me know if you encounter anything that is unclear!

Peter on Tuesday, Apr 14, 2020:

Hi Edwin! First of all many thanks for your kind reply and my apologies for the double-post. I got an error-message the first time - so I posted again…

I played around with the index-file, the command “gf” was new to me, so I was impressed, how things working.

My only question here is: your index file is linked to certain subfolders (or directories) and not to certain “documents” is that right? That’s why you implemented the tree structure - I guess?

BTW: I just set up a minimalistic system, which I can sync via “Syncthing” to my smartphone. There I have installed an app called Markor, which can read and edit all the files. Great stuff :-).

Edwin on Tuesday, Apr 14, 2020
In reply to Peter

Hi Peter! Yeah I received all five of your comments :-) My comment setup is a complete hack, because your comments are actually sent to a raspberry pi. I’m glad to hear you like it! With respect to your question: in the tree displayed in this post you can actually run gf and gF both on files and directories. Using it on a directory will just open Vim’s file explorer, called “netrw” (you can also access it with “:Explore”, by the way).

To be honest, I’ve almost immediately moved away from using the tree. It just looked cool, but it quickly gets unmanageable. Relying on directory structure forces you to categorize notes rather than relying on search tools and direct interlinking. I’ve switched to a “Zettelkasten” approach.

However, the idea of an index page is alive and kicking! You can always insert links to heavily used project notes. I currently use a page with all my tags as my index page (for tags, see the next post). I maintain that page automatically with a Python script that I have not published yet. It works great for me but I haven’t published it yet because it’s an ongoing project :-). Because there’s so much interest recently I should really start working on publishing it though.

Peter on Wednesday, Apr 15, 2020:

Hi Edwin! Again many thanks for your kind answer, now everything is clear to me. So this system is great and I also like the index page very much. The Zettelkastensystem seems a good approach here. I will give it a go for a while. Looking very forward, reading more of your fine articles here. Thanks a million for all the help and take care!

Edwin on Wednesday, Apr 15, 2020
In reply to Peter

Good to hear! Further feedback is always welcome. At the end of this series I might bundle everything somewhere in one place for easier reference, so all user experience is appreciated. Thanks for your enthusiasm :-).

Peter on Sunday, Apr 19, 2020:

Hi Edwin!

Sorry, me again ;-). After a couple of days trying out the note system with Vim, I’m getting happier and happier every day. I love the flexibility and the ability to set links to other documents.

From your article above, I found the f very helpful. Is there a keystroke, which opens the file in a vertical way (right beneath the index file)? I had a look into the help-function and did some research via Google, but couldn’t find anything - apart from splitting Vim-window straight from the beginning.

Many thanks in advance for your kind help!!!

Edwin on Sunday, Apr 19, 2020
In reply to Peter

Hi Peter, yes there is :-) (and if there wouldn’t be, we could figure out how to write exactly what you want without too much effort). If I understand you correctly, Ctrl-W f should do exactly what you want. This will open the file under your cursor, but then in a horizontal split. By the way, somewhat ironically opening it vertically is a regular horizontal split, and opening it side by side is a vertical split. If you happen to know the filename by heart, you can also open files in splits using :sp[lit] filename and :vs[plit] filename, where the parts between brackets are optional (i.e. you can abbreviate the commands).

The Ctrl-W prefix is not as elegant as some other Vim commands, but it’s still mnemonic, because the W stands for Window, and this prefix is used for all window-related commands. If you feel adventurous, you can explore a bit further with :help Ctrl-W. I’m glad to hear you are enjoying it! :-)

Peter on Monday, Apr 20, 2020:

Hi Edwin!

Once again many thanks - that’s very helpful!!!

Cheers, Peter

Robert on Wednesday, Apr 22, 2020:


A great post. I had been using vimwiki but when I added vim-pandoc there were a few conflicts based on file types. I have been inspired by you and Conner (the doctor you mentioned) to try to create a way of doing notes that does not depend on vimwiki.

Thank you.

Edwin on Wednesday, Apr 22, 2020
In reply to Robert

Great! Thanks for dropping by. I tried Vimwiki for about 5 minutes myself but encountered issues I didn’t bother fixing. Perhaps my issues were also caused by a conflict with vim-pandoc :-)

captain shambles on Thursday, Apr 22, 2021:

I’d love to see an update on how your current system is working in 2021! Maybe you could do another article to clean up all these edits too.

Edwin on Thursday, Apr 22, 2021
In reply to captain shambles

Noted :-)! To be completely honest, it’s long overdue!

Ritchie on Thursday, Apr 22, 2021:

Great post!

Edwin on Thursday, Apr 22, 2021
In reply to Ritchie

Thanks! Also thanks for your emails.