A native macOS Markdown editor with live preview, syntax highlighting, git integration, and static site generator support. Built with SwiftUI and AppKit.
- Monospaced plain-text editing with configurable font size (10–28 pt)
- Syntax highlighting for Markdown elements: headings, bold, italic, code, links, images, blockquotes, lists, horizontal rules, and task lists
- Line number gutter with accurate positioning for wrapped lines
- Find bar (Cmd+F) with incremental search
- Independent light/dark/system theme with full color customization
- Automatic substitutions disabled — no smart quotes or autocorrect interfering with Markdown syntax
- Full undo/redo support
- GitHub-styled HTML preview rendered in a WebKit view, debounced at 300ms
- Code syntax highlighting via Prism.js for 15+ languages (Swift, Python, JavaScript, TypeScript, Go, Rust, Ruby, Java, Bash, JSON, YAML, HTML, CSS, and more)
- YAML front matter parsed and rendered as a collapsible key/value table instead of broken Markdown
- Independent light/dark/system theme
- Developer tools available (right-click to Inspect Element)
- Horizontal (side by side) or vertical (top and bottom) layout
- Toggle via toolbar button or Cmd+Option+L
- Layout preference persisted across sessions
| Shortcut | Action |
|---|---|
| Cmd+B | Bold |
| Cmd+I | Italic |
| Cmd+K | Insert link |
| Cmd+Shift+I | Insert image |
| Cmd+Shift+K | Inline code |
| Cmd+Shift+1 | Heading 1 |
| Cmd+Shift+2 | Heading 2 |
| Cmd+Shift+3 | Heading 3 |
All formatting commands are smart: they wrap selected text or insert a placeholder when nothing is selected.
When the open file is inside a git repository, Marksmith provides:
- Live gutter indicators showing added (green), modified (blue), and deleted (red) lines compared to the last commit
- In-memory diffing using Swift's
CollectionDifference(Myers algorithm) — diffs the live buffer againstHEADcontent, debounced at 300ms - Auto-refresh on focus — re-fetches HEAD content when you switch back to the app, picking up external commits
- Commit sheet with:
- Scrollable list of all changed files with colored status labels (Modified, Added, Deleted, Untracked, Renamed)
- Commit message editor
- "Stage all changed files" toggle
- "Push after commit" toggle
No git libraries are used — Marksmith shells out to /usr/bin/git directly.
Marksmith can build and serve static sites (Hugo, Jekyll, Eleventy, etc.) directly from the editor. Configure commands in Preferences > SSG.
Build — runs a one-shot command (e.g., hugo build) and displays output in a terminal-style panel.
Serve — runs a long-running dev server (e.g., hugo server -D) with:
- Streaming output in a terminal-style panel (dark background, green monospace text)
- Auto-detection of the localhost URL from server output
- Clickable URLs in the output panel
- Globe button to open the site in your default browser
- Play/stop toggle in the toolbar
Build output panel appears as a sub-split inside the editor pane. ANSI escape sequences are automatically stripped from output.
Marksmith registers as an editor for .md, .markdown, .mdown, and .mkd files. After installation, you can right-click a Markdown file in Finder and choose "Open With > Marksmith", or set it as the default editor.
- macOS 14 (Sonoma) or later
- Xcode 16 or later (install from the Mac App Store or developer.apple.com)
- Xcode Command Line Tools — install with:
xcode-select --install
- Homebrew — install from brew.sh if you don't have it
-
Clone the repository:
git clone https://github.com/duanestorey/marksmith.git cd marksmith -
Install XcodeGen (one-time):
make setup
This runs
brew install xcodegen. XcodeGen generates the Xcode project fromproject.yml, so there's no.xcodeprojchecked into the repo. -
Build the app:
make build # Release build # or make debug # Debug build
The built app is at
build/Build/Products/{Debug|Release}/Marksmith.app. -
Run it:
make run # Debug build + launch -
Install to /Applications (optional):
cp -R build/Build/Products/Release/Marksmith.app /Applications/Marksmith.app
| Command | Description |
|---|---|
make setup |
Install XcodeGen via Homebrew |
make generate |
Generate Marksmith.xcodeproj from project.yml |
make build |
Release build (generates project first) |
make debug |
Debug build |
make run |
Debug build + launch the app |
make open |
Generate project + open in Xcode |
make clean |
Remove build/ directory and .xcodeproj |
make all |
Setup + generate + build |
If you prefer to work in Xcode:
make openThis generates the project and opens it. You can then build and run from Xcode as usual (Cmd+R).
The only external dependency is swift-markdown (v0.5.0+) for Markdown-to-HTML conversion. It's fetched automatically by Swift Package Manager during the build — no manual dependency installation needed.
- Open Marksmith > Preferences (Cmd+,)
- Go to the SSG tab
- Set your commands:
- Build Command: the command to build your site (e.g.,
hugo build,jekyll build,npx eleventy) - Serve Command: the command to start a dev server (e.g.,
hugo server -D,jekyll serve,npx eleventy --serve) - Override URL (optional): manually specify the dev server URL if auto-detection doesn't work
- Build Command: the command to build your site (e.g.,
Commands run from the git repository root of the currently open file. If the file isn't in a git repo, the file's parent directory is used.
- Hammer icon — runs the build command; output appears in the build output panel
- Play icon — starts the dev server; changes to a stop icon while running
- Globe icon (appears when server is running) — opens the detected/configured URL in your browser
Both buttons are disabled when their respective commands are empty (not configured) or when no file is open.
Marksmith's git integration is designed to show you what you've changed as you type, without needing to save first.
When you open a file that's inside a git repository:
- Marksmith detects the repo root via
git rev-parse --show-toplevel - It fetches the file's content at HEAD via
git show HEAD:<relative-path> - As you type, it diffs your current buffer against the HEAD content using Swift's
CollectionDifference(an implementation of the Myers diff algorithm) - The diff is debounced at 300ms to avoid excessive computation
- Results appear as colored bars in the line number gutter:
- Green — new line (added)
- Blue — changed line (modified)
- Red triangle — line was deleted at this position
For new files not yet committed, all lines show as added (green).
When you switch back to Marksmith from another app, it automatically re-fetches the HEAD content. This means if you commit from the terminal or another tool, the gutter indicators update when you return to Marksmith.
Click the git branch icon in the toolbar to open the commit sheet. It shows:
- A list of all changed, added, deleted, and untracked files in the repo (via
git status --porcelain) - A commit message field
- A toggle to stage all changes (
git add -A) before committing - A toggle to push immediately after committing
marksmith/
├── Makefile # Build automation
├── project.yml # XcodeGen project spec
├── CLAUDE.md # AI assistant context
└── Marksmith/
├── MarksmithApp.swift # App entry point, menu commands
├── MarkdownDocument.swift # ReferenceFileDocument model
├── Info.plist # Bundle config, file type registration
├── Marksmith.entitlements # Sandbox entitlements
├── Views/
│ ├── ContentView.swift # Main split view, toolbar, commit sheet
│ ├── Editor/
│ │ ├── EditorView.swift # NSTextView wrapper + gutter
│ │ ├── GutterView.swift # Gutter data model
│ │ └── SyntaxHighlighter.swift # Regex-based highlighting
│ ├── Preview/
│ │ ├── PreviewView.swift # WKWebView wrapper
│ │ └── MarkdownHTMLGenerator.swift # AST walker, front matter
│ └── Preferences/
│ └── PreferencesView.swift # General + SSG settings
├── Services/
│ ├── GitStatusProvider.swift # Git gutter + commit + file status
│ └── SSGService.swift # Build/serve process management
├── Models/
│ └── ThemeMode.swift # System/Light/Dark enum
└── Resources/
├── Assets.xcassets/ # App icon
├── preview-template.html
├── preview-light.css
├── preview-dark.css
├── prism.css # Code highlighting in preview
└── prism.js
Copyright 2026 Duane Storey. All rights reserved.