Add Quick Look previews, font settings, and a native installer - #15
Open
santiagobarros wants to merge 11 commits into
Open
Add Quick Look previews, font settings, and a native installer#15santiagobarros wants to merge 11 commits into
santiagobarros wants to merge 11 commits into
Conversation
A stale copy merged over by ditto keeps files the new bundle no longer ships, which breaks the code-signature seal and makes Gatekeeper reject the app.
The README promises no network calls, but the app contacted the GitHub releases API on every launch. The check now runs only from a new "Check for Updates…" menu item, with explicit feedback for up-to-date and unreachable cases.
New Settings window (Cmd+,) with three document fonts: the existing serif, GitHub's system sans stack, and Geist (vendored from the geist npm package with a pinned SHA-256 like the other libraries). The choice persists in NSUserDefaults and is applied live to all open windows as a data-font attribute driven by an injected user script.
A data-based QLPreviewProvider app extension built into Contents/PlugIns by build.sh — no Xcode project required. Markdown renders with the bundled marked.umd.js under JavaScriptCore; LaTeX math is extracted from the source (code-fence aware, so $a_i$ survives emphasis parsing) and rendered with katex.renderToString, which needs no DOM — Quick Look executes no JavaScript in data-based previews. KaTeX CSS ships with its woff2 fonts inlined as data URIs. Local images referenced by the markdown are embedded as cid: attachments on the QLPreviewReply, since data-based previews have no base URL; a read-only filesystem exception lets the sandboxed extension read them (macOS additionally asks once for privacy-protected folders like Desktop). Mermaid fences degrade to a styled source block for now. The appex is signed with its entitlements before the outer app — codesign --deep would strip them. Note for testing: qlmanage -p crashes on macOS 26 for all third-party Quick Look extensions; use a QLPreviewPanel harness or Finder itself.
The Quick Look sandbox cannot host a browser engine (WebContent processes are terminated immediately, and view-based preview extensions are never launched by quicklookd — both verified on macOS 26), so Mermaid is solved in two layers: 1. The app caches every SVG it renders, keyed by sha256 of the trimmed diagram source, in both light and dark themes (viewer.js renders the non-displayed theme in the background after the visible pass). 2. On cache miss the extension asks an optional on-demand launchd helper over XPC. launchd registers no running process at rest, spawns the helper when the extension connects, and it exits after 45 seconds idle. It is opt-in (./install.sh --with-mermaid-helper) because launchd agents surface as Login Items. The extension prefers the SVG matching the current system appearance, then a live helper render, then a stale-theme SVG; unseen diagrams with no helper degrade to the styled source fallback. A permissions section in the README documents the model.
./build.sh installer builds a standard macOS installer whose customize pane offers two optional selections: setting Markdown Viewer as the default .md handler (pre-selected) and installing the Mermaid Quick Look helper (off by default, since it registers a Login Items entry). The choices run per-user postinstall scripts that call the same set-default-handler.py and register-mermaid-helper.sh now shipped in the app's Resources; install.sh reuses them instead of embedding its own copies. The app package removes any previous install before laying down the payload so stale files cannot break the signature seal.
build.sh auto-selects a signing identity — CODESIGN_IDENTITY override, then Developer ID Application (with hardened runtime and secure timestamp, the notarization prerequisites), then Apple Development, then ad-hoc (unchanged default for contributors without certificates) — and reports what it used. New ./build.sh notarize submits the release zip via notarytool and staples the ticket; the installer is signed when a Developer ID Installer certificate exists. The render helper derives its own team identifier from its signature and rejects XPC callers signed by any other team (macOS 13+ setCodeSigningRequirement). Ad-hoc builds carry no team, so local development skips the check.
Author
|
Restructured the branch into feature-scoped commits so you can cherry-pick exactly what you want — each commit builds and works on its own:
1–4 are each independent of everything after them; the natural cherry-pick prefixes are 1, 1–2, 1–3, 1–4, etc. |
santiagobarros
force-pushed
the
pr/quicklook-preview
branch
from
July 10, 2026 17:01
62ce543 to
1268f9d
Compare
On the first launch where another app (usually Xcode on a developer Mac) owns Markdown files, ask once whether to make Markdown Viewer the default, using NSWorkspace's modern default-application API. Declining is remembered; if the app is already the default (e.g. the installer checkbox or install.sh set it), the prompt never appears.
…sions New optional, pre-selected choice: elects Markdown Viewer's Quick Look extension over any other Markdown previewer already registered (e.g. QLMarkdown), via pluginkit -e use, mirroring the existing default .md handler choice. install.sh now does the same unconditionally, matching its existing unconditional default-handler behavior.
…ages Installer.app renders custom welcome/conclusion resources via the legacy WebKit1 WebView class, which is deprecated (since macOS 10.14) and crashes on current macOS when that code path is exercised — this is what actually caused 'the installer says it failed' even though the payload had already been applied. RTF resources are rendered by TextKit directly, with no WebKit involved at all; confirmed via a minimal repro that the HTML path invokes WebView while the RTF path does not.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this adds
Quick Look (spacebar) previews in Finder with full component parity: tables, task lists, code blocks, images, LaTeX math, and Mermaid diagrams — plus a document font setting, a native
.pkginstaller, and distribution infrastructure (signing/notarization when certificates are available).Quick Look architecture
QLPreviewProviderapp extension (src/quicklook.m), built intoContents/PlugInsbybuild.sh— no Xcode required, same script-driven build as the rest of the repo.JSContext; math ($…$,$$…$$,\(…\),\[…\]) is extracted from the source (code-fence aware) and rendered withkatex.renderToString, which needs no DOM. KaTeX CSS ships with its woff2 fonts inlined as data URIs.cid:attachments on theQLPreviewReply(data-based previews have no base URL), with a read-only filesystem exception so previews can load images referenced from anywhere. macOS additionally shows its one-time privacy consent for Desktop/Documents/Downloads.preparePreviewOfFileAtURL:) extensions are never launched by quicklookd at all (both approaches were implemented and reverted; findings documented). Instead: the app caches every SVG it renders (keyed by sha256 of the diagram source, both light and dark themes), the extension reads that cache, and an optional on-demand launchd helper (./install.sh --with-mermaid-helper, off by default because it registers a Login Items entry) renders never-before-seen diagrams live. Without the helper, unseen diagrams degrade to a styled source block.Also included
geistnpm package with a pinned SHA-256, like the other libraries)../build.sh installer— a signed-when-possible.pkgwhose customize pane offers "default .md viewer" and the Mermaid helper as checkboxes.build.shauto-detects Developer ID → Apple Development → ad-hoc (unchanged default behavior for contributors without certificates), plus./build.sh notarize.Verification
Unit-tested render pipeline; end-to-end verified through real
QLPreviewPanelsessions (note:qlmanage -pcrashes on macOS 26 for all third-party QL extensions, including QLMarkdown — panel-based testing is the workaround); notarization accepted by Apple for both the app and installer on a Developer ID account.Happy to split this into smaller PRs (e.g. update-check fix, fonts, Quick Look, installer) if you prefer reviewing piecewise.