在 VS Code 中试试

虚拟工作区

诸如 GitHub Repositories 等扩展会在一个或多个由文件系统提供程序支持的文件夹上打开 VS Code。当扩展实现文件系统提供程序时,工作区资源可能不在本地磁盘上,而是虚拟的,位于服务器或云中,编辑操作在那里发生。

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

Remote indicator

并非所有扩展都能处理虚拟资源,它们可能要求资源位于磁盘上。一些扩展使用依赖磁盘访问、需要同步文件访问或缺乏必要文件系统抽象的工具。在这些情况下,当处于虚拟工作区时,VS Code 会向用户指出他们正运行在受限模式下,并且某些扩展已被禁用或功能受到限制。

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

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

我的扩展受影响吗?

当一个扩展没有可执行代码,而完全是声明性的,例如主题、键绑定、代码片段或语法扩展,它可以在虚拟工作区中运行,无需任何修改。

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

在虚拟工作区中运行您的扩展

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

这将打开一个 VS Code 窗口,用于虚拟工作区,其中所有资源都是虚拟的。

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

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

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

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

  • 切勿假定 URI Scheme 是 fileURI.fsPath 只能在 URI Scheme 是 file 时使用。
  • 注意使用 fs Node.js 模块进行文件系统操作的代码。如果可能,请使用 vscode.workspace.fs API,该 API 会委托给适当的文件系统提供程序。
  • 检查依赖 fs 访问的第三方组件(例如,语言服务器或 Node.js 模块)。
  • 如果您从命令运行可执行文件和任务,检查这些命令在虚拟工作区窗口中是否有意义,或者是否应该禁用它们。

声明您的扩展是否可以处理虚拟工作区

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 能力的所有扩展,"virtualWorkspaces": true 是默认值。

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

当然,扩展作者更适合做出此决定。扩展的 package.json 中的 virtualWorkspaces 能力将覆盖我们的默认设置,我们最终将移除我们的列表。

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

禁用命令和视图贡献点

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

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

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

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

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

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

通过编程方式检测虚拟工作区

要检查当前工作区是否包含非 file Scheme 且是虚拟的,您可以使用以下源代码

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

语言扩展和虚拟工作区

虚拟工作区对语言支持有什么期望?

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

A. 基本语言支持

  • TextMate 分词和着色
  • 语言特定的编辑支持:括号对、注释、按 Enter 键规则、折叠标记
  • 代码片段

B. 单文件语言支持

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

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

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

VS Code 内置的富语言扩展(TypeScript, JSON, CSS, HTML, Markdown)在处理虚拟资源时,其语言支持仅限于单文件。

禁用语言扩展

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

如果您的扩展同时提供语法和需要禁用的富语言支持,那么语法也将被禁用。为了避免这种情况,您可以创建一个与富语言支持分开的基本语言扩展(语法、语言配置、代码片段),从而拥有两个扩展。

  • 基本语言扩展设置为 "virtualWorkspaces": true,并提供语言 ID、配置、语法和代码片段。
  • 富语言扩展设置为 "virtualWorkspaces": false 并包含 main 文件。它提供语言支持、命令,并对基本语言扩展有扩展依赖 (extensionDependencies)。富语言扩展应该保留已有的扩展 ID,这样用户通过安装一个扩展就可以继续获得完整功能。

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

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

语言选择器

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

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

关于语言服务器协议 (LSP) 对访问虚拟资源的支持如何?

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