Skip to content

feat(plugins): 同一语言只由一个已启用插件提供语言服务器 - #1910

Merged
1lck merged 3 commits into
previewfrom
feat/exclusive-language-servers
Nov 14, 2026
Merged

1lck merged 3 commits into
previewfrom
feat/exclusive-language-servers

Conversation

@1lck

@1lck 1lck commented Nov 14, 2026 •

Copy link
Copy Markdown
Owner

关联 Issue / Linked issue

PR 类型 / Type

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

改动说明 / What changes

背景 / Why

Java Support(JDT LS)和 Java Navigation(轻量跳转)都为 java 声明语言服务器。两个同时启用时,宿主的 LanguageServerProvider 静默取插件列表里第一个,另一个形同失效:Java Navigation 按 ID 排在前面,装上它 JDT 就不启动,补全和诊断消失,界面没有任何提示。现在规定同一语言只由一个已启用插件提供语言服务器,启用或安装其中一个,另一个自动停用并提示用户。

改动 / Changes

  • Core 桥接 desktop/internal/core/plugin_lifecycle.go:PluginInstalledVersion 新增 LanguageServers;新步骤 PluginDisplacePlugin(带 PluginID、LanguageIDs),解析时缺插件或语言视为协议错误。
  • 插件管理器 desktop/internal/pluginmanager/pluginmanager.go:
    • 规划时为每个已安装版本有界读取清单 languageServers[].languageID(最多 8 MiB,与安装器上限一致);读不到或解析失败按“不提供语言服务器”处理(log-exempt:启动服务器和注册语言的路径会报告同一次失败)。
    • Apply 返回 Outcome{Changed, Displaced};执行 displacePlugin 时先把对方记为停用,与 Disable 先记录后停止的顺序一致。
    • 新增 Enable(id) 返回被顶替的插件;EnableInstalled 改为返回 Outcome;SetEnabled(id, true) 改走 Enable。
  • 插件服务 pluginservice/lifecycle.go:新增 StopDisplaced,停止被顶替插件的语言服务器和后端。
  • 工作台 新文件 workbench/plugin_displace.go,workbench/plugins.go 的启用和确认安装两处接入:
    • 后台读取插件和语言显示名;
    • 回到窗口线程用 detachPluginServer 摘除被顶替插件的服务器,再在后台停止它;
    • 停止后,项目里打开着共享语言的文档时,为新插件启动服务器;
    • 每个被顶替插件提示一条 desktop.marketplace.languageServerDisplaced。
  • 文案:新增 desktop.marketplace.languageServerDisplaced 中英词条和生成结果。
  • Core 固定修订:2c1fed18 → a320d16,新增 Feat/windows/terminal sessions #38(日志事件目录生成器、update.delta.fallback_selected)和 fix(database): keep workspace data fresh after refresh #39。
  • 功能矩阵:plugin-extension-management.json 补验证动作、证据和说明,两端仍是 partial / pending。
  • Agent Note:新增 .agents/notes/implemented/architecture/2026-11-14-one-enabled-plugin-per-language-server.md,在 plugin_displace.go 加反向引用。
  • 测试:pluginmanager_test.go 新增 4 个、调整 1 个;新增 workbench/plugin_displace_test.go。

不在本 PR 范围内 / Out of scope

  • 同一语言多服务器、按请求类型分配:不做,理由见 Agent Note。
  • Java Navigation 改名 Java Support Lite、商店图标、Java Support 收录进商店:在插件仓库和 Lithe-store 单独处理。
  • Windows 原生窗口验收、macOS 原生窗口验收。

类型专属:feat

多平台对齐

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

规则在 Core,宿主是 macOS 与 Windows 共用的 Viva Go 代码,没有平台分支。


范围检查 / Scope checks

功能矩阵 / Feature matrix

  • 已更新 shared/platform-feature-matrix/features/plugin-extension-management.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] 没有更新矩阵的理由:已更新

统一日志系统 / Structured logging

  • [N/A] 已接入统一日志系统:没有新增事件。停止被顶替插件失败、读取名称失败沿用现有 operationFailedEvent(字段 plugin_displace、plugin_list);用户操作和 Core 请求由现有执行轨迹记录
  • 一个操作只有一条终态,错误只在处理它的边界记录一次;高频路径没有用 INFO 逐项输出
  • 没有记录源码、编辑内容、环境变量值、命令输出、凭据;路径用 path、错误用 error 类型,动态通道段来自已校验的 ID
  • [N/A] generate-log-events.mjs --check、verify-log-usage.mjs:Viva 迁移后这两个脚本已移除(见 develop-lithe 日志参考页、[Feature] 恢复 Viva 日志事件类型生成和目录使用门禁 #1802),未能运行

界面文案 / i18n

  • 文案都走共享 i18n:在 shared/i18n/ 补齐中英词条,运行 node scripts/i18n/generate-i18n.mjs 并提交生成结果,没有手改生成文件;macOS 视图外使用 L10n.string
  • 已运行 node scripts/i18n/verify-app-language-localization.mjs 和 node scripts/i18n/generate-i18n.mjs --check,没有放宽脚本或扩大豁免名单

逻辑归属 / Logic placement

  • 可共享的逻辑在 Rust Core,共享契约和 fixture 先于平台接入:谁让位、只看最新版本、旧状态处理都在 plugins.installed.lifecycle(fix(database): keep workspace data fresh after refresh #39)。宿主只读清单字段、执行步骤、呈现提示
  • [N/A] 修改平台层已有的可共享逻辑时已迁入 Core:没有修改平台层已有的可共享规则
  • 工具或运行时专属的知识放在插件或成熟上游,宿主和 Core 没有按工具名加分支:按 languageServers 通用判断,没有 Java 或插件 ID 特判

性能与内存 / Performance and memory

  • 功能、子进程、语言服务器、WebView 首次需要才启动;没有新增空闲轮询;缓存和缓冲有上限;关闭项目、窗口、面板、标签时释放独占资源
  • 主线程没有文件读写、目录遍历、进程启动:读清单、读名称、停进程都在后台;窗口线程只摘除登记和提示
  • [N/A] 性能基线:不涉及启动、输入、滚动、大文件、长输出或搜索。每次规划启停时多读一次已安装插件的清单(通常几 KB,上限 8 MiB)

设置 / Settings

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

插件契约 / Plugin contract

发行包与资源 / Bundle and resources

  • [N/A] 运行时写入发行目录:只读取插件根下的清单,不写入,也不新增资源路径
  • [N/A] 下载、解压、生成或缓存资源:没有新增

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


验证 / Verification

命令或操作 平台 结果
Core cargo test -p lithe-core --lib shared_plugin_lifecycle_fixture(新增 8 个、非法请求 2 个用例;撤掉实现后失败) macOS arm64 通过
scripts/desktop/desktop-go.sh vet 受影响 4 个包 macOS arm64 通过
scripts/desktop/desktop-go.sh test ./internal/pluginmanager/ ./internal/core/ macOS arm64 通过
scripts/desktop/desktop-go.sh test ./internal/workbench -run 'TestInstallingAPluginTurnsOffTheOneServingTheSameLanguage|TestConfirmedInstallIsEnabled'(去掉 stopDisplaced 调用后新测试失败:notice = "") macOS arm64 通过
scripts/desktop/desktop-go.sh test ./...(链接 a320d16 内容的 Core) macOS arm64 只有 TestTerminalMenuSelectsAllAndCopies 失败。preview 基线在旧固定版本 2c1fed18 和新 Core 下同样失败,与本 PR 无关,已建 #1907
node scripts/i18n/generate-i18n.mjs --check、verify-app-language-localization.mjs macOS 通过
node --test scripts/i18n/test-i18n.mjs macOS 卡住不退出,preview 基线同样如此,已建 #1908
./scripts/agent-notes/verify-agent-notes.sh macOS 通过
./scripts/platform-feature-matrix/verify-platform-feature-matrix.sh、verify-platform-feature-matrix-change.sh origin/preview HEAD macOS 通过
./.agents/skills/write-stable-tests/scripts/verify-test-stability.sh macOS 通过

未能执行的检查和原因:

提交前确认 / Final checks

  • 分支从最新的 preview 创建;目标分支:feat、fix、docs 为 preview,release 以发布流程要求为准
  • 以 Draft 提交,本地验证通过后才标记 ready
  • 没有无关改动,没有提交 .build/、target/、dist/、.artifacts/ 等产物,没有凭据、个人路径和未脱敏的日志或截图
  • 本次构建、测试或预览启动的 Lithe 应用和子进程已全部关闭,没有进程残留

合并说明(2026-11-14):Windows(lithe-dev)与原生窗口手动验收尚未做,按维护者决定先合入 preview,与后续改动一起测试。macOS 本地针对性测试与 PR 的 Linux 检查已通过。

🤖 Generated with Claude Code

1lck and others added 2 commits November 14, 2026 00:53
启用插件或确认安装后,其他已启用、且为同一语言声明语言服务器的插件会被自动
停用:Core(Lithe-core-rust#39)在 plugins.installed.lifecycle 里返回
displacePlugin,宿主记为停用、停掉它的语言服务器和后端,提示用户停用了谁、
为什么,并为已打开的共享语言文档启动新插件的服务器。

- pluginmanager 规划时为每个已安装版本读出清单 languageServers,Apply 返回
  Outcome(Changed、Displaced),新增 Enable。
- pluginservice.StopDisplaced 停止被顶替插件的程序。
- 工作台 plugin_displace.go:读名称、摘除服务器、后台停止、提示和重启服务器。
- 新文案 desktop.marketplace.languageServerDisplaced(中英)。
- Core 固定修订升到 a320d16(#38、#39)。
- 功能矩阵与 Agent Note 同步。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent Note 与功能矩阵的验收步骤改用新名称,记录 Store 收录状态(Lithe-store#62 已合并,#63 等本规则发布)。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@1lck

1lck commented Nov 14, 2026

Copy link
Copy Markdown
Owner Author

轻量 Java 插件已改名为 Java Support Lite(ID 不变,Lithe-IDEA/lithe-plugin-java-navigation#9,预发布 v0.0.3),Store 已收录 0.0.3(Lithe-IDEA/Lithe-store#62 已合并)。Java Support 1.2.0 的收录 Lithe-IDEA/Lithe-store#63 保持 Draft,等本 PR 合入并有包含该规则的 preview 发布后再合。本 PR 的 Agent Note 与功能矩阵已同步新名称(6ee68933e)。

@1lck
1lck marked this pull request as ready for review November 14, 2026 09:26
@1lck
1lck merged commit e08f796 into preview Nov 14, 2026
7 of 12 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