call-graph-cli 0.3.0

Interactive call and type hierarchy TUI
Documentation
# 命令与交互

## 命令行

```text
cgraph [OPTIONS] [COMMAND]
```

### Commands

| 命令 | 作用 |
| --- | --- |
| `cgraph` | 打开空画布 |
| `cgraph call <SYMBOL>` | 创建 call anchor |
| `cgraph type <SYMBOL>` | 创建 type anchor |
| `cgraph help` | 显示帮助 |

### Options

| 选项 | 作用 |
| --- | --- |
| `--workspace <PATH>` | 设置 LSP 工作区,默认是当前目录 |
| `--lsp <PROGRAM>` | 显式选择语言服务器,覆盖自动检测;Python 默认是 `pyrefly` |
| `--lsp-arg <ARG>` | 向语言服务器传递一个参数,可重复使用 |
| `--no-lsp` | 禁止自动启动语言服务器 |
| `--ipc-socket <PATH>` | 在指定 Unix socket 上启用编辑器双向联动;父目录必须已存在 |
| `-h`, `--help` | 显示帮助 |
| `-V`, `--version` | 显示版本 |

以连字符开头的服务器参数推荐使用等号形式,避免被当成 cgraph 自己的选项:

```bash
cgraph --lsp clangd --lsp-arg=--background-index
cgraph --lsp pyrefly --lsp-arg=--indexing-mode --lsp-arg=lazy-blocking
```

选择 `pyrefly` 时 cgraph 自动添加其必需的 `lsp` 子命令,`--lsp-arg` 只填写 `lsp` 后面的参数。显式 `--lsp pylsp` 仍可覆盖 Python 默认值。

全局选项可以放在子命令前后,但团队脚本建议统一放在子命令前,便于阅读。

## Canvas 模式

| 输入 | 当前行为 |
| --- | --- |
| `ac` | 打开 call symbol 搜索框 |
| `at` | 打开 type symbol 搜索框 |
| `tl` | 按需加载或收起当前节点左侧 incoming/parent 子节点 |
| `tr` | 按需加载或收起当前节点右侧 outgoing/child 子节点 |
| `r` | 同时刷新当前节点左右一层关系,不递归刷新后代 |
| `ec` | 使用 `$EDITER`(回退 `$EDITOR`)编辑项目配置,返回后重载并刷新图 |
| `w` | 打开关系图保存弹窗 |
| `?` | 打开完整、可滚动的操作帮助 |
| `Left` / `h` | 选择当前节点左侧最近的可见节点 |
| `Right` / `l` | 选择当前节点右侧最近的可见节点 |
| `Up` / `k` | 选择当前节点上方最近的可见节点 |
| `Down` / `j` | 选择当前节点下方最近的可见节点 |
| 鼠标左键拖拽节点 | 平移整个画布;不会单独移动节点 |
| 鼠标左键拖拽空白处 | 平移整个画布,以查看屏幕外节点 |
| 鼠标左键双击节点 | 通过 IPC 把精确源码位置发送给所有已连接编辑器客户端 |
| `dd` | 当前节点是 anchor 时取消该入口;普通共享节点不删除 |
| `dp` | 清除当前节点的左侧 incoming/parent 分支缓存 |
| `dn` | 清除当前节点的右侧 outgoing/child 分支缓存 |
| `q` | 退出 |
| `Esc` | 退出 |

`a`、`t`、`d` 和 `e` 都是前缀键。按下后,底部状态栏会提示合法后缀;输入其他键只取消本次前缀,不会误触发操作。`ec` 的编辑器与刷新语义见[项目配置](project-configuration.md)。`dd` 只取消显式 anchor,不按连通分量删除共享图;对普通节点执行会在底栏显示 `Selected node is not an anchor`。取消后选择移动到剩余 anchor,没有入口时回到空画布。`dp` / `dn` 会清除该节点对应方向的缓存和该分支对边的确认,并把方向恢复为未加载状态;其他分支仍确认的共享边不会被误删。

`t` 也是前缀键:`tl` 和 `tr` 始终独立操作左右分支,不存在同时展开父节点和子节点的单键 `t`。节点两侧按钮同时表达查询状态:`[+]` 可加载或展开,`[~]` 正在请求,`[-]` 已展开,`·` 是成功查询后的空结果,`[!]` 是可重试错误。首次展开优先通过同一个 LSP 进程执行已声明能力的标准 call/type hierarchy;server 未声明当前 kind 时使用同语言 Tree-sitter 后备,不会先发送一个已知不支持的请求。成功结果写入全局关系图,收起后再次展开不会重复请求。同一 hierarchy kind 和精确源码位置只显示一个节点,即使它由多个路径或 incoming/outgoing 查询共同发现。无论使用 `tl` / `tr` 还是鼠标按钮,操作节点的屏幕中心在 toggle 及异步结果到达前后都保持不变。

裸 `r` 不属于 `t` 前缀,它会同时重新查询当前节点 incoming/outgoing 两个方向的一层结果。刷新期间旧节点仍可见;成功后仍存在的节点及其更深层缓存、展开状态和 `NodeId` 保持不变,消失的关系从当前分支撤销,新节点以收起状态加入。刷新失败会在底栏显示原因但保留原缓存;连续刷新时只有最新 request id 的结果能生效。

在画布中鼠标左键单击可见节点会选中它;选中框和鼠标命中区域来自同一份布局结果。单击左右 toggle 按钮时也会把对应节点设为当前选择。选择已有节点不会把它自动移动到画布中心:鼠标单击和键盘空间导航都会保留该节点选择前的屏幕中心位置。只有接受搜索结果时才会按产品语义重置 viewport,把新建或重定位的 anchor 放回中心。

启用 `--ipc-socket` 后,在 500 ms 内对同一节点完成两次普通点击会发送跳转事件;两次点击之间发生拖拽时不会误触发。没有精确 URI、行或列的 provisional 节点不会发送伪造位置,底栏会说明原因。外部客户端也可以发送带 request id 的 `focus_symbol`,按 call/type、符号名和可选精确位置固定、选中并居中 anchor;无位置同名歧义会得到结构化错误。未启用 IPC、没有客户端或后台通道关闭时也只显示错误提示,不会退出 TUI。连接方式、协议和 Neovim 示例见[编辑器联动](editor-integration.md)。

按住鼠标左键拖拽节点主体或画布空白处会平移整个 viewport,内容与指针同向移动;这两种手势都不会改变节点在图中的关系或单独修改某个节点的位置。节点两侧的 toggle 按钮只执行展开/收起,不会开始拖拽。节点与 viewport 仍有交集时会显示真实可见切片,可见主体和按钮继续参与命中;完全离屏后方框才从当前帧消失,世界布局和节点身份始终保留。端点方框离屏不会连带删除边:完整路径仍穿过 viewport 时,屏内线段和可见目标箭头继续显示。

键盘空间导航只考虑当前屏幕中可见、且确实位于目标方向的节点,再按二维几何距离选择最近目标;它不会按照节点创建顺序循环。目标方向没有节点时,选择保持不变。`tl` / `tr` 作为完整前缀命令优先解释,因此其中的 `l` / `r` 不会被误当成单键导航。

搜索加入多个不同符号时,画布会同时布局多个 anchor;接受搜索结果时会重置 viewport,使当前选中入口回到中心。再次接受相同 hierarchy kind 和源码位置的结果不会创建重复节点或入口,而是复用已有节点。规范边按 caller/parent 到 callee/child 从左向右分层;循环、自环或其他非前向边使用黄色双线、箭头或 `↺` 标记。普通拐角使用 `╭╮╰╯`,真实交叉点使用 `┼`、`╪`、`╫` 或 `╬` 并高亮,详细图例与字体建议见[显示与终端字体](display-and-fonts.md)。可见节点使用完整矩形做碰撞检测;节点框只显示符号名,不在左上角重复显示 `call` / `type`。

## 底部状态栏

最底部一栏同时显示快捷键提示和源码分析状态。左侧常驻文本只保留 `?`、`ac/at`、`tl/tr`、`hjkl` 和退出等高频入口,不再枚举全部低频命令;按 `?` 可查看完整清单。等待前缀键或最近操作结果会临时替换常驻提示。右侧紧挨快捷键显示紧凑的后端摘要,不为两者预留固定比例的空白区域。

| 字段 | 含义 |
| --- | --- |
| `LSP: <server>` | 当前连接的语言服务器名称 |
| `Tree-sitter: <language>` | LSP 不可用时初始化的 Tree-sitter grammar/query |
| `Backend: none` | 没有可用分析后端 |
| `Ready` | 后端已经建立连接,当前没有已知后台任务 |
| `Working [N%]` | 后端报告正在加载、索引或执行任务;百分比仅在后端提供时显示 |
| `Warning` / `Error` | 后端报告需要注意或失败的状态,后面附带详情 |
| `Disconnected` | 已建立的 LSP 连接已经关闭或异常退出 |
| `Inactive` | 没有 LSP,且工作区未检测到支持的 Tree-sitter 语言 |

状态摘要展示分析后端的全局状态,不等同于搜索弹窗的单次查询状态。终端较窄或消息较长时,整行按可用宽度自然裁剪,不会另行覆盖画布。

### 消息与 pager 模式

最底行始终保留快捷键提示和分析后端状态,不会被普通信息或错误替换。保存、配置、IPC、Tree-sitter 置信度提示以及 workspace symbol / hierarchy 错误等消息默认显示在倒数第二行;错误带有红色 `ERROR:` 前缀。所有这些消息同时追加到历史,按 `g<` 可从倒数第二行向上打开最多 15 行的 Ratatui pager:

- `j` / `k` 或方向键上下滚动一行;
- `Space` / `f` / `PageDown` 下一页,`b` / `PageUp` 上一页;
- `Ctrl-d` / `Ctrl-u` 下移或上移半页;
- `g` / `G` 或 `Home` / `End` 跳到开头或末尾;
- `V` 进入或取消按屏幕行选择,选择模式中移动键扩展范围;`y` 通过 OSC 52 复制所选原始文本;
- 鼠标拖拽使用终端原生文本选择,再使用终端自己的复制命令;
- `q` 或 `Esc` 关闭 pager 并返回画布。

pager 打开时仍保留最底行快捷键与后端状态。cgraph 暂停 Crossterm 鼠标捕获,让本地终端、SSH 或 tmux 自己处理鼠标选择;关闭后立即恢复 Canvas 鼠标事件。`y` 使用终端 OSC 52 能力写入剪贴板,是否生效取决于终端以及 tmux 的 `set-clipboard` 配置。pager 只接管上述浏览和选择键,Canvas 的全局快捷键保持不变。

## Help modal 模式

`?` 帮助层列出 Canvas、搜索、保存、配置编辑和帮助自身的全部键鼠操作。它覆盖画布但不修改图或 viewport;打开时其他 Canvas 命令不会透传。

| 输入 | 当前行为 |
| --- | --- |
| `Up` / `Down`, `k` / `j` | 上下滚动一行 |
| `PageUp` / `PageDown` | 上下滚动一页 |
| `Home` / `End` | 跳到第一项或最后一项 |
| 鼠标滚轮 | 上下滚动帮助 |
| `?`, `q`, `Esc` | 关闭帮助,不退出 cgraph |

## Search modal 模式

| 输入 | 当前行为 |
| --- | --- |
| 普通字符 | 编辑查询;约 200 ms 后按完整文本重新查询当前分析 provider |
| `Backspace` | 删除一个 Unicode 字符并重新安排查询 |
| `Up`, `Ctrl-p` | 选择上一项 |
| `Down`, `Ctrl-n` | 选择下一项 |
| `Enter` | 接受当前结果 |
| `Esc` | 关闭弹窗,不创建节点 |
| 鼠标移动 | 高亮指针所在结果 |
| 鼠标左键 | 接受指针所在结果 |
| 鼠标滚轮 | 上下移动选择 |

call 搜索当前保留 function、method 和 constructor;type 搜索保留 class、interface、struct、enum 和 type parameter。LSP 与 Tree-sitter 都映射到同一公共 symbol-kind 分类。

打开 `ac` 或 `at` 弹窗会安排一次空文本查询;输入变化会重置约 200 ms 的防抖计时,然后把当前完整文本交给当前 provider。查询不要求两个字符。LSP 模式下,若前一次请求已经发出,cgraph 会发送 `$/cancelRequest`;无论 provider 是否能停止工作,request id 都会阻止旧结果覆盖当前列表。

状态行会区分两个阶段:`Waiting for typing pause…` 表示仍在等待 200 ms 防抖,尚未请求 server;`Searching workspace symbols…` 表示当前 `workspace/symbol` 请求已经开始。

LSP 负责按 query 搜索;Tree-sitter 返回项目静态索引候选。cgraph 对候选去重并进行不区分大小写的模糊评分。匹配允许字符按顺序但不连续地出现,排名依次偏好精确匹配、前缀匹配、连续子串和更紧凑的子序列。默认只展示 `--workspace` 根目录内的项目符号,不展示依赖或其他工作区外文件中的符号。

## Save modal 模式

| 输入 | 当前行为 |
| --- | --- |
| 普通字符 | 编辑目标路径 |
| `Backspace` | 删除一个 Unicode 字符 |
| `Enter` | 创建并写入目标;失败时保留弹窗并显示原因 |
| `Esc` | 关闭弹窗,不写入文件 |

目标已经存在时不会覆盖或截断。相对路径按 cgraph 进程的当前工作目录解析;导出内容包含从当前 anchors 可达的全部已知关系,而不只包含屏幕可见节点。格式与示例见[导出关系图](export.md)。