Skip to content

feat(macos): 彩色 LSP 状态菜单与普通日志标签页 - #1631

Merged
xiaoyumuxi merged 4 commits into
previewfrom
feat/lsp-status-bar
Nov 1, 2026
Merged

xiaoyumuxi merged 4 commits into
previewfrom
feat/lsp-status-bar

Conversation

@xiaoyumuxi

@xiaoyumuxi xiaoyumuxi commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator

背景与范围

接续 #1630 和此前的状态栏讨论。#1630 已合并内存图标化、FPS 去图标和紧凑按钮;本 PR 从最新 preview 独立开发,只处理 macOS 右下角彩色 LSP 状态控制与专用日志视图。原来的 wip: LSP status bar widget stash 保留,没有删除或混入其他暂存工作。

功能改动

  • 状态栏入口常驻:宽/窄两套状态栏都保留 LSP,没有源文件、活跃会话或语言模块尚未激活时也可打开;空列表保留日志与设置入口,多运行服务器时显示数量。蓝色表示启动/初始化、绿色表示运行、黄色表示停止中、红色表示失败;使用现有主题颜色,与 LSP 设置页一致,不以编辑器诊断错误冒充服务器故障。
  • 插件注入列表:仅来自已接受、已注册且当前启用的插件的 LSP 声明,不填充宿主语言目录。内置可管理插件也只有启用后才贡献行。禁用、隔离、安全模式抑制、卸载和等待首次重启注册的插件不贡献行;运行状态不按当前文件类型过滤。
  • 名称与兼容:packaged/systemCommand 复用插件已有 executableNames;runtime 启动复用关联描述元数据已有的 languageServerLaunch.executableNames(如 jdtls),不显示 java/node 运行时名称。无对应字段直接显示插件 ID,不回退语言名、插件展示名或服务器自报名称。元数据只供名称,不能单独生成行;不新增契约字段、能力版本或发布版本,Rust/Windows 无改动。版本仍仅来自 initialize。
  • 共享标准菜单:使用向上打开的 LitheMenu,每个服务器有彩色状态点、状态/版本说明和“查看日志 / 重启服务器 / 停止服务器”子菜单;支持“重启所有 / 停止所有”、顶层日志和 LSP 设置入口;批量动作只处理已有会话,无会话时禁用。修正日志入口跟随应用语言。重启、停止和设置使用已有 IDEA SVG,保留原色。
  • 会话控制:单个/批量操作不改变工作区启用偏好。重启先停止,再恢复匹配的打开文档;没有打开文档的预热服务器也会重启,而不是只停止。停止/禁用/配置变化使旧异步激活 token 失效,防止旧的候选校验或模块激活完成后立即重新启动;Java 准备取消由依赖组装登记,不在通用菜单按语言名称分支。
  • 普通 LSP 日志编辑器标签页:复用混合编辑器标签顺序、选择、拖动分组和关闭机制,不新增底部工具窗口;重复查看聚焦同一标签并切换服务器;“查看日志”选中对应服务器,不跳到通用诊断设置页。日志观察独立于 AppModel 广播,复用 session 现有最多 100 条缓冲,不建立无限缓存。
  • 日志内容与操作:服务器选择、最低级别(Info/Warning/Error)、空状态、清空当前视图;按时间顺序显示会话事件和服务器输出。清空不删除持久诊断日志,也不影响其他服务器,新日志继续出现。复用原生 OutputTextView 的等宽字体、着色、选择/复制、水平滚动和视口所有权;窄标签页工具栏改为两行。
  • 真实能力边界:本次只显示底层已经提供的 Server Logs。Server Trace / RPC Messages 没有采集入口,信息提示明确说明不支持,不把相同日志伪装成不同通道,不在 Swift 重写协议抓包。
  • 结构调整:把原有文档激活方法从过大的 AppModel.swift 移到现有语言运行时 extension,保留流程并增加过期 token 检查;增加只读的模块关闭状态投影,没有放宽架构门禁。
  • i18n 与文档:新增文案补齐共享中英词条并生成原生资源;更新语言运行时和编辑器标签分屏 Agent Notes;新增 lsp-status-logs 功能矩阵记录。Windows 尚未实现该状态项和日志视图,明确标为 missing,不宣称跨平台完成。

验证

  • 使用仓库固定 Swift 6.3.3,SDKROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX26.5.sdk。本机默认 Swift 6.4.2 / macOS 27.2 SDK 与 CI 不同,未以默认编译器替代验证。

  • ./.agents/skills/write-stable-tests/scripts/test-stability-macos.sh --stall-timeout-seconds 300 --report .artifacts/test-stability/lsp-status.json -- --jobs 4 --filter 'LanguageServerStatusTests|LSPControlCenterPresentationTests|WorkspaceLanguageServerPreferencesTests|WorkbenchModuleUIRegistryTests|ContextMenuCoverageTests|WorkbenchRenderingSafetyTests|AppModelLanguageSessionShutdownTests|LanguageIntelligenceModuleCoordinatorTests|JavaLanguageServerRuntimeTests|EditorTabOrderFeatureModelTests|ConsolePresentationTests'

  • 前序范围回归通过;最终插件来源/名称修正只补跑直接相关的 17 项检查(2 个套件),全部通过。新增覆盖状态过滤/排序/版本/优先级、日志变化不重发状态、重启顺序与匹配文档、无文档重启、停用保护、过期激活身份、按服务器筛选/清空、新日志恢复、普通日志标签去重/切换/关闭返回未保存文件、排序和分组、单个/批量菜单动作。

  • 最终报告:.artifacts/test-stability/lsp-registration.json / .junit.xml,HTML 为 .artifacts/test-stability/index.html。名称解析读取真实 Java 插件清单与生产 Rust catalog,确认 jdtls;无元数据时显示插件 ID。另覆盖直接命令名、内置插件默认禁用/启用/禁用、声明式插件启停、未注册不贡献行和空菜单入口。

  • 最终命令:test-stability-macos.sh --stall-timeout-seconds 300 --report .artifacts/test-stability/lsp-registration.json -- --jobs 4 --filter 'LanguageServerStatusTests|PluginManagerTests.bundledServersAreInjectedOnlyAfterTheirPluginIsEnabled|PluginManagerTests.serverRegistrationUsesDeclaredCommandsOrExistingServerMetadataWithoutInventingNames|PluginManagerTests.registeredPluginIsDisabledAndReEnabledWithoutRestart|PluginManagerTests.enablingAPluginInstalledAfterLaunchPersistsPreferenceAndRequiresRestart|PluginManagerTests.internalLifecycleModulesAreNotShownAsInstalledPlugins'。名称解析 19ms、插件启用边界 1ms。

  • 前序组件渲染覆盖 360pt/900pt、明暗主题。测试夹具只验证组件,不作为真实服务器运行证据;真实预览显示应用自身事件,未伪造服务器/日志。

  • node scripts/i18n/verify-app-language-localization.mjs

  • node scripts/i18n/generate-i18n.mjs --check

  • node --test --test-timeout=60000 scripts/i18n/test-i18n.mjs:35 个通过。

  • ./scripts/architecture/verify-service-boundaries.sh

  • ./scripts/architecture/verify-shared-contracts.sh

  • ./scripts/windows/verify/verify-windows-boundaries.sh

  • ./scripts/macos/verify/verify-runtime-bundle-immutability.sh(覆盖 macOS 和 Windows 打包路径扫描)

  • ./scripts/agent-notes/verify-agent-notes.sh

  • node scripts/platform-feature-matrix/generate-platform-feature-matrix.mjs

  • ./scripts/platform-feature-matrix/verify-platform-feature-matrix.sh

  • ./scripts/platform-feature-matrix/verify-platform-feature-matrix-change.sh origin/preview HEAD

  • git diff --check

  • 编译曾在测试开始前触发无输出 watchdog;最终相同 300s 静默上限的聚焦检查重跑通过,未放宽 15s 单项期限。

未验证与限制

  • 没有运行 macOS 全量套件;最终修正仅声明直接相关的 17 项检查通过,其余交给 CI。
  • 已打开真实分支预览,看到普通日志标签和真实 Java 准备/未就绪事件;该次未达到 JDTLS 成功运行,不能声称绿色运行、重启/停止真实进程或完整多语言端到端验收通过,矩阵保留 pending。
  • Windows 没有新增实现;没有在 Windows 实机运行。
  • 不新增原始 Trace/RPC 采集、不提供 Server Info 独立页、不新增设置页;设置入口复用现有 LSP 页。
  • 临时预览和 supervisor 已关闭,无本次实例、JDTLS 或测试进程残留;未替换已安装应用包。

PR 最初以 Draft 创建,后续已被标为 ready;本次保留当前状态,全部修正集中 push 一次,不为观察 CI 反复推送。

Review 修复(bb51d5ae8)

已处理 review 中两条 P2:

  1. 等待旧会话真正终止后再重启
    • 新增内部 LanguageServerSession.stopAndWait(),生产 runtime 等待 Core 的终止事件、迟到异步启动的清理及异步资源释放完成;停止发送移出主线程,等待有本地期限。
    • SessionManager 在显式重启期间保留提供方占位和 .stopping 投影,拒绝文档/其他入口启动重叠会话。关闭失败/超时不启动替代进程;显式重试继续确认同一个旧会话的释放。
    • 功能模型持有可取消的重启任务,恢复文档或无文档预热服务器前重新校验工作区、会话所有者和激活 token。等待期间再次停止、禁用或切换工作区不能复活旧服务。
    • 迟到的后台/远程启动也先停止并确认终止,再销毁 Core 会话、释放包资源,不再直接销毁仍运行的会话。
  2. 重建 Java 索引保留其他服务投影
    • Java 索引入口改为 resetProviderState(providerID: "java"),不调用工作区整体重置;其他服务状态、去重订阅及当前日志选择/内容保持。
    • 回归同时启动 Java 与另一提供方,再执行真实 SessionManager 的 Java 索引重置动作,检查另一提供方继续 ready、日志选择不变,后续日志无须重发状态才能恢复界面。

验证:最终只运行直接相关的 8 项回归,全部通过(Swift 6.3.3,macOS 26.5 SDK)。覆盖有/无文档重启、延迟停止、资源释放屏障、等待时再次停止、失败后重试和多提供方局部索引重置;最慢为资源释放测试 63ms。HTML / JSON / JUnit:.artifacts/test-stability/lsp-review.*、.artifacts/test-stability/index.html。

相关静态门禁、运行时 bundle 只读、i18n 生成/语言检查、35 项 i18n 测试、共享契约、Windows 边界、Agent Notes 和功能矩阵检查通过。同步了中英失败提示、功能矩阵和语言运行时决策说明;没有新增插件清单字段、能力版本、Rust 协议或发行资源写入。

截图建议暂未补充:本轮没有启动真实 LSP 做视觉验收,不用测试夹具截图冒充真实运行。真实多语言项目的进程控制/视觉验收仍保留 pending。测试结束已确认没有本轮 Lithe 应用或测试进程残留。

@ghfind-review ghfind-review Bot added the review: high ghfind author score; see https://ghfind.com label Nov 1, 2026
@xiaoyumuxi
xiaoyumuxi marked this pull request as ready for review November 1, 2026 05:19
@lithe-code-review

lithe-code-review Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Lithe Review

结论: ⚠️ 有建议
范围: preview ← feat/lsp-status-bar · head: ce90a8f

未发现需要阻塞合并的问题。

Findings

  1. [P2] 等待旧会话真正终止后再启动替代会话
    macos/Sources/Lithe/Application/Features/LanguageToolingFeatureModel.swift:206

    • 实际影响:无打开文档的服务器重启时,新旧进程可能同时运行。对于复用同一工作区状态目录的 JDT,新进程可能因目录锁仍被旧进程占用而启动失败。
    • 触发条件:预热服务器仍在运行、没有匹配的打开文档,且关闭需要等待服务器响应或超时。
    • 复现步骤:让服务器延迟响应 shutdown,关闭其文档后点击“重启服务器”。这里调用 stop 后立即执行 startLanguageServer;现有 SessionManager 会立即移除旧会话并发布 .stopped,但 LanguageServerRuntimeSession.stop() 仅发起异步关闭,并未等待进程退出。Rust 启动路径也没有等待旧会话的屏障。
    • 来源:本次引入。新增的无文档重启动作将既有的“发起停止”接口当作了“停止完成”。
  2. [P2] 重建 Java 索引时保留其它服务器的状态投影
    macos/Sources/Lithe/Application/Features/LanguageToolingFeatureModel.swift:99

    • 实际影响:其它语言服务器仍在运行,状态栏入口却被清空,无法从入口查看日志或控制这些服务器。
    • 触发条件:同时运行 Java 和其它语言服务器,然后重建 Java 索引。
    • 复现步骤:AppModel+JavaIndex.swift:19 只重建 Java 的状态,随后调用这里的 resetWorkspaceState()。新增赋值将整个列表清空;订阅中的 removeDuplicates() 仍记住重置前的投影,因此其它服务器状态不变时不会重新发布,日志更新也不能恢复入口。
    • 来源:本次引入。原有重置方法没有清空这一新增投影。

Scope Check

  • 关联需求:未找到可验证的关联 Issue;按 PR 声明的 macOS 范围审查。
  • 已完成范围:状态菜单、日志标签、筛选与清空、共享标签接入、i18n、架构笔记和功能矩阵均有实现。
  • 未完成范围:真实 LSP 进程控制及完整工作台交互尚未验收;Windows 明确记录为 missing。
  • 上游复用:继续使用现有 SessionManager、Rust LSP Runtime、共享菜单和原生输出组件,未发现新增协议或语言领域的并行实现。
  • 两项 Finding 均由本次新增行为触发,属于本 PR 职责范围。

Suggestions

  1. 为重启动作提供有界的异步停止完成接口,等待旧会话终止和资源释放后再启动;等待期间保留真实 .stopping 投影,并用可控的延迟关闭测试验证启动顺序。
  2. 区分工作区整体重置与单提供方索引重置;保留或从当前会话重新计算仍在运行服务器的投影,补充多语言同时运行时重建 Java 索引的回归测试。
  3. 补充状态菜单及日志标签的截图,已有状态栏提供前后对比。正文虽称人工检查过截图,但提供的上下文中没有附图。

Summary

整体复用了现有生命周期和呈现组件,日志存储保持有界。主要缺口在真实异步关闭与局部重置边界;现有同步假会话测试未覆盖这两种情况。

Verification

  • 静态检查范围:ae0c12d...ce90a8f 的语义改动,并追踪 SessionManager、RuntimeSession、Rust 启停、Java 索引重建、标签选择及输出呈现调用链。生成资源正文按要求未读取。
  • 已提供结果:作者报告 152 个针对性 Swift 测试、35 个 i18n 测试及相关架构检查通过;所附 Check Run 中 Swift tests 为 skipped,不能据此认定 Swift CI 已通过。
  • 本次未运行任何代码、测试或应用,也未访问网络。
  • 验证缺口:真实多语言停止/重启、完整标签交互及 Windows 实机验证;截图需补充,视觉效果尚未验证。

@xiaoyumuxi

Copy link
Copy Markdown
Collaborator Author

Review 修复(bb51d5ae8)

已处理 review 中两条 P2:

  1. 等待旧会话真正终止后再重启
    • 新增内部 LanguageServerSession.stopAndWait(),生产 runtime 等待 Core 的终止事件、迟到异步启动的清理及异步资源释放完成;停止发送移出主线程,等待有本地期限。
    • SessionManager 在显式重启期间保留提供方占位和 .stopping 投影,拒绝文档/其他入口启动重叠会话。关闭失败/超时不启动替代进程;显式重试继续确认同一个旧会话的释放。
    • 功能模型持有可取消的重启任务,恢复文档或无文档预热服务器前重新校验工作区、会话所有者和激活 token。等待期间再次停止、禁用或切换工作区不能复活旧服务。
    • 迟到的后台/远程启动也先停止并确认终止,再销毁 Core 会话、释放包资源,不再直接销毁仍运行的会话。
  2. 重建 Java 索引保留其他服务投影
    • Java 索引入口改为 resetProviderState(providerID: "java"),不调用工作区整体重置;其他服务状态、去重订阅及当前日志选择/内容保持。
    • 回归同时启动 Java 与另一提供方,再执行真实 SessionManager 的 Java 索引重置动作,检查另一提供方继续 ready、日志选择不变,后续日志无须重发状态才能恢复界面。

验证:最终只运行直接相关的 8 项回归,全部通过(Swift 6.3.3,macOS 26.5 SDK)。覆盖有/无文档重启、延迟停止、资源释放屏障、等待时再次停止、失败后重试和多提供方局部索引重置;最慢为资源释放测试 63ms。HTML / JSON / JUnit:.artifacts/test-stability/lsp-review.*、.artifacts/test-stability/index.html。

相关静态门禁、运行时 bundle 只读、i18n 生成/语言检查、35 项 i18n 测试、共享契约、Windows 边界、Agent Notes 和功能矩阵检查通过。同步了中英失败提示、功能矩阵和语言运行时决策说明;没有新增插件清单字段、能力版本、Rust 协议或发行资源写入。

截图建议暂未补充:本轮没有启动真实 LSP 做视觉验收,不用测试夹具截图冒充真实运行。真实多语言项目的进程控制/视觉验收仍保留 pending。测试结束已确认没有本轮 Lithe 应用或测试进程残留。

@xiaoyumuxi
xiaoyumuxi merged commit 705ac69 into preview Nov 1, 2026
15 of 19 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