Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,5 @@ jobs:
files: |
artifacts/termdown-*
artifacts/SHA256SUMS
install.sh
uninstall.sh
10 changes: 10 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,13 @@ If `make check` fails, fix the underlying issue — do not bypass with `#[allow(
### When you add a new build/lint/test command

Add it as a Makefile target first, then reference the target from CI. Never let CI and local commands diverge.

## Git workflow

**Do not commit or push to `master` directly.** All changes land on `master` via PR merges. For any code or docs change:

1. Create a feature branch (e.g. `feat/...`, `fix/...`, `docs/...`).
2. Commit there, push the branch, open a PR.
3. Never run `git commit` while `HEAD` is on `master`, and never run `git push origin master` — even for "small" doc tweaks. Committing to local master (even without pushing) tends to contaminate the merge base of later feature branches.

If you notice you're on `master` with uncommitted changes, stash them, switch to a new branch, and pop the stash before committing.
89 changes: 64 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,77 @@

Render Markdown with large-font headings in the terminal using the Kitty graphics protocol.

<table>
<tr>
<td><img src="docs/screenshots/termdown_render_cn_demo.png" width="380" alt="termdown rendering the Chinese README" /></td>
<td><img src="docs/screenshots/termdown_render_en_tui_demo.png" width="380" alt="termdown --tui rendering the English README" /></td>
</tr>
</table>

## Motivation

Inspired by [glow](https://github.com/charmbracelet/glow) and [mdfried](https://github.com/benjajaja/mdfried).

glow is a great terminal Markdown renderer, but headings are only distinguished by ANSI bold/color -- they can't actually be displayed at a larger size. mdfried supports image-rendered headings, but requires entering a TUI.

termdown aims to be **a lightweight `cat`-like tool where headings are truly rendered large**. It rasterizes H1-H3 text as PNG images and displays them via the Kitty graphics protocol -- no TUI, pipe-friendly, just direct output.
termdown rasterizes H1-H3 headings as PNG and paints them via the Kitty graphics protocol. Two modes share the same renderer:

## Terminal Support
- **Direct output** -- `cat`-like, pipe-friendly; dump rendered Markdown straight into your terminal.
- **Interactive TUI** (`--tui`) -- vim-style browser with search, Table of Contents, and link-follow navigation for longer documents.

Requires a terminal with **Kitty graphics protocol** support:
H4-H6 headings always fall back to ANSI bold text.

- [Ghostty](https://ghostty.org)
- [Kitty](https://sw.kovidgoyal.net/kitty/)
- [WezTerm](https://wezfurlong.org/wezterm/)
- [iTerm2](https://iterm2.com)
## Installation

On unsupported terminals, termdown will print a warning and heading images may not display correctly. H4-H6 headings always render as plain ANSI bold text.
### Install script

## Installation
```sh
curl -fsSL https://raw.githubusercontent.com/rrbe/termdown/master/install.sh | bash
```

Defaults to `/usr/local/bin`. Override the target directory with `TERMDOWN_INSTALL_DIR`.

<details>
<summary>Manual download (no script)</summary>

```sh
TARGET=aarch64-apple-darwin
BASE="https://github.com/rrbe/termdown/releases/latest/download"

curl -LO "${BASE}/termdown-${TARGET}.tar.gz"
curl -LO "${BASE}/SHA256SUMS"
grep "termdown-${TARGET}.tar.gz" SHA256SUMS | shasum -a 256 -c -

tar xzf "termdown-${TARGET}.tar.gz"
sudo mv termdown /usr/local/bin/
```

</details>

### Install from source

### From source
```sh
cargo install --git https://github.com/rrbe/termdown
```

Installs into `~/.cargo/bin/`.

## Uninstall

```sh
cargo install --path .
curl -fsSL https://raw.githubusercontent.com/rrbe/termdown/master/uninstall.sh | bash
```

### Build manually
<details>
<summary>Manual uninstall</summary>

```sh
cargo build --release
cp target/release/termdown /usr/local/bin/
rm $(which termdown)
rm -rf ~/.termdown
```

</details>

## Usage

```sh
Expand All @@ -50,7 +87,7 @@ cat notes.md | termdown
# Use a specific theme instead of auto-detect
termdown --theme light README.md

# Flags
# View help
termdown --help
termdown --version
```
Expand Down Expand Up @@ -94,18 +131,18 @@ termdown reads configuration from `~/.termdown/config.toml`.
theme = "auto"

[font.heading]
# Font for Latin/English text in H1-H3 headings (sans-serif recommended)
# English heading font (sans-serif recommended)
latin = "Inter"

# Font for CJK text in H1-H3 headings
# CJK heading font
cjk = "LXGW WenKai"

# Optional emoji / symbol fallback font for image-rendered headings
# Emoji / symbol fallback font for image-rendered headings (optional)
emoji = "Apple Color Emoji"
```

Headings with mixed scripts (e.g. "Hello 世界") will render each character with the appropriate font automatically.
Standalone emoji in H1-H3 headings are also supported through font fallback when the selected emoji font exposes outline or raster glyphs.
Standalone emoji in H1-H3 headings are also rendered via font fallback where possible.

> **Note:** Body text is rendered as plain ANSI text -- its font is determined by your terminal emulator settings, not by termdown. To change the body font, configure your terminal directly.

Expand All @@ -131,14 +168,16 @@ If no config file exists, termdown uses platform-specific defaults and falls bac
| Songti SC | Noto Serif | Microsoft YaHei |
| STSong | DejaVu Serif | |

## Uninstall
## Terminal Support

Remove the binary and delete the configuration directory:
Requires a terminal with **Kitty graphics protocol** support:

```sh
rm $(which termdown)
rm -rf ~/.termdown
```
- [Ghostty](https://ghostty.org)
- [Kitty](https://sw.kovidgoyal.net/kitty/)
- [WezTerm](https://wezfurlong.org/wezterm/)
- [iTerm2](https://iterm2.com)

On unsupported terminals, termdown will print a warning and heading images may not display correctly. H4-H6 headings always render as plain ANSI bold text.

## Known Issues

Expand Down
145 changes: 92 additions & 53 deletions README_CN.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,79 @@
# Termdown

在终端中以大字体标题渲染 Markdown,基于 Kitty 图形协议。
在终端中以大字体标题渲染 Markdown,让观感更接近 GUI Markdown 阅读器的体验,基于 Kitty 图形协议。

<table>
<tr>
<td><img src="docs/screenshots/termdown_render_cn_demo.png" width="380" alt="termdown 渲染中文 README" /></td>
<td><img src="docs/screenshots/termdown_render_en_tui_demo.png" width="380" alt="termdown --tui 渲染英文 README" /></td>
</tr>
</table>

## 为什么做这个

本项目受 [glow](https://github.com/charmbracelet/glow) 和 [mdfried](https://github.com/benjajaja/mdfried) 启发。

glow 是优秀的终端 Markdown 渲染器,但标题只能用 ANSI 粗体/颜色区分,无法真正放大显示。mdfried 支持图片化标题,但需要进入 TUI 模式。
- **glow** 不支持放大标题字体
- **mdfried** 支持放大 markdown 标题,但个人感觉可以做的更美观一点

termdown 的目标很简单:**像 `cat` 一样轻量,但标题能真正大写化显示**。它将 H1-H3 标题栅格化为 PNG 图片,通过 Kitty 图形协议直接输出到终端,无需 TUI,管道友好。
termdown H1-H3 标题栅格化为 PNG 图片,通过 Kitty 图形协议直接绘制到终端。提供两种使用模式:

## 终端支持
- **直接输出** —— `termdown README.md`, 像 `cat` 一样轻量、管道友好,把渲染后的 Markdown 直接打到终端。适合快速查看短文档。
- **交互式 TUI** —— `termdown --tui README.md`,类 vim/less 的体验,支持常见的翻页、搜索等快捷键,支持查看 TOC、链接跳转,适合阅读较长文档。

需要支持 **Kitty 图形协议** 的终端:
H4-H6 标题始终以 ANSI 粗体文本渲染。不想让文档加入那么多种字重,那样反而损害可读性。

- [Ghostty](https://ghostty.org)
- [Kitty](https://sw.kovidgoyal.net/kitty/)
- [WezTerm](https://wezfurlong.org/wezterm/)
- [iTerm2](https://iterm2.com)
## 安装

不支持的终端会打印警告。H4-H6 标题始终以 ANSI 粗体文本渲染。
### 安装脚本

## 安装
```sh
curl -fsSL https://raw.githubusercontent.com/rrbe/termdown/master/install.sh | bash
```

默认装到 `/usr/local/bin`。用 `TERMDOWN_INSTALL_DIR` 覆盖安装目录。

<details>
<summary>手动下载</summary>

```sh
TARGET=aarch64-apple-darwin
BASE="https://github.com/rrbe/termdown/releases/latest/download"

curl -LO "${BASE}/termdown-${TARGET}.tar.gz"
curl -LO "${BASE}/SHA256SUMS"
grep "termdown-${TARGET}.tar.gz" SHA256SUMS | shasum -a 256 -c -

tar xzf "termdown-${TARGET}.tar.gz"
sudo mv termdown /usr/local/bin/
```

</details>

### 源码安装

### 从源码安装
```sh
cargo install --git https://github.com/rrbe/termdown
```

安装到 `~/.cargo/bin/`。

## 卸载

```sh
cargo install --path .
curl -fsSL https://raw.githubusercontent.com/rrbe/termdown/master/uninstall.sh | bash
```

### 手动构建
<details>
<summary>手动卸载</summary>

```sh
cargo build --release
cp target/release/termdown /usr/local/bin/
rm $(which termdown)
rm -rf ~/.termdown
```

</details>

## 使用

```sh
Expand All @@ -45,7 +83,7 @@ termdown README.md
# 从 stdin 管道输入
cat notes.md | termdown

# 指定主题(不使用自动检测
# 指定主题(不使用终端亮色、暗色主题自动检测
termdown --theme light README.md

# 查看帮助
Expand All @@ -63,22 +101,22 @@ termdown --tui README.md

按键绑定:

| 按键 | 动作 |
|---|---|
| `j` / `↓` | 向下滚动一行 |
| `k` / `↑` | 向上滚动一行 |
| `d` / `u` | 半屏向下 / 向上 |
| `f` / `Space` / `PgDn` | 整屏向下 |
| `b` / `PgUp` | 整屏向上 |
| `gg` / `G` | 跳到文档开头 / 末尾 |
| `]` / `[` | 下一个 / 上一个标题 |
| `t` | 切换目录面板 |
| `/` | 正向搜索 |
| `n` / `N` | 下一个 / 上一个匹配 |
| `?` | 切换快捷键帮助弹窗 |
| `Enter` | 打开链接(屏幕中有多个链接时显示序号选择器) |
| `o` / `i` | 在已跳转的 `.md` 文档之间前进 / 后退 |
| `q` / `Ctrl-C` | 退出 |
| 按键 | 动作 |
| ---------------------- | -------------------------------------------- |
| `j` / `↓` | 向下滚动一行 |
| `k` / `↑` | 向上滚动一行 |
| `d` / `u` | 半屏向下 / 向上 |
| `f` / `Space` / `PgDn` | 整屏向下 |
| `b` / `PgUp` | 整屏向上 |
| `gg` / `G` | 跳到文档开头 / 末尾 |
| `]` / `[` | 下一个 / 上一个标题 |
| `t` | 切换目录面板 |
| `/` | 正向搜索 |
| `n` / `N` | 下一个 / 上一个匹配 |
| `?` | 切换快捷键帮助弹窗 |
| `Enter` | 打开链接(屏幕中有多个链接时显示序号选择器) |
| `o` / `i` | 在已跳转的 `.md` 文档之间前进 / 后退 |
| `q` / `Ctrl-C` | 退出 |

TUI 模式需要指定文件路径,不支持从 stdin 读取。

Expand Down Expand Up @@ -113,39 +151,40 @@ H1-H3 标题中的单个 emoji 也会通过 fallback 字体尽量渲染出来。

**Latin**(无衬线):

| macOS | Linux | Windows |
|-------|-------|---------|
| Avenir | Inter | Segoe UI |
| Avenir Next | Noto Sans | Arial |
| Futura | DejaVu Sans | Verdana |
| Helvetica Neue | Liberation Sans | |
| macOS | Linux | Windows |
| -------------- | --------------- | -------- |
| Avenir | Inter | Segoe UI |
| Avenir Next | Noto Sans | Arial |
| Futura | DejaVu Sans | Verdana |
| Helvetica Neue | Liberation Sans | |

**CJK**:

| macOS | Linux | Windows |
|-------|-------|---------|
| Noto Serif CJK SC | Noto Serif CJK SC | SimSun |
| Source Han Serif SC | Source Han Serif SC | KaiTi |
| Songti SC | Noto Serif | Microsoft YaHei |
| STSong | DejaVu Serif | |
| macOS | Linux | Windows |
| ------------------- | ------------------- | --------------- |
| Noto Serif CJK SC | Noto Serif CJK SC | SimSun |
| Source Han Serif SC | Source Han Serif SC | KaiTi |
| Songti SC | Noto Serif | Microsoft YaHei |
| STSong | DejaVu Serif | |

## 卸载
## 终端支持

删除二进制文件和配置目录
需要支持 **Kitty 图形协议** 的终端(目前仅在 Ghostty 和 iTerm2 上测试过)

```sh
rm $(which termdown)
rm -rf ~/.termdown
```
- [Ghostty](https://ghostty.org)
- [Kitty](https://sw.kovidgoyal.net/kitty/)
- [WezTerm](https://wezfurlong.org/wezterm/)
- [iTerm2](https://iterm2.com)

不支持的终端会打印警告。H4-H6 标题始终以 ANSI 粗体文本渲染。

## 已知问题

- **换行显示** -- 含 ANSI 转义序列的长行可能无法正确换行
- **终端兼容** -- 目前仅在 Ghostty 和 iTerm2 上测试过,其他支持 Kitty 协议的终端可能表现不一致
- **字体选择与降级** -- 字体粗细匹配依赖平台 API(Core Text / fontconfig),不一定能解析到预期的字重变体
- **主题检测** -- 自动检测依赖终端对 OSC 11 的响应;如终端不支持,请通过 `--theme` 或配置文件手动指定主题
- **复杂 emoji 序列** -- 依赖 ZWJ 的复杂 emoji(例如家庭/群组类组合、部分肤色组合)目前仍可能拆成多个字形,因为标题渲染还没有完整文本 shaping
- **TUI 帮助弹窗与标题图片** -- TUI 模式下 `?` 帮助弹窗绘制在文字层,而标题图片位于 Kitty graphics 层(始终覆盖在文字之上)。与弹窗区域重叠的标题图片会在弹窗打开时被临时移除,关闭后自动恢复 —— 这是 Kitty graphics 协议的限制,不是 bug
- **TUI 帮助弹窗与标题图片** -- TUI 模式下 `?` 帮助弹窗绘制在文字层,而标题图片位于 Kitty graphics 层(始终覆盖在文字之上)。与弹窗区域重叠的标题图片会在弹窗打开时被临时移除,关闭后自动恢复 —— 这是 Kitty graphics 协议的限制

## 许可证

Expand Down
3 changes: 3 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- [ ] 测试 html 标签支持
- [ ] 图片支持
- [ ] 长文本换行时缩进的处理
Binary file added docs/screenshots/termdown_render_cn_demo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/termdown_render_en_tui_demo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading