Scribe is a native GNOME Markdown editor built with Rust, GTK4 and libadwaita. It renders Markdown live on the editing buffer so headings look like headings and bold text looks bold, without switching to a separate preview or browser engine.
I wanted a Markdown editor that felt like part of GNOME, not a port of a web app. The ones I tried either wrapped a browser engine (ProseMirror, Milkdown inside WebKit) and consumed hundreds of megabytes, or they showed a plain source buffer next to a rendered preview. I kept both panes open, going back and forth between them instead of just writing.
The idea is an editor where the source text IS the preview: the buffer stays
plain Markdown, but the rendering happens on top with GtkTextTag. That way
there is nothing to sync, no HTML under the hood, no browser engine to
bundle. It started as mockups for a GTK4 design exploration and evolved into
something I actually use to draft notes and docs.
- Rust + GTK4 + libadwaita — native toolkit, no Electron. The binary is around 8 MB and idles at a few dozen megabytes of RAM. A WebKit-based editor would be ten times that before opening a file.
- GtkSourceView 5 for the text buffer and pulldown-cmark for Markdown
parsing, then custom
GtkTextTagspans for rendering. No HTML or CSS involved in the preview. The editor is a singleGtkTextViewwith decorations applied to the buffer. - No database, no server, no JavaScript. It is a desktop application that opens, edits and saves files. Preferences go through GSettings, not a config file or a web UI.
- Live WYSIWYG rendering on the editing buffer: headings at real scale, bold/italic/strikethrough, inline and fenced code, quotes, nested lists with hanging indent, task lists, links, images, footnotes, rules, tables in monospace, and dimmed HTML blocks
- Configurable markup visibility: hide syntax markers like
**,#and backticks entirely, reveal them on the cursor line, or keep them dimmed everywhere - Focus mode (Ctrl+Shift+F) dims everything except the current paragraph
- Typewriter mode (Ctrl+Shift+T) keeps the cursor vertically centered
- Templates: Markdown files in
~/.local/share/scribe/templateswith{{title}},{{date}},{{time}},{{datetime}}and{{year}}markers. Four examples are seeded on first launch - Split preview (Ctrl+Shift+P) renders the full document in a side panel
using the same
GtkTextTagengine. Useful for tables and images - Ctrl+B/I/K wraps the selection in
**,*or backticks - List continuation: pressing Enter starts the next item and re-numbers ordered lists. Leaving an item empty closes the list
- Zoom (Ctrl +/−/0) with controls in the main menu
- Go to line from the status bar
- Header bar follows GNOME Text Editor: open button with recent files dropdown, new document button, centered title, main menu with zoom row on the right
- Preferences window with three pages: Appearance, Editor and Templates
- Files: open, save and save-as with
GtkFileDialog, atomic writes (temp + rename), unsaved-changes warning, configurable autosave - Sidebar (F9) with filterable recent files and a navigable document outline
- Light and dark theme follows the GtkSourceView style scheme
- Integration:
scribe file.mdand "Open with" from the file manager
GtkTextTag changes how text looks but cannot replace or overlay it, so
some things are rendered as styled text rather than true widgets:
- Bullet markers stay as
-or*, colored and with hanging indent, rather than• - Task lists show styled
[x]and[ ]instead of checkboxes - Rules (
---) are dimmed and centered, not a drawn line - Tables are rendered in monospace so columns align when pipes are lined up in the source; they are not a grid widget
- Images are not embedded
Drawing with a custom snapshot() or embedding widgets with text anchors
would alter the source buffer. That is out of scope for this phase.
The interface is in Spanish. English localization is not done yet.
Main window with live Markdown rendering
Main menu with zoom controls
Preferences window
Focus mode (everything dimmed except the current paragraph)
- Tabs / multiple documents (
AdwTabView) - Find and replace
- Export to HTML or PDF
- Spell checking
- English and other UI translations
- Rust 1.80 or later
- GTK4 (≥ 4.14), libadwaita (≥ 1.5), GtkSourceView 5 and GLib development files
Arch / CachyOS:
sudo pacman -S rust gtk4 libadwaita gtksourceview5 glib2Debian / Ubuntu:
sudo apt install libgtk-4-dev libadwaita-1-dev libgtksourceview-5-dev libglib2.0-devFedora:
sudo dnf install gtk4-devel libadwaita-devel gtksourceview5-devel glib2-develcargo build --release
cargo runGSettings schema needs to be installed for preferences to work. During development:
glib-compile-schemas data/
GSETTINGS_SCHEMA_DIR=$PWD/data cargo runThe application starts with defaults if the schema is not found, logging a warning to stderr.
A Flatpak manifest is at build-aux/flatpak. Work in
progress. The module builds with cargo --offline, so generate
cargo-sources.json first with
flatpak-cargo-generator
and keep Cargo.lock in the repository:
cargo generate-lockfile
python3 flatpak-cargo-generator.py Cargo.lock -o build-aux/flatpak/cargo-sources.json
cd build-aux/flatpak
flatpak-builder --user --install build-dir app.scribe.Scribe.json --force-cleangit clone https://github.com/gnacho/scribe.git
cd scribe
cargo build
cargo test
cargo runAGPL-3.0. See LICENSE.


