Skip to content

feat: support multi file diff editor#4523

Merged
ensorrow merged 23 commits intomainfrom
feat/multi-file-diff
May 8, 2025
Merged

feat: support multi file diff editor#4523
ensorrow merged 23 commits intomainfrom
feat/multi-file-diff

Conversation

@ensorrow
Copy link
Copy Markdown
Contributor

@ensorrow ensorrow commented Apr 29, 2025

Types

  • 🎉 New Features

Background or solution

feat: support multi file diff editor

支持多文件 diff 编辑器管理,支持通过 resolverService 响应文件信息变化(command 多次调用更新,chat 文件改动自动更新),内置支持通过 command 和 chat 能力使用。(Git 需要后续升级 SCM 适配插件)

image
image

Changelog

feat: support multi file diff editor
feat: support view-changes for chat session

Summary by CodeRabbit

  • 新功能

    • 编辑器全面支持多文件对比(Multi-Diff Editor),实现多文件差异的创建、展示与交互。
    • 聊天编辑会话新增“查看改动”入口,点击可直接打开多文件对比视图。
    • 状态栏新增“MultiDiff Test”按钮,便于测试多文件对比功能。
    • 多文件对比支持原始与修改内容的高亮、导航,并与会话代码块动态联动。
    • 编辑器组支持多文件对比编辑器类型,实现生命周期和布局管理。
    • 引入多文件对比资源提供者和解析服务,实现动态解析与管理。
    • Monaco 编辑器新增多文件对比编辑器 Widget 及资源标签渲染支持。
    • 新增多文件对比相关命令注册与执行,支持通过命令打开多文件对比视图。
    • 新增聊天编辑多文件差异源解析器,支持基于聊天会话的多文件差异展示。
    • 新增多文件对比相关贡献点注册机制,支持多源解析器和资源提供者的动态扩展。
    • 编辑器新增多文件对比视图的 DOM 挂载与尺寸监听,确保布局和交互流畅。
    • 新增多文件对比编辑器状态管理,支持视图状态保存与恢复。
  • 样式优化

    • 优化多文件对比相关按钮、标签的布局与交互样式,提升可用性和视觉一致性。
    • 新增多文件对比资源标签样式,支持图标和名称的统一展示。
  • 国际化

    • 新增“查看改动”多语言支持(中英文)。
  • 其他改进

    • 新增多文件对比相关的 API、服务和类型声明,提升扩展性与集成能力。
    • 引入多文件对比相关的可观察状态管理工具,增强异步数据处理能力。

@opensumi opensumi Bot added the 🎨 feature feature required label Apr 29, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 29, 2025

## Walkthrough

本次更改为编辑器系统引入了多文件对比(multi-diff)编辑器功能。主要内容包括新增多文件对比相关的抽象接口、服务、贡献点、资源解析器、编辑器实现和 UI 组件。AI Native 聊天模块集成了多文件对比能力,支持通过会话代码块动态生成多文件对比资源。Monaco 编辑器和前端样式也同步扩展以支持多文件对比编辑器的渲染和交互。此外,命令系统、状态栏和本地化文件也做了相应适配,允许通过命令或 UI 操作打开多文件对比视图。

## Changes

| 文件/路径分组 | 变更摘要 |
|---|---|
| `packages/editor/src/common/multi-diff.ts` | 新增多文件对比相关接口与类型定义,包括资源解析、编辑器模型和编辑器项等。 |
| `packages/editor/src/common/editor.ts` | `EditorCollectionService` 增加 `createMultiDiffEditor` 抽象方法,`EditorOpenType` 增加 `multiDiff` 类型。 |
| `packages/editor/src/browser/editor-collection.service.ts` | 实现 `createMultiDiffEditor` 方法,支持创建多文件对比编辑器实例。 |
| `packages/editor/src/browser/multi-diff/`(多个文件) | 新增多文件对比编辑器实现(`BrowserMultiDiffEditor`)、资源提供器、解析器、服务和贡献点,支持多文件对比的注册、资源解析与渲染。 |
| `packages/editor/src/browser/editor.contribution.ts` | 注册 `_workbench.openMultiDiffEditor` 命令,支持通过命令打开多文件对比编辑器。 |
| `packages/editor/src/browser/editor.view.tsx` | 编辑器容器支持渲染多文件对比编辑器,并处理其 DOM 挂载与布局。 |
| `packages/editor/src/browser/index.ts` | 编辑器模块注册多文件对比相关服务、贡献点,并在初始化时完成注册。 |
| `packages/editor/src/browser/types.ts` | 新增 `MultiDiffSourceContribution` 贡献点接口及符号。 |
| `packages/editor/src/browser/workbench-editor.service.ts` | `EditorGroup` 支持多文件对比编辑器的生命周期、布局、打开与挂载。 |
| `packages/ai-native/src/browser/chat/`(多个文件) | 聊天模块新增多文件对比资源与解析器,实现基于会话代码块的多文件对比能力。 |
| `packages/ai-native/src/browser/ai-core.contribution.ts` | 聊天贡献点实现多文件对比源注册和内容提供能力。 |
| `packages/ai-native/src/browser/components/ChangeList.tsx` | 增加“查看改动”按钮,支持一键打开多文件对比视图。 |
| `packages/ai-native/src/browser/components/change-list.module.less` | 样式调整,新增 `viewChanges` 类,优化按钮与图标的交互和布局。 |
| `packages/ai-native/src/browser/mcp/base-apply.service.ts` | 新增 `CHAT_EDITING_SOURCE_RESOLVER_SCHEME` 常量。 |
| `packages/core-browser/src/common/common.command.ts` | 新增多文件对比编辑器命令常量。 |
| `packages/core-browser/src/monaco/index.ts` | `MonacoService` 增加 `createMultiDiffEditorWidget` 抽象方法。 |
| `packages/core-browser/src/services/label-service.ts` | `getIconClass` 重命名为 `getResourceIconClass` 并导出。 |
| `packages/i18n/src/common/en-US.lang.ts`<br>`packages/i18n/src/common/zh-CN.lang.ts` | 新增“查看改动”相关本地化字符串。 |
| `packages/monaco/src/browser/monaco.service.ts` | 实现 `createMultiDiffEditorWidget`,支持创建多文件对比编辑器控件。 |
| `packages/monaco/src/browser/monaco-api/editor.ts` | 对外暴露 `createMultiFileDiffEditor`|
| `packages/monaco/src/browser/contrib/multi-diff-editor/resource-label.ts`<br>`resource-label.module.less` | 新增资源标签组件及样式,用于多文件对比资源展示。 |
| `packages/monaco/src/common/observable.ts` | 新增若干 observable 工具类,支持 lazy 计算与 promise 状态跟踪。 |
| `packages/editor/src/browser/editor.module.less` | 多文件对比编辑器样式适配。 |
| `packages/startup/entry/sample-modules/status-bar.contribution.ts` | 状态栏贡献点注册测试命令,可打开多文件对比编辑器。 |
| `packages/ai-native/src/browser/ai-core.contribution.ts` | `AINativeBrowserContribution` 实现 `MultiDiffSourceContribution`,注册多文件对比源解析器和编辑器内容提供者。 |
| `packages/ai-native/src/browser/chat/chat-edit-resource.ts` | 新增 `ChatEditSchemeDocumentProvider`,基于 URI 动态提供聊天编辑会话代码内容。 |
| `packages/ai-native/src/browser/chat/chat-multi-diff-source.ts` | 新增 `ChatMultiDiffResolver``ChatMultiDiffSource`,实现基于聊天会话的多文件对比资源解析。 |
| `packages/ai-native/src/browser/components/ChangeList.tsx` | 增加“查看改动”按钮,点击打开多文件对比视图。 |
| `packages/editor/src/browser/multi-diff/multi-diff-editor.ts` | 新增 `BrowserMultiDiffEditor`,实现多文件对比编辑器核心逻辑与界面交互。 |
| `packages/editor/src/browser/multi-diff/multi-diff-resolver.ts` | 新增 `MultiDiffResolver`,管理多文件对比资源的注册与解析。 |
| `packages/editor/src/browser/multi-diff/multi-diff-resource.ts` | 新增 `MultiDiffResourceProvider`,提供多文件对比资源的解析和图标支持。 |
| `packages/editor/src/browser/multi-diff/multi-diff.contribution.ts` | 新增 `MultiDiffEditorContribution`,注册多文件对比源解析器、资源提供器和编辑器组件。 |
| `packages/editor/src/browser/multi-diff/resolver.service.ts` | 新增 `MultiDiffSourceResolverService`,管理多文件对比源解析器的注册和调用。 |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant 用户
    participant UI组件
    participant WorkbenchEditorService
    participant MultiDiffSourceResolverService
    participant MultiDiffResolver/ChatMultiDiffResolver
    participant BrowserMultiDiffEditor
    participant MonacoService

    用户->>UI组件: 点击“查看改动”按钮
    UI组件->>WorkbenchEditorService: 调用 open(),openType=multiDiff
    WorkbenchEditorService->>MultiDiffSourceResolverService: resolve(multiDiffSourceUri)
    MultiDiffSourceResolverService->>MultiDiffResolver/ChatMultiDiffResolver: resolveDiffSource(uri)
    MultiDiffResolver/ChatMultiDiffResolver-->>MultiDiffSourceResolverService: 返回 diff 资源列表
    MultiDiffSourceResolverService-->>WorkbenchEditorService: 返回资源
    WorkbenchEditorService->>BrowserMultiDiffEditor: compareMultiple(resource, options)
    BrowserMultiDiffEditor->>MonacoService: createMultiDiffEditorWidget()
    BrowserMultiDiffEditor->>BrowserMultiDiffEditor: 渲染多文件对比视图
    BrowserMultiDiffEditor-->>用户: 展示多文件对比编辑器

Suggested reviewers

  • Ricbet
  • hacke2
  • Aaaaash

<!-- walkthrough_end -->
<!-- This is an auto-generated comment: all tool run failures by coderabbit.ai -->

> [!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.
> 
> <details>
> <summary>🔧 ESLint</summary>
> 
> > 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...
> 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.
> 
> 
> 
> </details>

<!-- end of auto-generated comment: all tool run failures by coderabbit.ai -->


---

<details>
<summary>📜 Recent review details</summary>

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

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 1aefb9c3e4fe3c38da2bbe2400ad7cfef52a6f62 and 08b6d70ccfd2486941d18f52e3f3554466a8c6f9.

</details>

<details>
<summary>📒 Files selected for processing (3)</summary>

* `packages/ai-native/src/browser/components/ChangeList.tsx` (4 hunks)
* `packages/editor/src/browser/multi-diff/multi-diff.contribution.ts` (1 hunks)
* `packages/startup/entry/sample-modules/status-bar.contribution.ts` (3 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (2)</summary>

* packages/ai-native/src/browser/components/ChangeList.tsx
* packages/editor/src/browser/multi-diff/multi-diff.contribution.ts

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (6)</summary>

* GitHub Check: unittest (ubuntu-latest, 18.x, jsdom)
* GitHub Check: unittest (ubuntu-latest, 18.x, node)
* GitHub Check: ubuntu-latest, Node.js 20.x
* GitHub Check: build-windows
* GitHub Check: build (ubuntu-latest, 20.x)
* GitHub Check: build (macos-latest, 20.x)

</details>

<details>
<summary>🔇 Additional comments (6)</summary><blockquote>

<details>
<summary>packages/startup/entry/sample-modules/status-bar.contribution.ts (6)</summary>

`13-20`: **导入了必要的命令相关接口和多文件对比所需的常量**

代码正确引入了CommandContribution、CommandRegistry和CommandService接口,这些是实现命令注册所必需的。同时也引入了MULTI_DIFF_SCHEME常量,用于多文件对比编辑器的实现。

---

`22-24`: **实现了命令常量和执行计数器**

executeCount变量用于跟踪命令执行次数,这样可以在第二次点击时添加额外的文件对比。命令常量的命名符合规范。

---

`26-28`: **正确扩展了类的实现接口**

类正确地扩展为实现CommandContribution接口,这对于注册命令是必要的。Domain装饰器的更新也符合预期。

---

`32-33`: **注入了CommandService服务**

正确地通过Autowired注入了CommandService,用于执行多文件对比命令。

---

`57-64`: **实现了命令注册**

按照标准方式注册了测试命令,并将执行逻辑指向openDiff方法。实现简洁明了。

---

`102-108`: **添加了状态栏测试入口**

状态栏元素添加正确,包含了适当的工具提示、文本和命令绑定。这为用户提供了一个触发测试命令的界面元素。

</details>

</blockquote></details>

</details>
<!-- internal state start -->


<!-- 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= -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

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.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=opensumi/core&utm_content=4523):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `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 generate unit testing code for this file.`
  -	`@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 generate unit testing code.`
  - `@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](https://www.coderabbit.ai/contact-us/support) 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](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in 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](https://docs.coderabbit.ai/guides/configure-coderabbit) 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](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

Copy link
Copy Markdown
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: 8

🔭 Outside diff range comments (2)
packages/monaco/src/common/observable.ts (2)

58-64: ⚠️ Potential issue

dispose 时未清理定时器,存在潜在内存泄漏

debouncedObservable2dispose 仅释放 autorun,但若已经设置了 timeout,仍会在组件销毁后继续执行回调。建议在销毁时一并 clearTimeout

dispose() {
  d.dispose();
+  if (timeout) {
+    clearTimeout(timeout);
+    timeout = undefined;
+  }
  hasValue = false;
  lastValue = undefined;
}

1-2: 🛠️ Refactor suggestion

全文件使用 // @ts-nocheck 关闭类型检查,建议逐步移除

当前文件直接禁用了 TS 类型检查,长期会掩盖大量潜在问题。建议分阶段恢复类型检查:

  1. 先启用 // @ts-check 查看报错概况;
  2. 借助 ts-expect-error 精准忽略无法立刻解决的位置;
  3. 最终完全移除。
🧹 Nitpick comments (17)
packages/monaco/src/browser/contrib/multi-diff-editor/resource-label.module.less (1)

1-5: flex-gap 在旧版浏览器可能失效,可按需兜底

gap 在旧版 Safari(≤14.1)及部分 Electron 老版本的嵌套 WebView 中并不支持。若对这些环境有兼容需求,可考虑添加 margin-right/margin-bottom 方案或升级运行时。

packages/editor/src/browser/editor.module.less (1)

10-14: 样式 OK,可考虑补充 overflow 防止溢出

.kt_editor_multi_diff_editor 填充父容器且 position: relative 设置正确;如后续需要在内部叠加浮层组件,建议同时设置 overflow: hidden 以避免内容溢出。

packages/monaco/src/browser/monaco-api/editor.ts (1)

73-73: 将多文件 Diff 编辑器暴露至 API
createMonacoEditorApi 添加 createMultiFileDiffEditor 方法,已满足多文件对比编辑器功能需求。请同时更新文档和示例,指导外部消费者如何使用该新 API。

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

54-72: 查看变更功能实现

renderViewChanges函数实现了查看多文件差异的功能,设计合理:

  1. 当没有文件时正确处理了边缘情况
  2. 使用编辑器服务打开多文件差异视图
  3. 阻止事件冒泡以避免触发父元素的点击事件
  4. 使用本地化字符串支持国际化

建议考虑将URI常量提取为模块级常量或配置项,以增强可维护性。

+const CHAT_EDITING_MULTI_DIFF_URI = URI.parse('chat-editing-multi-diff-source://chat-editing-multi-diff-source/');

 const renderViewChanges = (totalFiles: number) => {
   if (!totalFiles) {
     return null;
   }
   return (
     <span
       className={styles.viewChanges}
       onClick={(e) => {
         e.stopPropagation();
-        editorService.open(URI.parse('chat-editing-multi-diff-source://chat-editing-multi-diff-source/'), {
+        editorService.open(CHAT_EDITING_MULTI_DIFF_URI, {
           label: localize('aiNative.chat.view-changes'),
         });
       }}
     >
packages/monaco/src/browser/contrib/multi-diff-editor/resource-label.ts (2)

6-23: ResourceLabel类实现高内聚

ResourceLabel类设计简洁明了:

  1. 构造函数接收一个HTML元素作为容器
  2. setUri方法处理URI规范化并委托给renderFile
  3. renderFile方法生成包含图标和显示名称的HTML
  4. clear方法提供了清理功能

建议添加类级别的JSDoc注释以提高代码的可维护性,并明确类的用途和职责。

+/**
+ * 管理资源标签渲染的类
+ * 负责在指定的HTML元素中渲染包含图标和名称的资源标签
+ */
 export class ResourceLabel {
   constructor(private readonly element: HTMLElement) {}

+  /**
+   * 设置要显示的URI和选项
+   * @param uri 要显示的资源URI
+   * @param options 标签选项,如是否添加删除线
+   */
   setUri(uri: Uri, options?: IResourceLabelOptions) {
     this.renderFile(URI.from(uri), options);
   }

13-18: renderFile方法实现简洁有效

renderFile方法的实现简洁高效:

  1. 获取资源图标类
  2. 根据选项条件性地应用删除线样式
  3. 直接使用innerHTML设置内容

一个潜在的安全考虑是使用innerHTML可能引起XSS风险,特别是当处理用户输入或不受信任的URI时。考虑使用更安全的DOM操作方法。

 private renderFile(uri: URI, options?: IResourceLabelOptions) {
   const icon = getResourceIconClass(uri);
-  this.element.innerHTML = `<span class="${styles.resourceLabel}${
-    options?.strikethrough ? ' strikethrough' : ''
-  }"><span class="${icon.iconClass}"></span>${uri.displayName}</span>`;
+  this.element.innerHTML = '';
+  
+  const labelElement = document.createElement('span');
+  labelElement.className = `${styles.resourceLabel}${options?.strikethrough ? ' strikethrough' : ''}`;
+  
+  const iconElement = document.createElement('span');
+  iconElement.className = icon.iconClass;
+  
+  labelElement.appendChild(iconElement);
+  labelElement.appendChild(document.createTextNode(uri.displayName));
+  
+  this.element.appendChild(labelElement);
 }
packages/startup/entry/sample-modules/status-bar.contribution.ts (2)

22-27: 添加测试变量和命令常量

添加了用于测试的计数变量和命令常量,但变量名和命令名称过于简单,建议使用更具描述性的名称。

建议修改变量和命令名称为更具描述性的形式:

-let executeCount = 0;
-const TEST_MULTI_DIFF_COMMAND = 'testMultiDiffCommand';
+let multiDiffTestExecuteCount = 0;
+const TEST_MULTI_DIFF_EDITOR_COMMAND = 'testMultiDiffEditorCommand';

76-83: 条件添加文件对比项

使用了简单的计数变量来切换不同的文件对比组合,这个实现比较简单,但在更复杂的场景中可能不够灵活。

考虑使用更灵活的方式来管理多文件对比的测试用例,例如:

-        executeCount++ === 0
+        multiDiffTestExecuteCount++ % 3 === 0
           ? []
-          : [
+          : multiDiffTestExecuteCount % 3 === 1 ? [
               {
                 originalUri: Uri.file('./packages/startup/webpack.lite.config.js'),
                 modifiedUri: Uri.file('./packages/startup/webpack.preview.config.js'),
               },
-            ],
+            ] : [
+               {
+                 originalUri: Uri.file('./packages/startup/webpack.lite.config.js'),
+                 modifiedUri: Uri.file('./packages/startup/webpack.preview.config.js'),
+               },
+               {
+                 originalUri: Uri.file('./tsconfig.json'),
+                 modifiedUri: Uri.file('./tsconfig.web.json'),
+               },
+            ],

这样可以测试更多的多文件对比组合情况。

packages/ai-native/src/browser/chat/chat-edit-resource.ts (2)

39-46: 实现文档内容提供逻辑

根据URI查询参数提取代码内容,使用了合理的空值处理。但代码块查找使用了数组搜索,在大量代码块的情况下可能效率不高。

对于大量代码块的情况,考虑使用Map结构来提高查找效率:

@Injectable()
export class ChatEditSchemeDocumentProvider implements IEditorDocumentModelContentProvider {
  // 现有代码...

+ private codeBlocksMap: Map<string, any> = new Map();
+
+ private updateCodeBlocksMap() {
+   this.codeBlocksMap.clear();
+   const codeBlocks = this.baseApplyService.getSessionCodeBlocks();
+   for (const block of codeBlocks) {
+     if (block.toolCallId) {
+       this.codeBlocksMap.set(block.toolCallId, block);
+     }
+   }
+ }

  async provideEditorDocumentModelContent(uri: URI, encoding?: string | undefined): Promise<string> {
    // Get the content from the base apply service based on the uri query parameters
    const { id, side } = uri.getParsedQuery();
-   const codeBlocks = this.baseApplyService.getSessionCodeBlocks();
-   const codeBlock = codeBlocks.find((block) => block.toolCallId === id);
+   this.updateCodeBlocksMap();
+   const codeBlock = this.codeBlocksMap.get(id);
    const content = side === 'left' ? codeBlock?.originalCode : codeBlock?.updatedCode;
    return content || '';
  }
}

52-52: 处理模型释放事件

提供了空的模型释放处理方法,但应该考虑在资源释放时进行适当的清理。

模型释放时应考虑进行资源清理:

- onDidDisposeModel() {}
+ onDidDisposeModel(uri: URI) {
+   // 清理与该URI相关的资源或缓存
+ }
packages/editor/src/browser/multi-diff/multi-diff-resource.ts (1)

55-58: 资源关闭决策方法

shouldCloseResource方法目前总是返回true,允许关闭资源。注释指出这是临时实现,未来可能会增强。

建议未来实现时考虑检查是否有未保存的更改。

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

831-854: 重复且命名不一致的 DOM 节点字段易混淆

文件中同时存在 _multiFileDiffEditorDomNode_multiDiffEditorDomNode 两套字段,但只有后一套被真正使用。冗余成员不仅增加心智负担,还可能在后续维护中导致引用错误。
建议统一为一套命名(如 _multiDiffEditorDomNode),并删除未使用的 _multiFileDiffEditorDomNode* 相关代码。


2475-2482: 缺少与其他编辑器一致的 Ready 事件,可能影响外部监听

createMultiDiffEditor 里未触发类似 multiDiffEditorReady 的就绪信号,而 codeEditor, diffEditor, mergeEditor 均有对应 ReadyEvent。为保持一致,建议补充:

this.multiDiffEditor = editor;
this.multiDiffEditorReady?.ready(); // 需提前声明

或在现有生命周期中提供统一回调。

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

57-64: 事件发射器未在 dispose 中清理

multiDiffModelChangeEmitter 创建后只在类销毁时通过 super.dispose() 释放 multiDiffWidget,但未显式 disposeEmitter。为避免潜在的事件泄漏,建议在 dispose() 中补充:

this.multiDiffWidget.dispose();
+ this.multiDiffModelChangeEmitter.dispose();
packages/editor/src/common/multi-diff.ts (3)

17-34: 建议为接口添加JSDoc文档注释

接口 IMultiDiffSourceResolverServiceIMultiDiffSourceResolverIResolvedMultiDiffSource 缺少JSDoc注释。为这些关键接口添加文档注释将有助于开发者理解它们的用途、职责和使用方法。

添加文档注释示例:

+/**
+ * 多文件差异源解析器服务接口
+ * 负责管理和解析多文件差异源
+ */
export interface IMultiDiffSourceResolverService {
  registerResolver(resolver: IMultiDiffSourceResolver): IDisposable;

  resolve(uri: URI): Promise<IResolvedMultiDiffSource | undefined>;

  getResolvers(): IMultiDiffSourceResolver[];
}

+/**
+ * 多文件差异源解析器接口
+ * 负责处理特定类型的URI并解析对应的差异源
+ */
export interface IMultiDiffSourceResolver {
  canHandleUri(uri: URI): boolean;

  resolveDiffSource(uri: URI): Promise<IResolvedMultiDiffSource | undefined>;
}

+/**
+ * 已解析的多文件差异源接口
+ * 包含差异资源列表和可选的上下文键值对
+ */
export interface IResolvedMultiDiffSource {
  readonly resources: IValueWithChangeEvent<readonly MultiDiffEditorItem[]>;
  readonly contextKeys?: Record<string, ContextKeyValue>;
}

36-51: 建议优化键生成方法并添加类文档

  1. MultiDiffEditorItem 类缺少JSDoc文档注释,建议添加以说明其用途和重要性。
  2. getKey() 方法直接使用 JSON.stringify 可能在URI包含特殊字符或非常长时导致问题。

建议改进如下:

+/**
+ * 多文件差异编辑器项
+ * 表示差异编辑中的一对文件(原始文件和修改后文件)
+ */
export class MultiDiffEditorItem {
  constructor(
    readonly originalUri: URI | undefined,
    readonly modifiedUri: URI | undefined,
    readonly goToFileUri: URI | undefined,
    readonly contextKeys?: Record<string, ContextKeyValue>,
  ) {
    if (!originalUri && !modifiedUri) {
      throw new Error('Invalid arguments');
    }
  }

  getKey(): string {
-    return JSON.stringify([this.modifiedUri?.toString(), this.originalUri?.toString()]);
+    // 使用更可靠的方式生成唯一键
+    const original = this.originalUri?.toString() || 'undefined';
+    const modified = this.modifiedUri?.toString() || 'undefined';
+    return `${modified}:${original}`;
  }
}

61-61: 建议为方法参数添加详细文档注释

compareMultiple 方法参数缺少详细说明,这对于使用该API的开发者理解参数要求很重要。

建议添加参数说明:

  /**
   * Compare multiple file pairs
+  * @param resource 包含多文件差异信息的资源
+  * @param options 可选的资源打开选项
   */
  compareMultiple(resource: IResource, options?: IResourceOpenOptions): Promise<void>;
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between dc1a4c3 and d916e08.

📒 Files selected for processing (31)
  • packages/ai-native/src/browser/ai-core.contribution.ts (6 hunks)
  • packages/ai-native/src/browser/chat/chat-edit-resource.ts (1 hunks)
  • packages/ai-native/src/browser/chat/chat-multi-diff-source.ts (1 hunks)
  • packages/ai-native/src/browser/components/ChangeList.tsx (4 hunks)
  • packages/ai-native/src/browser/components/change-list.module.less (2 hunks)
  • packages/ai-native/src/browser/mcp/base-apply.service.ts (1 hunks)
  • packages/core-browser/src/common/common.command.ts (1 hunks)
  • packages/core-browser/src/monaco/index.ts (2 hunks)
  • packages/core-browser/src/services/label-service.ts (2 hunks)
  • packages/editor/src/browser/editor-collection.service.ts (3 hunks)
  • packages/editor/src/browser/editor.contribution.ts (5 hunks)
  • packages/editor/src/browser/editor.module.less (1 hunks)
  • packages/editor/src/browser/editor.view.tsx (3 hunks)
  • packages/editor/src/browser/index.ts (7 hunks)
  • packages/editor/src/browser/multi-diff/multi-diff-editor.ts (1 hunks)
  • packages/editor/src/browser/multi-diff/multi-diff-resolver.ts (1 hunks)
  • packages/editor/src/browser/multi-diff/multi-diff-resource.ts (1 hunks)
  • packages/editor/src/browser/multi-diff/multi-diff.contribution.ts (1 hunks)
  • packages/editor/src/browser/multi-diff/resolver.service.ts (1 hunks)
  • packages/editor/src/browser/types.ts (2 hunks)
  • packages/editor/src/browser/workbench-editor.service.ts (10 hunks)
  • packages/editor/src/common/editor.ts (3 hunks)
  • packages/editor/src/common/multi-diff.ts (1 hunks)
  • packages/i18n/src/common/en-US.lang.ts (1 hunks)
  • packages/i18n/src/common/zh-CN.lang.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-api/editor.ts (2 hunks)
  • packages/monaco/src/browser/monaco.service.ts (3 hunks)
  • packages/monaco/src/common/observable.ts (2 hunks)
  • packages/startup/entry/sample-modules/status-bar.contribution.ts (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (7)
packages/startup/entry/sample-modules/status-bar.contribution.ts (4)
packages/editor/src/browser/multi-diff/multi-diff-resolver.ts (1)
  • Injectable (12-44)
packages/editor/src/browser/multi-diff/multi-diff.contribution.ts (1)
  • Domain (16-54)
packages/editor/src/browser/editor.contribution.ts (2)
  • Domain (96-1415)
  • Domain (1417-1546)
packages/editor/src/common/multi-diff.ts (1)
  • MULTI_DIFF_SCHEME (13-13)
packages/editor/src/browser/multi-diff/multi-diff-resolver.ts (1)
packages/editor/src/common/multi-diff.ts (4)
  • IMultiDiffSourceResolver (25-29)
  • MultiDiffEditorItem (36-51)
  • MULTI_DIFF_SCHEME (13-13)
  • IResolvedMultiDiffSource (31-34)
packages/editor/src/browser/types.ts (1)
packages/editor/src/common/multi-diff.ts (2)
  • IMultiDiffSourceResolverService (15-15)
  • IMultiDiffSourceResolverService (17-23)
packages/monaco/src/browser/monaco.service.ts (1)
packages/monaco/src/browser/contrib/multi-diff-editor/resource-label.ts (1)
  • ResourceLabel (6-23)
packages/editor/src/browser/index.ts (2)
packages/editor/src/common/multi-diff.ts (2)
  • IMultiDiffSourceResolverService (15-15)
  • IMultiDiffSourceResolverService (17-23)
packages/editor/src/browser/types.ts (4)
  • BrowserEditorContribution (154-154)
  • BrowserEditorContribution (156-190)
  • MultiDiffSourceContribution (192-192)
  • MultiDiffSourceContribution (194-196)
packages/ai-native/src/browser/chat/chat-multi-diff-source.ts (2)
packages/ai-native/src/browser/chat/chat-edit-resource.ts (1)
  • Injectable (11-53)
packages/editor/src/common/multi-diff.ts (3)
  • IMultiDiffSourceResolver (25-29)
  • IResolvedMultiDiffSource (31-34)
  • MultiDiffEditorItem (36-51)
packages/ai-native/src/browser/ai-core.contribution.ts (2)
packages/core-browser/src/monaco/index.ts (2)
  • MonacoContribution (79-79)
  • MonacoContribution (92-106)
packages/monaco/src/common/types.ts (1)
  • IDisposable (27-29)
⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: unittest (ubuntu-latest, 18.x, node)
  • GitHub Check: unittest (ubuntu-latest, 18.x, jsdom)
  • GitHub Check: unittest (macos-latest, 18.x, node)
  • GitHub Check: unittest (macos-latest, 18.x, jsdom)
  • GitHub Check: build (macos-latest, 20.x)
  • GitHub Check: build (ubuntu-latest, 20.x)
  • GitHub Check: build-windows
  • GitHub Check: ubuntu-latest, Node.js 20.x
🔇 Additional comments (61)
packages/ai-native/src/browser/mcp/base-apply.service.ts (1)

38-38: 新增 URI scheme 常量命名验证
静态常量 CHAT_EDITING_SOURCE_RESOLVER_SCHEME 的命名清晰,且值 'chat-editing-source' 与对应的 ChatEditSchemeDocumentProvider 保持一致。请确认在 ai-core.contribution.ts 中已正确注册该 scheme。

packages/monaco/src/browser/monaco-api/editor.ts (1)

42-42:

Details

❓ Verification inconclusive

确认 createMultiFileDiffEditor 导入有效
请验证 @opensumi/monaco-editor-core/esm/vs/editor/standalone/browser/standaloneEditor 模块中已经导出 createMultiFileDiffEditor,以避免运行时 undefined 错误。


🏁 Script executed:

#!/bin/bash
# 验证 createMultiFileDiffEditor 是否在项目中定义并导出
rg "createMultiFileDiffEditor" -n .

Length of output: 203


🏁 Script executed:

#!/bin/bash
# 获取 @opensumi/monaco-editor-core 版本号
version=$(grep '"@opensumi/monaco-editor-core"' -n package.json | head -1 | sed -E 's/.*"@opensumi\/monaco-editor-core": *"([^"]+)".*/\1/')
echo "Detected @opensumi/monaco-editor-core version: $version"

# 拉取 standaloneEditor 模块并查找 createMultiFileDiffEditor 导出
curl -s "https://unpkg.com/@opensumi/monaco-editor-core@$version/esm/vs/editor/standalone/browser/standaloneEditor.js" \
  | grep -nE "export .*createMultiFileDiffEditor"

Length of output: 408


确认 createMultiFileDiffEditor 导入有效
请手动检查 @opensumi/monaco-editor-core/esm/vs/editor/standalone/browser/standaloneEditor.js 中是否已导出 createMultiFileDiffEditor,以避免运行时出现 undefined 错误。

packages/i18n/src/common/zh-CN.lang.ts (1)

1250-1250: 中文本地化条目添加完毕
确认 'aiNative.chat.view-changes': '查看改动' 已添加且与英文对应项同步,并已更新 i18n 系统来加载此新键值。

packages/i18n/src/common/en-US.lang.ts (1)

1481-1481: 英文本地化条目添加完毕
确认 'aiNative.chat.view-changes': 'View Changes' 已正确添加,并与中文翻译保持一致。

packages/core-browser/src/common/common.command.ts (1)

305-306: 新增多文件差异编辑器命令常量

常量命名符合项目规范,与其他编辑器命令如API_OPEN_EDITOR_COMMAND_IDAPI_OPEN_DIFF_EDITOR_COMMAND_ID保持一致的命名风格,这有助于代码的一致性和可维护性。

packages/core-browser/src/services/label-service.ts (2)

128-128: 函数调用更新为使用重命名后的函数

将内部使用的getIconClass更新为了新重命名的getResourceIconClass函数。此修改使代码逻辑保持一致,同时也使得引用明确清晰。


264-329: 函数重命名并导出为公共API

getIconClass重命名为getResourceIconClass并将其导出,使外部模块可以利用资源URI的图标类检索逻辑。这种改变遵循了良好的代码重用实践,使功能组件化并提高了可重用性。

这一修改与PR中引入的多文件差异编辑器功能相匹配,新的多文件差异资源可能需要适当的图标解析支持。

🧰 Tools
🪛 Biome (1.9.4)

[error] 274-274: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 289-290: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

packages/core-browser/src/monaco/index.ts (2)

3-3: 导入MultiDiffEditorWidget类型

从Monaco编辑器核心包导入了MultiDiffEditorWidget类型,为新增的多文件差异编辑器功能提供类型支持,这是符合TypeScript最佳实践的做法。


53-57: 新增创建多文件差异编辑器widget的抽象方法

新增了createMultiDiffEditorWidget抽象方法,该方法与类中已有的createCodeEditorcreateDiffEditor等方法保持了一致的风格和参数模式。这种一致性有助于开发者理解和使用API。

该方法将由具体的MonacoService实现类提供实现,为多文件差异编辑器功能提供基础设施。

packages/editor/src/browser/types.ts (2)

30-30: 导入多文件差异源解析器服务接口

../common/multi-diff模块导入了IMultiDiffSourceResolverService接口,为新增的多文件差异功能提供类型支持。


192-196: 定义多文件差异源贡献点

新增了MultiDiffSourceContribution符号和接口,遵循了项目中已有的贡献点模式(如BrowserEditorContribution)。这个接口允许组件注册多文件差异源解析器,从而扩展多文件差异编辑器的能力。

接口设计简洁明了,只包含一个registerMultiDiffSourceResolver方法,符合单一职责原则,有助于后续组件实现该接口。

packages/ai-native/src/browser/components/change-list.module.less (4)

23-25: 样式过渡效果优化

过渡效果的添加使悬停状态变化更加平滑,提升了用户体验。


38-41: 图标样式与交互优化

添加间距并确保图标继承颜色是一个很好的改进,使元素更加一致和易于维护。


48-48: 布局对齐优化

添加align-items: center确保了标题内容的垂直居中对齐,提升了视觉一致性。


131-143: 新增的查看变更按钮样式实现得当

新增的.viewChanges类样式设计合理,与现有UI风格一致。悬停效果和过渡动画增强了交互体验,图标颜色继承确保了样式的一致性。

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

30-30: 确保导入顺序和分组一致

导入的相关类型和实现已正确添加,与项目的导入规范一致。

Also applies to: 40-40, 42-42


157-163: 多文件差异编辑器创建方法实现完善

新增的createMultiDiffEditor方法设计合理,遵循了与其他编辑器创建方法一致的模式:

  1. 获取转换后的Monaco配置选项
  2. 创建底层编辑器组件
  3. 合并选项
  4. 使用依赖注入创建并返回编辑器实例

方法签名和实现与整体代码风格保持一致。

packages/ai-native/src/browser/components/ChangeList.tsx (3)

4-5: 依赖导入优化

新增的导入正确地包含了所需的WorkbenchEditorService和其他依赖,保持了导入的清晰和有序。


29-29: 编辑器服务注入

使用useInjectable注入WorkbenchEditorService的方式符合项目的依赖注入模式。


109-116: UI布局更新

在标题部分添加查看变更按钮的集成方式合理,使用现有的样式结构保持了UI的一致性。按钮的布局顺序合理,从切换按钮到变更统计再到查看变更,符合用户操作的自然流程。

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

1-5: 导入依赖设计合理

导入了必要的依赖,包括URI处理、资源图标类和样式模块,符合项目的模块组织结构。


20-22: 清理方法简单明了

clear方法实现简单,有效地清除了元素内容。

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

19-19: 引入新的多文件差异编辑器接口

引入了新的 IMultiDiffEditor 接口为多文件差异编辑器特性提供支持。


348-359: 扩展 EditorCollectionService 抽象类以支持多文件差异编辑器

新增的抽象方法 createMultiDiffEditor 使编辑器集合服务能够创建多文件差异编辑器实例。方法签名与其他编辑器创建方法保持一致,维持了良好的接口设计。


885-885: 添加新的编辑器打开类型

EditorOpenType 枚举中添加了 multiDiff 类型,使系统能够识别和支持新的多文件差异编辑器类型。

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

9-9: 引入多文件差异编辑器所需的依赖

正确导入了实现多文件差异编辑器所需的相关组件和服务。

Also applies to: 19-19, 23-26, 31-31


161-192: 实现多文件差异编辑器部件创建方法

该方法实现了创建多文件差异编辑器部件的功能,但有两个注释掉的行(189-190行)可能表示实现不完整或有意禁用某些功能。

-    // this.overrideMonacoKeybindingService(editor);
-    // this.addClickEventListener(editor);
+    this.overrideMonacoKeybindingService(editorWidget);
+    this.addClickEventListener(editorWidget);

请确认是否有意注释这些行,以及是否需要在合并前取消注释并实现这些功能?如果有意注释,建议添加说明注释解释原因。


173-185: 资源标签创建实现

createResourceLabel 回调函数的实现合理,能够正确处理 URI 为空的情况并提供清理方法。资源标签的创建和管理方式符合组件设计模式。

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

1-35: 多文件差异源解析器服务实现

MultiDiffSourceResolverService 类实现了 IMultiDiffSourceResolverService 接口,提供了注册、解析和获取解析器的功能。实现逻辑清晰,使用 Set 存储解析器以避免重复,并正确实现了所有必要的方法。

注意到在 registerResolver 方法中有一个显式的重复检查(第16-18行),虽然 Set 本身就会自动防止重复元素。不过这种显式检查可能是为了提供更清晰的错误消息,有助于调试。

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

1-44: 多文件差异解析器实现

MultiDiffResolver 类实现了 IMultiDiffSourceResolver 接口,能够管理和解析基于 MULTI_DIFF_SCHEME 方案的 URI 的多文件差异源。该实现支持注册新源或更新现有源,并正确处理解析和释放资源。

实现使用 ValueWithChangeEvent 包装 MultiDiffEditorItem 数组,这种设计能够在源发生变化时通知监听器,支持编辑器的反应式更新。

packages/ai-native/src/browser/ai-core.contribution.ts (4)

53-54: 实现 MultiDiffSourceContribution 接口

类定义和实现列表中已添加 MultiDiffSourceContribution 接口,确保了多文件对比功能的正确集成。

Also applies to: 73-77


102-104: 导入聊天编辑资源提供器

已正确导入 ChatEditSchemeDocumentProvider 类,用于支持聊天会话中的编辑资源。


282-286: 注入多文件对比相关的依赖

已添加两个关键依赖的自动注入,这些依赖对于实现聊天会话中的多文件对比功能至关重要。


292-298: 实现 MultiDiffSourceContribution 接口方法

这两个方法负责注册多文件对比源解析器和编辑器文档模型内容提供器,是实现多文件对比功能的核心部分。实现简洁明了,职责分明。

packages/editor/src/browser/editor.view.tsx (3)

319-319: 添加多文件对比编辑器的 React 引用

为多文件对比编辑器容器添加了 React 引用,与现有的编辑器引用保持一致的命名风格。


371-384: 添加多文件对比编辑器 DOM 挂载逻辑

实现了多文件对比编辑器的 DOM 元素挂载和大小观察功能,使用 ResizeObserver 确保编辑器在容器大小变化时能够正确布局。代码风格与其他编辑器类型的处理一致。


497-502: 添加多文件对比编辑器的 DOM 容器

为多文件对比编辑器添加了条件渲染的 DOM 容器,样式类和条件判断与其他编辑器类型保持一致,使用了正确的 CSS 类和引用。

packages/startup/entry/sample-modules/status-bar.contribution.ts (3)

13-20: 添加命令相关的导入

导入了实现命令功能所需的接口和服务,包括 CommandContribution, CommandRegistry, CommandService 以及多文件对比所需的 URI 和方案常量。


27-33: 扩展贡献类以实现命令接口

正确地扩展了 StatusBarContribution 类以实现 CommandContribution 接口,并添加了 CommandService 依赖。


98-104: 添加状态栏测试按钮

添加了一个状态栏按钮用于测试多文件对比功能,提示文本清晰地描述了功能。

packages/ai-native/src/browser/chat/chat-edit-resource.ts (4)

1-8: 导入必要的依赖

正确导入了实现文档模型内容提供器所需的所有依赖,包括核心服务和编辑器相关接口。


11-33: 实现文档模型内容提供器类

类定义和依赖注入清晰,创建了必要的事件发射器用于内容变更通知。依赖了多个服务以支持聊天会话中的编辑资源。


35-37: 实现方案处理逻辑

方法判断当前URI方案是否由该提供器处理,使用了BaseApplyService中定义的常量,确保了一致性。


48-50: 实现只读判断逻辑

所有文档被标记为只读,符合查看差异的场景需求。

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

16-17: 良好的类注解使用

类注解 @Domain 正确地将此类标记为同时实现 BrowserEditorContributionMultiDiffSourceContribution 接口,使其能够被依赖注入系统正确识别和实例化。


27-30: 多Diff源解析器注册实现

这个方法将内置的 multiDiffResolver 注册到解析器服务中,使其可以通过命令使用。代码简洁明了,功能定义清晰。


32-34: 资源提供器注册实现

该方法将 multiDiffResourceProvider 注册到资源服务中,使多文件比对能够被识别为一种资源类型。实现简单有效。


36-53: 编辑器组件解析器实现

这个方法实现了对多文件对比编辑器组件的支持。它通过检查是否有注册的解析器能够处理给定的URI方案来确定优先级,并在支持时添加multiDiff编辑器打开类型。

实现逻辑清晰,特别是优先级判断和结果推送的处理方式得当。

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

236-238: 依赖注入MultiDiffResolver

正确地注入了MultiDiffResolver依赖,这是实现多文件对比编辑器命令的基础。


1240-1268: 多文件对比编辑器命令实现

此命令实现了打开多文件对比编辑器的功能,支持指定标题、多文件对比源URI和资源列表。代码实现以下关键功能:

  1. 从配置中提取原始和修改后的URI
  2. 将URI组件转换为URI对象并创建MultiDiffEditorItem实例
  3. 将源注册到resolver中,支持相同URI的更新操作
  4. 打开带有指定标题的多文件对比编辑器

实现得当且考虑了URI的正确转换和更新场景。

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

9-25: 资源提供器类依赖注入

类定义和依赖注入实现正确,继承了WithEventBus并实现了IResourceProvider接口。注入了所有必要的服务,包括标签服务、资源服务、文件服务客户端、应用配置和多文件对比源解析器服务。


26-34: URI处理优先级方法

handlesUri方法通过检查所有注册的解析器是否能处理给定URI来确定优先级。返回10表示支持,-1表示不支持,这种设计简单明了。


36-53: 资源提供实现

provideResource方法从URI查询参数中提取名称和源文件信息,并尝试从第一个修改文件URI获取图标。如果没有找到,则使用通用的diff图标。返回的资源对象包含名称、图标、URI、是否支持恢复以及包含源的元数据。

实现合理且考虑了图标获取的回退策略。

packages/editor/src/browser/index.ts (6)

187-190: 多文件对比源解析器服务注册

正确注册了IMultiDiffSourceResolverService令牌并将其绑定到MultiDiffSourceResolverService实现类,这是实现多文件对比功能的基础服务。


193-193: 多文件对比编辑器贡献注册

MultiDiffEditorContribution添加到模块提供者列表中,确保它在应用启动时被正确初始化。


207-207: 贡献提供者扩展

通过添加MultiDiffSourceContribution到贡献提供者列表,允许其他模块通过实现此接口来提供多文件对比源。


236-238: 多文件对比源解析器服务依赖注入

EditorClientAppContribution中注入IMultiDiffSourceResolverService,使其可用于初始化过程。


242-244: 多文件对比源贡献依赖注入

注入MultiDiffSourceContribution提供者,使EditorClientAppContribution能够访问所有多文件对比源贡献实现。


263-265: 多文件对比源解析器初始化

初始化过程中,遍历所有MultiDiffSourceContribution实现并调用其registerMultiDiffSourceResolver方法,确保所有多文件对比源都被正确注册到解析器服务中。

这种设计允许各种模块(如AI原生模块)提供自己的多文件对比源实现,增强了系统的扩展性。

packages/editor/src/common/multi-diff.ts (2)

1-12: 代码导入结构良好,满足功能需求

导入的各个模块和类型清晰明确,符合功能需求。代码遵循了TypeScript的最佳实践,使用了显式类型声明。


53-87: 接口设计合理且文档完善

IMultiDiffEditor 接口设计合理,方法职责清晰,并且有良好的JSDoc文档。接口扩展了 IDisposable,确保了资源的正确释放。API设计符合编辑器功能的需求,包括比较、检索、布局和事件通知等核心功能。

Comment thread packages/monaco/src/common/observable.ts
Comment thread packages/startup/entry/sample-modules/status-bar.contribution.ts
Comment thread packages/ai-native/src/browser/chat/chat-multi-diff-source.ts Outdated
Comment thread packages/ai-native/src/browser/chat/chat-multi-diff-source.ts Outdated
Comment thread packages/editor/src/browser/workbench-editor.service.ts
Comment thread packages/editor/src/browser/workbench-editor.service.ts
Comment thread packages/editor/src/browser/multi-diff/multi-diff-editor.ts
Comment thread packages/editor/src/browser/multi-diff/multi-diff-editor.ts
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 29, 2025

Codecov Report

Attention: Patch coverage is 19.09814% with 305 lines in your changes missing coverage. Please review.

Project coverage is 52.91%. Comparing base (dc1a4c3) to head (08b6d70).
Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
...editor/src/browser/multi-diff/multi-diff-editor.ts 16.94% 78 Missing and 20 partials ⚠️
...-native/src/browser/chat/chat-multi-diff-source.ts 0.00% 34 Missing and 4 partials ⚠️
packages/monaco/src/common/observable.ts 12.19% 33 Missing and 3 partials ⚠️
...s/ai-native/src/browser/chat/chat-edit-resource.ts 0.00% 23 Missing and 2 partials ⚠️
...ges/editor/src/browser/workbench-editor.service.ts 21.42% 18 Missing and 4 partials ⚠️
...itor/src/browser/multi-diff/multi-diff-resolver.ts 19.04% 15 Missing and 2 partials ⚠️
...itor/src/browser/multi-diff/multi-diff-resource.ts 41.37% 13 Missing and 4 partials ⚠️
.../editor/src/browser/multi-diff/resolver.service.ts 18.75% 11 Missing and 2 partials ⚠️
packages/monaco/src/browser/monaco.service.ts 18.75% 12 Missing and 1 partial ⚠️
...rowser/contrib/multi-diff-editor/resource-label.ts 25.00% 9 Missing ⚠️
... and 4 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4523      +/-   ##
==========================================
- Coverage   53.03%   52.91%   -0.13%     
==========================================
  Files        1668     1677       +9     
  Lines      102934   103315     +381     
  Branches    22286    22377      +91     
==========================================
+ Hits        54590    54664      +74     
- Misses      40216    40478     +262     
- Partials     8128     8173      +45     
Flag Coverage Δ
jsdom 48.41% <19.09%> (-0.12%) ⬇️
node 12.07% <0.00%> (-0.05%) ⬇️

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.

Copy link
Copy Markdown
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 (1)
packages/editor/src/browser/multi-diff/multi-diff-editor.ts (1)

122-124: 使用错误的API

ValueWithChangeEvent.const 方法并不存在,这将导致编译错误。应使用已导入的 constObservable 函数。

请应用以下修复:

- ? { resources: ValueWithChangeEvent.const(resource.metadata.sources) }
+ ? { resources: constObservable(resource.metadata.sources) }
🧹 Nitpick comments (5)
packages/editor/src/browser/multi-diff/multi-diff-editor.ts (5)

157-161: 添加空值检查以增强代码健壮性

当前代码假设 originalmodifiedinstance 属性始终可用。虽然使用了可选链接操作符,但建议在创建 result 对象时进行更全面的空值检查。

建议更健壮的实现方式:

const result = {
  multiDiffEditorItem: r,
- original: original?.instance.getMonacoModel(),
- modified: modified?.instance.getMonacoModel(),
+ original: original?.instance?.getMonacoModel() ?? null,
+ modified: modified?.instance?.getMonacoModel() ?? null,
  contextKeys: r.contextKeys,
  options: {
    readOnly: modified?.instance.readonly,
    ...this.convertedOptions.diffOptions,
  },

226-228: reveal方法缺少参数验证和错误处理

reveal方法直接将参数传递给底层widget,但没有验证参数的有效性或处理可能的错误。如果resource无效,可能导致未处理的异常。

添加参数验证和错误处理:

reveal(resource: IMultiDiffResourceId, options?: { range?: Range; highlight: boolean }): void {
+ if (!resource) {
+   return;
+ }
+ try {
    this.multiDiffWidget.reveal(resource, options);
+ } catch (error) {
+   console.error('Failed to reveal resource:', error);
+ }
}

167-173: 优化配置变更监听方式

当前实现为每个文档项都创建了一个偏好设置变更监听器,这可能在大量文件差异比较时导致性能问题。

考虑使用一个共享的监听器来处理所有文档项的配置变更,或者在适当的时候清理这些监听器:

onOptionsDidChange: (h) => {
- return this.preferenceService.onPreferenceChanged((e) => {
+ const disposable = this.preferenceService.onPreferenceChanged((e) => {
    if (e.affects(uri.toString()) && e.preferenceName.includes('editor')) {
      h();
    }
  });
+ return disposable; // 返回disposable以便后续清理
}

214-224: getCurrentDiffEntry方法实现效率低下

当前实现先获取活动编辑器,然后从原始编辑器获取URI,最后再次查找文档差异项,这个过程可能不是最高效的。

考虑使用MultiDiffEditorWidget提供的更直接方法(如果存在):

getCurrentDiffEntry(): IDocumentDiffItem | undefined {
+ // 如果MultiDiffEditorWidget有直接提供当前活动项的方法,请使用它
+ // return this.multiDiffWidget.getActiveDocumentDiffItem();

  const activeControl = this.multiDiffWidget.getActiveControl();
  if (!activeControl) {
    return undefined;
  }
  const originalUri = activeControl.getOriginalEditor().getModel()?.uri;
  if (!originalUri) {
    return undefined;
  }
  return this.multiDiffWidget.findDocumentDiffItem(originalUri);
}

176-176: RefCounted对象创建方式可能引起资源管理复杂性

当前代码使用RefCounted.createOfNonDisposable将多个可释放对象组合在一起,这种模式虽然有效,但增加了资源管理的复杂性。

在大型代码库中,这种资源管理模式可能变得难以追踪。考虑封装这种模式到一个更高级别的抽象中,或者使用更明确的资源生命周期管理策略。例如,可以创建一个专门的DiffItemResourceManager类来处理这些资源的生命周期管理。

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between d916e08 and c36eb92.

📒 Files selected for processing (4)
  • packages/ai-native/src/browser/chat/chat-multi-diff-source.ts (1 hunks)
  • packages/editor/src/browser/multi-diff/multi-diff-editor.ts (1 hunks)
  • packages/editor/src/browser/workbench-editor.service.ts (10 hunks)
  • packages/startup/entry/sample-modules/status-bar.contribution.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/startup/entry/sample-modules/status-bar.contribution.ts
  • packages/ai-native/src/browser/chat/chat-multi-diff-source.ts
  • packages/editor/src/browser/workbench-editor.service.ts
⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: build-windows
  • GitHub Check: build (macos-latest, 20.x)
  • GitHub Check: build (ubuntu-latest, 20.x)
  • GitHub Check: unittest (ubuntu-latest, 18.x, jsdom)
  • GitHub Check: ubuntu-latest, Node.js 20.x
  • GitHub Check: unittest (macos-latest, 18.x, jsdom)
  • GitHub Check: unittest (ubuntu-latest, 18.x, node)
  • GitHub Check: unittest (macos-latest, 18.x, node)
🔇 Additional comments (2)
packages/editor/src/browser/multi-diff/multi-diff-editor.ts (2)

74-74: 代码中存在待解决的问题

注释中提到当前设计不支持动态修改 resource 的 name,且在 diff 数量变化时会有问题。

请考虑是否需要在正式发布前解决此问题,或者添加更多细节说明何时会出现此问题及其影响。这个限制应该在文档中明确说明,以便用户了解使用限制。


192-193: 通过调用dispose方法正确释放旧模型

代码现在在赋值新的multiDiffModel之前调用了dispose()方法,这解决了之前审阅中提出的内存泄漏问题。

Comment thread packages/editor/src/browser/multi-diff/multi-diff-editor.ts
Comment thread packages/editor/src/browser/multi-diff/multi-diff-editor.ts
Comment thread packages/ai-native/src/browser/components/ChangeList.tsx Outdated
Comment thread packages/editor/src/browser/multi-diff/multi-diff-editor.ts Outdated
Comment thread packages/editor/src/browser/multi-diff/multi-diff-editor.ts Outdated
Comment thread packages/editor/src/browser/multi-diff/multi-diff-resource.ts
Comment thread packages/editor/src/browser/multi-diff/multi-diff.contribution.ts Outdated
Comment thread packages/startup/entry/sample-modules/status-bar.contribution.ts Outdated
@ensorrow ensorrow requested a review from erha19 May 8, 2025 07:57
Copy link
Copy Markdown
Member

@erha19 erha19 left a comment

Choose a reason for hiding this comment

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

LGTM

@ensorrow ensorrow merged commit a693495 into main May 8, 2025
11 checks passed
@ensorrow ensorrow deleted the feat/multi-file-diff branch May 8, 2025 08:08
@erha19 erha19 mentioned this pull request May 20, 2025
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.

2 participants