Skip to content

feat(desktop): Markdown 文件的结构窗口显示标题大纲 - #1920

Merged
xiaoyumuxi merged 1 commit into
previewfrom
feat/markdown-structure-outline
Nov 14, 2026
Merged

xiaoyumuxi merged 1 commit into
previewfrom
feat/markdown-structure-outline

Conversation

@xiaoyumuxi

Copy link
Copy Markdown
Collaborator

关联 Issue / Linked issue

PR 类型 / Type

  • feat:新功能或用户可见的改进
  • fix:缺陷修复
  • docs:文档、Agent Note、Skill 等规则文件
  • release:稳定版发布准备

改动说明 / What changes

背景 / Why

打开 AGENTS.md 这类 Markdown 文件时,结构(Structure)工具窗口只显示“没有语言服务器为此文件提供结构。”,而同一文件的预览浮动目录明明能列出一级、二级标题。结构窗口原来只认语言服务器的 documentSymbols,Markdown 没有语言服务器,所以永远是空的。

做法:Rust Core 新增 markdown.outline,用预览同一套 Markdown 方言解析标题,输出与语言服务器 documentSymbols 归一化后相同的符号树;桌面端对 Markdown 文件直接向 Core 要这棵树,不再依赖任何语言服务器或插件。结构窗口原有的筛选、排序、全部折叠/展开、跟随光标都直接可用。

改动 / Changes

Core 接入(desktop/internal/core/)

  • markdown.go:新增 Client.MarkdownOutline(ctx, source),调用 Core markdown.outline,返回 []DocumentSymbol(一级标题是根,下级标题挂到前面最近的更高级标题下;selectionRange 是标题行,range 是到下一个同级或更高级标题前的整节)。
  • markdown_test.go:新增 TestMarkdownOutlineSharedFixture,逐例比对 Core 契约 fixture editor/markdown-outline-v1.json(经 contractfixture 从正在链接的 Core 检出读取,不复制到本仓库)。

结构窗口(desktop/internal/workbench/outline.go、outline_view.go)

  • 新增可用性 outlineMarkdown:Markdown 文件(与预览同一判定 isMarkdownDocument)优先走 Core,即使装了提供 Markdown 语言服务器的插件也用 Core 的大纲,保证和预览目录一致。
  • outlineMarkdownSync:与语言服务器路径相同的节流——窗口打开时请求一次,之后文本变化等 outlineDelay(300ms)后再请求;在后台任务里调用 Core,不占窗口线程;按请求令牌丢弃切换文件或重复请求后迟到的旧结果。
  • 文件超过预览上限 markdownPreviewMaxBytes(1 MiB)时不发给 Core,结构窗口说明“此文件过大,无法显示结构。”。
  • 没有标题时显示“此文件没有标题。”,而不是通用的“没有符号”。
  • 请求失败时沿用已有的“获取结构失败”说明和“重试”按钮(原来只对语言服务器路径显示),同一文本不会自动反复重试。
  • outlineGo:Markdown 处于“仅预览”模式时编辑器是隐藏的,点击标题除了移动源码光标,还会把预览页面滚到该标题。

预览(desktop/internal/workbench/markdown_preview.go)

  • 新增 markdownPreviewState.showLine(d, line):web view 预览发送已有的 scroll 消息,原生预览用已有的 scrollTo,供结构窗口跳转使用。

文案(shared/i18n/)

  • 新增 desktop.outline.noHeadings(“此文件没有标题。” / “This file has no headings.”)和 desktop.outline.tooLarge(“此文件过大,无法显示结构。” / “This file is too large to show its structure.”),已运行 node scripts/i18n/generate-i18n.mjs 并提交生成的 desktop/internal/i18n/shared.generated.go。

Core 固定版本(scripts/desktop/build-desktop-core.sh)

功能矩阵(shared/platform-feature-matrix/features/outline-symbols.json)

  • 两端证据补上 core/markdown.go、core/markdown_test.go、workbench/markdown_preview.go、workbench/outline_markdown_test.go;验证动作补充 Markdown 回归覆盖与命令;notes 记录 2026-11-14 的 Markdown 结构行为。验证状态保持 pending。

测试(desktop/internal/workbench/outline_markdown_test.go,新文件)

  • TestMarkdownOutlineShowsHeadingsWithoutServer:无语言服务器时按层级显示标题,光标所在节选中对应标题,跳转把光标放到标题行。
  • TestMarkdownOutlineFollowsEditsAfterTheDelay:编辑后延迟未到不重复请求,延迟过后刷新出新标题。
  • TestMarkdownOutlineSaysWhenThereAreNoHeadings:只有段落和代码块里的 # 时显示“没有标题”。
  • TestMarkdownOutlineSkipsTooLargeFile:超过 1 MiB 不请求 Core 并显示“过大”。
  • TestMarkdownOutlineFailureOffersRetry:失败显示重试、不自动重复请求,点重试后成功加载。
  • TestMarkdownOutlineDropsTheAnswerForAnotherFile:a.md 的请求被挂起时切到 b.md,放行后只显示 b.md 的结果。
  • TestMarkdownOutlineMovesThePageShownAlone:仅预览模式下跳到 Part 12,页面顶部是该标题所在行。
  • 测试替身只包一层计数/挂起/失败,实际解析仍走 Core;挂起的闸门在 t.Cleanup 中必定放行。

不在本 PR 范围内 / Out of scope


类型专属:feat

多平台对齐

  • 两端都具备:合入后 macOS 与 Windows 都具备该能力(本 PR 同时实现,或本 PR 补齐另一端)

Viva 桌面端 macOS 与 Windows 共用同一份 Go 代码,解析逻辑在 Rust Core;Windows 实机尚未验收(见“验证”)。


范围检查 / Scope checks

功能矩阵 / Feature matrix

  • 已更新 shared/platform-feature-matrix/features/outline-symbols.json:两端的实现状态和验证状态、证据路径、owner、验证动作都如实填写;没有运行验证的保持 pending
  • 已运行 ./scripts/platform-feature-matrix/verify-platform-feature-matrix.sh;改了平台实现路径的,还运行了 ./scripts/platform-feature-matrix/verify-platform-feature-matrix-change.sh origin/preview HEAD
  • 没有提交 .artifacts/ 下生成的矩阵视图
  • [N/A] 没有更新矩阵的,理由:已更新矩阵

插件归属 / Plugin ownership

  • 已在仓库根目录运行 develop-lithe 第三节“插件归属与宿主零依赖”的自查命令,结果为空
  • 新增或修改的测试只使用测试内联的合成插件、Core 契约 fixture 或插件市场索引快照;没有读取具体插件的插件包、仓库检出、构建产物或清单,没有使用真实插件 ID,没有“缺少插件时跳过”的测试
  • 没有为具体插件提供的能力新建或更新宿主功能矩阵条目;宿主条目的证据和验证动作不引用插件的测试、插件包或插件仓库
  • 插件文案没有写进 shared/i18n/;插件的构建步骤、资源路径和补丁没有写进 scripts/resources/、docs/ci-builds.md、Agent Note 或 Skill
  • [N/A] 修改了通用扩展点、可能影响已发布插件的:没有改插件扩展点,Markdown 大纲由宿主 + Core 提供,语言服务器路径行为不变

统一日志系统 / Structured logging

  • 已接入统一日志系统:Core 请求失败时记录已声明的 app.notification.operation_failed,operation 为 markdown_outline;没有 NSLog、os_log/Logger、直接写 stderr、print 或手写事件 ID
  • 一个操作只有一条终态,错误只在处理它的边界记录一次;高频路径没有用 INFO 逐项输出(成功不记日志)
  • 没有记录源码、编辑内容、环境变量值、命令输出、凭据;错误用 error 类型
  • [N/A] 旧日志生成和使用校验脚本:本 PR 未涉及

界面文案 / i18n

  • 宿主文案都走共享 i18n:在 shared/i18n/ 补齐中英词条,运行 node scripts/i18n/generate-i18n.mjs 并提交生成结果,没有手改生成文件;Viva 代码通过 desktop/internal/i18n/ 的接口读取
  • [N/A] 插件提供的文字:本 PR 不涉及插件文案
  • 已运行 node scripts/i18n/verify-app-language-localization.mjs 和 node scripts/i18n/generate-i18n.mjs --check,没有放宽脚本或扩大豁免名单

逻辑归属 / Logic placement

  • 可共享的逻辑(标题识别、层级嵌套、节范围、UTF-16 列)在 Rust Core(Lithe-core-rust#41),契约 fixture editor/markdown-outline-v1.json 随 Core PR 提交;桌面端只做请求、节流和呈现
  • [N/A] 修改平台层已有的可共享逻辑:没有修改平台层已有的可共享逻辑
  • 工具或运行时专属的知识放在插件或成熟上游,宿主和 Core 没有按工具名加分支(Markdown 是宿主自带的预览格式,判定复用预览的 isMarkdownDocument)

性能与内存 / Performance and memory

  • 只在结构窗口打开时请求;文本变化按 300ms 节流;没有新增空闲轮询;结果只保存当前文件的一棵树
  • Core 调用在后台任务里执行,主线程只取文本快照;超过 1 MiB 的文件不发送
  • [N/A] 性能基线:没有改动编辑器模块(desktop/internal/editor/**、editorview/**),不涉及启动、输入、滚动路径

设置 / Settings

N/A:没有新增或修改设置。

插件契约 / Plugin contract

  • [N/A] 契约改动:没有改插件契约、能力版本或插件函数协议;markdown.outline 是宿主调用的 Core 命令,fixture 在 Core 的 rust/fixtures/ 随 Lithe-core-rust#41 提交
  • scripts/desktop/build-desktop-core.sh 的 PINNED_CORE_REVISION 已升到包含该命令的 Core commit b0e19d5(feat(windows): 完善 W1 文档安全与多文件编辑 #41 尚未合入,合入后改为 main 上的 commit),桌面端测试经 scripts/desktop/desktop-go.sh 读到的就是这份 fixture
  • [N/A] 修改插件后端协议:没有
  • [N/A] 新增或修改宿主方法、宿主通知:没有

发行包与资源 / Bundle and resources

  • 运行时不向已安装的 app bundle 或 Windows 安装目录写入;没有新增资源路径,已运行 ./scripts/desktop/verify/verify-runtime-bundle-immutability.sh
  • [N/A] 下载、解压、生成或缓存资源:没有新增

无用代码与重构 / Dead code and refactoring

  • 本次改动导致变成无用的代码已在本 PR 删除(无)
  • [N/A] 既有无用代码或可重构之处:本次未发现

验证 / Verification

命令或操作 平台 结果
cargo test -p lithe-project、cargo test -p lithe-core、fmt、clippy、注释检查(Core #41 分支) macOS 通过(81 / 820 个测试)
scripts/desktop/desktop-go.sh test ./internal/core -run 'TestMarkdownOutlineSharedFixture|TestRenderMarkdownSharedFixture' -count=1 macOS 通过
scripts/desktop/desktop-go.sh test ./internal/workbench -run 'TestOutline|TestMarkdownOutline|TestMarkdown' -count=3 macOS 通过
scripts/desktop/desktop-go.sh test ./internal/workbench -run 'TestMarkdownOutline' -count=20 macOS 通过
scripts/desktop/desktop-go.sh test ./... -count=1 macOS 通过(55 个包)
.agents/skills/write-stable-tests/scripts/test-stability-macos.sh --package ./internal/workbench --filter 'TestMarkdownOutline' macOS 通过(7 个测试,每个 80–340ms);verify-test-stability.sh 通过
node scripts/i18n/verify-app-language-localization.mjs、node scripts/i18n/generate-i18n.mjs --check macOS 通过
./scripts/platform-feature-matrix/verify-platform-feature-matrix.sh、verify-platform-feature-matrix-change.sh origin/preview HEAD macOS 通过
./scripts/desktop/verify/verify-runtime-bundle-immutability.sh macOS 通过
插件零依赖自查命令(develop-lithe 第三节) macOS 结果为空
gofmt -l 改动文件 macOS 无输出

未能执行的检查和原因:

  • 没有启动整机应用做手动验收(本次只做无头回归),没有截图;ready 前需在 macOS 打开一个 Markdown 文件确认结构窗口与预览目录一致。
  • Windows 实机未验证,矩阵保持 pending。

提交前确认 / Final checks

  • 分支从最新的 preview 创建;目标分支:preview
  • 以 Draft 提交,本地验证通过后才标记 ready(Core feat(windows): 完善 W1 文档安全与多文件编辑 #41 合入并改固定版本前不 ready)
  • 没有无关改动,没有提交 .build/、target/、dist/、.artifacts/ 等产物,没有凭据、个人路径和未脱敏的日志或截图
  • 本次构建、测试或预览启动的 Lithe 应用和子进程已全部关闭,没有进程残留(只运行了无头测试)

结构窗口原来只认语言服务器的 documentSymbols,Markdown 没有语言服务器,
只能显示“没有语言服务器为此文件提供结构”。现在 Markdown 文件向 Core
markdown.outline 要标题树(与预览浮动目录同一方言),按层级嵌套显示,
筛选、排序、折叠、跟随光标照常可用。

- core: 新增 Client.MarkdownOutline,并按 Core 契约 fixture 校验
- workbench: 新增 outlineMarkdown 路径,后台请求、300ms 节流、丢弃过期结果;
  超过预览上限不请求并说明过大;没有标题时单独说明;失败可重试
- workbench: 仅预览模式下点击标题滚动预览页面
- i18n: 新增 desktop.outline.noHeadings、desktop.outline.tooLarge
- 固定 Core 到 Lithe-core-rust#41 的 b0e19d5(尚未合入)
- 功能矩阵 outline-symbols 补充 Markdown 证据与验证
@ghfind-review ghfind-review Bot added the review: high ghfind author score; see https://ghfind.com label Nov 14, 2026
@xiaoyumuxi
xiaoyumuxi marked this pull request as ready for review November 14, 2026 11:38
@xiaoyumuxi
xiaoyumuxi merged commit 059d878 into preview Nov 14, 2026
5 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review: high ghfind author score; see https://ghfind.com

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant