Clearly icon

Clearly

A native markdown editor for Mac and iPhone.

Mac App Store · Direct Download · Website · @Shpigford

Clearly — markdown editor with live preview

Open a `.md` file. Write with syntax highlighting. Toggle to preview. That's it. Native macOS and iOS, no Electron, no subscriptions, no telemetry. ## Features ### Writing - **Syntax highlighting** — headings, bold, italic, links, code blocks, tables, highlighted as you type - **Format shortcuts** — ⌘B bold, ⌘I italic, ⌘K links, plus a full Format menu - **Extended markdown** — ==highlights==, ^superscript^, ~subscript~, :emoji: shortcodes, `[TOC]` generation - **Document outline** — heading tree per document, click to jump - **Find & replace** — ⌘F with regex and case-sensitive options - **Scratchpad** — menu-bar floating notes with a global hotkey ### Preview - **GFM rendering** — tables, task lists, footnotes, strikethrough - **KaTeX math** — inline and block equations - **Mermaid diagrams** — flowcharts, sequence diagrams from code blocks - **Code blocks** — syntax-highlighted, line numbers, diff highlighting, one-click copy - **Callouts** — NOTE, TIP, WARNING, and 15+ types, foldable - **Interactive** — toggle checkboxes, zoom images, hover footnotes, double-click to jump to source ### Integration - **QuickLook** — preview `.md` files in Finder with Space - **PDF export** — export or print, page breaks handled - **iOS** — same renderer, same syntax highlighter, opens any `.md` from the Files app ## Screenshots

## Prerequisites - **macOS 15** (Sequoia) or later for the Mac app - **iOS 17** or later for the iPhone app - **Xcode 16+** with command-line tools (`xcode-select --install`) - **Homebrew** ([brew.sh](https://brew.sh)) - **xcodegen** — `brew install xcodegen` Dependencies (cmark-gfm, Sparkle, KeyboardShortcuts) are pulled automatically by Xcode via Swift Package Manager. ## Quick Start ```bash git clone https://github.com/Shpigford/clearly.git cd clearly brew install xcodegen # skip if already installed xcodegen generate # generates Clearly.xcodeproj from project.yml open Clearly.xcodeproj # opens in Xcode ``` Then hit **⌘R** to build and run. > The Xcode project is generated from `project.yml`. If you change `project.yml`, re-run `xcodegen generate`. Don't edit the `.xcodeproj` directly. ### CLI build ```bash xcodebuild -scheme Clearly -configuration Debug build xcodebuild -scheme Clearly-iOS -destination 'generic/platform=iOS Simulator' build ``` ## Project Structure ``` Clearly/ ├── ClearlyApp.swift # @main — DocumentGroup + menu commands (⌘1/⌘2) ├── MarkdownDocument.swift # FileDocument conformance for .md files (Mac + iOS) ├── ContentView.swift # Per-document scene root (Mac) ├── EditorView.swift # NSViewRepresentable wrapping NSTextView ├── ClearlyTextView.swift # Subclassed NSTextView with formatting actions ├── PreviewView.swift # NSViewRepresentable wrapping WKWebView ├── ScratchpadManager.swift # Menu-bar floating scratchpad windows ├── SettingsView.swift # General + About preferences └── iOS/ ├── ClearlyApp_iOS.swift # @main — DocumentGroup, system Files browser ├── DocumentDetailBody.swift # Per-document scene root (iOS) ├── EditorView_iOS.swift # UIViewRepresentable wrapping UITextView ├── ClearlyUITextView.swift # TextKit 1 UITextView subclass └── PreviewView_iOS.swift # UIViewRepresentable wrapping WKWebView ClearlyQuickLook/ ├── PreviewProvider.swift # QLPreviewProvider for Finder previews └── Info.plist Packages/ClearlyCore/ # Local SwiftPM package, platform-agnostic └── Sources/ClearlyCore/ ├── Rendering/ # MarkdownRenderer, syntax highlighter, theme, mermaid/math/table support ├── State/ # OpenDocument, OutlineState, FindState, JumpToLineState, StatusBarState ├── Editor/ # ImagePasteService, ImageDownloader ├── Diagnostics/ # DiagnosticLog, BugReportURL ├── Stats/ # MarkdownStats (word counts) └── Platform/ # PlatformFont/Color/Image typealiases Shared/Resources/ # Bundled JS/CSS (KaTeX, Mermaid, Highlight.js), demo.md website/ # Static site deployed to clearly.md scripts/ # Release pipeline project.yml # xcodegen config (source of truth) ``` ## Architecture **SwiftUI + AppKit/UIKit**, document-based on both platforms. ### Targets 1. **Clearly** (Mac) — `DocumentGroup` with `MarkdownDocument`. AppKit `NSTextView` editor + `WKWebView` preview, both bridged via `NSViewRepresentable`. Includes a menu-bar `MenuBarExtra` for floating scratchpads. 2. **Clearly-iOS** — `DocumentGroup`. UIKit `UITextView` editor + `WKWebView` preview, bridged via `UIViewRepresentable`. The system Files browser is the entry point. 3. **ClearlyQuickLook** — Finder extension for previewing `.md` files with Space, sharing `MarkdownRenderer` from `ClearlyCore`. ### Editor Wraps platform text views (`NSTextView` on Mac, `UITextView` on iOS) via `NSViewRepresentable` / `UIViewRepresentable`. This provides native undo/redo, the system find UI, and `NSTextStorageDelegate`-based syntax highlighting on every keystroke. iOS stays on TextKit 1 because TextKit 2 makes `textStorage` effectively dead. ### Preview `PreviewView` (Mac) and `PreviewView_iOS` both wrap `WKWebView` and render HTML via `MarkdownRenderer` (cmark-gfm). Post-processing pipeline: math → highlight marks → superscript/subscript → emoji → callouts → TOC → tables → code highlighting. ### Dependencies | Package | Purpose | |---------|---------| | [cmark-gfm](https://github.com/brokenhandsio/cmark-gfm) | GitHub Flavored Markdown → HTML | | [Sparkle](https://sparkle-project.org) | Auto-updates (direct distribution only) | | [KeyboardShortcuts](https://github.com/sindresorhus/KeyboardShortcuts) | Global hotkey for the menu-bar scratchpad | ### Key Decisions - **AppKit/UIKit bridge** — platform text views over `TextEditor` for undo, find, and `NSTextStorageDelegate` syntax highlighting - **Dynamic theming** — all colors through `Theme.swift` with `NSColor(name:)` for automatic light/dark - **Shared rendering** — `MarkdownRenderer` and `PreviewCSS` live in `ClearlyCore` and compile into Mac, iOS, and QuickLook - **Dual distribution** — Sparkle for direct, App Store without. All Sparkle code wrapped in `#if canImport(Sparkle)` - **No `.inspector()`** — outline panel uses `HStack` due to fullscreen safe area bugs ## Common Dev Tasks ### Change syntax highlighting Edit `Packages/ClearlyCore/Sources/ClearlyCore/Rendering/MarkdownSyntaxHighlighter.swift`. Patterns are applied in order — code blocks first, then everything else. ### Modify preview styling Edit `Packages/ClearlyCore/Sources/ClearlyCore/Rendering/PreviewCSS.swift`. Used by both in-app preview and QuickLook. Keep in sync with `Theme.swift` colors. Base styles must come before `@media (prefers-color-scheme: dark)` overrides. ### Add a preview feature Follow the `MathSupport`/`MermaidSupport` pattern: create a `*Support.swift` enum in `ClearlyCore/Rendering/` with a static method that returns a `