I spend a lot of time looking at Markdown. For a while, my workflow involved switching to a browser with a preview extension or splitting my editor in half with VS Code, neither of which felt right. I wanted a persistent preview panel I could glance at from anywhere, without switching focus.
So I built one.
Why Native Swift
The obvious path would have been Electron, but I wanted a binary that was small, started instantly, and didn’t contribute to my memory-hogging tab stack. MDMenuBar is pure Swift with AppKit: no dependencies, no package manager, no bloat.
The tradeoff is that AppKit is “grubby” compared to modern frameworks. You’re managing frame math and view hierarchies manually, but for a menu bar app that needs to float above other windows and ignore the application activation model, it’s the right tool for the job.
The File Watching Hurdle
Live reload sounds simple until you realize how most editors handle saves. VS Code performs atomic saves, writing to a temp file and renaming it, which breaks file watchers that only listen for write events on the original file.
I spent an embarrassing amount of time figuring out that I needed to listen for .write, .rename, and .delete events, and re-open the path to catch the new inode whenever a rename occurred. When it finally clicked, I felt clever, until I realized it’s just the standard approach everyone else already uses.
Building the Renderer
I didn’t want to pull in a third-party Markdown library with a massive dependency graph. I wrote MarkdownRenderer.swift as a two-pass state machine, about 350 lines of code. The first pass handles block-level elements, and the second handles inline elements using ordered regex substitutions.
Is it spec-compliant? No. But it handles every edge case I’ve run into in six months of daily use, and I’ve been able to fix the ones I did hit in ten minutes each.
The Global Hotkey
I used Carbon’s legacy RegisterEventHotKey to register global shortcuts without requiring those annoying Accessibility permissions. It’s a deprecated technique, but it’s exactly what apps like Raycast and Alfred use; until Apple provides a better option, it’s the only answer.