diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 45a698b..e98a732 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -103,3 +103,5 @@ jobs:
files: |
artifacts/termdown-*
artifacts/SHA256SUMS
+ install.sh
+ uninstall.sh
diff --git a/CLAUDE.md b/CLAUDE.md
index 7f29a30..efa195e 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -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.
diff --git a/README.md b/README.md
index 13e4b1d..98aedf5 100644
--- a/README.md
+++ b/README.md
@@ -4,40 +4,77 @@
Render Markdown with large-font headings in the terminal using the Kitty graphics protocol.
+
+
+ |
+ |
+
+
+
## 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`.
+
+
+Manual download (no script)
+
+```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/
+```
+
+
+
+### 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
+
+Manual uninstall
```sh
-cargo build --release
-cp target/release/termdown /usr/local/bin/
+rm $(which termdown)
+rm -rf ~/.termdown
```
+
+
## Usage
```sh
@@ -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
```
@@ -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.
@@ -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
diff --git a/README_CN.md b/README_CN.md
index bf13095..96f11e0 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -1,41 +1,79 @@
# Termdown
-在终端中以大字体标题渲染 Markdown,基于 Kitty 图形协议。
+在终端中以大字体标题渲染 Markdown,让观感更接近 GUI Markdown 阅读器的体验,基于 Kitty 图形协议。
+
+
+
+ |
+ |
+
+
## 为什么做这个
本项目受 [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` 覆盖安装目录。
+
+
+手动下载
+
+```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/
+```
+
+
+
+### 源码安装
-### 从源码安装
+```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
```
-### 手动构建
+
+手动卸载
```sh
-cargo build --release
-cp target/release/termdown /usr/local/bin/
+rm $(which termdown)
+rm -rf ~/.termdown
```
+
+
## 使用
```sh
@@ -45,7 +83,7 @@ termdown README.md
# 从 stdin 管道输入
cat notes.md | termdown
-# 指定主题(不使用自动检测)
+# 指定主题(不使用终端亮色、暗色主题自动检测)
termdown --theme light README.md
# 查看帮助
@@ -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 读取。
@@ -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 协议的限制
## 许可证
diff --git a/TODO.md b/TODO.md
new file mode 100644
index 0000000..5cf9b71
--- /dev/null
+++ b/TODO.md
@@ -0,0 +1,3 @@
+- [ ] 测试 html 标签支持
+- [ ] 图片支持
+- [ ] 长文本换行时缩进的处理
diff --git a/docs/screenshots/termdown_render_cn_demo.png b/docs/screenshots/termdown_render_cn_demo.png
new file mode 100644
index 0000000..0d70657
Binary files /dev/null and b/docs/screenshots/termdown_render_cn_demo.png differ
diff --git a/docs/screenshots/termdown_render_en_tui_demo.png b/docs/screenshots/termdown_render_en_tui_demo.png
new file mode 100644
index 0000000..4370cb0
Binary files /dev/null and b/docs/screenshots/termdown_render_en_tui_demo.png differ
diff --git a/install.sh b/install.sh
new file mode 100755
index 0000000..d43182c
--- /dev/null
+++ b/install.sh
@@ -0,0 +1,98 @@
+#!/usr/bin/env bash
+# termdown installer
+#
+# Downloads the prebuilt binary for your platform from GitHub Releases,
+# verifies its SHA-256 checksum, and installs it. Never invokes sudo; if the
+# install directory is not writable, prints a clear hint and exits.
+#
+# Usage:
+# curl -fsSL https://raw.githubusercontent.com/rrbe/termdown/master/install.sh | bash
+#
+# Environment variables:
+# TERMDOWN_INSTALL_DIR install directory (default: /usr/local/bin)
+
+set -euo pipefail
+
+REPO="rrbe/termdown"
+INSTALL_DIR="${TERMDOWN_INSTALL_DIR:-/usr/local/bin}"
+BASE="https://github.com/${REPO}/releases/latest/download"
+
+info() { printf '\033[1;32m==>\033[0m %s\n' "$*"; }
+warn() { printf '\033[1;33mwarning:\033[0m %s\n' "$*" >&2; }
+err() { printf '\033[1;31merror:\033[0m %s\n' "$*" >&2; }
+
+OS="$(uname -s)"
+ARCH="$(uname -m)"
+
+case "$OS" in
+ Darwin) OS_STR=apple-darwin ;;
+ Linux) OS_STR=unknown-linux-gnu ;;
+ *)
+ err "Unsupported OS: $OS (only macOS and Linux are supported by this script)."
+ err "For Windows, download the archive manually from https://github.com/${REPO}/releases."
+ exit 1
+ ;;
+esac
+
+case "$ARCH" in
+ x86_64|amd64) ARCH_STR=x86_64 ;;
+ arm64|aarch64) ARCH_STR=aarch64 ;;
+ *) err "Unsupported architecture: $ARCH"; exit 1 ;;
+esac
+
+TARGET="${ARCH_STR}-${OS_STR}"
+ARCHIVE="termdown-${TARGET}.tar.gz"
+
+info "Installing termdown (${TARGET})"
+
+TMP="$(mktemp -d)"
+trap 'rm -rf "$TMP"' EXIT
+
+info "Downloading ${ARCHIVE}"
+curl -fsSL -o "${TMP}/${ARCHIVE}" "${BASE}/${ARCHIVE}"
+curl -fsSL -o "${TMP}/SHA256SUMS" "${BASE}/SHA256SUMS"
+
+info "Verifying checksum"
+if command -v shasum >/dev/null 2>&1; then
+ CHECK_CMD="shasum -a 256 -c -"
+elif command -v sha256sum >/dev/null 2>&1; then
+ CHECK_CMD="sha256sum -c -"
+else
+ err "Neither 'shasum' nor 'sha256sum' is available; cannot verify the download."
+ exit 1
+fi
+(cd "$TMP" && grep " ${ARCHIVE}\$" SHA256SUMS | $CHECK_CMD >/dev/null)
+
+info "Extracting"
+tar -xzf "${TMP}/${ARCHIVE}" -C "$TMP"
+
+mkdir -p "$INSTALL_DIR" 2>/dev/null || true
+DEST="${INSTALL_DIR%/}/termdown"
+if ! install -m 0755 "${TMP}/termdown" "$DEST" 2>/dev/null; then
+ err "Cannot write to ${INSTALL_DIR} (permission denied)."
+ cat >&2 <&2
+ ;;
+esac
+
+"$DEST" --version
diff --git a/uninstall.sh b/uninstall.sh
new file mode 100755
index 0000000..ea979d4
--- /dev/null
+++ b/uninstall.sh
@@ -0,0 +1,54 @@
+#!/usr/bin/env bash
+# termdown uninstaller
+#
+# Removes the installed binary and deletes the config directory (~/.termdown).
+# Never invokes sudo; if the binary's location is not writable, prints a clear
+# hint and exits.
+#
+# Usage:
+# curl -fsSL https://raw.githubusercontent.com/rrbe/termdown/master/uninstall.sh | bash
+#
+# Environment variables:
+# TERMDOWN_INSTALL_DIR location of the binary (default: auto-detect via `command -v`)
+# TERMDOWN_KEEP_CONFIG set to 1 to keep ~/.termdown (default: remove it)
+
+set -euo pipefail
+
+REPO="rrbe/termdown"
+
+info() { printf '\033[1;32m==>\033[0m %s\n' "$*"; }
+err() { printf '\033[1;31merror:\033[0m %s\n' "$*" >&2; }
+
+if [ -n "${TERMDOWN_INSTALL_DIR:-}" ]; then
+ BIN="${TERMDOWN_INSTALL_DIR%/}/termdown"
+else
+ BIN="$(command -v termdown 2>/dev/null || true)"
+fi
+
+if [ -z "$BIN" ] || [ ! -e "$BIN" ]; then
+ info "termdown binary not found — nothing to remove"
+else
+ info "Removing ${BIN}"
+ if ! rm -f "$BIN" 2>/dev/null; then
+ err "Cannot remove ${BIN} (permission denied)."
+ cat >&2 <