UPDATE: I no longer use this approach. I still have obsidian.nvim in my nvim configuration, however I mainly take notes through Obsidian instead.
I realized that the context switch actually helps makes me focus more and slow down a bit when taking notes, which results in better quality notes I believe.
Also, since I use hyprland
, Obsidian just stays open on one of my workspaces all the time, and the switch is not a big deal.
Of course, feel free to refer to this blog if it is helpful to you in any way, but be warned that obsidian.nvim
api might have also changed since this was not updated for so long.
Recently, I started using obsidian.nvim to edit notes in
neovim instead of obsidian. The goal, as described by the obsidian.nvim developer, is that I enjoy
the neovim experience so much that I prefer editing notes in it rather than obsidian. I still use
obsidian for viewing and certain editing workflows (such as excalidraw), but most of my note-taking
time is spent in neovim.
The experience so far has been good. However, I have noticed a lack of support for certain workflows.
In the following sections, I will discuss these workflows and then explain how I implemented a custom
lua
function and nvim keymaps for them.
Note Capture
Sometimes, you simply want to quickly jot down some notes without worrying about where to put them or
their structure. Later on, you can review and process those notes along with others.
One example would be when you are coding. Suppose you have discovered that a library function you are
using is buggy, and you do not want to forget what causes the bug, or for some other similar reason.
In this example, during the normal workflow, you would determine a location to save the file, decide
on its name and structure, and additionally, implement a mechanism to ensure that you do not forget this
note later on.
This workflow is too distracting for me, and I easily lose focus on what I was previously working on.
Yes, it is possible to automate this through neovim configuration, but there is still the problem of
having two different “note-taking mechanisms” if you are also using Obsidian and cannot really give it up
in favor of neovim for note taking.
The workflow I desire for this “capture” process is as follows:
- Quickly create a capture note on a split window using a keymap.
- The note should be saved in a subfolder named ‘capture’ within the Obsidian vault.
- The note’s name should be in the ‘zettelkasten’ style ISO time stamp format.
Notes with templates
Another workflow involves automatically creating notes using specific templates. For instance, you can
create a blog post note (similar to this one) with specific front matter lines that you configure for
your static site generator configuration or other use cases. Ideally, this note would be stored in a
different subfolder as well.
obsidian.nvim already provides “templating” functionality with the ObsidianTemplate
command, which
opens a telescope window listing the templates in your vault. When you select a template, it is applied
to the file. This feature is convenient and works perfectly fine. However, I would like to have specific
templates automatically applied to files created in specific subfolders immediately after they are created.
The desired workflow for this “templating” process is as follows:
- Create a note quickly on a split window using a keymap.
- The note should be saved in a specific subfolder within the Obsidian vault.
- Immediately apply a template specific to the subfolder to the note.
As you can see, this workflow is more generic, although it shares some similarities with the previous one.
Let’s proceed to the next section where we will set these up.
obsidian.nvim configuration
Before we proceed with implementing our own note function, we should first check some of the options
available in obsidian.nvim, beginning with opening notes on a split window.
Opening notes in a split window
In both workflows, I want to open notes in a split window. Obsidian.nvim already has an option
called open_notes_in
for this purpose. However, as you will see, in our lua
function for
creating new notes, we will have to accomplish this using lua
code because the notes created
through that function will not be managed by obsidian.nvim for opening in a split.
Notes without a file name
We will prompt through neovim for the file name of the new note when we are creating a regular
note. However, what occurs when no file name is provided? By default, obsidian.nvim generates a
random filename/id that consists of a timestamp and random strings.
This can be changed via note_id_func
. In our case, as we will see later, we want the
yymmddHHMMSS
format for our file names if a file name is not given.
To manage or not to manage front matter
If you set disable_frontmatter = false
, obsidian.nvim is able to handle the front matter of your notes.
You can customize it by defining a function for note_id_func
. I was initially using this approach, but
found it limiting after a while.
The first reason is that you cannot selectively manage the front matter. What I mean by this is that for
certain notes in specific subfolders (such as ‘capture’), I do not want any front matter management or any
front matter at all.
The second reason is that I want to apply templates immediately after the note is created, which makes
front matter management completely unnecessary.
The obsidian.nvim configuration
Based on the points mentioned earlier, I have the following (partial) configuration in my neovim
configs for obsidian.nvim:
1-- ...
2
3open_notes_in = "vsplit",
4disable_frontmatter = true,
5templates = {
6 subdir = "templates",
7 date_format = "%Y-%m-%d",
8 time_format = "%H:%M",
9 -- A map for custom variables, the key should be the variable and the value a function
10 substitutions = {},
11},
12note_id_func = function(title)
13 -- If title is not given, use ISO timestamp, otherwise use as is
14 if title == nil then
15 return tostring(os.date("%y%m%d%H%M%S"))
16 end
17 return title
18end,
19note_frontmatter_func = function(note)
20 return {} -- return empty as we don't manage front matter anyway
21end,
22
23-- ...
Please note that I have also added the templates
option here in case you want to include
custom variables that will be used with your obsidian templates.
The custom note creation function
Finally, here is the lua
function I use for the workflows listed above:
1-- ...
2
3local client = require('obsidian').setup(...) -- save client after setup
4
5--- Create a note
6--
7---@param subdir string?
8---@param ask_name boolean?
9---@param template string?
10---@return nil
11local function new_note(subdir, ask_name, template)
12 -- get file name, otherwise use ISO timestamp
13 local fname = ""
14 if ask_name == true then
15 -- get file name from user input or return ""
16 inp = vim.fn.input("Name: ", "")
17
18 -- if no name given and ask_name == true, cancel note creation
19 if inp == "" then
20 return
21 end
22
23 fname = inp
24 else
25 -- if ask_name == false, then assign timestamp for filename
26 fname = tostring(os.date("%y%m%d%H%M%S"))
27 end
28
29 -- create query to check if note already exists
30 -- can be a file name or path to a file
31 local query = fname .. ".md"
32 if subdir ~= nil then
33 query = subdir .. "/" .. fname .. ".md"
34 end
35
36 -- try to find the note, and create if not found
37 -- if path given, checks all sub directories of the vault for the path
38 -- if file name is given, checks again all sub directories of the vault for the name
39 local note = client:resolve_note(query)
40 if note == nil then
41 note = client:new_note(fname, fname, client.dir .. "/" .. subdir)
42 end
43
44 -- create a split window and open note on that window
45 vim.cmd("vsplit")
46 vim.cmd("edit " .. tostring(note.path))
47
48 -- if a template is given, apply the template immediately
49 if template ~= nil then
50 vim.cmd("ObsidianTemplate " .. template .. ".md")
51 end
52end
53
54-- ...
Here you go. I have documented the function as well and hope it is easy to understand.
Now, let’s move on to the keymaps I have created for using this function.
1-- ...
2
3-- Create a permanent note on the vault root,
4-- get file name from the input, and apply the
5-- "basic" template
6vim.keymap.set("n", "<leader>nN", function()
7 new_note(nil, true, "basic")
8end, { noremap = true, desc = "Permanent Note" })
9
10-- Create a capture note on 'capture' sub directory
11-- of the vault, use ISO timestamp as the file name,
12-- and don't apply any templates.
13vim.keymap.set("n", "<leader>nn", function()
14 new_note("capture", false, nil)
15end, { noremap = true, desc = "Capture Note" })
16
17-- Create a project note on 'project' sub directory
18-- of the vault, get file name from the input,
19-- and apply the "project" template
20vim.keymap.set("n", "<leader>np", function()
21 new_note("projects", true, "project")
22end, { noremap = true, desc = "Project Note" })
23
24-- Create a project note on 'blog' sub directory
25-- of the vault, get file name from the input,
26-- and apply the "blog" template
27vim.keymap.set("n", "<leader>nb", function()
28 new_note("blog", true, "blog")
29end, { noremap = true, desc = "Blog Note" })
30
31-- ...
I hope these were clear as well. I have other keybindings for obsidian.nvim as well,
but they are using the default commands so were not mentioned here. For example, I still
use ObisidianToday
and ObsidianYesterday
commands for journal notes. You can
see my configuration from
here.
Closing thoughts
I hope that this will be helpful for your note-taking setup as well. Personally, I really
enjoy this workflow. It motivates me to take more notes and I am much more productive when
coding, etc. This is because I can quickly jot down notes on things that I don’t need to
remember at the moment and instead, focus on my coding. Though would prefer to have a better
lua
API from obsidian.nvim, but it is OSS so I can’t complain much.
I might add couple more custom functions for processing these ‘capture’ notes in bulk later,
or for more complex templating. I would be sure to share it here though, if I do implement
those (plug ‘follow me’ here - currently I don’t have the mechanism for follows yet, but
RSS should be available ( ͡❛ ‿‿ ͡❛) ).
Alright, long post already. See you later, byeee 👋