Skip to content

Conversation

@erha19
Copy link
Member

@erha19 erha19 commented May 21, 2025

Types

  • 🎉 New Features

Background or solution

支持平铺模式下的评论能力
image

Changelog

support comments on multi-diff view

Summary by CodeRabbit

  • 新功能
    • 多文件对比编辑器支持增强:新增多文件对比编辑器管理、生命周期、装饰器应用及打开选项支持,提升多文件差异查看体验。
    • 评论区增强:评论小部件智能管理显示时机,避免快速切换文件时的竞态和显示异常。
    • 图标与主题:新增 diff 图标映射,light 主题增加多文件对比编辑器专用配色,新增多文件对比相关 CSS 样式及资源标签路径显示优化。
  • 样式
    • 优化多文件对比编辑器、评论区、滚动条等组件样式表现。
    • 多文件对比资源标签支持路径省略号、斜体、删除线等新样式。
  • 修复
    • 修正评论小部件在快速切换文件时可能出现的竞态和显示异常。
    • 滚动条阴影透明度调整及事件监听方式优化,提升性能和兼容性。
  • 文档
    • 规范主题色 token 导出路径,新增多文件对比编辑器颜色说明。
  • 重构/优化
    • 编辑器集合服务重构,支持多文件对比编辑器的注册与管理,避免重复添加编辑器,提升扩展性与稳定性。
    • 编辑器装饰器应用改进,确保事件监听正确释放。
    • 编辑器生命周期管理增强,支持渲染取消与异步控制。

@erha19 erha19 requested review from Aaaaash, Ricbet and ensorrow May 21, 2025 08:43
@opensumi opensumi bot added the 🎨 feature feature required label May 21, 2025
@erha19
Copy link
Member Author

erha19 commented May 21, 2025

/next

private readonly multiDiffSourceResolverService: IMultiDiffSourceResolverService;

@Autowired(EditorCollectionService)
private readonly collectionService: EditorCollectionServiceImpl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个依赖关系好像搞反了,是从collection创建editor的

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我改成构造传入好了,实现效果应该没啥区别

@opensumi
Copy link
Contributor

opensumi bot commented May 21, 2025

🎉 PR Next publish successful!

3.8.3-next-1747817292.0

@codecov
Copy link

codecov bot commented May 21, 2025

Codecov Report

Attention: Patch coverage is 47.66839% with 202 lines in your changes missing coverage. Please review.

Project coverage is 52.61%. Comparing base (9d68f85) to head (ae16f99).
Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
packages/comments/src/browser/comments.service.ts 28.84% 53 Missing and 21 partials ⚠️
...editor/src/browser/multi-diff/multi-diff-editor.ts 12.50% 30 Missing and 12 partials ⚠️
packages/editor/src/browser/base-editor-wrapper.ts 76.86% 24 Missing and 7 partials ⚠️
...es/editor/src/browser/editor-collection.service.ts 48.88% 19 Missing and 4 partials ⚠️
packages/comments/src/browser/comments-thread.ts 26.31% 11 Missing and 3 partials ⚠️
...rowser/contrib/multi-diff-editor/resource-label.ts 0.00% 11 Missing and 2 partials ⚠️
packages/editor/src/browser/decoration-applier.ts 75.00% 2 Missing ⚠️
packages/monaco/src/browser/monaco.service.ts 50.00% 2 Missing ⚠️
...ges/editor/src/browser/workbench-editor.service.ts 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4567      +/-   ##
==========================================
- Coverage   52.64%   52.61%   -0.03%     
==========================================
  Files        1685     1687       +2     
  Lines      104157   104340     +183     
  Branches    22601    22666      +65     
==========================================
+ Hits        54833    54899      +66     
- Misses      40993    41081      +88     
- Partials     8331     8360      +29     
Flag Coverage Δ
jsdom 48.15% <47.66%> (-0.03%) ⬇️
node 12.03% <2.34%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@erha19
Copy link
Member Author

erha19 commented May 22, 2025

/next

@erha19
Copy link
Member Author

erha19 commented May 22, 2025

/next

@opensumi
Copy link
Contributor

opensumi bot commented May 22, 2025

🎉 PR Next publish successful!

3.8.3-next-1747895552.0

@erha19
Copy link
Member Author

erha19 commented Jun 6, 2025

/next

@opensumi
Copy link
Contributor

opensumi bot commented Jun 6, 2025

🎉 PR Next publish successful!

3.9.1-next-1749196667.0

@erha19
Copy link
Member Author

erha19 commented Jun 6, 2025

/next

@opensumi
Copy link
Contributor

opensumi bot commented Jun 6, 2025

🎉 PR Next publish successful!

3.9.1-next-1749204089.0

@erha19 erha19 changed the title WIP: feat: support comments on multi-diff view feat: support comments on multi-diff view Jun 11, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 11, 2025

"""

Walkthrough

本次变更主要围绕多文件 Diff 编辑器(multi-diff editor)功能的引入与完善,涵盖编辑器集合服务、装饰应用、评论服务、样式、主题色、接口定义等多个模块。包括新增多 diff 编辑器的管理、编辑器装饰应用接口、评论区 race condition 处理、UI 细节优化以及相关依赖注入和事件管理等,涉及多处代码结构和接口调整。

Changes

文件/模块分组 变更摘要
packages/editor/src/browser/base-editor-wrapper.ts 新增 Monaco 编辑器基础包装类 BaseMonacoEditorWrapperDiffEditorPart,实现选项合并、装饰应用、事件监听等功能,提供统一的编辑器接口和装饰应用能力。
packages/editor/src/browser/editor-collection.service.ts 支持多 diff 编辑器(multi-diff editor)的注册与管理,增加相关事件与方法,完善编辑器唯一性检查,移除基础包装类、工具函数等冗余代码。
packages/editor/src/common/editor.ts 新增 IEditorDecorationApplier 接口,IEditor 增加 decorationApplier 属性与 updateDocumentModel 方法,EditorCollectionService 增加多 diff 编辑器相关抽象方法与事件。
packages/editor/src/common/multi-diff.ts IMultiDiffEditor 接口扩展,compareMultiple 方法签名变更,增加 multiDiffWidget 属性和 reveal 方法。
packages/editor/src/browser/multi-diff/multi-diff-editor.ts compareMultiple 方法重构,支持多 diff 编辑器实例注册与管理,新增 createAndRegisterEditorParts 私有方法,完善编辑器挂载时机处理。
packages/editor/src/browser/workbench-editor.service.ts 调整 multiDiffEditor.compareMultiple 的调用参数,增加编辑器实例传递。
packages/editor/src/browser/editor.contribution.ts 多 diff 编辑器打开命令支持传递 editorOptions,便于外部指定打开参数。
packages/monaco/src/browser/monaco.service.ts 注入 IWorkspaceServicecreateMultiDiffEditorWidget 方法中 setUri 支持工作区相对路径显示。
packages/monaco/src/browser/contrib/multi-diff-editor/resource-label.ts setUri 方法签名调整,支持工作区服务,渲染文件相对路径及样式增强。
packages/monaco/src/browser/contrib/multi-diff-editor/resource-label.module.less 新增 .strikethrough.relativePath.ellipsisPath 样式类,支持资源标签展示优化。
packages/editor/src/browser/editor.less 新增多 diff 编辑器相关样式,区分不同状态(新增、删除、重命名、修改)颜色。
packages/design/src/browser/theme/light-theme.ts
packages/theme/src/common/color-tokens/multi-diff-editor.ts
packages/theme/src/common/color-tokens/index.ts
新增多 diff 编辑器主题色 token,完善主题色导出与引用。
packages/comments/src/browser/comments-thread.ts
packages/comments/src/common/index.ts
packages/comments/src/browser/comments.service.ts
packages/comments/src/browser/comments-zone.view.ts
评论线程 race condition 处理,增加超时管理与新接口 removePendingShowedWidgets,完善编辑器切换时评论区显示与隐藏逻辑。
packages/editor/src/browser/decoration-applier.ts 事件监听注册方式优化,applyDecorationFromProvider 方法权限由 private 改为 public。
packages/components/src/icon/iconfont/iconMap.ts 新增 'diff': 'open-changes' 图标映射。
packages/components/src/markdown/styles.less .kt-popover .kt-md-renderer-wrap hr 增加 border-bottom: none;,优化分割线样式。
packages/components/src/scrollbars/index.tsx
packages/components/src/scrollbars/styles.less
滚动条阴影透明度逻辑调整,滚动条装饰定位由 absolute 改为 fixed,视觉交互优化。
packages/extension/__tests__/hosted/api/vscode/ext.host.comments.test.ts 注入并 mock EditorCollectionService,完善测试依赖。
packages/ai-native/src/browser/components/ChatEditor.tsx
packages/extension/src/browser/vscode/api/main.thread.editor.ts
packages/scm/src/browser/dirty-diff/index.ts
ISumiEditor 等接口 import 路径调整,适配基础包装类迁移。
packages/monaco-enhance/src/browser/zone-widget.ts 移除未用默认常量,_getWidth 计算优化,提升健壮性。
packages/editor/src/browser/multi-diff/multi-diff-resource.ts 移除多余空行,代码格式微调。

Sequence Diagram(s)

sequenceDiagram
    participant 用户
    participant EditorCollectionService
    participant BrowserMultiDiffEditor
    participant DiffEditorPart
    participant IEditor
    participant CommentsService

    用户->>EditorCollectionService: createMultiDiffEditor()
    EditorCollectionService->>BrowserMultiDiffEditor: 构造实例并注册
    BrowserMultiDiffEditor->>DiffEditorPart: createAndRegisterEditorParts()
    DiffEditorPart->>IEditor: 绑定装饰应用、事件监听等
    用户->>EditorCollectionService: listMultiDiffEditors()
    EditorCollectionService-->>用户: 返回多 diff 编辑器列表

    用户->>BrowserMultiDiffEditor: compareMultiple(editor, resource, options)
    BrowserMultiDiffEditor->>DiffEditorPart: 注册/更新编辑器部件
    DiffEditorPart->>IEditor: updateDocumentModel(uri)
    IEditor->>IEditor: 应用装饰、更新选项

    用户->>CommentsService: renderCommentRange(editor, selection)
    CommentsService->>IEditor: 检查/取消上一次渲染
    CommentsService->>IEditor: 应用注释装饰
    CommentsService->>IEditor: 更新保留空间
Loading

Possibly related PRs

Suggested reviewers

  • Ricbet
  • Aaaaash
  • life2015
    """

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

yarn install v1.22.22
[1/4] Resolving packages...
(node:16681) [DEP0169] DeprecationWarning: url.parse() behavior is not standardized and prone to errors that have security implications. Use the WHATWG URL API instead. CVEs are not issued for url.parse() vulnerabilities.
(Use node --trace-deprecation ... to show where the warning was created)
warning eslint@8.57.1: This version is no longer supported. Please see https://eslint.org/version-support for other options.
warning eslint > @humanwhocodes/config-array@0.13.0: Use @eslint/config-array instead
warning eslint > @humanwhocodes/config-array > @humanwhocodes/object-schema@2.0.3: Use @eslint/object-schema instead
warning eslint > file-entry-cache > flat-cache > rimraf@3.0.2: Rimraf versions prior to v4 are no longer supported
warning eslint > file-entry-cache > flat-cache > rimraf > glob@7.2.3: Glob versions prior to v9 are no longer supported
warning eslint > file-entry-cache > flat-cache > rimraf > glob > inflight@1.0.6: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
warning eslint-import-resolver-typescript > glob@7.2.3: Glob versions prior to v9 are no longer supported
error Couldn't find any versions for "@opensumi/ide-dev-tool" that matches "workspace:*"
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Commit Unit Tests in branch feat/support-comments-on-multi-diff-widget
  • Post Copyable Unit Tests in Comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (12)
packages/extension/__tests__/hosted/api/vscode/ext.host.comments.test.ts (1)

68-73: Mock 服务最小实现可能不足

此处仅 stub 了 listEditors,若 CommentsService 后续调用 onDidAddEditor 等事件,将导致单测潜在崩溃。
可视情况扩充 mock,或使用 jest.fn() 捕获未知调用并返回安全默认值。

packages/monaco/src/browser/contrib/multi-diff-editor/resource-label.module.less (1)

11-15: 建议:补充 Fallback 颜色变量

color: var(--descriptionForeground) 依赖于外部主题变量。若第三方主题未定义该 token,会导致字体颜色回退为 inherit,在暗色主题下可能出现对比度不足。可考虑添加后备颜色值:

-  color: var(--descriptionForeground);
+  color: var(--descriptionForeground, #8a8a8a);
packages/editor/src/browser/editor.less (1)

24-53: 样式逻辑 OK,但 .renamed 状态颜色疑似误用

.renamed 使用了 --kt-decoration-deletedResourceForeground,与语义不符(应更接近 modified / added)。请确认设计稿,或调整为专用 token,以避免误导用户。
其他部分(默认 M、空状态处理)实现简洁 👍

packages/editor/src/browser/decoration-applier.ts (1)

72-74: applyDecorationFromProvider 提升为 public

公开此方法有助于外部强制刷新,但请同步更新接口文档,避免误用造成不必要的频繁异步调用。

packages/theme/src/common/color-tokens/multi-diff-editor.ts (1)

15-16: 缺少本地化处理

描述字符串直接写了英文常量,而同文件中的其它颜色注册均通过 localize。建议保持一致,避免遗漏国际化。

-  "The background color of the diff editor's header",
+  localize('multiDiffEditor.headerBackground', "The background color of the diff editor's header"),
packages/editor/src/common/multi-diff.ts (3)

65-65: compareMultiple 的首参设计存疑

接口自身代表 Multi-Diff Editor,却要求调用方再把 editor: IMultiDiffEditor 传进来,容易造成重复或误传。若实现里只需 this,建议去掉该参数;如需比较“目标”编辑器,可更明确命名(如 targetEditor)。


105-106: multiDiffWidget 建议设为只读

UI 组件实例应当由实现类内部控制,暴露为 readonly 可防止外部误改。

-  multiDiffWidget: MultiDiffEditorWidget;
+  readonly multiDiffWidget: MultiDiffEditorWidget;

108-110: highlight 应为可选字段

目前 options?highlight 必填,调用者若只想传 range 需额外写 highlight: false,不够友好。

-  reveal(resource: IMultiDiffResourceId, options?: { range?: Range; highlight: boolean }): void;
+  reveal(resource: IMultiDiffResourceId, options?: { range?: Range; highlight?: boolean }): void;
packages/monaco/src/browser/monaco.service.ts (1)

178-190: 缺少资源释放,可能造成内存泄漏

createResourceLabel 返回的对象 dispose() 是空实现,但内部持有的 ResourceLabel 没有被销毁或从 DOM 移除。应在 dispose() 中调用 resourceLabel.clear() 或移除元素,确保事件与引用释放。

-            dispose: () => {},
+            dispose: () => {
+              resourceLabel.clear();
+            },
packages/comments/src/browser/comments-thread.ts (1)

278-287: 考虑将延迟时间设为可配置项

当前使用硬编码的 100ms 延迟来防止竞态条件。建议将此值提取为配置项或常量,以便根据不同场景进行调整。

+private static readonly WIDGET_SHOW_DELAY_MS = 100;
+
 public showWidgetsIfShowed() {
   // 清除之前的待执行 timeout,避免竞态条件
   this.pendingShowTimeouts.forEach((timeout) => clearTimeout(timeout));
   this.pendingShowTimeouts.clear();

   for (const editor of this.getEditorsByUri(this.uri)) {
     let widget = this.widgets.get(editor);
     // 说明是在新的 group 中打开
     if (!widget) {
       widget = this.addWidgetByEditor(editor);
     }
     // 如果标记之前是已经展示的 widget,则调用 show 方法
     if (editor.currentUri?.isEqual(this.uri)) {
       const timeout = setTimeout(() => {
         // 在异步回调中再次检查编辑器的当前 URI 是否仍然匹配 thread 的 URI
         // 防止用户快速滚动时 widget 渲染到错误的文件中
         if (widget && editor.currentUri?.isEqual(this.uri)) {
           widget.show();
         }
         // 执行完成后从跟踪集合中移除
         this.pendingShowTimeouts.delete(timeout);
-      }, 100);
+      }, CommentsThread.WIDGET_SHOW_DELAY_MS);
       this.pendingShowTimeouts.add(timeout);
     }
   }
 }
packages/comments/src/browser/comments.service.ts (2)

313-316: 优化重复编辑器检查逻辑

当前的重复检查只基于 Monaco 编辑器 ID。建议同时检查 URI 以确保更准确的重复检测。

 const disposer = new Disposable();
-if (this.allEditors.some((e) => e.monacoEditor.getId() === editor.monacoEditor.getId())) {
-  return this.editorDisposerMap.get(editor.monacoEditor.getId()) || disposer;
+const existingEditor = this.allEditors.find((e) => 
+  e.monacoEditor.getId() === editor.monacoEditor.getId() ||
+  (e.currentUri && editor.currentUri && e.currentUri.isEqual(editor.currentUri))
+);
+if (existingEditor) {
+  return this.editorDisposerMap.get(editor.monacoEditor.getId()) || disposer;
 }

1086-1088: 考虑为 FRAME_THREE 延迟添加注释说明

使用 FRAME_THREE 延迟可能是为了等待渲染完成,建议添加注释说明使用此延迟的原因。

               const editor = this.editorCollectionService.getEditorByUri(thread.uri);
               if (editor) {
+                // 延迟 3 帧确保编辑器渲染完成后再显示评论组件
                 setTimeout(() => {
                   thread.show(editor);
                 }, FRAME_THREE);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9d68f85 and 7c47904.

📒 Files selected for processing (29)
  • packages/ai-native/src/browser/components/ChatEditor.tsx (1 hunks)
  • packages/comments/src/browser/comments-thread.ts (6 hunks)
  • packages/comments/src/browser/comments-zone.view.tsx (1 hunks)
  • packages/comments/src/browser/comments.service.ts (10 hunks)
  • packages/comments/src/common/index.ts (1 hunks)
  • packages/components/src/icon/iconfont/iconMap.ts (1 hunks)
  • packages/components/src/markdown/styles.less (1 hunks)
  • packages/components/src/scrollbars/index.tsx (2 hunks)
  • packages/components/src/scrollbars/styles.less (2 hunks)
  • packages/design/src/browser/theme/light-theme.ts (1 hunks)
  • packages/editor/src/browser/base-editor-wrapper.ts (1 hunks)
  • packages/editor/src/browser/decoration-applier.ts (2 hunks)
  • packages/editor/src/browser/editor-collection.service.ts (9 hunks)
  • packages/editor/src/browser/editor.contribution.ts (2 hunks)
  • packages/editor/src/browser/editor.less (1 hunks)
  • packages/editor/src/browser/multi-diff/multi-diff-editor.ts (7 hunks)
  • packages/editor/src/browser/multi-diff/multi-diff-resource.ts (0 hunks)
  • packages/editor/src/browser/workbench-editor.service.ts (1 hunks)
  • packages/editor/src/common/editor.ts (4 hunks)
  • packages/editor/src/common/multi-diff.ts (3 hunks)
  • packages/extension/__tests__/hosted/api/vscode/ext.host.comments.test.ts (2 hunks)
  • packages/extension/src/browser/vscode/api/main.thread.editor.ts (1 hunks)
  • packages/monaco-enhance/src/browser/zone-widget.ts (1 hunks)
  • packages/monaco/src/browser/contrib/multi-diff-editor/resource-label.module.less (1 hunks)
  • packages/monaco/src/browser/contrib/multi-diff-editor/resource-label.ts (1 hunks)
  • packages/monaco/src/browser/monaco.service.ts (4 hunks)
  • packages/scm/src/browser/dirty-diff/index.ts (1 hunks)
  • packages/theme/src/common/color-tokens/index.ts (1 hunks)
  • packages/theme/src/common/color-tokens/multi-diff-editor.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • packages/editor/src/browser/multi-diff/multi-diff-resource.ts
🧰 Additional context used
🧬 Code Graph Analysis (3)
packages/theme/src/common/color-tokens/multi-diff-editor.ts (1)
packages/theme/src/common/color-tokens/editor.ts (1)
  • editorBackground (97-101)
packages/editor/src/browser/editor.contribution.ts (1)
packages/editor/src/common/editor.ts (1)
  • IResourceOpenOptions (625-737)
packages/editor/src/browser/multi-diff/multi-diff-editor.ts (4)
packages/editor/src/browser/types.ts (1)
  • IConvertedMonacoOptions (474-478)
packages/editor/src/common/multi-diff.ts (1)
  • IMultiDiffEditor (61-111)
packages/editor/src/common/editor.ts (2)
  • ICodeEditor (297-311)
  • IResourceOpenOptions (625-737)
packages/utils/src/types.ts (1)
  • isString (38-44)
⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: build (ubuntu-latest, 20.x)
  • GitHub Check: build (macos-latest, 20.x)
  • GitHub Check: unittest (ubuntu-latest, 18.x, jsdom)
  • GitHub Check: build-windows
  • GitHub Check: unittest (macos-latest, 18.x, jsdom)
  • GitHub Check: unittest (ubuntu-latest, 18.x, node)
  • GitHub Check: unittest (macos-latest, 18.x, node)
  • GitHub Check: ubuntu-latest, Node.js 20.x
🔇 Additional comments (24)
packages/components/src/scrollbars/styles.less (1)

44-56: position: fixed 可能导致装饰条脱离容器上下文

.scrollbar-decoration-*absolute 改为 fixed 后,装饰条会相对视口定位,而不是相对滚动容器。这在多层滚动容器或组件(如弹窗、嵌套 diff 视图)中可能出现:

  1. 装饰条漂浮在最外层页面顶部/左侧,遮挡其他 UI。
  2. 多个滚动区域并存时叠加在一起,z-index 竞争更加明显。

请在实际多 diff 场景下确认:

  • 装饰条是否仍然跟随对应滚动区域移动 / 显隐。
  • 是否需按滚动容器尺寸裁剪或使用 position: absolute + overflow: hidden 的父容器。

若只为解决某些 EdgeCase,可考虑仅在特定模式下切换定位或增加 pointer-events: nonecontain: layout 等保护。

packages/components/src/scrollbars/index.tsx (1)

105-109: 阴影透明度轴向对调:请再次确认业务含义

现在垂直阴影(左侧竖向渐变)的透明度取 scrollLeft,而水平阴影取 scrollTop。如果设计意图是:

  • 横向滚动→显示左侧阴影
  • 纵向滚动→显示顶部阴影
    则实现正确,无需改动。

若仅因代码重构误换,请回滚。

packages/scm/src/browser/dirty-diff/index.ts (1)

17-18: 导入路径更新符合模块拆分,OK

仅替换 ISumiEditor 的来源,功能不变,编译亦能通过。

packages/components/src/markdown/styles.less (1)

20-22: 细节 👍:Popover 中 HR 去除下边框

在气泡内移除 hr 的底边,避免双线效果,符合设计一致性。

packages/extension/src/browser/vscode/api/main.thread.editor.ts (1)

31-32: 同步 editor 模块重构的导入路径,LGTM

与核心编辑器结构调整保持一致,无其他风险。

packages/components/src/icon/iconfont/iconMap.ts (1)

209-210: 新增映射符合预期

新增 'diff': 'open-changes' 与已有 'open-changes' value 一致,可帮助调用方使用更直观的 diff key,无其他问题。

packages/ai-native/src/browser/components/ChatEditor.tsx (1)

28-28: 确认新导入路径在所有包中可解析

insertSnippetWithMonacoEditor 路径由 editor-collection.service 迁至 base-editor-wrapper。请确保:

  1. @opensumi/ide-editor/lib/browser/base-editor-wrapper 在发布包中确实导出该函数;
  2. 所有其他引用已同步更新,避免重复导出导致的编译冲突。

建议在 CI 中增加一次 tsc --noEmit 静态编译验证。

packages/design/src/browser/theme/light-theme.ts (1)

810-813: 新增配色需同步 Dark/Hc 主题

已为 Light 主题添加 multiDiffEditor.* 三个 token,但在深色与高对比度主题中未见同名条目,UI 将回退至默认值。
请确认是否需要在其它主题文件内补充对应颜色,保持跨主题一致性。

packages/monaco/src/browser/contrib/multi-diff-editor/resource-label.module.less (2)

7-9: 命名与职责清晰,LGTM

.strikethrough 的职责和实现都非常直观,没有发现问题。


17-23: RTL 方案需再次验证可读性

为了在路径过长时保留末尾片段,这里使用了 direction: rtl; text-align: left;
在英文或绝大部分 LTR 语言下没问题,但在真正的 RTL 文本环境(阿拉伯语、希伯来语)可能导致光标移动与文本渲染错位。请确认:

  1. 是否需要对 dir="rtl" 的文档做不同处理;
  2. 是否可接受复制文本时字符顺序被反转的副作用。

如果需要兼容 RTL,可考虑用 mask-image: linear-gradient()<span dir="ltr"> 包装实现省略号,而不是依赖 direction

packages/comments/src/browser/comments-zone.view.tsx (2)

209-213: 隐藏逻辑可能与组件内部状态不一致

onDidChangeModel 时调用 thread.hide(),但未同步 CommentsZoneWidget_isShow 状态,也未触发 hide() 方法。若其他逻辑依赖 widget.isShow,可能出现“线程已隐藏但组件状态仍为显示”的不一致。

建议改为:

-  const disposer = editor.monacoEditor.onDidChangeModel(() => {
-    thread.hide();
-  });
+  const disposer = editor.monacoEditor.onDidChangeModel(() => {
+    this.hide();          // 保证内部状态同步
+    thread.hide();        // 如仍需通知线程自身
+  });

请确认是否必须双重调用,或者仅调用 this.hide() 即可。


217-218: 👍 资源释放到位,避免内存泄漏

dispose 中正确销毁了 disposer,实现规范。

packages/editor/src/browser/editor.contribution.ts (1)

1248-1250:

Details

❓ Verification inconclusive

editorOptions 参数命名清晰,但请注意与 label 的覆盖顺序

label: options.title 先于 ...options.editorOptions 展开意味着当调用方在 editorOptions 中再次传入 label 时,会覆盖掉前面的标题。这种“后者优先”的行为是否与预期一致需要再确认。

如果希望始终以 options.title 为准,请将展开顺序对调:

-  await this.workbenchEditorService.open(multiDiffSourceUri, {
-    label: options.title,
-    ...options.editorOptions,
-  });
+  await this.workbenchEditorService.open(multiDiffSourceUri, {
+    ...options.editorOptions,
+    label: options.title,
+  });

注意:label 属性展开顺序会导致后者覆盖前者

当前在 packages/editor/src/browser/editor.contribution.ts 第1248–1250 行,调用

await this.workbenchEditorService.open(multiDiffSourceUri, {
  label: options.title,
  ...options.editorOptions,
});

由于 JavaScript 对象展开时后面同名属性会覆盖前面,若 options.editorOptions 中含有 label,就会覆盖掉 options.title。请确认这种“后者优先”行为是否符合预期:

  • 如希望调用方传入的 label 能覆盖标题,可保留当前写法。
  • 如希望始终以 options.title 为准,请调整顺序:
- await this.workbenchEditorService.open(multiDiffSourceUri, {
-   label: options.title,
-   ...options.editorOptions,
- });
+ await this.workbenchEditorService.open(multiDiffSourceUri, {
+   ...options.editorOptions,
+   label: options.title,
+ });
packages/theme/src/common/color-tokens/index.ts (1)

32-40:

Details

✅ Verification successful

路径更名与新增导出需确认文件存在

已将 debugToolbar → debug-toolbarchatColors → chat-colors 并新增 multi-diff-editor
请确认三处目标文件均已提交,避免运行时 Cannot find module


🏁 Script executed:

#!/bin/bash
# 检查目标 token 文件是否存在
fd 'debug-toolbar.ts' packages/theme/src/common/color-tokens
fd 'chat-colors.ts'   packages/theme/src/common/color-tokens
fd 'multi-diff-editor.ts' packages/theme/src/common/color-tokens

Length of output: 354


已验证:color-tokens 相关文件均已存在,无需额外处理

  • packages/theme/src/common/color-tokens/debug-toolbar.ts
  • packages/theme/src/common/color-tokens/chat-colors.ts
  • packages/theme/src/common/color-tokens/multi-diff-editor.ts

导出语句(index.ts 第32–40行)无需变更。

packages/monaco-enhance/src/browser/zone-widget.ts (1)

298-302: 空值判断修复 👍

minimap && minimapWidth ? minimapWidth + 5 : 0 有效避免 undefined + 5,逻辑正确。
无其他问题。

packages/editor/src/browser/decoration-applier.ts (1)

37-48: 订阅加入 Disposable,泄漏风险已解决

onDidChangeModelonDidDispose 包装进 this.addDispose,确保编辑器关闭时及时清理,👍
无额外问题。

packages/monaco/src/browser/monaco.service.ts (1)

58-60: 注入 IWorkspaceService 需确认所有运行时环境可用

某些无工作区场景(如纯只读 diff 查看器)可能没有 IWorkspaceService,强制注入会导致 DI 解析失败。请确认或在构造函数加可选依赖处理。

packages/editor/src/common/editor.ts (1)

242-246: decorationApplier 设为必需字段会破坏旧实现

现有所有 IEditor 实现都必须立即提供 decorationApplier,否则编译不过。请确认所有实现均已同步更新;若非强需求,可改为可选属性以保证向后兼容。

packages/comments/src/browser/comments-thread.ts (1)

117-124: LGTM: 编辑器组件初始化逻辑正确

在构造函数中添加的逻辑确保了在创建评论线程时,为所有匹配 URI 的编辑器正确初始化组件。

packages/editor/src/browser/multi-diff/multi-diff-editor.ts (1)

201-205: 🛠️ Refactor suggestion

改进只读状态的判断逻辑

当前只读状态的判断使用了 OR 逻辑,这可能导致当只有一个编辑器实例存在时,整个 diff 视图都变为只读。建议根据实际的编辑器类型分别设置只读状态。

           originalInstance: original?.instance,
           modifiedInstance: modified?.instance,
           contextKeys: r.contextKeys,
           options: {
-            readOnly: (modified || original)?.instance.readonly,
+            readOnly: modified?.instance.readonly ?? original?.instance.readonly ?? false,
             // TODO: codelens,wordWrap options
             ...this.convertedOptions.diffOptions,
           },

Likely an incorrect or invalid review comment.

packages/editor/src/browser/base-editor-wrapper.ts (1)

1-279: LGTM: 代码提取合理,结构清晰

将编辑器包装类从 editor-collection.service.ts 提取到独立文件中,提高了代码的模块化和可维护性。DiffEditorPart 类正确地扩展了 BaseMonacoEditorWrapper,并实现了必要的文档模型更新逻辑。

packages/comments/src/browser/comments.service.ts (1)

536-540: LGTM: 多 Diff 编辑器支持实现正确

正确处理了多 Diff 编辑器的文档模型更新,确保评论能在平铺模式下正常工作。

packages/editor/src/browser/editor-collection.service.ts (2)

122-147: LGTM: 重复编辑器检查逻辑完善

改进后的 addEditors 方法正确处理了重复编辑器的情况:

  • 通过 URI 查找现有编辑器
  • 通过 Monaco 编辑器 ID 进行二次验证
  • 对于已存在的编辑器,清理并重新应用装饰

176-182: LGTM: 多 Diff 编辑器创建实现正确

createMultiDiffEditor 方法正确实现了多 Diff 编辑器的创建,并将当前服务实例传递给编辑器以便进行生命周期管理。

Comment on lines 134 to 138
if (tabBarMode && scrollerRef.current) {
scrollerRef.current.addEventListener('wheel', onMouseWheel);
scrollerRef.current.addEventListener('wheel', onMouseWheel, { passive: true });
}
return () => {
scrollerRef.current?.removeEventListener('wheel', onMouseWheel);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

被动监听器中调用 preventDefault 会抛错 – 需移除 passive: true

addEventListener('wheel', onMouseWheel, { passive: true })onMouseWheel 内的 e.preventDefault() 冲突,运行时浏览器会输出
“Unable to preventDefault inside passive event listener invocation” 并且滚动拦截失效。

建议改为非被动监听,或移除 preventDefault

- scrollerRef.current.addEventListener('wheel', onMouseWheel, { passive: true });
+scrollerRef.current.addEventListener('wheel', onMouseWheel, { passive: false });

或完全省略第三参以保持默认行为(非 passive)。

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (tabBarMode && scrollerRef.current) {
scrollerRef.current.addEventListener('wheel', onMouseWheel);
scrollerRef.current.addEventListener('wheel', onMouseWheel, { passive: true });
}
return () => {
scrollerRef.current?.removeEventListener('wheel', onMouseWheel);
if (tabBarMode && scrollerRef.current) {
- scrollerRef.current.addEventListener('wheel', onMouseWheel, { passive: true });
+ scrollerRef.current.addEventListener('wheel', onMouseWheel, { passive: false });
}
return () => {
scrollerRef.current?.removeEventListener('wheel', onMouseWheel);
};
🤖 Prompt for AI Agents
In packages/components/src/scrollbars/index.tsx around lines 134 to 138, the
'wheel' event listener is added with the option { passive: true }, but the
onMouseWheel handler calls e.preventDefault(), causing a runtime error and
preventing scroll interception. To fix this, remove the { passive: true } option
when adding the event listener so that preventDefault can be called without
error, or alternatively remove the preventDefault call from onMouseWheel if
passive listening is required.

Comment on lines 543 to 546
/**
* 移除即将显示的 widget,避免竞态条件
*/
removePaddingShowedWidgets(): void;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

❓ Verification inconclusive

接口命名疑似拼写错误,建议统一为 Pending

removePaddingShowedWidgets 中的 Padding 看起来应为 Pending(待处理)而非内边距 Padding
为了避免误解,建议将方法名及对应实现统一改为 removePendingShowedWidgets,并同步更新相关调用处。

-  removePaddingShowedWidgets(): void;
+  /** 移除即将展示但尚未渲染完成的 widget,避免竞态 */
+  removePendingShowedWidgets(): void;

请修正方法命名:removePendingShowedWidgets
packages/comments/src/common/index.ts 中,方法 removePaddingShowedWidgets 中的 “Padding” 应为 “Pending”(待处理),建议统一改为 removePendingShowedWidgets,并同步更新 JSDoc 注释及所有调用处以避免歧义。

变更示例:

--- packages/comments/src/common/index.ts
@@ -543,7 +543,7 @@
-  /**
-   * 移除即将显示的 widget,避免竞态条件
-   */
-  removePaddingShowedWidgets(): void;
+  /**
+   * 移除待渲染的 widget,避免竞态条件
+   */
+  removePendingShowedWidgets(): void;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* 移除即将显示的 widget,避免竞态条件
*/
removePaddingShowedWidgets(): void;
/**
* 移除待渲染的 widget,避免竞态条件
*/
removePendingShowedWidgets(): void;
🤖 Prompt for AI Agents
In packages/comments/src/common/index.ts around lines 543 to 546, the method
name removePaddingShowedWidgets contains a typo where "Padding" should be
"Pending". Rename the method to removePendingShowedWidgets, update the JSDoc
comment accordingly, and refactor all references and calls to this method
throughout the codebase to maintain consistency and avoid confusion.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/comments/__test__/browser/comment-thread.test.ts (1)

32-37: listEditors 建议使用 jest.fn 便于断言

目前 listEditors 仅返回空数组,若将来需要验证该方法被调用次数,可改成 jest mock 函数:

-  useValue: mockService({
-    listEditors: () => [],
-  }),
+  useValue: mockService({
+    listEditors: jest.fn(() => []),
+  }),

这样既不影响现有行为,又方便后续断言。

packages/comments/__test__/browser/comments-feature.registry.test.ts (1)

33-38: 同样建议将 listEditors 设为 jest.fn

与其他测试保持一致,便于后期验证调用情况:

- listEditors: () => [],
+ listEditors: jest.fn(() => []),
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between da828d5 and 88e04dd.

📒 Files selected for processing (3)
  • packages/comments/__test__/browser/comment-thread.test.ts (2 hunks)
  • packages/comments/__test__/browser/comment.service.test.ts (3 hunks)
  • packages/comments/__test__/browser/comments-feature.registry.test.ts (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: unittest (ubuntu-latest, 18.x, node)
  • GitHub Check: unittest (macos-latest, 18.x, jsdom)
  • GitHub Check: unittest (ubuntu-latest, 18.x, jsdom)
  • GitHub Check: unittest (macos-latest, 18.x, node)
  • GitHub Check: ubuntu-latest, Node.js 20.x
  • GitHub Check: build-windows
  • GitHub Check: build (macos-latest, 20.x)
  • GitHub Check: build (ubuntu-latest, 20.x)
🔇 Additional comments (5)
packages/comments/__test__/browser/comment-thread.test.ts (1)

5-7: 引入 mockService & EditorCollectionService 👍

新增的 mockServiceEditorCollectionService 引入与后续依赖注入保持一致,没有问题。

packages/comments/__test__/browser/comment.service.test.ts (3)

79-81: 补充 currentUri 属性 ✅

currentEditor 增加 currentUri 能避免空值访问,保持与业务实现一致。


98-101: listEditors 返回空数组可能导致覆盖面不足

在真实环境中 listEditors 会包含当前活动编辑器。测试时始终返回 [] 可能掩盖跨编辑器渲染逻辑的问题。建议:

- listEditors: () => [],
+ listEditors: jest.fn(() => [currentEditor]),

并根据需要调整断言,以提升测试覆盖率。


297-298: deltaDecorations 期望次数由 9→1 需要确认逻辑变化

调用次数骤减意味着高亮装饰的内部实现已有调整,建议回顾 comments.service.ts 中相关逻辑,确认只调用一次即可满足全部场景,避免遗漏其他装饰更新。

packages/comments/__test__/browser/comments-feature.registry.test.ts (1)

4-9: 测试依赖注入重构良好

统一使用 createBrowserInjectorMockInjector 等工具后,代码更简洁一致,无问题。

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (4)
packages/editor/src/browser/multi-diff/multi-diff-editor.ts (2)

160-165: 未使用的形参 editor 应删除

compareMultiple 的第一个参数 editor 整个函数体内未被引用,保留会增加阅读噪音。若未来无需使用,直接移除并更新接口。


260-275: any 类型掩盖真实问题,降低类型安全

通过 (ref.object as any).modifiedInstance 取值会绕过类型检查,出现属性变更时编译无法提示。建议为 RefCounted<IDocumentDiffItem> 定义扩展接口或使用类型守卫,彻底去掉 any

packages/comments/src/browser/comments.service.ts (2)

373-398: 对多-diff 编辑器的判断粗糙且变量未使用

const currentMultiDiffEditor = this.editorCollectionService.listMultiDiffEditors()[0];
if (currentMultiDiffEditor) {
  editor.updateDocumentModel?.(URI.from(newModelUrl));
}
  1. 当同时存在多个 multi-diff editor 时,仅取首个实例并未校验 uri 是否匹配,可能误判。
  2. currentMultiDiffEditor 之后未被再次使用,完全可以删除该临时变量并改写为更明确的条件。

708-715: AbortController Map 需限定生命周期

editorRenderAbortControllers 以 editorId 为键,但仅在 editor onDidChangeModel 与 disposer 回调里清理。若编辑器因为其它路径被销毁(例如工作区关闭),Map 可能遗留未清理条目。建议在 editor.onDispose 时同样调用清理逻辑。

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4c2d124 and 2e96dc0.

📒 Files selected for processing (2)
  • packages/comments/src/browser/comments.service.ts (10 hunks)
  • packages/editor/src/browser/multi-diff/multi-diff-editor.ts (7 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/editor/src/browser/multi-diff/multi-diff-editor.ts (4)
packages/editor/src/browser/types.ts (1)
  • IConvertedMonacoOptions (474-478)
packages/editor/src/common/multi-diff.ts (1)
  • IMultiDiffEditor (61-111)
packages/editor/src/common/editor.ts (2)
  • ICodeEditor (297-311)
  • IResourceOpenOptions (625-737)
packages/utils/src/types.ts (1)
  • isString (38-44)

Comment on lines +131 to +158
private createAndRegisterEditorParts(
modifiedEditor: { editor: ICodeEditor } | undefined,
originalEditor: { editor: ICodeEditor } | undefined,
modifiedInstance: any,
originalInstance: any,
documents: ISettableObservable<readonly RefCounted<IDocumentDiffItem>[] | 'loading', void>,
): void {
const editors: DiffEditorPart[] = [];
if (modifiedEditor) {
const modifiedDiffEditorPart = this.injector.get(DiffEditorPart, [
modifiedEditor.editor,
() => modifiedInstance,
EditorType.MODIFIED_DIFF,
documents,
]);
editors.push(modifiedDiffEditorPart);
}
if (originalEditor) {
const originalDiffEditorPart = this.injector.get(DiffEditorPart, [
originalEditor.editor,
() => originalInstance,
EditorType.ORIGINAL_DIFF,
documents,
]);
editors.push(originalDiffEditorPart);
}
this.editorCollectionService.addEditors(editors);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

DiffEditorPart 未集中管理,生命周期难以保证

createAndRegisterEditorParts 每次新建 DiffEditorPart 实例后立即交给 editorCollectionService,但当前类本身既不保存引用,也不在 dispose() 中统一销毁。这意味着若 editorCollectionService 没有完整托管其生命周期,会产生悬挂实例。
建议:

  1. 维护 private readonly registeredEditorParts: DiffEditorPart[] = [];
  2. 在此方法里向数组 push,dispose() 时遍历并调用 dispose()
🤖 Prompt for AI Agents
In packages/editor/src/browser/multi-diff/multi-diff-editor.ts between lines 131
and 158, the DiffEditorPart instances created in createAndRegisterEditorParts
are passed to editorCollectionService but not stored or disposed by this class,
risking dangling instances. Fix this by adding a private array
registeredEditorParts to hold these instances, push each new DiffEditorPart into
this array inside createAndRegisterEditorParts, and then override the dispose()
method of this class to iterate over registeredEditorParts and call dispose() on
each to ensure proper lifecycle management.

Comment on lines +75 to 83
constructor(
public readonly multiDiffWidget: MultiDiffEditorWidget,
private convertedOptions: IConvertedMonacoOptions,
private editorCollectionService: EditorCollectionServiceImpl,
) {
super();
this.editorCollectionService.addMultiDiffEditors([this as IMultiDiffEditor]);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

构造函数注册但未解除,可能导致内存泄漏

在构造函数中调用 editorCollectionService.addMultiDiffEditors 注册自身,但 dispose() 中没有对应的移除逻辑;当多-diff editor 被销毁后,集合里仍会残留引用。建议在 dispose() 里补充反向操作。

   dispose(): void {
     super.dispose();
+    // 避免泄漏
+    this.editorCollectionService.removeMultiDiffEditors?.([this as IMultiDiffEditor]);
     this.multiDiffWidget.dispose();
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
constructor(
public readonly multiDiffWidget: MultiDiffEditorWidget,
private convertedOptions: IConvertedMonacoOptions,
private editorCollectionService: EditorCollectionServiceImpl,
) {
super();
this.editorCollectionService.addMultiDiffEditors([this as IMultiDiffEditor]);
}
dispose(): void {
super.dispose();
+ // 避免泄漏
+ this.editorCollectionService.removeMultiDiffEditors?.([this as IMultiDiffEditor]);
this.multiDiffWidget.dispose();
}
🤖 Prompt for AI Agents
In packages/editor/src/browser/multi-diff/multi-diff-editor.ts around lines 75
to 83, the constructor registers the instance with
editorCollectionService.addMultiDiffEditors but the dispose() method lacks the
corresponding removal logic, causing potential memory leaks. To fix this,
override the dispose() method and call
editorCollectionService.removeMultiDiffEditors with this instance to unregister
it, ensuring references are properly cleaned up when the editor is destroyed.

Comment on lines 555 to 557
this.onCommentRangeProviderChange(() => {
this.renderCommentRange(editor);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

重复注册事件且未纳入 disposer,存在泄漏风险

onCommentRangeProviderChange 的监听在 529-533 行已通过 disposer.addDispose 注册,这里再次注册且未加入 disposer,将导致同一 editor 创建多次监听且无法自动释放。请去除重复代码或使用 disposer.addDispose 统一管理。

-    this.onCommentRangeProviderChange(() => {
-      this.renderCommentRange(editor);
-    });
+    // 已在上方通过 disposer 注册,无需再次绑定
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
this.onCommentRangeProviderChange(() => {
this.renderCommentRange(editor);
});
// 已在上方通过 disposer 注册,无需再次绑定
🤖 Prompt for AI Agents
In packages/comments/src/browser/comments.service.ts around lines 555 to 557,
the event listener for onCommentRangeProviderChange is registered again without
adding it to the disposer, causing potential memory leaks due to multiple
listeners on the same editor. Remove this duplicate registration or ensure it is
added to the disposer using disposer.addDispose to properly manage and dispose
of the listener.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (4)
packages/editor/src/browser/multi-diff/multi-diff-editor.ts (3)

266-278: 仍然使用 setTimeout(0),时序问题未解决
上一轮评审已提出改为 Promise/事件机制。本段代码依旧保留 setTimeout,问题未得到解决。请参考既有建议完成替换。


131-158: 🛠️ Refactor suggestion

DiffEditorPart 生命周期未托管

createAndRegisterEditorParts 创建的 DiffEditorPart 仅通过 editorCollectionService.addEditors 注册,没有在本类或服务中统一保存 / 释放引用。
editorCollectionService 没有负责销毁这些实例,将造成悬挂对象。

建议:

  1. 增加 private readonly registeredParts: DiffEditorPart[] = [];
  2. editors.push(...) 后同步 this.registeredParts.push(...)
  3. dispose() 中遍历 registeredParts 调用 dispose()

[建议示例]

+private readonly registeredParts: DiffEditorPart[] = [];

...
 const editors: DiffEditorPart[] = [];
 ...
 editors.push(modifiedDiffEditorPart);
+this.registeredParts.push(modifiedDiffEditorPart);
 ...
 this.editorCollectionService.addEditors(editors);
dispose(): void {
  super.dispose();
+ for (const part of this.registeredParts) {
+   part.dispose();
+ }
  this.multiDiffWidget.dispose();
}

75-83: ⚠️ Potential issue

缺少反向注销,存在内存泄漏风险

构造函数中将当前 multiDiffEditor 注册进 editorCollectionService,但在 dispose() 中并未调用对应的 removeMultiDiffEditors(或类似接口)进行反向操作。
对象被销毁后,集合里仍会残留引用,导致潜在泄漏。

 dispose(): void {
   super.dispose();
+  this.editorCollectionService.removeMultiDiffEditors?.([this as IMultiDiffEditor]);
   this.multiDiffWidget.dispose();
 }
packages/comments/src/browser/comments.service.ts (1)

563-570: 重复注册 onCommentRangeProviderChange,会导致监听器泄漏

前面 533 行已通过 disposer.addDispose 绑定监听,这里再次注册且未加入 disposer,与先前评审指出的问题完全相同。

请删除该段或加入 disposer.addDispose(...),避免重复监听。

🧹 Nitpick comments (1)
packages/comments/src/browser/comments.service.ts (1)

721-734: AbortController 创建频繁但缺少超时/阈值策略

renderCommentRange 每次调用都会新建 AbortController,高频光标移动情况下可能造成大量实例快速创建与 GC。考虑:

  • 复用同一 AbortController,仅在未完成的情况下 abort() 并重置。
  • 或设置最小调用间隔/防抖。

虽非致命问题,但可显著降低开销。

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2e96dc0 and ae16f99.

📒 Files selected for processing (2)
  • packages/comments/src/browser/comments.service.ts (13 hunks)
  • packages/editor/src/browser/multi-diff/multi-diff-editor.ts (7 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: unittest (macos-latest, 18.x, node)
  • GitHub Check: unittest (macos-latest, 18.x, jsdom)
  • GitHub Check: build (ubuntu-latest, 20.x)
  • GitHub Check: build (macos-latest, 20.x)
  • GitHub Check: unittest (ubuntu-latest, 18.x, node)
  • GitHub Check: unittest (ubuntu-latest, 18.x, jsdom)
  • GitHub Check: build-windows
  • GitHub Check: ubuntu-latest, Node.js 20.x

Comment on lines +249 to +259
const documentRefs = documents.get();
for (const ref of documentRefs) {
if (isString(ref)) {
continue;
}
const modified = ref.object.modified;
const original = ref.object.original;
if (!modified && !original) {
continue;
}
let modifiedEditor = modified ? this.multiDiffWidget.tryGetCodeEditor(modified.uri) : undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

documents 可能为 'loading',for-of 会误遍历字符串

documents.get() 仍为 'loading' 时,for (const ref of documentRefs) 将按字符遍历 'loading'
虽然内部用 isString(ref) 过滤,但仍产生不必要循环,并可能掩盖真实的等待逻辑。

-const documentRefs = documents.get();
-for (const ref of documentRefs) {
+const documentRefs = documents.get();
+if (isString(documentRefs)) {
+  // 仍在加载,等待后续 onMultiDiffModelChange 处理
+  return;
+}
+for (const ref of documentRefs as typeof documentRefs & RefCounted<IDocumentDiffItem>[]) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const documentRefs = documents.get();
for (const ref of documentRefs) {
if (isString(ref)) {
continue;
}
const modified = ref.object.modified;
const original = ref.object.original;
if (!modified && !original) {
continue;
}
let modifiedEditor = modified ? this.multiDiffWidget.tryGetCodeEditor(modified.uri) : undefined;
const documentRefs = documents.get();
if (isString(documentRefs)) {
// 仍在加载,等待后续 onMultiDiffModelChange 处理
return;
}
for (const ref of documentRefs as typeof documentRefs & RefCounted<IDocumentDiffItem>[]) {
if (isString(ref)) {
continue;
}
const modified = ref.object.modified;
const original = ref.object.original;
if (!modified && !original) {
continue;
}
let modifiedEditor = modified
? this.multiDiffWidget.tryGetCodeEditor(modified.uri)
: undefined;
// … 后续逻辑保持不变 …
}
🤖 Prompt for AI Agents
In packages/editor/src/browser/multi-diff/multi-diff-editor.ts around lines 249
to 259, the documents.get() call may return the string 'loading', causing the
for-of loop to iterate over each character of the string. To fix this, add a
check before the loop to verify that documentRefs is not a string (i.e., not
'loading') and only proceed with the loop if it is an array or iterable of
document references. This prevents unnecessary looping and avoids masking the
actual loading state.

Comment on lines +308 to 316
private editorDisposerMap = new Map<string, Disposable>();

public handleOnCreateEditor(editor: IEditor) {
const disposer = new Disposable();
if (this.allEditors.some((e) => e.monacoEditor.getId() === editor.monacoEditor.getId())) {
return this.editorDisposerMap.get(editor.monacoEditor.getId()) || disposer;
}
this.editorDisposerMap.set(editor.monacoEditor.getId(), disposer);
this.allEditors.push(editor);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

editorDisposerMap 条目未在编辑器销毁后移除

虽然在 disposer 内部对 AbortController 做了清理,但并未将对应条目从 editorDisposerMapallEditors 中删除,长时间使用可能导致集合无限增长。

建议在 disposerdispose 回调中同步执行:

+this.editorDisposerMap.delete(editor.monacoEditor.getId());
+this.allEditors = this.allEditors.filter(e => e !== editor);

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/comments/src/browser/comments.service.ts around lines 308 to 316,
the editorDisposerMap and allEditors collections are not cleaned up when an
editor is destroyed, causing potential memory leaks. To fix this, add a dispose
callback to the disposer that removes the editor's entry from editorDisposerMap
and also removes the editor from allEditors when dispose is called, ensuring
proper cleanup of resources.

@erha19 erha19 merged commit 228c24c into main Jun 13, 2025
11 checks passed
@erha19 erha19 deleted the feat/support-comments-on-multi-diff-widget branch June 13, 2025 03:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🎨 feature feature required

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants