Skip to content

Fix Quick Look extension bugs (blank preview, entitlements, baseURL)#368

Merged
schuyler merged 7 commits into
mainfrom
claude/issue-367-quicklook-fixes-Pr6Cn
Apr 10, 2026
Merged

Fix Quick Look extension bugs (blank preview, entitlements, baseURL)#368
schuyler merged 7 commits into
mainfrom
claude/issue-367-quicklook-fixes-Pr6Cn

Conversation

@schuyler

@schuyler schuyler commented Apr 9, 2026

Copy link
Copy Markdown
Owner

Summary

  • Defer Quick Look completion handler until WKWebView finishes rendering (fixes blank preview pane)
  • Add missing sandbox entitlements: files.user-selected.read-only and network.client
  • Use baseURL:nil for sandbox safety (extension only has access to the specific file URL)
  • Add WKNavigationDelegate error handling (didFailNavigation:, didFailProvisionalNavigation:)
  • Add encoding fallback in MPQuickLookRenderer (UTF-8 → auto-detection)
  • Enable ENABLE_QUICKLOOK_TESTS in Xcode project and wire Quick Look source/test files into build

Related Issue

Related to #367

Manual Testing Plan

Quick Look extensions run in a sandboxed, out-of-process environment that unit tests cannot replicate. Manual testing is recommended:

  1. Blank preview fix: Build and install MacDown 3000, select a .md file in Finder, press Space. Expected: rendered HTML appears, not a blank pane.
  2. Sandbox entitlements: Preview a file stored outside the app container (e.g., Desktop). Expected: renders without sandbox violation. Check Console.app for deny messages filtered to MacDownQuickLook.
  3. Encoding fallback: Create a Latin-1 Markdown file (iconv -f UTF-8 -t ISO-8859-1 test.md > latin1.md). Preview it. Expected: renders correctly.
  4. Navigation error handling: Verify Quick Look doesn't hang indefinitely on malformed content.
  5. Syntax highlighting: Preview a Markdown file with fenced code blocks — Prism highlighting should still work.

Review Notes

  • TDD approach: failing tests written first (11 new tests across 2 files), then implementation to make them pass
  • Chico code review: all 5 requirements fully implemented, no critical issues
  • Two tests are regression guards (pass both before and after fix) per Zeppo's review
  • Build fix: added missing hoedown/escape.h import exposed by compiling MPQuickLookRenderer.m in test target

claude added 5 commits April 9, 2026 20:37
New tests that expose five bugs in the Quick Look extension:

MPQuickLookRendererTests.m:
- testRenderMarkdownFromURLWithLatin1Encoding: FAILS because
  renderMarkdownFromURL: only tries UTF-8, no encoding fallback
- testRenderMarkdownFromURLWithUTF16Encoding: same issue
- testRenderMarkdownFromURLUTF8TakesPrecedenceOverFallback: PASSES (regression guard)

MPPreviewViewControllerTests.m (new file):
- testPreviewViewControllerConformsToWKNavigationDelegate: FAILS
- testPreviewViewControllerImplementsDidFinishNavigation: FAILS
- testPreviewViewControllerImplementsDidFailNavigation: FAILS
- testPreviewViewControllerImplementsDidFailProvisionalNavigation: FAILS
- testCompletionHandlerIsNotCalledSynchronously: FAILS (handler called immediately)
- testCompletionHandlerIsEventuallyCalledAfterNavigation: FAILS (no deferred call)
- testLoadViewCreatesWKWebViewWithNavigationDelegate: FAILS (delegate not set)
- testPreferredContentSizeIsSet: FAILS (NSZeroRect used)

project.pbxproj:
- Enable ENABLE_QUICKLOOK_TESTS=1 in MacDownTests build settings
- Add HEADER_SEARCH_PATHS for MacDownCore and MacDownQuickLook
- Wire Quick Look source and test files into Compile Sources phase
- Add MacDownCore and MacDownQuickLook groups to project navigator

Related to #367
PreviewViewController.h/m:
- Conform to WKNavigationDelegate so the completion handler can be
  deferred until WKWebView finishes rendering
- Store QL completion handler in pendingHandler property and fire it
  from didFinishNavigation: instead of calling it synchronously
  (fixes blank Quick Look preview pane)
- Implement didFailNavigation:withError: and
  didFailProvisionalNavigation:withError: to propagate navigation
  errors (e.g. sandbox violations) back to Quick Look
- Set webView.navigationDelegate = self in loadView
- Use baseURL:nil — the extension sandbox only grants access to the
  specific file URL, not its parent directory
- Set preferredContentSize to 800x600 so Quick Look has a non-zero
  initial size

MacDownQuickLook.entitlements:
- Add com.apple.security.files.user-selected.read-only (needed to
  read the file being previewed)
- Add com.apple.security.network.client (required by WKWebView
  WebContent process IPC inside an extension sandbox)

MPQuickLookRenderer.m:
- Add encoding fallback in renderMarkdownFromURL:error: — if UTF-8
  decoding fails, retry with usedEncoding: auto-detection for files
  encoded as Latin-1, UTF-16, etc.

Related to #367
The hoedown_escape_html function (used in the blockcode renderer
callback) is declared in escape.h but was not explicitly imported.
This compiled in the main app target due to transitive includes but
triggers -Wimplicit-function-declaration when the file is compiled
in the test target (macOS 26 SDK).

Related to #367
- quick-look-xcode-setup.md: document that ENABLE_QUICKLOOK_TESTS
  is now configured and three test files are wired into the project
- test_coverage_improvement_plan.md: add Quick Look test files to
  the coverage inventory

Related to #367
PreviewViewController.m uses WKWebView and WKWebViewConfiguration,
which require WebKit.framework. The main app target already links it
but the test target did not, causing linker errors when compiling
PreviewViewController.m in the test target.

Related to #367
@github-actions

github-actions Bot commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Report

Current Coverage: 0.00%

Coverage Details (Summary)
Coverage unavailable - xccov failed

claude added 2 commits April 9, 2026 20:48
If the view controller is deallocated while pendingHandler is still
set (e.g. Quick Look tears down the extension before WKWebView
finishes loading), drain the handler with a cancellation error so
Quick Look doesn't hang waiting for a callback that will never come.

Related to #367
MPQuickLookRenderer.m:
- Add ISO Latin-1 as a last-resort encoding fallback. The
  usedEncoding: auto-detection requires markers like BOM to work;
  single-byte encodings (Latin-1, Windows-1252) lack markers and
  fail auto-detection. Latin-1 can decode any byte sequence so it
  serves as a universal fallback.

MPQuickLookRendererTests.m:
- Fix testPrismScriptsIncluded to check for language-javascript
  class rather than Prism script content. The test bundle does not
  include Prism resource files, so the renderer correctly omits
  the scripts. The language class on the code block is always
  present regardless of bundle resources.

Related to #367
@schuyler schuyler merged commit 3264549 into main Apr 10, 2026
6 of 10 checks passed
schuyler added a commit that referenced this pull request Jun 30, 2026
## Summary

- Add MacDownCore (framework) and MacDownQuickLook (app extension) as
native targets in the Xcode project
- Wire CocoaPods dependencies for both targets
- Embed the Quick Look extension in the main app bundle
- Remove `public.text` from `QLSupportedContentTypes` so the extension
only claims markdown files

## Background

The Quick Look source code was merged in PRs #299, #368, and #385 but
the Xcode project was never configured to build it. This caused 3000.0.6
to register the QL handler without providing a working preview — worse
than the macOS default.

## Key decisions

- **Resource copying via script phase**: MacDownCore copies Styles and
Prism resources via its own shell script build phase rather than reusing
MacDown's PBXFileReferences. Those refs are declared outputs of
MacDown's "Fetch Prism Resources" and "Transpile Styles" script phases,
which would create a dependency cycle.
- **No MacDown→MacDownCore dependency**: The main app only depends on
MacDownQuickLook. MacDownCore is embedded inside the extension only,
since only the extension uses it.
- **Per-configuration bundle IDs**: Debug uses `-debug` suffix to match
the parent app's pattern.

## Test plan

- [ ] `xcodebuild build` succeeds (verified locally)
- [ ] 1003 tests pass with 0 unexpected failures (verified locally)
- [ ] `.app` bundle contains `MacDownQuickLook.appex` in
`Contents/PlugIns/` (verified locally)
- [ ] `MacDownQuickLook.appex` contains `MacDownCore.framework` with
`Styles/` and `Prism/` resources (verified locally)
- [ ] Quick Look preview renders markdown files in Finder
- [ ] Quick Look does NOT activate for `.txt`, `.csv`, or other
non-markdown text files

Related to #284
schuyler added a commit that referenced this pull request Jun 30, 2026
## Summary

- Add MacDownCore (framework) and MacDownQuickLook (app extension) as
native targets in the Xcode project
- Wire CocoaPods dependencies for both targets
- Embed the Quick Look extension in the main app bundle
- Remove `public.text` from `QLSupportedContentTypes` so the extension
only claims markdown files

## Background

The Quick Look source code was merged in PRs #299, #368, and #385 but
the Xcode project was never configured to build it. This caused 3000.0.6
to register the QL handler without providing a working preview — worse
than the macOS default.

## Key decisions

- **Resource copying via script phase**: MacDownCore copies Styles and
Prism resources via its own shell script build phase rather than reusing
MacDown's PBXFileReferences. Those refs are declared outputs of
MacDown's "Fetch Prism Resources" and "Transpile Styles" script phases,
which would create a dependency cycle.
- **No MacDown→MacDownCore dependency**: The main app only depends on
MacDownQuickLook. MacDownCore is embedded inside the extension only,
since only the extension uses it.
- **Per-configuration bundle IDs**: Debug uses `-debug` suffix to match
the parent app's pattern.

## Test plan

- [ ] `xcodebuild build` succeeds (verified locally)
- [ ] 1003 tests pass with 0 unexpected failures (verified locally)
- [ ] `.app` bundle contains `MacDownQuickLook.appex` in
`Contents/PlugIns/` (verified locally)
- [ ] `MacDownQuickLook.appex` contains `MacDownCore.framework` with
`Styles/` and `Prism/` resources (verified locally)
- [ ] Quick Look preview renders markdown files in Finder
- [ ] Quick Look does NOT activate for `.txt`, `.csv`, or other
non-markdown text files

Related to #284
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants