jolleyDesign/tudo
GitHub: jolleyDesign/tudo
一款本地优先、键盘驱动的终端待办事项列表与 Markdown 笔记本 TUI 应用。
Stars: 37 | Forks: 4
# tudo

## 功能
- **双标签页 — 任务和笔记**:按 `1` 切换到任务,`2` 切换到笔记。任务标签页即下方的待办事项列表;笔记标签页是一个 markdown 笔记本(参见 [笔记](#notes))。
- **多个列表 / 项目**:在侧边栏中切换不同的命名列表。
- **丰富的任务属性**:优先级、故事点、截止日期、标签、自由文本笔记,以及一层可勾选的子任务。
- **跨所有列表的标签筛选**:你的标签存放在固定于侧边栏底部的专属面板中(高度最多占一半,数量多时可独立滚动,确保你的列表始终保持在顶部)。选择一个标签即可查看包含该标签的所有任务,它们将从你所有的列表中汇总到单一视图中(每行都会标明其所属的列表)。你可以直接在此处编辑、完成或重新安排任务 —— 所做的更改会同步回其原始列表。
- **自由重新排序**:将任务上移/下移,或直接将其发送到列表的顶部或底部 —— 你也可以用同样的方式在侧边栏中对列表重新排序。
- **按需排序**:按 `o` 可按优先级、故事点、截止日期、创建日期或标题,对列表进行升序或降序排列(在选择器中按 `r` 可切换方向) —— 你也可以保持手动排序,完全由你的自定义排列(和重排快捷键)决定。
- **归档而非删除**:按 `d` 可将任务收纳到变暗的 **Archived**(已归档)列表中(固定在侧边栏底部),以免丢失;`X` 会彻底删除,而 `m` 可将任务移出以取消归档。
- **键盘优先,鼠标友好**:支持 vim 按键和方向键;支持点击行,点击复选框进行切换,以及滚动移动。
- **搜索与筛选**:支持对标题/标签/笔记进行子字符串搜索,以及状态筛选(全部 / 进行中 / 已完成)。
- **Markdown 笔记**:将笔记整理到笔记本中;使用纯 markdown 编写,并提供渲染后的阅读视图;通过 `[[wiki links]]` 和反向链接连接笔记;支持行内标签(`#tag`)、置顶、归档,还可以在你的 `$EDITOR` 中弹出并打开任意笔记(参见 [笔记](#notes))。
- **人类可读的存储**:每个列表对应一个格式化的 JSON 文件,每个笔记对应一个 `.md` 文件,采用原子写入方式,确保程序崩溃也不会损坏你的数据。
- **本地优先**:所有数据都不离开你的设备。
## 安装
### 快速安装(预编译二进制文件)
macOS 和 Linux:
```
curl -fsSL https://raw.githubusercontent.com/jolleydesign/tudo/main/install.sh | sh
```
这会从最新的[发布版本](https://github.com/jolleydesign/tudo/releases)中获取适合你平台的二进制文件,并将其安装到
`~/.local/bin`。你可以设置 `TUDO_INSTALL_DIR` 来指定其他安装位置,或者设置 `TUDO_VERSION`(例如 `v0.1.0`)来指定特定版本。
**更新:** 重新运行上述安装命令即可升级到最新版本 - 它会直接覆盖现有的二进制文件。你可以使用 `tudo --version` 查看当前运行的版本。
### 通过 Homebrew 安装
macOS 和 Linux(通过 [Homebrew](https://brew.sh)):
```
brew install jolleydesign/tudo/tudo
```
这会添加 `jolleydesign/homebrew-tudo` tap 并安装预编译的二进制文件。之后可使用 `brew upgrade tudo` 进行升级。
### 通过 Cargo 安装
从 [crates.io](https://crates.io/crates/tudo-tui) 安装 - 该 crate 发布时的名称为 `tudo-tui`(因为 `tudo` 这个名称已被占用),但安装后的命令依然是 `tudo`:
```
cargo install tudo-tui
```
或者,你也可以使用 Rust 工具链(1.95+)从源码构建:
```
# 直接来自 GitHub
cargo install --git https://github.com/jolleydesign/tudo
# 或来自本地 checkout
cargo install --path .
# 或者直接 build 和 run
cargo run --release
```
`cargo install` 会将 `tudo` 二进制文件安装到你的 `PATH` 中(通常是 `~/.cargo/bin`)。
## 首次运行
当你首次启动 `tudo` 时,它会询问你数据的保存位置,并提供几个标准位置(或自定义路径)。你的选择会被记录在一个位于 `~/.config/tudo/config.json` 的微型指针文件中。系统还会自动创建一个名为 **Tasks** 的初始列表,让你可以立即开始使用。
## 快捷键
在应用中按 `?` 可查看分组显示在浮层中的相同列表 —— 该浮层具有标签页感知能力,因此在笔记标签页下,它会显示笔记相关的快捷键。所有这些按键都可以在配置文件中进行[自定义](#customizing-keybindings),并且帮助浮层始终显示你当前的快捷键绑定。下表涵盖了 **任务** 标签页的内容;**笔记** 标签页会复用相同的按键来执行对应的笔记本 / 笔记操作(参见 [笔记](#notes))。
**导航**
| 按键 | 操作 |
|-----|--------|
| `1` / `2` | 切换到任务 / 笔记标签页(在任一标签页下均有效) |
| `Tab` / `Shift`+`Tab` | 在侧边栏和任务面板之间切换焦点 |
| `h`/`l`, `←`/`→` | 在侧边栏和任务面板之间跳转 |
| `\` | 在列表和标签面板之间切换侧边栏(`#` 可直接跳转到标签) —— 无需滚动经过每一个列表 |
| `j`/`k`, `↑`/`↓` | 在当前聚焦的面板内移动选择(支持循环:移过底部会回到顶部,反之亦然) |
| `Enter` | 打开任务详情视图 / 进入列表 |
| `Esc` | 关闭对话框 / 退出详情 / 清除筛选 |
**组织管理**
| 按键 | 操作 |
|-----|--------|
| `Space` | 切换选中任务(或子任务)的完成状态 |
| `J`/`K`, `Shift`+`↓`/`↑` | 将选中的任务(或侧边栏聚焦时的列表)下移 / 上移 |
| `g`/`G` | 将选中的任务发送到列表的顶部 / 底部 |
| `m` | 将选中的任务移动到其他列表(也可用于取消归档) |
**创建与编辑**
| 按键 | 操作 |
|-----|--------|
| `a` / `A` | 添加任务 / 添加列表 |
| `e` | 编辑选中任务的标题,或在列表面板聚焦时重命名列表 |
| `s` | 添加子任务 |
| `p` | 循环切换优先级(无 → 低 → 中 → 高) |
| `P` | 设置或清除故事点(整数) |
| `D` | 设置或清除截止日期 |
| `t` | 编辑标签 |
| `n` | 编辑笔记(支持多行:`Enter` 换行,`Ctrl+S` 保存) |
**移除**
| 按键 | 操作 |
|-----|--------|
| `d` | 归档选中的任务 |
| `X` | 永久删除选中的任务/列表/子任务(需确认) |
**查找与应用**
| 按键 | 操作 |
|-----|--------|
| `/` | 搜索(标题、标签、笔记) |
| `f` | 循环切换状态筛选(全部 / 进行中 / 已完成) |
| `o` | 对任务进行排序(菜单:手动 / 优先级 / 点数 / 截止日期 / 创建时间 / A–Z;`r` 切换方向) |
| `c` | 复制选中的任务(菜单:完整 JSON / 标题 / 描述) |
| `T` | 打开主题选择器 |
| `S` | 打开设置(路径、数据位置) |
| `?` | 显示帮助浮层 |
| `q`, `Ctrl+C` | 退出 |
**截止日期输入** 接受 `YYYY-MM-DD`、`today`、`tomorrow` 或 `+N`(距离今天 N 天)格式。输入空值将清除日期。
**快速添加语法:** 添加任务(`a`)时,你可以直接在行内设置其字段,而无需事后再逐一编辑。例如:
```
Ship the release !! ~5 #work @tomorrow n:double-check the changelog s:tag it, publish, announce
```
会创建一个名为 "Ship the release" 的中等优先级任务,估算为 5 个故事点,带有 `work` 标签,截止日期为明天,并附带相应的笔记和三个子任务。具体说明:
| 标记 | 设置 | 说明 |
|--------|------|-------|
| `!` `!!` `!!!` | 优先级 低 / 中 / 高 | 作为独立标记(4个或更多符号等同于高) |
| `~N` | 故事点 | `~` + 整数(以最后一个为准) |
| `#tag` | 标签 | 可重复使用 |
| `@date` | 截止日期 | `@` + 任何截止日期输入接受的格式(`@today`、`@+3`、`@2026-07-10`) |
| `n:…` | 笔记 | 持续到下一个 `n:`/`s:`;多次出现将以换行符连接 |
| `s:a, b, c` | 子任务 | 以逗号分隔;多次出现会累加 |
优先级、点数、标签和日期可以以任何顺序出现在第一个 `n:`/`s:` 之前的任意位置;此后的所有内容都将作为笔记/子任务文本。标记仅在单词边界处被识别,因此普通的 "We won!" 或 "C# rewrite" 会保留其标点符号,任何无法识别的内容都会直接保留在标题中。
**鼠标:** 点击列表或任务即可选中,点击任务的复选框可切换完成状态,使用滚轮可在当前聚焦的面板内移动。
## 笔记
按 `2`(或点击顶部的 **Notes** 标签页)可从任务切换到你的 markdown 笔记本。按 `1` 可切换回任务界面。其布局与任务标签页相呼应:侧边栏为**笔记本**(其下方固定有笔记标签面板,就像任务标签一样),右上角为**笔记列表**,下方则是所选笔记的实时**预览**。在笔记上按 `Enter` 即可在**全屏编辑器**中打开(`Esc` 或 `Ctrl+S` 会保存并关闭 —— 无论如何它都会自动保存);如果需要长时间写作,按 `E` 可将文件交给你的 `$EDITOR` 处理。
笔记是纯 markdown 格式。在原始编辑器和预览中,标记会被**淡化** —— 标题的 `#`、列表项符号、引用块的 `>`、代码块以及行内的 `` ` ``/`**` 分隔符都会褪变为柔和的颜色,从而突出你的文本。在打开的笔记中,按 `Tab` 可切换到**渲染阅读视图** —— 标题、列表、引用线、分隔线、代码块和链接都会正确排版,并支持使用方向键/`j`/`k`/`PageUp`/`Down`/滚轮进行滚动 —— 再次按 `Tab` 即可跳回编辑模式。
标签和置顶信息存储在每个文件顶部的简短 YAML frontmatter 块中,从而确保文件保持良好的可移植性,并支持使用任何其他工具进行编辑。
**笔记间的链接。** 在笔记的任意位置写入 `[[笔记标题]]` 即可链接到另一条笔记。在渲染阅读视图下,按 `f`(或点击链接)可打开**跳转链接**选择器 —— 它会列出该笔记的对外链接*以及*反向链接("linked from"),并跳转到你选择的项目。每条笔记的阅读视图都会显示一个 **Linked from** 区域,其中列出了指向该笔记的来源笔记。
**笔记标签页快捷键**(与任务标签页的按键相同,用于执行对应的笔记本/笔记操作):
| 按键 | 操作 |
|-----|--------|
| `a` / `A` | 添加笔记 / 添加笔记本 —— 在笔记标题中输入 `#tag` 标记即可为其添加标签(类似于任务的快速添加功能) |
| `e` | 编辑笔记标题,或在笔记本面板聚焦时重命名笔记本 |
| `Enter` / `n` | 打开全屏正文编辑器 —— 方向键 & `PageUp`/`Down`(以及滚轮)可进行导航,长笔记支持滚动;`Enter` 可插入换行;`Esc` 或 `Ctrl+S` 可保存并关闭 |
| `Tab`(在打开的笔记中) | 在原始编辑器和渲染阅读视图之间切换 |
| `f`(在阅读视图下) | 跟随 `[[链接]]` —— 包含对外链接 + 反向链接的选择器(或点击链接) |
| `E` | 在你的 `$EDITOR`(查找 `$VISUAL`/`$EDITOR`,缺省回退至 `vi`)中打开选中的笔记 |
| `t` | 编辑笔记的标签 |
| `*` | 置顶 / 取消置顶笔记(置顶的笔记会浮动到顶部) |
| `J`/`K` | 将选中的笔记重新排序 —— 或在笔记本面板聚焦时对笔记本进行排序(仅限手动排序) |
| `g`/`G` | 将选中的笔记发送到顶部 / 底部(仅限手动排序) |
| `c` | 复制笔记(菜单:正文 / 标题 / 完整 markdown) |
| `/` | 搜索笔记(标题、正文、标签) |
| `o` | 对笔记进行排序(手动 / A–Z / 创建时间 / 修改时间;`r` 切换方向) |
| `d` | 归档选中的笔记 |
| `m` | 将笔记移动到其他笔记本(也可用于取消归档) |
| `X` | 删除选中的笔记或笔记本(需确认) |
| `#` | 跳转到笔记标签面板;选择某个标签即可查看所有笔记本中包含该标签的笔记 |
与任务一样,笔记也有一个固定在侧边栏底部的 **Archived**(已归档)笔记本(显示为灰色):按 `d` 可将笔记隐藏其中,按 `m` 可将其移出以取消归档(或移动到任何其他笔记本),而 `X` 会将其彻底删除。已归档的笔记不会出现在标签视图中,并且 Archived 笔记本本身无法被重命名或删除。
## 主题
按 `T` 打开**主题选择器**:使用 `↑/↓` 浏览,即可在整个 UI 中实时预览每个主题,按 `Enter` 应用,按 `Esc` 恢复。内置了十二种配色方案 - **Tokyo Night**、**Catppuccin Mocha**、**Dracula**、
**Nord**、**Gruvbox Dark**、**Gruvbox Material**、**Solarized Dark**、**One Dark**、**Rosé Pine**、
**Gotham**、**Black & White** 以及 **Terminal**(默认)。你的选择会被记录在配置指针文件中。
彩色主题采用了 truecolor,因此无论你终端本身使用什么主题,它们看起来都是一样的;而 **Terminal** 则恰恰相反 - 它不会强制设定背景色,而是使用 16 种 ANSI 颜色,使应用融入你终端的配色方案。你可以设置 `TUDO_THEME`(例如 `TUDO_THEME=dracula` 或 `TUDO_THEME=none`)来为单次运行覆盖主题设置。
## 设置与配置
按 `S` 可打开设置面板,其中会显示你的**数据目录**、**配置文件**路径、存储格式、当前主题、你的列表/任务计数,以及当前生效的任何环境变量覆盖配置。
配置是一个小型的 **JSON** 文件(而非 TOML)- 默认位于 `~/.config/tudo/config.json`(可通过 `$TUDO_CONFIG` 覆盖)。它保存了 `data_dir`、`theme` 以及可选的 `keybindings`;其他所有内容(即你的实际列表)都以独立的 JSON 文件形式存放在数据目录中。如果需要移动数据,请按 `S` 然后按 `d`,输入新路径(允许使用 `~`),然后按 `Enter` - tudo 会将你的列表文件移动到那里并重新指向配置。
## 自定义快捷键
tudo 会在你的 `config.json` 中写入完整的 `keybindings` 块(在首次运行时写入,并在升级时自动填充任何缺失的操作),因此你不必从头编写 - 只需编辑你想要的按键并重启 tudo 即可。每个条目将一个**操作名称**映射到触发该操作的按键列表;该列表会**替换**该操作的默认设置,因此请确保包含你想要的所有按键。例如,要为一些操作添加 `Ctrl` 备选键:
```
{
"data_dir": "/Users/you/.local/share/tudo",
"theme": "dracula",
"keybindings": {
"move-down": ["j", "down", "ctrl+n"],
"move-up": ["k", "up", "ctrl+p"],
"quit": ["q", "ctrl+q"],
"search": ["/", "ctrl+f"]
}
}
```
**按键语法:** 单个字符即代表该键,且区分大小写(`j` 和 `J` 不同)。命名键包括 `space`、`tab`、`enter`、`esc`、`up`、`down`、`left`、`right`、`home`、`end`、`pageup`、`pagedown`、`backspace`、`delete` 和 `insert`。使用 `ctrl+`、`alt+` 或 `shift+` 添加修饰键(例如 `ctrl+q`、`shift+down`);对于字母,直接使用大写字母(`J`)而不是 `shift+j`。
**操作名称**(括号内为默认值):
| 操作 | 默认值 | 作用 |
|--------|---------|------|
| `toggle-focus` | `tab` / `backtab` | 在侧边栏和任务面板之间切换焦点 |
| `toggle-sidebar-pane` | `\` | 在列表和标签面板之间切换侧边栏 |
| `focus-lists` / `focus-tasks` / `focus-tags` | `h`/`left`, `l`/`right`, `#` | 跳转到列表 / 任务面板 / 标签 |
| `move-down` / `move-up` | `j`/`down`, `k`/`up` | 移动选择 |
| `activate` | `enter` | 打开任务详情 / 进入列表 |
| `back` | `esc` | 关闭对话框 / 退出详情 / 清除筛选 |
| `toggle-done` | `space` | 切换选中任务或子任务的完成状态 |
| `reorder-down` / `reorder-up` | `J`/`shift+down`, `K`/`shift+up` | 将任务(或侧边栏聚焦时的列表)下移 / 上移 |
| `send-top` / `send-bottom` | `g` / `G` | 将任务发送到顶部 / 底部 |
| `move-task` | `m` | 将任务移动到其他列表(也可用于取消归档) |
| `add-task` / `add-list` | `a` / `A` | 添加任务 / 列表 |
| `edit` | `e` | 编辑任务标题,或重命名列表 |
| `add-subtask` | `s` | 添加子任务 |
| `cycle-priority` | `p` | 循环切换优先级(无 → 低 → 中 → 高) |
| `set-points` | `P` | 设置或清除故事点(整数) |
| `set-due` | `D` | 设置或清除截止日期 |
| `set-tags` | `t` | 编辑标签 |
| `set-notes` | `n` | 编辑笔记 |
| `archive` | `d` | 归档选中的任务 |
| `delete` | `X` | 永久删除(需确认) |
| `search` | `/` | 搜索标题、标签和笔记 |
| `cycle-filter` | `f` | 循环切换状态筛选(全部 / 进行中 / 已完成) |
| `sort` | `o` | 打开排序选择器(手动 / 优先级 / 点数 / 截止日期 / 创建时间 / A–Z;`r` 切换方向) |
| `copy` | `c` | 复制选中的任务 |
| `theme-picker` | `T` | 打开主题选择器 |
| `settings` | `S` | 打开设置 |
| `help` | `?` | 显示帮助浮层 |
| `quit` | `q` | 退出 |
注意:`Ctrl+C` 始终用于退出且无法被禁用。只有这些主(常规/详情)快捷键是可配置的 - 文本输入、确认提示和各类选择器均保持固定按键。包含未知操作名称或无法识别的按键的条目将被忽略(应用启动时会有简短提示),但在你的配置文件中会保持原样,因此拼写错误不会清除你的其他设置。
## 存储格式
每个列表都是数据目录中的一个单独的 JSON 文件(`.json`):
```
{
"name": "Work",
"tasks": [
{
"id": "f7c1…",
"title": "Ship the TUI",
"done": false,
"priority": "high",
"points": 8,
"due": "2026-07-01",
"tags": ["rust", "urgent"],
"notes": "the big one",
"subtasks": [
{ "id": "a2…", "title": "data model", "done": true }
],
"created": "2026-06-28T14:40:00Z",
"completed_at": null
}
]
}
```
笔记存放在 `notes/` 子目录中:每个笔记本对应一个文件夹(文件夹名即笔记本的名称),每条笔记对应一个 `.md` 文件。每条笔记的元数据都保存在 YAML frontmatter 块中:
```
notes/
Work Ideas/
api-redesign.md
standup-notes.md
Personal/
reading-list.md
```
```
---
title: API redesign
tags: [work, backend]
pinned: true
order: 1
created: 2026-07-05T10:00:00Z
---
The body is plain markdown, starting here.
```
你可以手动编辑所有这些内容,或将它们保存在 git repo 中 - 它们只是纯文本而已。
## 环境变量
- `TUDO_DIR` - 覆盖数据目录(跳过已保存的配置;非常适合针对特定项目划定任务范围或用于脚本控制)。
- `TUDO_CONFIG` - 覆盖配置指针文件的存放位置。
- `TUDO_THEME` - 为单次运行覆盖主题(`tokyo-night`、`catppuccin`、
`dracula`、`nord`、`gruvbox`、`gruvbox-material`、`solarized`、`one-dark`、
`rose-pine`、`gotham`、`black-white` 或 `none`/`terminal`)。
## 开发
```
cargo test # unit + headless render tests (no real terminal needed)
cargo clippy --all-targets
cargo run
```
源码布局:`model`(类型)、`storage`(JSON I/O)、`config`(数据目录解析)、`keybind`(可配置的键盘映射)、`app`(状态 + 操作)、`event`(按键/鼠标映射)、`ui`(渲染)。操作逻辑和渲染层与终端无关,因此它们直接使用 `tempfile` 和 ratatui 的 `TestBackend` 进行测试。
标签:Homebrew安装, 可视化界面, 通知系统, 防御加固