It took me a while to understand that I need/needed to write everything down or there was a greater-than-fifty-percent chance that, whatever it was, I'd forget about it. Initially I was scribbling on random bits of paper, then moleskins, then markdown files scattered around my hard drive, then I started messing with Standard Notes; which I used happily for nearly a year. But then I started predominantly using Emacs for my development work (after moving from Vim "just cuz") and got tired of moving out of Emacs to write notes.
I knew of Org-mode, but it seemed odd to me. I was still married to the syntax of standard Markdown, so the org syntax grated on me.
No longer. Down the org rabbit hole...
Like most new-to-org/emacs users, I relied (and still do, to some extent) heavily on external packages. Many of them are wonderful pieces of software and I tip my hat to the creators of those packages (namely, @jethrokuan and @alphapapa; both of whom have been personally helpful when I've asked questions). Whether it was initiated by my need to tweak my editor to my specifications or simply to satisfy my curiosity, I started writing tiny functions in Elisp to aid in getting my notes written-out as quickly--and painlessly--as possible.
Generally, my note-taking process in Emacs is as such:
I've purposely hidden my org-tags via their face configuration. I don't find them useful (with the exception of one, which I'll discuss later), but I do tag my headings heavily.
In #3's image I've linked to the last time I worked on "Project X" via the "see yesterday" org-link, which references...you guessed it, my note from yesterday.
The above has worked well for me for a while, but I continually found myself either losing context in the sprawl of daily notes in my org directory, people mentioned in my notes, or how to quickly lookup a conversation I had with such-and-such person. So, as any good hacker is wont to do, I stayed up later and started losing myself in the parenthetical ~hell~ heaven. Some of the pain points I hit were tagging people and building references (backlinks) to notes. It was easy enough to store a link and insert it where I needed it, but there was a bi-directionality that I was missing.
Let's say I want to insert a link like the "see yesterday" link in the image above. Simple, right?
org-store-link...move to necessary file/region...
But then I hit the problem of knowing if the note I'm reading has been referenced anywhere else. It's not a thing I do a lot, but I do occasionally need to do it. Grep/ag/ripgrep work, but that's a lot of work. So I wrote this elisp function:
(defun my/org-insert-link-and-ref () "effectively duplicates the org-insert-link function and adds a ref (a link to the file the linked-entry is pasted into) in the linked-entries property drawer." (interactive) (let* ((buf (current-buffer)) (current-heading-id (org-id-get-create)) (current-heading (format "%s" (org-get-heading t t t t))) (heading-of-inserted-link (format "%s" (cadr (car org-stored-links)))) (id-of-inserted-link (substring-no-properties (car (car org-stored-links)))) (file-of-inserted-link (car (org-id-find (cadr (split-string id-of-inserted-link "id:"))))) (buffer-of-inserted-link (org-find-base-buffer-visiting file-of-inserted-link)) (marker-to-inserted-link (org-find-exact-headline-in-buffer heading-of-inserted-link buffer-of-inserted-link)) (marker-to-current-link (org-find-exact-headline-in-buffer current-heading buf))) (with-current-buffer (get-buffer-create buffer-of-inserted-link) ;; check the REFS for existence/enries (if (org-entry-get marker-to-inserted-link "REFS") ;; check if the id has already been inserted (avoid placing the same ref) (if (not (string-match-p current-heading-id (format "%s" (org-entry-get marker-to-inserted-link "REFS")))) ;; if there's no ref already in the property, append it (org-entry-put marker-to-inserted-link "REFS" (format "%s //// [[id:%s][%s]]" (org-entry-get marker-to-inserted-link "REFS") current-heading-id current-heading))) ;; else, place the ref (org-entry-put marker-to-inserted-link "REFS" (format "[[id:%s][%s]]" current-heading-id current-heading))) (save-buffer)) (insert (format "[[id:%s][%s]]" id-of-inserted-link heading-of-inserted-link))))
There's a lot going on here and I'm completely aware that
org-roam solves this with its
backlinks paradigm, but I like to make life harder and learn on my own, so here's a recreated wheel!
my/org-insert-link-and-ref does is insert the "last stored" org link, visits the headline that was just inserted, adds a property
REFS to the
PROPERTY drawer of said headline, and adds (or appends) a link to the headline that I just inserted into. This might be better visualized with another image:
Now, when I read that note, I can easily see that I referenced it somewhere else (namely, in a headline dubbed "More Hume"). Excellent.
But what about people? I would like to be able to consolidate my conversations with people so that I can "at" a person (
@someperson) in a note and look that up easily. For example, one day I might think,
I know I had a convo with so-and-so about unit tests, but I don't know when that was...
I could search my tags for various terms (
so-and-so, etc.), but that's pretty inefficient. What if I had a file I called
contacts.org that held headlines of each person I've ever mentioned in my note taking? That could work. There might also be a package for it, but why not just re-invent another wheel? Let's do it...
When I press
CTRL-@ I get an
ivy popup which let's me select a name that is queried from a
If a name doesn't exist, I get prompted to add the name to the file as well as an alias (which is stored in the person's PROPERTY drawer), that will be placed in the tag (link) like so:
@ a person in my notes I have a custom function which links the heading I'm pasting into into the person's heading in the
contacts file. It's really helpful for answering the question of "I know I talked to...but I can't remember...":
When I begin a new note I like to have a running list of things I'm working on. I define these by tagging a given heading with an
in_progress tag. When my file is generated I get a list of things marked as "in progress". Yeah, I could probably use
TODOs and look at my agenda, but in all honesty, I haven't leaned too much on
org-agenda yet. I like to keep as much context in my daily notes as possible.
(defun my/get-current-tasks () (interactive) (insert "Current tasks:\n") (dolist (item (org-ql-select (org-agenda-files) '(tags "in_progress"))) (insert (format "- [[id:%s][%s]] (last worked-on: %s)\n" (org-element-property :ID item) (org-element-property :raw-value item) (org-element-property :DATE_MODIFIED item)))))
Those are, roughly, the wheels I've recreated. I still have some pain-points I'm working through, but I really like my flow so far. If you have any questions or suggestions feel free to reach out to me: dev (AT) mttyng (dot) com