HomeAboutPostsTagsProjectsRSS
┌─
ARTICLE
─┐

└─
─┘

Emacs’s markdown-mode offers several preview options, but finding one that “just works” took some exploration.

The xwidget-webkit Approach

My first attempt used markdown-live-preview-window-function with xwidget-webkit—Emacs’s embedded WebKit browser. The idea: render markdown to HTML and display it in a split window.

(defun my/markdown-live-preview-window-xwidget (file)
  (xwidget-webkit-browse-url (concat "file://" file))
  (xwidget-webkit-buffer))

Four problems killed this approach:

  1. External dependency — HTML generation requires markdown (default) or pandoc binary
  2. Emacs build requirement — xwidget support must be compiled in (–with-xwidgets), which isn’t universal
  3. Temp file pollution — Live preview generates HTML files that require cleanup
  4. Complexity — Managing the xwidget buffer lifecycle adds code I’d rather not maintain

The Obsidian Solution

Obsidian is primarily a note-taking app, but it’s also an excellent free markdown renderer with real-time preview. Using it as an external viewer sidesteps all the complexity.

The key discovery: Use custom URI scheme to open a file directly in Obsidian:

obsidian://open?path=/path/to/file.md

Final Configuration

(setopt markdown-open-command
        (lambda ()
          (let ((uri (concat "obsidian://open?path="
                             (url-hexify-string (buffer-file-name)))))
            (start-process "obsidian" nil "open" uri))))

Now C-c C-c o opens the current markdown file in Obsidian instantly.

Implementation Notes

  • markdown-open-command accepts either an executable path (string) or a function
  • When using a function, it receives no arguments—access the file via (buffer-file-name)
  • url-hexify-string handles paths with spaces or special characters
  • macOS open command launches URI schemes directly

Why This Works

Concernxwidget-webkitObsidian
External binaryRequires markdown or pandocNone
Emacs buildRequires –with-xwidgetsWorks with any build
Temp filesGenerates HTML requiring cleanupNone
Setup complexityCustom buffer managementSingle variable
Rendering qualityBasic HTMLFull GFM support

Sometimes the best solution is delegating to a tool that already does the job well.