现已推出!了解 11 月份的新功能和修复。

虚拟工作区

GitHub 仓库 扩展这样的扩展,会在一个或多个由 文件系统提供程序 支持的文件夹上打开 VS Code。当一个扩展实现了一个文件系统提供程序时,工作区资源可能不会位于本地磁盘上,而是 虚拟的,位于服务器或云端,并且编辑操作在那里进行。

这种配置被称为 虚拟工作区。当虚拟工作区在 VS Code 窗口中打开时,会在左下角的远程指示器中用标签指示,类似于其他 远程开发 窗口。

Remote indicator

并非所有扩展都能够使用虚拟资源,并且可能需要资源位于磁盘上。一些扩展使用依赖于磁盘访问的工具,需要同步文件访问,或者没有必要的文件系统抽象。在这些情况下,当在虚拟工作区中时,VS Code 会向用户指示他们正在受限模式下运行,并且某些扩展被停用或功能有限。

通常,用户希望尽可能多的扩展在虚拟工作区中工作,并在浏览和编辑远程资源时获得良好的用户体验。本指南展示了扩展如何针对虚拟工作区进行测试,描述了修改以允许它们在虚拟工作区中工作,并介绍了 virtualWorkspaces 功能属性。

修改扩展以使用虚拟工作区也是在 Web 版 VS Code 中良好工作的重要一步。Web 版 VS Code 完全在浏览器内部运行,由于浏览器沙箱,工作区是虚拟的。有关更多详细信息,请参阅 Web 扩展 指南。

我的扩展是否受影响?

当扩展没有可执行代码,而是纯粹的声明性代码,如主题、快捷键绑定、代码片段或语法扩展时,它可以运行在虚拟工作区中,并且不需要进行修改。

具有代码的扩展,即定义了 main 入口点的扩展,需要检查并可能进行修改。

针对虚拟工作区运行你的扩展

安装 GitHub 仓库 扩展,并从命令面板运行 打开 GitHub 仓库... 命令。该命令会显示一个快速选择下拉列表,你可以粘贴任何 GitHub URL,或者选择搜索特定的仓库或拉取请求。

这将为所有资源都是虚拟的虚拟工作区打开一个 VS Code 窗口。

检查扩展代码是否已为虚拟资源做好准备

VS Code API 对虚拟文件系统的支持已经存在很长时间了。你可以查看 文件系统提供程序 API

文件系统提供程序是为新的 URI 方案(例如,vscode-vfs)注册的,并且该文件系统上的资源将由使用该方案的 URI 表示 (vscode-vfs://github/microsoft/vscode/package.json)

检查你的扩展如何处理从 VS Code API 返回的 URI

  • 永远不要假设 URI 方案是 fileURI.fsPath 只能在 URI 方案为 file 时使用。
  • 注意查看 fs node 模块的文件系统操作用法。如果可能,请使用 vscode.workspace.fs API,它会委托给适当的文件系统提供程序。
  • 检查是否存在依赖于 fs 访问的第三方组件(例如,语言服务器或 node 模块)。
  • 如果你从命令运行可执行文件和任务,请检查这些命令在虚拟工作区窗口中是否有意义,或者是否应该禁用它们。

指示你的扩展是否可以处理虚拟工作区

package.jsoncapabilities 下的 virtualWorkspaces 属性用于指示扩展是否可以使用虚拟工作区。

不支持虚拟工作区

下面的示例声明扩展不支持虚拟工作区,并且不应在这种设置中被 VS Code 启用。

{
  "capabilities": {
    "virtualWorkspaces": {
      "supported": false,
      "description": "Debugging is not possible in virtual workspaces."
    }
  }
}

对虚拟工作区的局部和完全支持

当扩展在虚拟工作区中工作或部分工作时,应定义 "virtualWorkspaces": true

{
  "capabilities": {
    "virtualWorkspaces": true
  }
}

如果扩展可以工作,但功能有限,则应向用户解释限制

{
  "capabilities": {
    "virtualWorkspaces": {
      "supported": "limited",
      "description": "In virtual workspaces, resolving and finding references across files is not supported."
    }
  }
}

该描述会显示在“扩展”视图中

Extensions view

然后,扩展应禁用虚拟工作区中不支持的功能,如下所述。

默认

"virtualWorkspaces": true 是所有尚未填写 virtualWorkspaces 功能的扩展的默认值。

但是,在测试虚拟工作区时,我们列出了一些我们认为应该在虚拟工作区中禁用的扩展。该列表可以在 问题 #122836 中找到。这些扩展默认具有 "virtualWorkspaces": false

当然,扩展作者更适合做出这个决定。扩展的 package.json 中的 virtualWorkspaces 功能将覆盖我们的默认值,我们最终将停用我们的列表。

当打开虚拟工作区时禁用功能

禁用命令和视图贡献

可以通过 when 子句 中的上下文键来控制命令和视图以及许多其他贡献的可用性。

当所有工作区文件夹都位于虚拟文件系统上时,会设置 virtualWorkspace 上下文键。下面的示例仅在不在虚拟工作区中时,在命令面板中显示命令 npm.publish

{
  "menus": {
    "commandPalette": [
      {
        "command": "npm.publish",
        "when": "!virtualWorkspace"
      }
    ]
  }
}

resourceScheme 上下文键设置为文件资源管理器中当前选定元素或编辑器中打开的元素的 URI 方案。

在下面的示例中,仅当底层资源位于本地磁盘上时,才会显示编辑器上下文菜单中的 npm.runSelectedScript 命令。

{
  "menus": {
    "editor/context": [
      {
        "command": "npm.runSelectedScript",
        "when": "resourceFilename == 'package.json' && resourceScheme == file"
      }
    ]
  }
}

以编程方式检测虚拟工作区

要检查当前工作区是否由非 file 方案组成并且是虚拟的,可以使用以下源代码

const isVirtualWorkspace =
  workspace.workspaceFolders &&
  workspace.workspaceFolders.every(f => f.uri.scheme !== 'file');

语言扩展和虚拟工作区

对虚拟工作区的语言支持有何期望?

并非所有扩展都能完全使用虚拟资源是不现实的。许多扩展使用需要同步文件访问和磁盘上文件的外部工具。因此,仅提供有限的功能(例如,下面列出的 基本单文件 支持)是可以接受的。

A. 基本 语言支持

  • TextMate 标记化和着色
  • 特定于语言的编辑支持:括号对、注释、回车规则、折叠标记
  • 代码片段

B. 单文件 语言支持

  • 文档符号(大纲)、折叠、选择范围
  • 文档突出显示、语义突出显示、文档颜色
  • 基于当前文件和静态语言库中的符号的补全、悬停提示、签名帮助、查找引用/声明
  • 格式化、链接编辑
  • 语法验证和相同文件的语义验证以及代码操作

C. 跨文件、工作区感知 语言支持

  • 跨文件的引用
  • 工作区符号
  • 验证工作区/项目中的所有文件

当处理虚拟资源时,VS Code 附带的丰富的语言扩展(TypeScript、JSON、CSS、HTML、Markdown)仅限于单文件语言支持。

禁用语言扩展

如果处理单个文件不是选项,则语言扩展也可以决定在虚拟工作区中禁用扩展。

如果你的扩展既提供语法又提供需要禁用的丰富语言支持,则语法也将被禁用。为了避免这种情况,你可以创建一个基本语言扩展(语法、语言配置、代码片段),与丰富的语言支持分开,并拥有两个扩展。

  • 基本语言扩展具有 "virtualWorkspaces": true,并提供语言 ID、配置、语法和代码片段。
  • 丰富的语言扩展具有 "virtualWorkspaces": false,并且包含 main 文件。它贡献语言支持、命令,并具有基本语言扩展的扩展依赖项 (extensionDependencies)。丰富的语言扩展应保留已建立扩展的扩展 ID,以便用户可以通过安装单个扩展来继续拥有完整功能。

你可以在内置语言扩展(例如 JSON)中看到这种方法,它由 JSON 扩展和 JSON 语言功能扩展组成。

这种分离还有助于在 受限模式 下运行的 不受信任的工作区。丰富的语言扩展通常需要信任,而基本语言功能可以在任何设置中运行。

语言选择器

当为语言功能(例如,补全、悬停提示、代码操作等)注册提供程序时,请确保指定提供程序支持的方案

return vscode.languages.registerCompletionItemProvider(
  { language: 'typescript', scheme: 'file' },
  {
    provideCompletionItems(document, position, token) {
      // ...
    }
  }
);

语言服务器协议 (LSP) 中对访问虚拟资源的支持怎么样?

正在进行将文件系统提供程序支持添加到 LSP 的工作。在语言服务器协议 问题 #1264 中跟踪。