Skip to content

stevenjswanson/md-preview

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MD Preview

Quick Look for Markdown files on macOS. Press Space on any .md or .markdown file in Finder and see it rendered as formatted HTML — headings, tables, task lists, code blocks, images, and more — instead of raw text.

macOS Swift License

#vibecoding — This project was built with Claude Code (Anthropic's AI coding assistant). All Swift source files, the embedded JavaScript Markdown parser, CSS, Xcode project configuration, and this documentation were written by AI and have not been independently reviewed or tested. Things may be wrong. That said, I'll do my best to respond to bug reports and questions — feel free to open an issue.


Installation

Option A — Download pre-built app (recommended)

  1. Go to the Releases page and download the latest MDPreview.zip
  2. Unzip and drag MDPreview.app into your /Applications folder
  3. Open the app once (right-click → Open if Gatekeeper blocks it)
  4. Run in Terminal:
    pluginkit -a /Applications/MDPreview.app/Contents/PlugIns/MDPreviewExtension.appex
    pluginkit -a /Applications/MDPreview.app/Contents/PlugIns/MDThumbnailExtension.appex
    qlmanage -r && qlmanage -r cache
    killall Finder
  5. Select a .md file in Finder and press Space — you should see formatted Markdown

Option B — Build from source

See Building with Xcode below.


Uninstalling

pluginkit -r /Applications/MDPreview.app/Contents/PlugIns/MDPreviewExtension.appex
pluginkit -r /Applications/MDPreview.app/Contents/PlugIns/MDThumbnailExtension.appex
rm -rf /Applications/MDPreview.app
qlmanage -r && qlmanage -r cache
killall Finder

Troubleshooting

Preview still shows raw text after installing Another app (commonly TeXShop, Typora, or BBEdit) has claimed the .md file type. Force-register MDPreview:

/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -f /Applications/MDPreview.app
killall Finder

If that doesn't work, right-click any .md file → Get Info → Open With → select MDPreview → click Change All.

Preview window is blank The extension registered but isn't responding. Re-run the pluginkit -a commands, then:

qlmanage -r && qlmanage -r cache

Extension doesn't appear in pluginkit -m -p com.apple.quicklook.preview The app must be in /Applications (not Downloads or Desktop). Confirm the path and re-run pluginkit -a.

Nothing changed after a rebuild Quick Look caches extension bundles aggressively. After copying a new build to /Applications, always run qlmanage -r && qlmanage -r cache && killall Finder.


What it supports

Feature Supported
ATX and Setext headings
Bold, italic, strikethrough
Inline and fenced code blocks
Syntax class on code blocks
GFM tables
Task lists - [x]
Blockquotes (nested)
Ordered and unordered lists (nested)
Images (relative paths resolved)
Links
YAML / TOML front matter (stripped)
Inline math $...$
Math blocks $$...$$
Light / dark mode
Finder thumbnail

Why it exists

macOS has no built-in Quick Look support for Markdown. Most third-party alternatives use the legacy .qlgenerator format (which is brittle across macOS upgrades) or are abandoned. This plugin uses Apple's modern App Extension architecture — it installs like a normal app and survives OS updates.

A secondary problem: apps like TeXShop silently claim the .md UTI, causing macOS to fall back to a synthetic com.unknown.md type that no Quick Look plugin matches. This plugin exports the net.daringfireball.markdown UTI directly, which fixes the association system-wide.


How it works

The project contains three targets bundled inside a single macOS app:

MDPreview.app — Host app

Required by macOS's App Extension model. Contains a minimal SwiftUI window with installation instructions. Its only real job is to carry the extensions and export the Markdown UTI via UTExportedTypeDeclarations in its Info.plist.

MDPreviewExtension.appex — Quick Look Preview Extension

Uses QLPreviewingController via the modern com.apple.quicklook.preview extension point with QLIsDataBasedPreview = true.

When the system requests a preview:

  1. Swift reads the file (UTF-8 with latin-1 fallback)
  2. Content is JSON-encoded for safe embedding in JavaScript
  3. An HTML page is built with an embedded, self-contained ~250-line JavaScript Markdown parser (no external dependencies) and GitHub-inspired CSS
  4. A QLPreviewReply carrying the raw HTML is returned — the system renders it in its own WebView

CSS responds to prefers-color-scheme automatically, so the preview matches the user's light/dark mode setting.

MDThumbnailExtension.appex — Quick Look Thumbnail Extension

Uses QLThumbnailProvider via com.apple.quicklook.thumbnail. Reads the file, strips markup, extracts the first heading as a title, and draws a styled card with NSAttributedString and Core Graphics. Dark/light mode detected via UserDefaults.


Building with Xcode

Requirements

  • macOS 12.0 or later
  • Xcode 14 or later
  • An Apple Developer account (free tier is fine for local use; paid account required for notarization/distribution)

Steps

1. Clone

git clone https://github.com/stevenjswanson/md-preview.git
cd md-preview
open "MDPreview.xcodeproj"

2. Set your Development Team

In Xcode, select the MDPreview project in the navigator. For each of the three targets — MDPreview, MDPreviewExtension, MDThumbnailExtension — go to Signing & Capabilities and choose your team from the dropdown.

3. Build

⌘B  (Product → Build)

All three targets build together. The extensions are automatically embedded into MDPreview.app.

4. Install

# Find your DerivedData path (shown in Xcode → Preferences → Locations)
cp -R ~/Library/Developer/Xcode/DerivedData/MDPreview-*/Build/Products/Debug/MDPreview.app /Applications/

pluginkit -a /Applications/MDPreview.app/Contents/PlugIns/MDPreviewExtension.appex
pluginkit -a /Applications/MDPreview.app/Contents/PlugIns/MDThumbnailExtension.appex

/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -f /Applications/MDPreview.app

qlmanage -r && qlmanage -r cache
killall Finder

5. Verify

pluginkit -m -p com.apple.quicklook.preview | grep mdpreview
# Expected: com.mdpreview.app.preview

Tip: After every rebuild, repeat the cp -R, pluginkit -a, and qlmanage -r steps to update the installed copy.


Project structure

MDPreview.xcodeproj/
MDPreview/                         Host app (SwiftUI)
├── MDPreviewApp.swift
├── ContentView.swift
├── Info.plist                     UTExportedTypeDeclarations for .md UTIs
└── MDPreview.entitlements
MDPreviewExtension/                Quick Look preview extension
├── PreviewViewController.swift    QLPreviewProvider + Markdown→HTML pipeline
└── Info.plist                     com.apple.quicklook.preview
MDThumbnailExtension/              Quick Look thumbnail extension
├── ThumbnailProvider.swift        QLThumbnailProvider + Core Graphics drawing
└── Info.plist                     com.apple.quicklook.thumbnail

License

MIT — do whatever you want with it.

About

macOS Quick Look plugin — renders Markdown (.md) files as formatted HTML in Finder's preview pane

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages