一个只为 macOS 设计的轻量 Markdown、HTML 与源码阅读器,界面支持简体中文与英文并跟随系统语言。
- 原生 SwiftUI + AppKit 外壳,正文使用 macOS 系统 WebKit,不捆绑 Chromium 或 Node
- 系统目录选择器,目录树按需展开;自动忽略
.DS_Store和 AppleDouble 元数据,但保留普通点文件 - 文件树支持方向键导航:上下移动,右键展开目录或进入第一个子项,左键收起目录或返回父级;空格键在当前活动阅读栏打开所选文件,回车键就地重命名,Command-C 复制绝对路径
- 记录最近 8 个目录;保留侧栏顶部目录卡片样式,点击后可在显示完整路径的切换面板中选择,并在下次启动时自动恢复最后打开的目录
- Markdown 使用墨读主题进行语义化渲染;HTML 以完整网页模式直接运行,保留原始 CSS、JavaScript、动画和交互,并可读取左侧已授权工作区内的关联资源
- 直接预览常见代码、配置和纯文本文件;按扩展名或特殊文件名选择高亮语言,无后缀文件还会尝试从 shebang 推断语言,无法推断时按纯文本打开;也可从文件标题栏右侧为单个文件手动调整语言或切换为纯文本
- 直接预览 PNG、JPEG、GIF、WebP、HEIC、TIFF、BMP、ICO、AVIF 和 SVG 等常见图片;进入阅读区前先验证实际图片内容,并保持比例居中适配
- Markdown、HTML、代码、配置和纯文本统一支持文档内查找;查找栏默认隐藏,使用 Command-F 显示并聚焦、Esc 关闭,支持区分大小写及前后匹配
- 源码高亮固定使用应用内 Highlight.js 11.12.0,不依赖运行时 CDN;关键字、类型、方法、字符串、字面量和变量使用不同语义配色;源码文件没有总大小限制,内部按最多约 256 KiB 或 2000 行分段,页位置使用稀疏检查点与有界近期索引,滚动接近边界时自动加载相邻内容,阅读体验保持连续;WebView 最多保留三个相邻分段,查找也以有界内容逐段扫描并支持跨页匹配
- 源码支持
Command-L行号跳转;快捷键只显示一个行号输入框,回车确认跳转、Esc 取消,输入框失去焦点时自动关闭,不提供分页或跳转按钮 - 文档顶部 YAML metadata 使用紧凑、无框线的 key/value 信息区展示,内容较多时可展开或收起
- 正文滚动与大纲当前项双向联动,大纲栏可拖拽调整宽度
- 多个应用窗口分别保存自己的工作区、文档、分栏、预览与大纲状态;菜单和 Finder 外部路径请求作用于当前活动窗口,每次 CLI 请求创建新窗口,语言、外观、主题及最近工作区继续在应用范围内共享
- 两个阅读栏完全平级,可通过工具栏分栏按钮或
⌘\随时开启;默认均分且可拖动中间分界线调整宽度,点击哪个阅读栏,文件树接下来就替换哪个栏,也可用 Option-回车在另一栏打开;大纲栏的拖拽宽度会在双栏切换、显隐和下次启动时保留 - 纸页、极简、暖沙、墨夜、GitHub 五套主题同时作用于应用界面与 Markdown 正文,每套均支持跟随系统、明墨和暗墨
- 支持使用应用内固定版本资源渲染 Mermaid 图表,复杂横向图会优先利用阅读区域宽度,不依赖运行时 CDN
- 宽表格会突破窄正文栏并优先利用阅读区域宽度;空间不足时在表格内横向滚动,避免长文本列被挤成逐字换行
- 不索引、不主动上传文档内容;Markdown 中的 HTTP/HTTPS 图片以及 HTML 原型声明的网络资源按需直接加载
- 本地图片仅从已选择目录读取并限制为 40 MB
- 正式应用启用 App Sandbox,仅能读写用户通过系统面板选择并授权的目录;当前写操作只用于重命名目录内项目。
- 最近目录使用 macOS 安全作用域书签保存访问权限,最多保留 8 条。
- 文档内的 HTTP/HTTPS 图片由 WKWebView 直接向图片地址请求,图片服务方可能获知 IP、User-Agent 等常规网络信息;请求使用
no-referrer,不会发送当前文档路径作为 Referer。 - Markdown 页面使用内容安全策略禁止 Fetch/XHR/WebSocket 连接、远程脚本、远程字体、媒体、对象和内嵌页面;仅图片资源允许
data:、安全本地资源协议和 HTTP/HTTPS。含 Mermaid 的文档只允许加载应用内固定版本脚本。 - HTML 作为用户授权运行的本地网页快照打开:允许执行通过 16 MiB 文档门禁的原始脚本,并加载工作区内的 CSS、JavaScript、图片及其他相对路径资源,也允许页面按自身逻辑请求网络资源。本地相对资源统一经工作区受限协议读取,越界请求会被拒绝,单个资源限制为 40 MiB。
- HTML 使用非持久化 WebView 会话;远程内嵌页面可按原页面加载,用户点击的顶层 HTTP/HTTPS 链接交给系统浏览器,脚本发起的顶层远程跳转不会替换阅读区域。
- 代码、配置和纯文本内容在进入页面前统一转义,不能执行文件中的标签或脚本;源码页面只允许加载应用内精确白名单中的高亮资源,并禁止图片、网络连接、媒体、对象、内嵌页面和 Worker。
- 墨读自身不会上传 Markdown 或 HTML 源文档;但 HTML 中的第三方或作者脚本具有网页代码的正常网络能力,可能把其能够读取的数据发送到外部服务,因此只应交互运行可信来源的 HTML 原型。交互快照加载失败时会回退到禁用脚本的静态视图。
需要 macOS 13 或更高版本,以及 Swift 6.1 工具链。
swift run MoDu执行 SwiftPM 测试(包含完整确定性核心自检):
swift test./scripts/build_app.sh
open 'build/MoDu Preview.app'构建脚本会先解析锁定的 SwiftPM 依赖,核对实际 checkout 的提交与 clean 状态,再执行测试与第三方资源校验;签名后分别使用英文和简体中文执行正式沙盒 WKWebView 冒烟检查。仓库内的持续开发验证产物位于 build/MoDu Preview.app,使用独立的显示名称和 Bundle Identifier,避免与正式安装的 MoDu 混淆;构建追溯信息位于 build/release-manifest.txt。如需生成 DMG:
./scripts/package_dmg.shDMG 内的正式应用仍为 MoDu.app(中文显示“墨读”)。正式应用只在打包期间生成于隐藏的临时构建目录,写入 DMG 后即清理,不会在仓库内留下第二个同名应用。
应用语言与明暗模式统一在“MoDu(墨读)> 设置…(⌘,)”中管理;语言支持跟随系统、English 和简体中文,修改后立即应用并在下次启动时保留。
正式应用内置 modu 启动器。打开“MoDu(墨读)> 设置…(⌘,)”,在“命令行工具”中点击“安装”,MoDu 会按 macOS 的第三方命令约定安装到 /usr/local/bin/modu,无需选择目录。安装与卸载由一次性授权助手发起 macOS 系统认证,操作结束后助手立即退出,主应用继续保持沙盒隔离;实际可用的密码或生物认证方式由系统决定。安装后同一设置会显示实际路径并提供“卸载”,且只会删除仍指向当前 MoDu 的命令链接。
命令行入口支持当前目录、其他目录或单个常规文件:
modu .
modu /path/to/workspace
modu /path/to/file.md
modu --help
modu --version当 MoDu 尚未运行时,首次 modu 请求会直接使用启动窗口;当 MoDu 已经运行时,每次 modu <path> 都会创建一个独立阅读窗口,不会覆盖当前窗口。
打开文件时,MoDu 会把文件所在目录作为工作区并立即打开该文件。启动器通过 macOS LaunchServices 把路径交给应用;无论 MoDu 是否已经运行,都不会通过未授权的进程参数绕过应用沙盒。
正式交付默认拒绝包含未提交或未跟踪输入的工作树。仅需验证开发态改动时可显式使用 ALLOW_DIRTY_BUILD=1;此时 build/ 会额外保留完整二进制 patch 和未跟踪文件归档,不能将其当作基于提交的正式发布。
Config/release-baseline.json 固定上一份正式交付的版本、构建号和 Git 提交;发布门禁会复核该提交中的真实 plist,并要求本次版本和构建号都严格递增。完成一次正式交付后,应在开始下一版本前把该基线更新为刚交付的提交,禁止把当前 HEAD 当作“上一版本”自比较。