Huy's Notes
Emacs for note-taking

Emacs for note-taking

#note-taking #editor

Previously, I use an editor called Obsidian to maintain this notes site. Now I'm moving back to Emacs.

Obsidian still a very good editor that has a lot of great features and it is very easy to maintain links between the notes files, there are a lot of things that doesn't fit my note-taking habit, also, it's lack of scripting ability.

Some noteworthy thing, for example, is you cannot paste an image from a clipboard with a customized name in Obsidian, or you cannot integrate it with a grammar checker, ...

Emacs, on the other hand, is a very old but powerful editor that let you customize everything, and when you find something you're not happy with, what you will do is, just write a small snippet to make it work the way you want.

This note will walkthrough some part of my setup to let me replace Obsidian with Emacs for daily note-taking, with some improvements.

Manage and search documents

This actually came from my original setup, deft is an Emacs mode that let you quickly browsing, filtering and editing your notes. It works with every plain text documents.

The movement to Obsidian makes me converting all my notes from org-mode to markdown format, I don't feel like I want to move back to org-mode anytime soon, the main reason is, this Gatsby site still also use markdown format, so let's stick with it.

We can config deft to only search for markdown files with deft-default-extension option.

;; Deft Package
(use-package deft
  :ensure t
  (setq deft-directory "~/notes"
        deft-recursive t
        deft-default-extension "md"
        deft-text-mode 'org-mode
        deft-use-filename-as-title t
        deft-use-filter-string-for-filename t)
  (global-set-key (kbd "C-c d") 'deft))

Links between notes

Emacs's markdown-mode also supports wikilink, but by default, it converts all the space characters to a dash "-", we can force it to use space.

(setq markdown-enable-wiki-links t)
(setq markdown-link-space-sub-char " ")

To open a link while editing markdown files, use C-c C-o.

To insert a wikilink to any exists note, and follow Obsidian's format at the same time (link with file name only, without the extension), I wrote a small function to help me quickly pickup the file from a list and insert it to the document between the double squared brackets.

;; Insert file names to current buffer
(defun insert-file-name-as-wikilink (filename &optional args)
  (interactive "*fInsert file name: \nP")
  (insert (concat "[[" (file-name-sans-extension (file-relative-name
  filename)) "]]")))
(define-key markdown-mode-map (kbd "C-c i") 'insert-file-name-as-wikilink)

Paste image from clipboard

Obsidian has the ability to paste an image directly from the clipboard, and it inserts a link to that image to the document, but you cannot change the file name of the pasted image right in the editor. In Emacs, we can fix this.

First, we need to have a way to save an image from clipboard to disk, I used a small bash script for this:

Create a script file at /usr/local/bin/pasteimage with the following content (Please note that this script only works on MacOS):

#!/usr/bin/env bash
filename=$(date +%Y-%m-%d\ at\ %H.%M.%S).png

if [ $# -ne 0 ]; then
    if [ -d $1 ]; then
        if [ "$1" != "." ]; then folder=$1; fi
        a=$(dirname "$1")    
        b=$(basename "$1" )

        if [ "$b" != "" ]; then filename=$b; fi

        if [ "$a" != "." ]; then folder=$a; fi

osascript -e "tell application \"System Events\" to ¬
        write (the clipboard as «class PNGf») to ¬
        (make new file at folder \"$folder\" ¬
        with properties {name:\"$filename\"})"

When we have an image in clipboard, we can use this script to save it to disk by calling:

pasteimage <path-to-saved-image>

Now, we can call it programmatically in Emacs with this function:

;; Insert image in clipboard to markdown
(defun insert-clipboard-image-to-buffer (filename &optional args)
  (interactive "*fSave image to: \nP")
  (shell-command (concat "pasteimage " filename))
  (insert (concat "![](" (file-relative-name filename) ")")))
(define-key markdown-mode-map (kbd "C-c u") 'insert-clipboard-image-to-buffer)

Rename a note and all the backlinks

One of Obsidian's notable ability is you can rename a note file and have all the backlinks to that note in other files updated automatically.

It's a bit complicated to do that in Emacs and string replacing in Elisp is not really efficient, so I'm gonna do that in JavaScript and call that script in Emacs. The idea of this script is:

1. For each markdown files in the current working folder
2. Check if we have the link to the old name of the note
3. If we do, replace it with the new link
4. Save that file if modification made

In Emacs, I write a function called rename-current-file-and-backlinks to rename the file, the buffer and run the backlink update script:

;; Rename current file and all its backlinks
(defun rename-current-file-and-backlinks (new-name &optional args)
  (interactive "*fEnter new file name: \nP")
  (let ((original-link-name (file-name-sans-extension (file-relative-name buffer-file-name)))
        (new-link-name (file-name-sans-extension (file-relative-name new-name)))
        (filename (buffer-file-name)))
    ;; Rename buffer and file name
    (rename-file filename new-name 1)
    (rename-buffer new-name)
    (set-visited-file-name new-name)
    (set-buffer-modified-p nil)
    ;; Relink all notes
    (shell-command (concat "note-relink" " " "--from=" original-link-name " " "--to=" new-link-name))
    ;; Replace current file title
      (goto-char (point-min))
      (while (search-forward (concat "title: " original-link-name) nil t)
        (replace-match (concat "title: " new-link-name)))))))

(define-key markdown-mode-map (kbd "C-c r") 'rename-current-file-and-backlinks)

This setup still lack of some features from Obsidian, such as the graph view, which I barely used. But it's good enough to do the job, I guess I'm gonna stick with Emacs for a while more.

Maybe sometimes in the future, I'll write the whole things in Elisp, but let's save it for future.

Referred in

If you think this note resonated, be it positive or negative, please feel free to send me an email and we can talk.