Skip to content

Unify zoom into one feature: ⌘+/⌘−/⌘0 scales both editor and preview #470

Description

@schuyler

Summary

We currently have four open zoom PRs that overlap on the same menu items and shortcuts but split into two half-features. Neither half is complete on its own, and they collide if merged together. This issue proposes consolidating them into a single "document zoom" feature: one zoom level, one key pair (⌘+ / ⌘− / ⌘0), scaling both the editor and the preview together — which is exactly what #335 originally asked for.

Implementation note: the synthesis described here is maintainer-led. #395 and #442 are starting points to build on — no further work is expected from their authors, and the Format-shortcut relocation below is part of our scope, not theirs.

Background: what the four PRs actually do

The PRs fall into two camps:

PR Author Model Scales editor? Scales preview? Persisted?
#337 @ssstonebraker transient per-document yes no (dead stub) no
#395 @schuyler transient per-document yes no (dead stub) no
#411 @yusufm transient per-document yes no (dead stub) no
#442 @dpankros preview-only no yes (works) yes

Key finding: the "both panes" PRs don't actually zoom the preview

The three per-document PRs (#337, #395, #411) route preview scaling through MPDocument's existing scaleWebview, whose body is dead code:

CGFloat scale = [self previewScale];   // computed…
#if 0
    // Sadly, this doesn't work correctly.
    // It looks fine, but selections are offset relative to the mouse cursor.
    ...                                 // …the code that applies `scale` is #if 0'd out
#endif

That #if 0 predates all of these PRs — MacDown disabled view-transform preview scaling long ago because of a selection-offset bug. So those three PRs compute a preview scale factor and throw it away: in practice they only zoom the editor font.

#442 is the only PR that actually zooms the preview, because it sidesteps that broken path entirely and uses WebKit's setPageSizeMultiplier: (true page zoom — text, images, and layout), which doesn't have the selection-offset problem.

So the real split is:

The missing piece that makes "one key pair, both panes" finally work is replacing the dead #if 0 transform with #442's setPageSizeMultiplier: approach.

Proposed unified design

One feature, built by synthesizing the working halves rather than picking a single PR:

What to take from each PR

Decision: persisted single preference ✅

Resolved — zoom is a persisted single preference, applied to every window (Safari-style), backed by a dedicated zoom-level preference + migration (the #442 plumbing). It is deliberately not the transient per-document model, and it is not the editor base font, so it never clobbers the user's saved font (which was the original objection in #335). The level is restored on launch.

Format-shortcut relocation

⌘+ / ⌘− / ⌘0 currently collide with Format menu items — Highlight (⌘=), Strikethrough (⌘−), and Paragraph (⌘0). The headline zoom shortcuts win these keys; the Format actions get reassigned (or moved to ⌘⇧ variants). This is in scope for the unified feature itself and is maintainer-side work — not a request to any PR author.

Test plan

  • Editor: font, tab stops, and paragraph style all scale; zoom survives an editor-font preference change; no highlighter re-parse per step (perf).
  • Preview: setPageSizeMultiplier: applied and re-applied after each render/reload; images and text scale together.
  • Bounds: clamp at 50%–300% (or chosen preset range); menu items validate at the limits; Actual Size resets.
  • Shortcuts: ⌘+/⌘−/⌘0 reach zoom; relocated Format shortcuts (Highlight/Strikethrough/Paragraph) still function at their new bindings.
  • Persistence: migration default (100%), value restored on launch, shared across open windows.
  • Carry over MPZoomTests.m (Address issue #335: Add zoom keyboard shortcuts (Cmd+Shift+=/Cmd+Shift+-) #395) and MPPreviewZoomTests.m (Add zoom controls for the preview pane #442).

Related issues and PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions