My notes database consists primarily of Emacs Org mode files, interspersed with
a small number of markdown files, some of them from previous note-taking
systems (for example, I went through a Gollum stage early in 2014, according to
my notes then), and some of them for easier mobile consumption and production.
To demonstrate the unified org / markdown node completion (note that it’s
listing org-roam nodes in this markdown file), I’ve selected a choice note from
10 years ago, in which I was already trying to find a better mobile note-taking
However, md-roamrequires each markdown file to have a ---\n...\n----delineated
yaml section at the start with at a minimum the note’s title and ID.
I thought that it would be much more convenient if md-roam could use the first
non-empty line of text as the note title, the filename as ID and as a bonus,
extract hashtags from anywhere in the file.
This would also make it much easier to author these files on my mobile device
using the 1writer app, and many others like it which follow the same title and
Thanks to the magic of Emacs Lisp, it was not too tricky to override a number
of md-roam functions to make exactly this happen.
We use advice to override a number of md-roam-... functions to extract the
title and id we want, and more subtly we modify
md-roam-get-yaml-front-matter-endpoint in two different ways, first to support
generally frontmatter-less operation, and second to extract tags from
Once implemented (see the code below), almost any old markdown file in your
org-roam directory will be indexed by org-roam, and available for linking and
viewing via the usual org-roam functions.
(defuncpb/get-first-line()"Get first non-empty line from the current buffer"(interactive)(save-excursion(goto-char(point-min))(if(re-search-forward"[a-zA-Z]");; go back 1 char as re-search-point leaves point to the right of first hit(buffer-substring-no-properties(1-(point))(line-end-position)))))(defuncpb/md-roam-get-id()"Return basename+ext of currently visited file, to be used as org-roam ID."(when-let*((bfn(buffer-file-name));; only if we are visiting a file(ext(file-name-extensionbfn)));; and it has an extension;; and ext is markdown, then we use the basename+ext(if(string=ext"md")(file-name-nondirectory(buffer-file-name)))));; thanks to nobiot we can include md files with our org-roam database!;; as per the docs https://github.com/nobiot/md-roam#basic-configuration;; NB: md-roam-mode should be active before org-roam-db-autosync-mode(use-packagemd-roam:quelpa(md-roam:fetchergithub:repo"nobiot/md-roam"):config(setqorg-roam-file-extensions'("org""md"))(md-roam-mode1);; the first line with characters in the file becomes the title;; (a heading will also work)(advice-add#'md-roam-get-title:override#'cpb/get-first-line);; use the basename+ext as the ID -- if you're using ZK-style timestamps, these should be unique(advice-add#'md-roam-get-id:override#'cpb/md-roam-get-id);; many md-roam functions require and assume front-matter and want to do stuff;; right after, in body of file. We don't want front-matter, so we substitute;; with start of buffer which is also start of body in our case!(advice-add#'md-roam-get-yaml-front-matter-endpoint:override#'point-min);; however, only for get-tags, we want to override the front-matter endpoint to be the end of the buffer;; as md-roam usually searches only in the frontmatter, but we want it to search the whole buffer;; #tags everywhere!;; 1. define around function(defunget-tags-whole-buffer(orig-get-tags&restargs)(cl-letf(((symbol-function'md-roam-get-yaml-front-matter-endpoint)#'point-max))(applyorig-get-tagsargs)));; 2. install it around the md-roam-get-tags function(advice-add#'md-roam-get-tags:around#'get-tags-whole-buffer))
Remember that you should also set (setq markdown-enable-wiki-links t) if you
want wiki-style [[...]] links to support opening, and auto-completion.