Clearly
一款适用于 Mac 和 iPhone 的原生 Markdown 编辑器。
Mac App Store ·
直接下载 ·
网站 ·
@Shpigford
打开 `.md` 文件。享受带有语法高亮的书写体验。一键切换至预览。就这么简单。原生支持 macOS 和 iOS,没有 Electron,无需订阅,没有遥测。
## 功能
### 书写
- **语法高亮** — 标题、粗体、斜体、链接、代码块、表格,边打字边高亮
- **格式快捷键** — ⌘B 粗体,⌘I 斜体,⌘K 链接,以及完整的“格式”菜单
- **扩展 Markdown** — ==高亮==,^上标^,~下标~,:emoji: 简码,`[TOC]` 生成
- **文档大纲** — 每个文档的标题树,点击跳转
- **查找与替换** — ⌘F,支持正则表达式和区分大小写选项
- **速记板** — 带全局热键的菜单栏浮动笔记
### 预览
- **GFM 渲染** — 表格、任务列表、脚注、删除线
- **KaTeX 数学公式** — 行内和块级公式
- **Mermaid 图表** — 从代码块生成的流程图、时序图
- **代码块** — 语法高亮、行号、diff 高亮、一键复制
- **标注** — NOTE、TIP、WARNING 等 15 种以上类型,可折叠
- **交互性** — 切换复选框、缩放图片、悬停脚注、双击跳转至源码
### 集成
- **QuickLook** — 在 Finder 中按空格键预览 `.md` 文件
- **PDF 导出** — 导出或打印,自动处理分页
- **iOS** — 相同的渲染器,相同的语法高亮器,可从“文件” App 打开任何 `.md` 文件
## 截图
## 前置条件
- Mac App 需要运行 **macOS 15** (Sequoia) 或更高版本
- iPhone App 需要运行 **iOS 17** 或更高版本
- **Xcode 16+** 及其命令行工具 (`xcode-select --install`)
- **Homebrew** ([brew.sh](https://brew.sh))
- **xcodegen** — `brew install xcodegen`
依赖项 (cmark-gfm, Sparkle, KeyboardShortcuts) 会由 Xcode 通过 Swift Package Manager 自动拉取。
## 快速开始
```
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
```
然后按下 **⌘R** 构建并运行。
### CLI 构建
```
xcodebuild -scheme Clearly -configuration Debug build
xcodebuild -scheme Clearly-iOS -destination 'generic/platform=iOS Simulator' build
```
## 项目结构
```
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)
```
## 架构
**SwiftUI + AppKit/UIKit**,双平台均基于文档架构。
### Targets
1. **Clearly** (Mac) — 包含 `MarkdownDocument` 的 `DocumentGroup`。AppKit 的 `NSTextView` 编辑器 + `WKWebView` 预览,两者均通过 `NSViewRepresentable` 进行桥接。包含一个用于浮动速记板的菜单栏 `MenuBarExtra`。
2. **Clearly-iOS** — `DocumentGroup`。UIKit 的 `UITextView` 编辑器 + `WKWebView` 预览,通过 `UIViewRepresentable` 进行桥接。系统“文件”浏览器是入口点。
3. **ClearlyQuickLook** — 用于按空格键预览 `.md` 文件的 Finder 扩展,与 `ClearlyCore` 共享 `MarkdownRenderer`。
### 编辑器
通过 `NSViewRepresentable` / `UIViewRepresentable` 封装平台原生文本视图(Mac 上的 `NSTextView`,iOS 上的 `UITextView`)。这提供了原生的撤销/重做、系统查找 UI,以及基于 `NSTextStorageDelegate` 在每次敲击键盘时触发的语法高亮。iOS 依然使用 TextKit 1,因为 TextKit 2 会让 `textStorage` 实际上失效。
### 预览
`PreviewView` (Mac) 和 `PreviewView_iOS` 均封装了 `WKWebView`,并通过 `MarkdownRenderer` (cmark-gfm) 渲染 HTML。后处理流水线:数学公式 → 高亮标记 → 上标/下标 → emoji → 标注 → TOC → 表格 → 代码高亮。
### 依赖项
| Package | Purpose |
|---------|---------|
| [cmark-gfm](https://github.com/brokenhandsio/cmark-gfm) | GitHub Flavored Markdown 转 HTML |
| [Sparkle](https://sparkle-project.org) | 自动更新(仅限直接下载分发版) |
| [KeyboardShortcuts](https://github.com/sindresorhus/KeyboardShortcuts) | 用于菜单栏速记板的全局热键 |
### 关键决策
- **AppKit/UIKit 桥接** — 在 `TextEditor` 之上使用平台原生文本视图,以实现撤销、查找和 `NSTextStorageDelegate` 语法高亮
- **动态主题** — 所有颜色均通过 `Theme.swift` 并使用 `NSColor(name:)` 实现自动浅色/深色模式切换
- **共享渲染** — `MarkdownRenderer` 和 `PreviewCSS` 位于 `ClearlyCore` 中,并编译进 Mac、iOS 和 QuickLook
- **双重分发** — 直接下载版使用 Sparkle,App Store 版不用。所有 Sparkle 代码均封装在 `#if canImport(Sparkle)` 中
- **不使用 `.insitor()`** — 由于全屏安全区 bug,大纲面板使用 `HStack`
## 常见开发任务
### 修改语法高亮
编辑 `Packages/ClearlyCore/Sources/ClearlyCore/Rendering/MarkdownSyntaxHighlighter.swift`。匹配模式按顺序应用——先是代码块,然后是其他所有内容。
### 修改预览样式
编辑 `Packages/ClearlyCore/Sources/ClearlyCore/Rendering/PreviewCSS.swift`。App 内预览和 QuickLook 均会使用此文件。需保持与 `Theme.swift` 的颜色同步。基础样式必须放在 `@media (prefers-color-scheme: dark)` 覆盖之前。
### 添加预览功能
遵循 `MathSupport`/`MermaidSupport` 的模式:在 `ClearlyCore/Rendering/` 中创建一个 `*Support.swift` 枚举,其中包含一个返回 `