A markdown editor that thinks in blocks.
brew install --cask zekevh/tap/marklensOr download the DMG.
- Block-based editing — each paragraph, heading, code block, and table is its own unit
- WYSIWYG inline rendering — syntax stays visible but steps aside so content leads
- Drag blocks to reorder your document
- Fenced code blocks with syntax highlighting for Swift, Python, JS, Go, Rust, SQL, and more
- Clickable task list checkboxes (
[ ]/[x]) right in the editor - Table rendering with borders drawn natively
- Folder sidebar with pinned files and recents
- File watching — detects external changes and prompts to resolve conflicts
- Raw mode (⌘⇧R) — toggle to plain text anytime
- Autosave — no Cmd+S needed
- Native Swift app, no Electron
Requirements:
- Xcode 16+
- macOS 15+ for local development
Open the project in Xcode:
open MarkLens.xcodeprojOr build from the command line:
xcodebuild -project MarkLens.xcodeproj -scheme MarkLens -destination 'platform=macOS' buildRun the full test suite, including unit tests and UI tests:
xcodebuild -project MarkLens.xcodeproj -scheme MarkLens -destination 'platform=macOS' testOr use the compact test runner:
./scripts/run-test.sh MarkLensTests
./scripts/run-test.sh MarkLensUITests
./scripts/run-test.sh MarkLensTests/AppStateTreeTestsRun only the unit tests:
xcodebuild -project MarkLens.xcodeproj -scheme MarkLens -destination 'platform=macOS' test -only-testing:MarkLensTestsRun only the UI tests:
xcodebuild -project MarkLens.xcodeproj -scheme MarkLens -destination 'platform=macOS' test -only-testing:MarkLensUITestsThe UI tests use a test harness that launches the app against a temporary writable workspace, so they can cover create, rename, and conflict-resolution flows reliably.
The compact runner writes full logs to .test-logs/ and prints only a short test summary unless the run fails.
Run the benchmark suite:
./scripts/run-benchmarks.shThis runs focused performance tests for:
- workspace tree building
- large-document search
- incremental block kind sync after a single edit
- markdown block serialization
Current synthetic benchmark sizes:
- workspace tree build:
120directories,24markdown files per directory (2,880markdown files total) - document search:
4,000mixed markdown blocks - incremental block sync:
3,000mixed markdown blocks with one edited block - serialization:
3,000mixed markdown blocks
The benchmark runner writes local logs to .benchmarks/, which is gitignored. These benchmarks are intended for before/after comparison while refactoring, not as profiler-grade absolute measurements.
Targets:
MarkLens: the macOS app targetMarkLensTests: unit tests for parser, app state, tree building, and editor logicMarkLensUITests: UI smoke and workflow tests
Key folders:
MarkLens/: app sourceMarkLensTests/: unit test sourceMarkLensUITests/: UI test sourceMarkLens.xcodeproj/: Xcode project configuration
Useful files:
MarkLens/MarkLensApp.swift: app entry, app state, file operations, workspace wiringMarkLens/ContentView.swift: main UI, sidebar, raw editor, and UI-test hooksMarkLens/MarkdownEngine.swift: markdown parsing and block classificationMarkLens/NodeEditor.swift: block editor behaviorMarkLensTests/PerformanceBenchmarksTests.swift: synthetic performance benchmarks for core editing and workspace flowsMarkLensTests/*.swift: focused unit coverage by subsystemMarkLensUITests/MarkLensUITests.swift: end-to-end coverage for launch and file workflows
Recommended workflow:
- Make changes in
MarkLens/. - Run the relevant unit tests first:
xcodebuild -project MarkLens.xcodeproj -scheme MarkLens -destination 'platform=macOS' test -only-testing:MarkLensTests- If your change touches window behavior, file operations, alerts, or editor flows, run the full suite:
xcodebuild -project MarkLens.xcodeproj -scheme MarkLens -destination 'platform=macOS' test- If you are iterating on UI behavior specifically, run just the UI target:
xcodebuild -project MarkLens.xcodeproj -scheme MarkLens -destination 'platform=macOS' test -only-testing:MarkLensUITestsGuidelines:
- Prefer adding unit tests for parser, state, and filesystem logic before adding UI coverage.
- Use UI tests for cross-cutting user workflows such as launch, selection, create, rename, and conflict handling.
- Keep new tests deterministic and fixture-based.
MIT © Zeke V. Holt
