This blog post could have just been a note in my Neorg workspace.
However, I didn't find much in the way of good explanations of how to set up Neorg in Nixvim when I was trying to do it, so hopefully this helps anyone attempting this after I did. I'm going to assume knowledge of Nix and NixOS in this post, if you aren't familiar then I recommend starting with the Nix tutorial.
What is Nixvim?
Lets start with Nixvim.
When I first switched to using NixOS I used Neovim from nixpkgs, with a bunch of lua plugin config to set things up to my liking. You can see this old config on my GitLab account.
However, I eventually ran into some difficulties with LSP configuration, specifically getting the Vue LSP (aka Volar) working reliably. I don't remember the details at this point (clearly my note taking habit still needs improvement), but it was frustrating enough I went looking to see if anyone had done it for me. That's when I found Nixvim.
Nixvim is a Nix flake, which allows you to configure Neovim and its plugins directly via Nix. Other people have already done the work of getting many plugins working nicely with minimal boilerplate, your config just needs to enable them and set any non-default config you need.
Details of how to use the almost 500 plugins currently packaged are in the documentation, along with LSPs and other configuration settings.
Here's an abridged version of my config before configuring the Neorg plugin.
{ pkgs, config, ... }:
{
programs.nixvim = {
enable = true;
defaultEditor = true;
viAlias = true;
vimAlias = true;
extraConfigVim = builtins.readFile (./neovim/config/init.vim);
colorschemes.catppuccin.enable = true;
globals.mapleader = ",";
plugins = {
# Many more here...
lsp = {
enable = true;
inlayHints = true;
keymaps.lspBuf = {
"grd" = "definition";
"grt" = "type_definition";
};
servers = {
clangd.enable = true;
cmake.enable = true;
efm.enable = true;
lua_ls.enable = true;
markdown_oxide.enable = true;
nil_ls.enable = true;
pyright.enable = true;
rust_analyzer.enable = true;
tailwindcss.enable = true;
ts_ls.enable = true;
volar.enable = true;
};
};
telescope = {
enable = true;
extensions = {
fzf-native.enable = true;
ui-select.enable = true;
};
};
treesitter = {
enable = true;
grammarPackages =
config.programs.nixvim.plugins.treesitter.package.allGrammars;
settings = {
highlight.enable = true;
indent.enable = true;
};
};
};
keymaps = [
# Omitted for brevity
];
};
}
What is Neorg?
Neorg is a note taking and organisation tool, built as a Neovim plugin. It's inspired by org-mode from emacs, but notably less feature rich.
I used to use VSCode, and used the Dendron plugin for managing my notes and tracking tasks. Dendron is pretty nice, and having it integrate with my default text editor was a lovely experience. However, Dendron has been dead and effectively unmaintained for several years, so replacing it with something else has been on the agenda for a while.
The obvious replacement is Obsidian, which I use for some worldbuilding notes already. However, I don't fully get on with it's editing experience, especially having switched to Neovim as my daily editor. I also don't like that it isn't FOSS, and prefer Dendron's approach to hierarchy to Obsidian's.
I looked at nvim-obsidian, which essentially adds some functionality to Neovim to help when interacting with Obsidian vaults, but that only solves some of those problems, and using a third-party thing for interacting with Obsidian notes feels likely to be a fraught experience.
So I ended up at Neorg. This project also seems a little bit on the quiet side, but I don't think it is fully dead yet and it is quite pleasant to use and suits my needs nicely.
All my existing notes are in markdown, so switching to the norg format is a
bit of a change. I actually really like how this ends up structuring documents
though, and the plugin has a bunch of nice features to help with viewing your
notes. I particularly like the automated folds provided by the treesitter
integration.
Neorg in Nixvim
Now, onto the thing I'm actually writing this post to remember and share.
Looking at the documentation, we can see that Neorg is already packaged. Enabling it is pretty easy, along with providing some basic config options.
neorg = {
enable = true;
telescopeIntegration.enable = true;
settings = {
load = {
"core.concealer" = {
config = {
icon_preset = "varied";
};
};
"core.defaults" = {
__empty = null;
};
"core.dirman" = {
config = {
workspaces = {
notes = "~/notes";
};
default_workspace = "notes";
};
};
"core.keybinds" = {
config = {
default_keybinds = true;
neorg_leader = "<Leader><Leader>";
};
};
};
};
};
Adding this to our plugins section does the job, and will set things up to
store all your notes in ~/notes. I'm not sure that the neorg_leader option
is actually doing anything, that's something on my list to debug.
Optionally you can add some keybinds for various commands, to make navigating your workspace easier. I have keybinds for creating new journal entries, injecting metadata, opening and closing the workspace, and some of the telescope integration.
Notably however, you'll find that Neorg doesn't work very well if you just drop in this config. There are a couple of issues to resolve.
First, Neorg makes use of <LocalLeader> in its default keybinds, which is not
set by default. We can fix that easily at the top level of our config.
globals.maplocalleader = ";";
Next, the biggest issue is that the treesitter grammar for norg files isn't
installed. Amongst other things, this means the concealer module doesn't work,
significantly degrading the user experience. Thankfully, despite (for some
reason) not being in allGrammars, the norg grammars are packaged in nixpkgs.
We can update the treesitter config to ensure we install them.
treesitter = {
enable = true;
grammarPackages =
with pkgs.tree-sitter-grammars;
config.programs.nixvim.plugins.treesitter.package.allGrammars
++ [
tree-sitter-norg
tree-sitter-norg-meta
];
settings = {
highlight.enable = true;
indent.enable = true;
};
};
At this point things should be working nicely, with automated folds, and proper
decoration of headings, tasks, etc. If not, you probably need to increase your
conceallevel in your Neovim config. I have an init.vim file which includes
extra vim config settings, so I also added a line in there.
set conceallevel=3
And then things are fully working.
Hopefully this is useful for anyone else who goes on a similar debugging journey. At some point I might write a post about how I'm actually using Neorg, once I've settled into a properly comfortable habit with it.