Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support VSCode API: Workspace.save and Workspace.saveAs #4277

Merged
merged 11 commits into from
Jan 2, 2025

Conversation

hui2334387208
Copy link
Contributor

@hui2334387208 hui2334387208 commented Dec 26, 2024

Types

  • 🎉 New Features

Background or solution

Changelog

Summary by CodeRabbit

  • 新功能

    • 增加了文件保存功能,包括 savesaveAs 方法,允许用户保存当前编辑器状态或指定新文件名。
    • 文件对话框服务增强,支持用户通过对话框选择文件保存位置和名称。
    • 增加了工作区 API 中的保存方法,提升了文件管理能力。
    • 更新了窗口对话框服务,支持选择是否以新文件名保存。
    • 增加了对文件创建的支持,允许用户在指定路径下创建新文件。
  • 文档

    • 更新了接口和命名空间,增加了与文件保存相关的新方法。
  • 修复

    • 改进了错误处理和日志记录功能,以确保保存操作的可靠性。
  • 演示
2024-12-27.17.04.01.mov

@opensumi opensumi bot added the 🎨 feature feature required label Dec 26, 2024
Copy link
Contributor

coderabbitai bot commented Dec 26, 2024

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.

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:*"

概述

演练

此拉取请求引入了一系列文件保存和对话框交互的新功能。主要变更包括在多个服务和接口中添加 savesaveAs 方法,如 WorkbenchEditorServiceImplWorkbenchEditorService 和相关的扩展主机工作空间类。这些新方法允许用户保存当前编辑器状态,并提供通过对话框选择新文件位置的能力。

变更

文件路径 变更摘要
packages/editor/src/browser/workbench-editor.service.ts 添加 save()saveAs() 方法,引入文件服务和对话框服务
packages/editor/src/common/editor.ts 添加抽象 save()saveAs() 方法到 WorkbenchEditorService
packages/editor/src/common/mocks/workbench-editor.service.ts MockWorkbenchEditorService 中添加 save()saveAs() 方法
packages/extension/__tests__/browser/extension-service/extension-service-mock-helper.ts MockWorkbenchEditorService 中添加 save()saveAs() 方法
packages/extension/src/browser/vscode/api/main.thread.workspace.ts 添加 $save()$saveAs() 方法,支持文件保存操作
packages/extension/src/common/vscode/workspace.ts IMainThreadWorkspace 接口中添加 $save()$saveAs() 方法
packages/extension/src/hosted/api/vscode/ext.host.workspace.ts ExtHostWorkspace 中添加 save()saveAs() 方法,并引入 URI 类型
packages/file-tree-next/src/browser/dialog/file-dialog.service.ts 新增 saveAs()createFile() 方法,增强文件对话框功能
packages/file-tree-next/src/browser/dialog/file-dialog.view.tsx 修改 ensure 函数以支持 saveAs 选项
packages/overlay/src/common/index.ts 更新 showSaveDialog() 方法签名,支持 saveAs 选项
packages/types/vscode/typings/vscode.workspace.d.ts vscode.workspace 命名空间中添加 savesaveAs 函数

建议的标签

🎨 feature

建议的审阅者

  • bk1012

可能相关的 PR


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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.
    • 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.

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. (Beta)
  • @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: 0

🧹 Nitpick comments (9)
packages/file-tree-next/src/browser/dialog/file-dialog.service.ts (3)

32-34: 新增 workbenchEditorService 字段
工作台编辑器服务的注入有助于文件打开流程,但建议在后续调用时增加错误处理,以提高健壮性。


140-151: saveAs 方法实现

  1. 建议在执行 this.workbenchEditorService.open(...) 之前对新文件路径做有效性或存在性校验。
  2. 函数内含 TODO 标注,后续如果迁移 fileSystemProvider,需要确保依赖关系调整安全。

152-161: createFile 方法实现

  1. readFilecreateFile 操作建议增加异常捕获,以防出现网络或权限导致的错误无法及时处理。
  2. 使用 content.toString() 并指定 'utf8' 编码可行,但若存在其他编码文件需考虑兼容性。
packages/extension/src/browser/vscode/api/main.thread.workspace.ts (1)

130-138: 新增 $save 方法

  1. 通过 editorService.save() 完成当前资源保存,若异常则返回 undefined
  2. 可额外考虑在调用前后对传入 URI 进行校验,以免出现不合法状态。
packages/file-tree-next/src/browser/dialog/file-dialog.view.tsx (1)

75-81: 对“saveAs”逻辑的条件判断

在此处,当 options.saveAs 为真时才执行 fileService.saveAs。逻辑上可行,但建议确保 oldFilePathnewFilePath 的构建方式不会出现路径拼接错误或用户输入无效情况。如果需要更健壮,可在调用前验证路径的有效性并在界面给出提示。

packages/extension/src/hosted/api/vscode/ext.host.workspace.ts (1)

2-11: 关于新的公共引用导入

此处批量引入了多种核心工具和类型,整体代码可读性尚可。但请留意确保只导入实际需要的依赖,以免增加包大小或引发循环依赖。

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

552-561: 新增的保存功能抽象方法

save()saveAs(uri: URI) 的抽象定义为编辑器提供了基础的保存操作扩展点,能与其他服务无缝衔接。确保在实现类中妥善处理异常情况,并考虑交互提示(如文件覆盖警告)。

packages/extension/__tests__/browser/extension-service/extension-service-mock-helper.ts (2)

335-337: 新增 save() 方法逻辑尚未实现

此处只是简单抛出了 Not implemented 错误。若需要在单元测试或集成测试中模拟具体保存行为,建议提供最少量的模拟逻辑(例如返回一个已完成的 Promise)或更完善的自定义实现,以便在测试环境下进行更真实的行为校验。


338-340: 新增 saveAs(uri: URI) 方法逻辑尚未实现

同上,当前实现仅抛出 Not implemented。如果后续测试需要校验保存到新文件路径产生的行为,建议在 Mock 中增加对应的模拟返回值或成功、失败的场景,以保证测试覆盖到相关逻辑。

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1a08936 and a1ccf50.

📒 Files selected for processing (11)
  • packages/editor/src/browser/workbench-editor.service.ts (4 hunks)
  • packages/editor/src/common/editor.ts (1 hunks)
  • packages/editor/src/common/mocks/workbench-editor.service.ts (1 hunks)
  • packages/extension/__tests__/browser/extension-service/extension-service-mock-helper.ts (1 hunks)
  • packages/extension/src/browser/vscode/api/main.thread.workspace.ts (1 hunks)
  • packages/extension/src/common/vscode/workspace.ts (1 hunks)
  • packages/extension/src/hosted/api/vscode/ext.host.workspace.ts (3 hunks)
  • packages/file-tree-next/src/browser/dialog/file-dialog.service.ts (3 hunks)
  • packages/file-tree-next/src/browser/dialog/file-dialog.view.tsx (1 hunks)
  • packages/overlay/src/common/index.ts (1 hunks)
  • packages/types/vscode/typings/vscode.workspace.d.ts (1 hunks)
🔇 Additional comments (22)
packages/file-tree-next/src/browser/dialog/file-dialog.service.ts (3)

5-7: 依赖引用检查
这些新增的导入语句为文件读取、编辑器服务和对话框功能提供支持,目前未发现冲突或重叠问题,使用合理。


29-31: 新增 fileServiceClient 字段
此字段使该服务可直接调用文件服务进行文件操作,实现符合需求。


35-37: 新增 dialogService 字段
注入对话框服务,用于与用户进行交互式对话,功能集成正常。

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

47-47: isWindows 导入
此处导入用于根据操作系统区分路径处理,逻辑上无冲突。


51-51: 引入 path
新增 path 工具辅助路径拼接与解析,十分实用。


53-53: 引入 IFileServiceClient
为后续的文件读写及保存提供支持,导入无误。


55-55: 引入 IWindowDialogService 等
为使用系统对话框进行保存路径选择作准备,场景适配合理。


131-133: fileServiceClient 字段自动注入
便于统一管理文件存储操作,实现方式合理。


181-183: windowDialogService 字段自动注入
弹窗服务为 saveAs 提供交互入口,与整体功能结合良好。


263-267: 新增 save 方法
仅在当前编辑器组存在时保存当前资源,逻辑简单明了,符合预期。


269-281: 新增 saveAs 方法

  1. 显示保存对话框让用户选择保存位置,体验较好。
  2. 在 Windows 下应注意非法路径字符,提高可用性和健壮性。

282-282: 方法结束行
实现已完成,没有其他明显问题。

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

34-36: 添加 mock save 方法
此方法抛出未实现错误,如需单测覆盖可适当模拟保存行为。


38-40: 添加 mock saveAs 方法
抛出未实现错误,用于在测试场景中模拟不同保存路径交互。

packages/overlay/src/common/index.ts (1)

95-95: showSaveDialog 方法签名更新
增加可选 saveAs 字段,暂未发现与现有功能冲突,可增强对不同保存需求的适配。

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

140-148: 新增 $saveAs 方法
editorService.saveAs(uri) 逻辑契合,异常处理方式一致且清晰。

packages/extension/src/common/vscode/workspace.ts (1)

14-15: 新增方法的接口定义看起来合理

这两个方法 $save$saveAs 在接口层面上符合保存逻辑的需求,能够为后续的具体实现提供清晰的契约。请在对应的实现中做好异常处理,防止未捕获错误导致线程异常退出。

packages/extension/src/hosted/api/vscode/ext.host.workspace.ts (3)

130-131: 在 createWorkspaceApiFactory 中注入新方法

通过将 savesaveAs 暴露到 workspace,可为外部插件提供统一的保存 API,增强扩展性。实现思路简单明了,可继续保持。


424-427: ExtHostWorkspace 的 save 方法

此处 save(uri: URI) 向主线程代理调用 $save,符合主从线程分离的架构。建议在后续实现时加入失败重试或错误提示,以提升用户体验。


428-431: ExtHostWorkspace 的 saveAs 方法

save 方法一致,saveAs 同样通过代理调用 $saveAs,在远程过程调用模型下逻辑清晰。请注意在调用时做好文件存储位置的验证和错误捕获。

packages/types/vscode/typings/vscode.workspace.d.ts (2)

407-416: 新增 workspace.save(uri: Uri) API

此方法允许通过给定的 Uri 保存对应的已打开编辑器,并返回保存后的资源路径或 undefined。从接口设计看,功能完备度良好,但请确认所有调用端已做好相应的异常处理和空返回情况的兼容。当无法找到对应的编辑器或保存失败时,返回 undefined 合理但需注意使用方的容错逻辑。


418-429: 新增 workspace.saveAs(uri: Uri) API

此方法增加了“另存为”逻辑,同样返回 Uri | undefined。建议在未来完善错误处理或用户取消操作时更明确地标识取消原因,以便调用方进行区分和处理。此外,请在相关的交互或 UI 上通知用户保存目标位置可能发生的异常状态。整体功能拓展性较好。

Copy link

codecov bot commented Dec 26, 2024

Codecov Report

Attention: Patch coverage is 19.51220% with 66 lines in your changes missing coverage. Please review.

Project coverage is 54.24%. Comparing base (b093d45) to head (299530d).
Report is 20 commits behind head on main.

Files with missing lines Patch % Lines
...ree-next/src/browser/dialog/file-dialog.service.ts 32.35% 20 Missing and 3 partials ⚠️
...ges/editor/src/browser/workbench-editor.service.ts 15.38% 17 Missing and 5 partials ⚠️
...on/src/browser/vscode/api/main.thread.workspace.ts 0.00% 13 Missing and 2 partials ⚠️
...ension/src/hosted/api/vscode/ext.host.workspace.ts 14.28% 6 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4277      +/-   ##
==========================================
+ Coverage   53.72%   54.24%   +0.51%     
==========================================
  Files        1622     1633      +11     
  Lines       98562    99804    +1242     
  Branches    20142    21660    +1518     
==========================================
+ Hits        52951    54135    +1184     
- Misses      37906    37944      +38     
- Partials     7705     7725      +20     
Flag Coverage Δ
jsdom 49.76% <19.51%> (+0.57%) ⬆️
node 12.25% <0.00%> (-3.21%) ⬇️

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.

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 (1)
packages/editor/src/browser/workbench-editor.service.ts (1)

263-267: save 方法实现可以增强

当前实现过于简单,建议增加错误处理和状态检查。

建议按如下方式改进:

 async save() {
+  if (!this._currentEditorGroup) {
+    return;
+  }
+
+  try {
     await this._currentEditorGroup.saveCurrent();
+  } catch (error) {
+    throw new Error(`保存失败: ${error.message}`);
+  }
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a1ccf50 and 73de913.

📒 Files selected for processing (3)
  • packages/editor/src/browser/workbench-editor.service.ts (4 hunks)
  • packages/editor/src/common/editor.ts (1 hunks)
  • packages/file-tree-next/src/browser/dialog/file-dialog.service.ts (3 hunks)
🔇 Additional comments (1)
packages/editor/src/common/editor.ts (1)

552-555: 新增的抽象方法设计合理

这两个抽象方法的签名设计清晰且符合预期:

  1. save 方法返回 void Promise,符合保存操作的语义
  2. saveAs 方法接收 URI 参数并返回可选的新 URI,满足另存为的使用场景

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: 1

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

276-299: saveAs 方法实现可以优化

建议进行以下改进:

  1. 使用 localize 函数对错误消息和对话框标题进行国际化
  2. 添加类型注释提高代码可读性
 private getDefaultSavePath(uri: URI): string {
   const defaultPath = uri.path.toString() !== '/' ? path.dirname(uri.path.toString()) : this.appConfig.workspaceDir;
   return isWindows ? defaultPath.replace(/\\/g, '/') : defaultPath;
 }

 async saveAs(uri: URI): Promise<URI | undefined> {
   if (!this._currentEditorGroup || !uri) {
     return undefined;
   }

   try {
     const defaultPath = this.getDefaultSavePath(uri);
     const result = await this.windowDialogService.showSaveDialog({
-      saveLabel: 'SaveAs File:',
+      saveLabel: localize('saveAs.dialog.title', 'SaveAs File:'),
       showNameInput: true,
       defaultFileName: this._currentEditorGroup.currentResource?.name,
       defaultUri: URI.file(defaultPath),
       saveAs: true,
     });
     return result;
   } catch (error) {
-    throw new Error(`SaveAs Failed: ${error.message}`);
+    throw new Error(localize('saveAs.error.failed', 'SaveAs Failed: {0}', error.message));
   }
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 2b4d82b and f857a31.

📒 Files selected for processing (3)
  • packages/editor/src/browser/workbench-editor.service.ts (4 hunks)
  • packages/editor/src/common/editor.ts (1 hunks)
  • packages/extension/src/browser/vscode/api/main.thread.workspace.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/extension/src/browser/vscode/api/main.thread.workspace.ts
🔇 Additional comments (4)
packages/editor/src/common/editor.ts (2)

552-553: 方法签名定义正确!

save 方法的签名设计合理,与 VSCode API 保持一致。


554-555: 方法签名设计合理!

saveAs 方法的签名设计合理:

  • 返回类型 Promise<URI | undefined> 符合 VSCode API 规范,可以处理用户取消保存的场景
  • 参数类型正确
packages/editor/src/browser/workbench-editor.service.ts (2)

131-133: 依赖注入设计合理!

fileServiceClient 属性的设计合理:

  • 使用 @Autowired 装饰器正确注入依赖
  • 使用 protected readonly 修饰符保护访问权限

181-183: 依赖注入设计合理!

windowDialogService 属性的设计合理:

  • 使用 @Autowired 装饰器正确注入对话框服务
  • 使用 private readonly 修饰符确保封装性

packages/editor/src/browser/workbench-editor.service.ts Outdated Show resolved Hide resolved
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 (2)
packages/editor/src/browser/workbench-editor.service.ts (2)

263-280: 🛠️ Refactor suggestion

save 方法实现需要改进

当前实现存在以下问题:

  1. find 回调函数中的 return 语句是多余的
  2. 缺少错误处理
  3. 未处理找不到资源的情况

建议按如下方式重构:

 async save(uri: URI): Promise<URI | undefined> {
+  try {
     if (!this.editorGroups.length || !uri) {
       return undefined;
     }
 
     for (const editorGroup of this.editorGroups) {
-      const res = editorGroup.resources.find((resource) => {
-        if (resource.uri.isEqual(uri)) {
-          return resource;
-        }
-      });
+      const res = editorGroup.resources.find((resource) => 
+        resource.uri.isEqual(uri)
+      );
       if (res) {
-        editorGroup.saveResource(res);
+        await editorGroup.saveResource(res);
+        return uri;
       }
     }
-
-    return uri;
+    throw new Error(`找不到要保存的资源: ${uri.toString()}`);
+  } catch (error) {
+    throw new Error(`保存失败: ${error.message}`);
   }
 }

282-305: 🛠️ Refactor suggestion

saveAs 方法需要改进路径处理和错误处理

当前实现存在以下问题:

  1. 路径处理逻辑可以提取为独立函数
  2. Windows 路径处理可以优化
  3. 错误处理可以增强

建议按如下方式重构:

 private getDefaultSavePath(uri: URI): string {
   const defaultPath = uri.path.toString() !== '/' ? path.dirname(uri.path.toString()) : this.appConfig.workspaceDir;
-  return isWindows ? defaultPath.replace(/\\/g, '/') : defaultPath;
+  return isWindows ? defaultPath.replaceAll('\\', '/') : defaultPath;
 }

 async saveAs(uri: URI): Promise<URI | undefined> {
+  if (!this._currentEditorGroup) {
+    return undefined;
+  }
+
+  if (!uri) {
+    throw new Error('URI is required');
+  }
+
   try {
-    if (!this._currentEditorGroup || !uri) {
-      return undefined;
-    }
-
     const defaultPath = this.getDefaultSavePath(uri);
     const result = await this.windowDialogService.showSaveDialog({
       saveLabel: 'SaveAs File:',
       showNameInput: true,
       defaultFileName: this._currentEditorGroup.currentResource?.name,
       defaultUri: URI.file(defaultPath),
       saveAs: true,
     });
     return result;
   } catch (error) {
-    throw new Error(`SaveAs Failed: ${error.message}`);
+    const errorMessage = `另存为失败: ${error.message}`;
+    this.logger.error(errorMessage);
+    throw new Error(errorMessage);
   }
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f857a31 and 70cc633.

📒 Files selected for processing (4)
  • packages/editor/src/browser/workbench-editor.service.ts (4 hunks)
  • packages/editor/src/common/editor.ts (1 hunks)
  • packages/editor/src/common/mocks/workbench-editor.service.ts (1 hunks)
  • packages/extension/src/browser/vscode/api/main.thread.workspace.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/editor/src/common/mocks/workbench-editor.service.ts
🔇 Additional comments (1)
packages/editor/src/common/editor.ts (1)

552-555: 接口定义正确且类型完整

新增的 save 和 saveAs 抽象方法定义清晰,返回类型合理。

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 (1)
packages/editor/src/browser/workbench-editor.service.ts (1)

282-285: 需要改进路径处理方法

当前实现存在以下问题:

  1. 缺少对 uri 的空值检查
  2. Windows 路径处理可以优化
  3. 缺少对工作区目录的空值检查

建议按如下方式重构:

 private getDefaultSavePath(uri: URI): string {
+  if (!uri) {
+    throw new Error('URI 不能为空');
+  }
+
+  if (!this.appConfig.workspaceDir) {
+    throw new Error('工作区目录未设置');
+  }
+
   const defaultPath = uri.path.toString() !== '/' ? path.dirname(uri.path.toString()) : this.appConfig.workspaceDir;
-  return isWindows ? defaultPath.replace(/\\/g, '/') : defaultPath;
+  return isWindows ? defaultPath.replaceAll('\\', '/') : defaultPath;
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 70cc633 and e4e85ca.

📒 Files selected for processing (2)
  • packages/editor/src/browser/workbench-editor.service.ts (4 hunks)
  • packages/extension/src/browser/vscode/api/main.thread.workspace.ts (1 hunks)
🔇 Additional comments (4)
packages/extension/src/browser/vscode/api/main.thread.workspace.ts (2)

144-155: 🛠️ Refactor suggestion

需要改进错误处理和空值检查

当前实现存在以下问题:

  1. URI 为空时直接返回 undefined,应该抛出错误
  2. 错误处理可以更详细
  3. 缺少对 windowDialogService 的空值检查

建议按如下方式重构:

 async $saveAs(uri: URI): Promise<URI | undefined> {
   if (!this._currentEditorGroup) {
     return undefined;
   }

+  if (!uri) {
+    throw new Error('URI 不能为空');
+  }
+
+  if (!this.windowDialogService) {
+    throw new Error('windowDialogService 未初始化');
+  }

   try {
     return await this.windowDialogService.showSaveDialog({
       saveLabel: 'SaveAs File:',
       showNameInput: true,
       defaultFileName: this._currentEditorGroup.currentResource?.name,
       defaultUri: URI.file(defaultPath),
       saveAs: true,
     });
   } catch (error) {
-    this.logger.error(`SaveAs Failed: ${error.message}`);
-    return undefined;
+    const errorMessage = `另存为失败: ${error.message}`;
+    this.logger.error(errorMessage);
+    throw new Error(errorMessage);
   }
 }

Likely invalid or redundant comment.


130-142: 🛠️ Refactor suggestion

需要改进错误处理和返回值逻辑

当前实现存在以下问题:

  1. 在找不到资源时直接返回 undefined,应该抛出错误
  2. 错误处理过于简单,应该区分不同类型的错误
  3. 成功保存后应该返回原始 URI

建议按如下方式重构:

 async $save(uri: URI): Promise<URI | undefined> {
   if (!this.editorGroups.length) {
     return undefined;
   }

   try {
     for (const editorGroup of this.editorGroups) {
       const res = editorGroup.resources.find((resource) => resource.uri.isEqual(uri));
       if (res) {
         await editorGroup.saveResource(res);
+        return uri;
       }
     }
-    return uri;
+    throw new Error(`找不到要保存的资源: ${uri.toString()}`);
   } catch (error) {
-    this.logger.error(`Save Failed: ${error.message}`);
-    return undefined;
+    this.logger.error(`保存失败: ${error.message}`);
+    throw error;
   }
 }

Likely invalid or redundant comment.

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

263-280: 🛠️ Refactor suggestion

需要改进 save 方法的实现

当前实现存在以下问题:

  1. 找不到资源时应该抛出错误
  2. 错误处理过于简单
  3. 保存成功后应该返回原始 URI

建议按如下方式重构:

 async save(uri: URI): Promise<URI | undefined> {
   if (!this.editorGroups.length) {
     return undefined;
   }

   try {
+    let found = false;
     for (const editorGroup of this.editorGroups) {
       const res = editorGroup.resources.find((resource) => resource.uri.isEqual(uri));
       if (res) {
+        found = true;
         await editorGroup.saveResource(res);
       }
     }

+    if (!found) {
+      throw new Error(`找不到要保存的资源: ${uri.toString()}`);
+    }

     return uri;
   } catch (error) {
-    throw new Error(`Save Failed: ${error.message}`);
+    const errorMessage = `保存失败: ${error.message}`;
+    this.logger.error(errorMessage);
+    throw new Error(errorMessage);
   }
 }

Likely invalid or redundant comment.


287-305: 🛠️ Refactor suggestion

需要改进 saveAs 方法的实现

当前实现存在以下问题:

  1. 缺少对 windowDialogService 的空值检查
  2. 错误处理可以更详细
  3. 保存对话框的标签应该国际化

建议按如下方式重构:

 async saveAs(uri: URI): Promise<URI | undefined> {
   if (!this._currentEditorGroup) {
     return undefined;
   }

+  if (!this.windowDialogService) {
+    throw new Error('windowDialogService 未初始化');
+  }

   try {
     const defaultPath = this.getDefaultSavePath(uri);
     const result = await this.windowDialogService.showSaveDialog({
-      saveLabel: 'SaveAs File:',
+      saveLabel: localize('saveAs.dialog.label', '另存为文件:'),
       showNameInput: true,
       defaultFileName: this._currentEditorGroup.currentResource?.name,
       defaultUri: URI.file(defaultPath),
       saveAs: true,
     });
     return result;
   } catch (error) {
-    throw new Error(`SaveAs Failed: ${error.message}`);
+    const errorMessage = `另存为失败: ${error.message}`;
+    this.logger.error(errorMessage);
+    throw new Error(errorMessage);
   }
 }

Likely invalid or redundant comment.

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/file-tree-next/src/browser/dialog/file-dialog.service.ts (2)

145-164: 建议对 saveAs 方法进行以下改进

  1. 建议添加对文件路径合法性的验证
  2. 建议在打开文件失败时提供更友好的错误提示
  3. 建议考虑添加进度提示

建议按如下方式优化:

 async saveAs(options: { oldFilePath: string; newFilePath: string }) {
   const { oldFilePath, newFilePath } = options;
   if (!oldFilePath || !newFilePath) {
     throw new Error('oldFilePath and newFilePath are required');
   }
+  
+  // 验证文件路径合法性
+  if (!URI.isUri(oldFilePath) || !URI.isUri(newFilePath)) {
+    throw new Error('无效的文件路径');
+  }
+
+  // 显示进度提示
+  await this.dialogService.showProgress({
+    title: '正在保存文件...',
+    task: async () => {
       await this.createFile(options);
       try {
         const openUri: URI = URI.file(options.newFilePath);
         const EDITOR_OPTIONS = {
           preview: false,
           focus: true,
           replace: true,
           forceClose: true,
         };
         await this.workbenchEditorService.open(openUri, EDITOR_OPTIONS);
         this.fileTreeModelService.handleTreeFocus();
       } catch (error) {
-        throw new Error(`Failed to open saveAs file: ${error.message}`);
+        throw new Error(`打开文件失败:${error.message}`);
       }
+  }});
 }

166-185: 建议对 createFile 方法进行以下改进

  1. 建议添加文件大小检查
  2. 建议添加文件权限检查
  3. 建议优化错误处理

建议按如下方式优化:

 async createFile(options: { oldFilePath: string; newFilePath: string }) {
   try {
     const { oldFilePath, newFilePath } = options;
     let fileStat = await this.fileServiceClient.getFileStat(oldFilePath);

     if (!fileStat) {
-      throw new Error(`Source file not found: ${oldFilePath}`);
+      throw new Error(`源文件不存在:${oldFilePath}`);
     }

+    // 检查文件大小
+    const MAX_FILE_SIZE = 50 * 1024 * 1024; // 50MB
+    if (fileStat.size > MAX_FILE_SIZE) {
+      throw new Error('文件过大,无法复制');
+    }
+
+    // 检查目标路径权限
+    try {
+      await this.fileServiceClient.access(URI.parse(newFilePath).parent.toString(), 2);
+    } catch (e) {
+      throw new Error('没有写入权限');
+    }

     const { content } = await this.fileServiceClient.readFile(oldFilePath);

     await this.fileServiceClient.createFile(newFilePath, {
       content: content.toString(),
       encoding: 'utf8',
       overwrite: true,
     });
   } catch (e) {
-    throw new Error(`Failed to create file: ${e.message}`);
+    throw new Error(`创建文件失败:${e.message}`);
   }
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between e4e85ca and c6ed562.

📒 Files selected for processing (2)
  • packages/extension/__tests__/browser/extension-service/extension-service-mock-helper.ts (1 hunks)
  • packages/file-tree-next/src/browser/dialog/file-dialog.service.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/extension/tests/browser/extension-service/extension-service-mock-helper.ts
🔇 Additional comments (2)
packages/file-tree-next/src/browser/dialog/file-dialog.service.ts (2)

5-7: 导入声明看起来没有问题!

新增的导入都被正确使用,并且放置在适当的位置。


30-40: 依赖注入声明正确!

所有新增的依赖都使用了正确的访问修饰符和类型声明。

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/editor/src/browser/workbench-editor.service.ts (2)

263-280: save 方法实现完善!

实现包含以下亮点:

  1. 空值检查防止无编辑器组时的错误
  2. 完善的错误处理
  3. 正确的资源保存逻辑

建议优化:

  • 可以考虑添加保存成功的日志记录

287-305: saveAs 方法实现完善!

实现包含以下亮点:

  1. 完善的参数验证
  2. 使用 try-catch 进行错误处理
  3. 对话框选项配置合理

建议优化:

  • 可以考虑将对话框标签文本提取为常量或使用国际化
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3236a4e and 299530d.

📒 Files selected for processing (2)
  • packages/editor/src/browser/workbench-editor.service.ts (4 hunks)
  • packages/file-tree-next/src/browser/dialog/file-dialog.service.ts (3 hunks)
🔇 Additional comments (7)
packages/file-tree-next/src/browser/dialog/file-dialog.service.ts (4)

5-7: 导入声明看起来不错!

新增的导入声明与新功能的需求相符,包括:

  • WorkbenchEditorService: 用于编辑器操作
  • IFileServiceClient: 用于文件操作
  • IDialogService: 用于对话框操作

31-44: 依赖注入的属性声明合理!

新增的服务依赖包括:

  • fileServiceClient: 用于文件操作
  • workbenchEditorService: 用于编辑器操作
  • dialogService: 用于对话框操作
  • fileTreeModelService: 用于文件树模型操作
  • fileTreeService: 用于文件树操作

访问修饰符的使用恰当,protected/private 的选择符合封装原则。


149-173: saveAs 方法实现完善!

实现包含以下亮点:

  1. 完善的参数验证
  2. 使用 try-catch 进行错误处理
  3. 编辑器选项通过常量 EDITOR_OPTIONS 统一管理
  4. 包含文件装饰和导航功能

175-194: createFile 方法实现合理!

实现包含以下亮点:

  1. 完善的错误处理
  2. 正确的文件操作顺序:
    • 先检查源文件是否存在
    • 再读取源文件内容
    • 最后创建新文件
packages/editor/src/browser/workbench-editor.service.ts (3)

47-51: 导入声明合理!

新增的导入包括:

  • isWindows: 用于跨平台路径处理
  • path: 用于路径操作

这些工具函数的导入对于实现跨平台的文件路径处理是必要的。


131-133: 依赖注入的属性声明看起来不错!

新增的服务依赖:

  • fileServiceClient: 用于文件操作
  • windowDialogService: 用于窗口对话框操作

访问修饰符的使用恰当,protected/readonly 的选择有助于确保属性的不可变性。

Also applies to: 181-183


282-285: getDefaultSavePath 方法实现合理!

实现包含以下亮点:

  1. 正确处理根路径和非根路径的情况
  2. 使用 replace 处理 Windows 路径分隔符
  3. 使用工作区目录作为默认路径

@bk1012 bk1012 merged commit d9ae67a into opensumi:main Jan 2, 2025
19 checks passed
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