MarkdownViewer is a desktop Markdown reader and editor built on GNUstep: rendered previews with tables, math, Mermaid diagrams and highlighted code, a source editor with linked scrolling, and a file explorer. Under the hood is ObjcMarkdown, the reusable Objective-C renderer that turns CommonMark and GitHub-flavored Markdown into an NSAttributedString, ready for any NSTextView.
MarkdownViewer uses only standard controls and system colours, and lets the GNUstep theme decide how they look. The same build looks like a GNOME app under Adwaita, with its header bar, GNOME's file chooser and dark mode, and like a classic GNUstep app under GNUstep's own theme. On Windows it will look like a WinUI app under WinUITheme; screenshots will follow when that theme is ready.
| Adwaita, dark | GNUstep theme |
|---|---|
![]() |
![]() |
On macOS the same code builds natively against Cocoa, so macOS draws it as a Mac app: its own controls and menu bar, SF Symbols in the toolbar, and the system's light or dark appearance, followed as it changes.
Read for the rendered document, Edit for the Markdown source, and Split for both side by side, with the preview following the editor as you scroll and type.
| Edit mode, with the formatting bar | Split mode, GNUstep theme |
|---|---|
![]() |
![]() |
- Read, Edit and Split modes, with linked scrolling between source and preview
- A source editor with syntax highlighting, line numbers, an optional formatting bar and optional Vim key bindings
- An explorer sidebar: the document's repository or folder as a tree, with recent folders, a filter, a Markdown-only option and a context menu (open in a new tab, reveal, copy paths)
- An outline of the document's headings that follows where you are
- Tabs for several documents in one window
- Find (Ctrl+F, Ctrl+G) in the preview and the editor
- A status bar with the editor's Vim mode, the preview's status and its zoom
- Open Location: Markdown files straight from GitHub or any web address, read-only
- Import and export: print or export to PDF, and, with
pandocinstalled, import and exportDOCX,RTF,ODTandHTML - Share: one command (File > Share, or the toolbar's Share button) exports the open document, unsaved edits included, as PDF, Word, Markdown or HTML and hands it on: email with the file attached or the document as the message, the system's share menu on macOS and the share sheet on Windows 10 and 11, Open With, Show in Folder, Copy File, or a file you drag out. Copy Rendered pastes the formatted document into Teams, Outlook or Mail, and Copy for Slack into Slack. Before sending it warns about images and links only on your computer (offering a PDF or a
.zipwith the images), can share just the selection, and with rclone set up it puts a link to an uploaded copy on the clipboard and says who can open it - Copy buttons on code blocks and diagrams
- Preferences for the theme, layout density, editor and explorer
The renderer parses with GitHub's cmark-gfm, vendored and compiled in, so the app, the editor's highlighting and the scroll sync agree on the document's structure. Try it on docs/showcase.md.
| Tables and code | Math and diagrams |
|---|---|
![]() |
![]() |
- CommonMark: headings, emphasis, links, images, blockquotes, lists, code blocks, thematic breaks
- GitHub-flavored Markdown: tables, task lists, strikethrough, autolinks and footnotes
- Tables laid out as text: selectable and searchable, with links and cells that wrap to fit (or drawn as an image that may run wider than the view, via
allowTableHorizontalOverflow) - Mermaid
flowchart(with subgraphs,classDefandstyle) anderDiagramblocks drawn as diagrams, with the source one click away; other Mermaid types show their source with a note - Math: inline and display math as styled text, or typeset through LaTeX when a TeX toolchain is installed
- Syntax highlighting for code blocks in Objective-C, C and C++, Swift, Python, JavaScript and TypeScript, Go, Rust, Java, Kotlin, C#, PHP, Ruby, SQL, JSON, YAML, TOML, HTML and XML
- HTML as GitHub READMEs use it: centred paragraphs and headings, images with a width,
<br>,<kbd>,<sup>/<sub>,<details>/<summary>, lists, rules and simple tables; scripts, styles and embedded content are dropped (OMMarkdownHTMLPolicyRenderSafeSubset, the default; HTML can also be shown as text or ignored) - Relative links and images resolved against the document's location
- Themes in TOML, with a GitHub-like default
MarkdownViewer is built on the same renderer library shipped in ObjcMarkdown/, so app developers can embed that rendering path directly.
If you just want Markdown rendered into an NSTextView, the small path is one renderer object and one method call:
#import "OMMarkdownRenderer.h"
OMMarkdownRenderer *renderer = [[[OMMarkdownRenderer alloc] init] autorelease];
NSAttributedString *rendered = [renderer attributedStringFromMarkdown:
@"# Hello\n\nThis is **Markdown** rendered into an `NSAttributedString`."];
[[textView textStorage] setAttributedString:rendered];-init uses the default GitHub-like theme and default parsing options, so the common embed case stays small. If you need more control, use OMTheme and OMMarkdownParsingOptions to load a TOML theme, set a base URL for relative links, change HTML handling, tune image behavior, or adjust syntax-highlighting and math-rendering behavior.
Download the latest release, 0.2.2:
- Windows:
ObjcMarkdown-<version>-win64.msi, or the portable ZIP. WinUITheme is bundled as the default theme. Installed copies update themselves. - macOS:
MarkdownViewer-<version>-macos.dmg, a universal app (Apple silicon and Intel, macOS 11 or later). Drag the app to Applications and open it from there. It isn't notarized yet, so macOS blocks the first open: open it once, then choose Open Anyway in System Settings > Privacy & Security (on macOS 14 and earlier, Control-click the app and choose Open). It includes a Quick Look preview: press Space on a Markdown file in the Finder to see it rendered. - Linux:
ObjcMarkdown-<version>-linux-x86_64.AppImage(make it executable and run it; it updates itself) orMarkdownViewer.flatpak(flatpak install --user MarkdownViewer.flatpak). Both carry the GNUstep runtime and the Adwaita theme, so nothing else needs installing. To build from source instead, see below.
MarkdownViewer 0.2.2 is the current release, with packages for Linux, Windows and macOS.
- Primary supported environment: GNUstep on Linux with a clang/libobjc2/libdispatch toolchain.
- Windows support exists through the MSYS2
clang64toolchain. PowerShell/Codex sessions should usescripts/windows/build-from-powershell.ps1; see WINDOWS_BUILD.md. - macOS builds natively with Xcode's clang and Cocoa:
make -C macos(app) andmake -C macos test; see the macOS section of AGENTS.md.
This project is validated against a clang-based GNUstep stack with libobjc2 and libdispatch.
Important: stock Debian/Ubuntu GNUstep packages are commonly built around the GCC Objective-C runtime and are not a drop-in environment for this repo. The supported path is a clang/libobjc2/libdispatch GNUstep installation, either from your own packages or from a source build using GNUstep's tooling.
If you are building GNUstep yourself on Debian-like systems, the reference path on this machine is GNUstep's clang flow from tools-scripts. See docs/linux-clang-toolchain.md.
- Clone the repo and submodules:
git clone https://github.com/danjboyd/ObjcMarkdown.git
cd ObjcMarkdown
git submodule update --init --recursive- Source the GNUstep environment:
source /usr/GNUstep/System/Library/Makefiles/GNUstep.sh- Build:
gmake- Run the app:
gmake run Resources/sample-commonmark.mdNotes:
- No system
cmarkis needed: GitHub'scmark-gfmparser (tables, task lists, strikethrough, autolinks, footnotes) is vendored inthird_party/cmark-gfmand compiled intolibObjcMarkdown. third_party/TextViewVimKitis a required submodule.- The GNUstep theme provides the open and save panels: the Windows shell's dialogs under WinUITheme (the default on Windows), GNOME's file chooser under the Adwaita theme (through the XDG desktop portal), and GNUstep's own panels under its default theme, other themes, or where no portal runs.
- The GNUstep build on the authoring machine currently uses GNUstep Base
1.31.1.
The test runner is tools-xctest.
scripts/ci/run-linux-ci.shThat script builds the repo, prepares the GNUstep defaults lock directory, and runs:
xctest ObjcMarkdownTests/ObjcMarkdownTests.bundleGitHub Actions builds and tests on Linux in the GNUstep clang environment this project uses (clang/libobjc2/libdispatch, not the stock distro packages), on GitHub-hosted runners inside a container image that holds that toolchain:
- linux-gnustep-clang.yml: build and tests, on pushes to
main, pull requests and by hand - ci-image.yml: builds the image from ci/linux/Dockerfile (every source pinned by commit) and pushes it to
ghcr.io/danjboyd/objcmarkdown-ci; the CI workflow is pinned to its digest
Linux release packaging is handled separately so the build/test lane stays small:
Windows packaging and release publishing are handled by:
macOS builds natively with Xcode's clang and Cocoa (no GNUstep):
- macos.yml: universal build, tests and a launch smoke test on pushes to
mainand pull requests; for a version tag, the disk image is attached to the release
Release flow:
- Ensure the target commit has already passed the separate Linux CI workflow if you want a GNUstep/Linux gate before release tagging.
- Set the version in
VERSION(what About shows), then push an annotated tag likev0.1.0. - GitHub Actions runs
linux-appimageas a thin caller to the reusablegnustep-packagerworkflow pinned to4814554c9e445170217bd6849efea05b98e62856, on a GitHub-hosted runner inside the same CI image, using this repo's Linux manifest, stage script and preflight. It bundles the Adwaita theme at the commit pinned in packaging/inputs.json. - GitHub Actions runs
windows-packagingas a thin caller to the reusablegnustep-packagerworkflow pinned tobac42892f79ae1c7d56017d7cdb1d1637d729e6b, using this repo's Windows MSI manifest and normalized Windows stage script. The Windows manifest owns app-specific host dependencies (currently none:cmark-gfmis vendored). The staged Windows payload includes the GNUstep runtime, bundled Windows themes, and TinyTeX runtime for external LaTeX rendering. Windows releases are expected to bundleWinUIThemeand use it as the default packaged theme. - Each tagged packaging workflow then downloads its
-packagesartifact and attaches the release files to the matching GitHub Release page. Linux publishes the.AppImageand.zsync; Windows publishes the.msiand portable ZIP, along with generated sidecars such as.update-feed.json; macOS publishes the.dmg(ad-hoc signed, not notarized). - Clean-machine Windows validation is documented in docs/windows-otvm-msi-validation.md. Going forward, the supported Debian and Windows VM path is libvirt-backed
OracleTestVMsleases. The older direct-OCI helper has been retired; docs/windows-oci-msi-validation.md is kept only as a retirement note.
- Roadmap.md
- Issues on GitHub (the earlier OpenIssues.md and ClosedIssues.md are an archive)
- WINDOWS_BUILD.md
- packaging/README.md
- docs/windows-oci-msi-validation.md
- docs/linux-clang-toolchain.md
- docs/linux-appimage-packaging.md
- docs/linux-debian-vm-validation.md
Working notes, milestone handoffs, and validation checklists that were cluttering the repo root now live under docs/internal.
Licensing is split by component:
ObjcMarkdown/:LGPL-2.1-or-laterObjcMarkdownViewer/andObjcMarkdownTests/:GPL-2.0-or-laterthird_party/: upstream licenses apply









