# mdedit: A Terminal Markdown Editor That Actually Shows You the Rendered Output

By Leon Johnson, 2026-04-03. Web version: https://sholuv.net/blog/posts/mdedit-terminal-markdown-editor/

I write a lot of markdown. READMEs, documentation, notes, blog posts. It's everywhere. And every tool I've used to edit it has the same problem: it either can't show me the rendered output, or it needs a browser to do it.

Vim and nano are fast but you're staring at raw markup. VS Code works but you're launching an entire IDE for a README. Obsidian is nice but it locks your files in a vault and isn't available over SSH. So I built [mdedit](https://github.com/sho-luv/mdedit), a terminal markdown editor with live rendered preview, side by side, in a single binary.

![mdedit demo](https://github.com/sho-luv/mdedit/raw/main/demo/mdedit-demo.gif)

<video src="https://github.com/user-attachments/assets/8fdf074f-c237-4759-a589-46ab6648425d" width="100%" autoplay loop muted playsinline></video>

## Why Another Markdown Editor

The pitch is simple: **edit on the left, see the rendered result on the right, never leave the terminal.**

I wanted something that felt like vim (because that's what my hands know) but showed me what the markdown would actually look like. Not the raw asterisks and brackets. The bold text, the headers, the formatted code blocks. And it had to work over SSH, because half the time I'm editing files on a remote box.

Nothing I found hit all three: terminal-native, live preview, vim keybindings. So I wrote one in Rust.

## What It Does

You open a file and get a split view. Left side is your editor with syntax highlighting and line numbers. Right side renders the markdown in real time as you type. Headers get sized, lists get bullets, code blocks get formatted, links get colored.

```bash
mdedit README.md
```

That's it. The binary is 2.8MB, starts in under 50ms, and has zero runtime dependencies. No Node, no Python, no config files required.

**Vim mode** is the default. Normal, insert, visual, command mode all work the way you'd expect. `hjkl` to move, `dd` to delete a line, `yy` to yank, `/` to search, `:w` to save. If you prefer something simpler, there's a nano mode with `Ctrl+S` to save and `Ctrl+Q` to quit.

**Ctrl+P** cycles through three layouts: split view, editor only, and preview only. You can drag the divider with your mouse to resize the panes.

![layout modes](https://github.com/sho-luv/mdedit/raw/main/demo/screenshots/layouts.gif)

## The Stack

I built this with [ratatui](https://github.com/ratatui/ratatui) for the TUI framework, [pulldown-cmark](https://github.com/pulldown-cmark/pulldown-cmark) for markdown parsing, and [syntect](https://github.com/trishume/syntect) for syntax highlighting. The text editor widget is [tui-textarea](https://github.com/rhysd/tui-textarea) which gives you undo/redo, line numbers, and selection out of the box.

The markdown rendering was the interesting part. I started with [tui-markdown](https://github.com/joshka/tui-markdown) but ended up building a custom renderer to get the preview looking right. Proper heading sizes, nested lists, code block styling with the active theme colors, and horizontal rules.

The preview updates are debounced at 80ms so it doesn't re-render on every keystroke, and the preview scroll follows your cursor position so you're always looking at the part of the document you're editing.

## Clipboard Over SSH

This was a surprisingly tricky problem. On a local terminal, clipboard is easy. Just shell out to `pbcopy` on macOS or `xclip` on Linux. But over SSH, those commands run on the remote machine, not your local one.

The solution is [OSC 52](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html), a terminal escape sequence that tells your terminal emulator to put text on the local clipboard. Most modern terminals support it (iTerm2, Alacritty, Kitty, Windows Terminal). mdedit detects whether you're in an SSH session and automatically uses OSC 52 when you are, with DCS passthrough wrapping when you're inside tmux.

Every yank and delete syncs to the system clipboard. Paste reads from it. You don't configure anything.

## Live Settings

Type `:set` in normal mode and you get an interactive settings panel. Arrow keys to navigate, left/right to cycle through themes, Enter to apply. The four built-in themes (ocean, dracula, solarized-light, and gruvbox-dark) preview live as you switch between them, so you can see exactly what you're getting before you commit.

![settings panel](https://github.com/sho-luv/mdedit/raw/main/demo/screenshots/settings.gif)

Hit "Save to config" and it writes to `~/.config/mdedit/config.toml`. Next time you open mdedit, your preferences are there. There's also a "Reset defaults" option if you want to go back to the ocean theme and vim mode.

## Install

One line:

```bash
curl -fsSL https://raw.githubusercontent.com/sho-luv/mdedit/main/install.sh | sh
```

The install script detects your OS and architecture, downloads the right binary from GitHub Releases, and drops it in `/usr/local/bin`. Pre-built binaries are available for macOS (Intel and Apple Silicon) and Linux x86_64.

If you have Rust installed, you can also build from source:

```bash
cargo install --git https://github.com/sho-luv/mdedit.git
```

The source is at [github.com/sho-luv/mdedit](https://github.com/sho-luv/mdedit). It's a single Rust crate with no async runtime and no C dependencies.
