deno.com
本页内容

语言服务器集成

提示

如果您正在寻找关于如何在各种编辑器中使用 Deno 的 LSP 的信息,请访问设置你的环境页面

Deno CLI 内置了一个语言服务器,可以提供智能的编辑体验,并可以轻松访问 Deno 内置的其他工具。对于大多数用户来说,使用语言服务器通常是通过编辑器,例如Visual Studio Code其他编辑器

此页面专为那些创建与语言服务器集成或为 Deno 提供智能集成的软件包注册表的人员而设计。

Deno 语言服务器提供了语言服务器协议的服务器实现,该协议专门为提供代码的 Deno 视图而定制。它集成到命令行中,可以通过 lsp 子命令启动。

结构 跳转到标题

当语言服务器启动时,将创建一个 LanguageServer 实例,该实例保存语言服务器的所有状态。它还定义了客户端通过语言服务器 RPC 协议调用的所有方法。

设置 跳转到标题

语言服务器支持工作区的许多设置

  • deno.enable
  • deno.enablePaths
  • deno.cache
  • deno.certificateStores
  • deno.config
  • deno.importMap
  • deno.internalDebug
  • deno.codeLens.implementations
  • deno.codeLens.references
  • deno.codeLens.referencesAllFunctions
  • deno.codeLens.test
  • deno.suggest.completeFunctionCalls
  • deno.suggest.names
  • deno.suggest.paths
  • deno.suggest.autoImports
  • deno.suggest.imports.autoDiscover
  • deno.suggest.imports.hosts
  • deno.lint
  • deno.tlsCertificate
  • deno.unsafelyIgnoreCertificateErrors
  • deno.unstable

语言服务器在每个资源的基础上支持以下设置

  • deno.enable
  • deno.enablePaths
  • deno.codeLens.test

Deno 在语言服务器进程的多个点分析这些设置。首先,当客户端发送 initialize 请求时,initializationOptions 将被假定为表示 deno 命名空间的选项的对象。例如,以下值将为此语言服务器实例启用具有不稳定 API 的 Deno。

{
  "enable": true,
  "unstable": true
}

当语言服务器收到 workspace/didChangeConfiguration 通知时,它将评估客户端是否已指示它是否具有 workspaceConfiguration 功能。如果它有,它将发送一个 workspace/configuration 请求,该请求将包括对工作区配置的请求以及语言服务器当前正在跟踪的所有 URI 的配置。

如果客户端具有 workspaceConfiguration 功能,则语言服务器将在收到 textDocument/didOpen 通知时为 URI 发送配置请求,以便获取资源特定设置。

如果客户端不具有 workspaceConfiguration 功能,则语言服务器将假定工作区设置应用于所有资源。

命令 跳转到标题

语言服务器可能会向客户端发出几个命令,客户端需要实现这些命令

.cache 跳转到标题

当有未缓存的模块标识符被导入模块时,deno.cache 作为解析代码操作发送。它将随一个参数一起发送,该参数包含要缓存的已解析标识符作为字符串。

showReferences 跳转到标题

deno.showReferences 作为某些代码镜头上的命令发送,以显示引用的位置。参数包含作为命令主题的标识符、目标起始位置和要显示的引用的位置。

test 跳转到标题

deno.test 作为测试代码镜头的一部分发送,客户端应根据参数运行测试,参数是测试所在的标识符和用于过滤测试的测试名称。

请求 跳转到标题

LSP 当前支持以下自定义请求。客户端应实现这些请求,以便拥有一个功能齐全且与 Deno 良好集成的客户端

/cache 跳转到标题

deno/cache 将指示 Deno 尝试缓存一个模块及其所有依赖项。如果只传递 referrer,则将加载模块标识符的所有依赖项。如果 uris 中有值,则只缓存这些 uris

它期望以下参数:

interface CacheParams {
  referrer: TextDocumentIdentifier;
  uris: TextDocumentIdentifier[];
}

performance 跳转到标题

deno/performance 请求返回 Deno 内部检测的计时平均值。它不期望任何参数。

reloadImportRegistries 跳转到标题

deno/reloadImportRegistries 重新加载来自导入注册表的任何缓存响应。它不期望任何参数。

virtualTextDocument 跳转到标题

deno/virtualTextDocument 从 LSP 请求虚拟文本文档,这是一个只读文档,可以在客户端中显示。这允许客户端访问 Deno 缓存中的文档,例如远程模块和 Deno 内置的 TypeScript 库文件。Deno 语言服务器将在自定义模式 deno: 下编码所有内部文件,因此客户端应将对 deno: 模式的所有请求路由回 deno/virtualTextDocument API。

它还支持一个特殊的 URL deno:/status.md,它提供一个 markdown 格式的文本文档,其中包含有关 LSP 状态的详细信息,以供用户显示。

它期望以下参数:

interface VirtualTextDocumentParams {
  textDocument: TextDocumentIdentifier;
}

task 跳转到标题

deno/task 请求返回可用的 deno 任务,请参阅 task_runner。它不期望任何参数。

通知 跳转到标题

目前有一个从服务器发送到客户端的自定义通知,deno/registryState。当 deno.suggest.imports.autoDiscovertrue 并且添加到文档的导入的来源未在 deno.suggest.imports.hosts 中显式设置时,将检查来源,并将状态通知发送给客户端。

当收到通知时,如果参数 suggestiontrue,客户端应向用户提供启用来源并将其添加到 deno.suggest.imports.hosts 配置的选择。如果 suggestionfalse,则客户端应将其添加到配置中为 false,以阻止语言服务器尝试检测是否支持建议。

通知的参数为

interface RegistryStatusNotificationParams {
  origin: string;
  suggestions: boolean;
}

语言 ID 跳转到标题

语言服务器支持以下文本文档语言 ID 的诊断和格式化

  • "javascript"
  • "javascriptreact"
  • "jsx" 非标准,与 javascriptreact 相同
  • "typescript"
  • "typescriptreact"
  • "tsx" 非标准,与 typescriptreact 相同

语言服务器仅支持以下语言 ID 的格式化

  • "json"
  • "jsonc"
  • "markdown"

测试 跳转到标题

Deno 语言服务器支持一组自定义 API 来启用测试。这些 API 围绕提供信息以启用 vscode 的测试 API 构建,但可以被其他语言服务器客户端使用以提供类似的界面。

客户端和服务器都应支持实验性的 testingApi 功能

interface ClientCapabilities {
  experimental?: {
    testingApi: boolean;
  };
}
interface ServerCapabilities {
  experimental?: {
    testingApi: boolean;
  };
}

当支持测试 API 的 Deno 版本遇到支持该功能的客户端时,它将初始化处理测试检测的代码,并将开始提供启用它的通知。

应该注意的是,启用测试 API 功能后,将不再向客户端发送测试代码镜头。

测试设置 跳转到标题

有一些特定的设置会更改语言服务器的行为

  • deno.testing.args - 一个字符串数组,将在执行测试时作为参数提供。这与 deno test 子命令的工作方式相同。
  • deno.testing.enable - 一个二进制标志,用于启用或禁用测试服务器

测试通知 跳转到标题

服务器将在某些条件下向客户端发送通知。

deno/testModule 跳转到标题

当服务器发现包含测试的模块时,它将通过发送 deno/testModule 通知来通知客户端,并附带 TestModuleParams 的有效负载。

Deno 以这种方式构建

  • 一个模块可以包含 n 个测试。
  • 一个测试可以包含 n 个步骤。
  • 一个步骤可以包含 n 个步骤。

当 Deno 对测试模块进行静态分析时,它会尝试识别任何测试和测试步骤。由于在 Deno 中声明测试的动态方式,它们并不总是可以静态识别,只能在模块执行时识别。该通知旨在处理这两种情况,以便在更新客户端时使用。当静态发现测试时,通知 kind 将为 "replace",当在执行时发现测试或步骤时,通知 kind 将为 "insert"

当在编辑器中编辑测试文档,并且从客户端收到 textDocument/didChange 通知时,将执行这些更改的服务器端静态分析,如果测试已更改,客户端将收到通知。

当客户端收到 "replace" 通知时,它可以安全地“替换”测试模块表示,而当收到 "insert" 时,它应该递归地尝试添加到现有表示。

对于测试模块,textDocument.uri 应用作任何表示的唯一 ID(因为它是到唯一模块的字符串 URL)。TestData 项包含唯一的 id 字符串。此 id 字符串是服务器跟踪的测试的标识信息的 SHA-256 哈希值。

interface TestData {
  /** The unique ID for this test/step. */
  id: string;

  /** The display label for the test/step. */
  label: string;

  /** Any test steps that are associated with this test/step */
  steps?: TestData[];

  /** The range of the owning text document that applies to the test. */
  range?: Range;
}

interface TestModuleParams {
  /** The text document identifier that the tests are related to. */
  textDocument: TextDocumentIdentifier;

  /** A indication if tests described are _newly_ discovered and should be
   * _inserted_ or if the tests associated are a replacement for any existing
   * tests. */
  kind: "insert" | "replace";

  /** The text label for the test module. */
  label: string;

  /** An array of tests that are owned by this test module. */
  tests: TestData[];
}

deno/testModuleDelete 跳转到标题

当服务器正在观察的测试模块被删除时,服务器将发出 deno/testModuleDelete 通知。收到通知后,客户端应删除测试模块及其所有子测试和测试步骤的表示。

interface TestModuleDeleteParams {
  /** The text document identifier that has been removed. */
  textDocument: TextDocumentIdentifier;
}

deno/testRunProgress 跳转到标题

当从客户端请求 deno/testRun 时,服务器将通过 deno/testRunProgress 通知支持该测试运行的进度。

客户端应处理这些消息并更新任何 UI 表示。

状态更改在 TestRunProgressParams.message.kind 属性中表示。状态为

  • "enqueued" - 测试或测试步骤已加入队列以进行测试。
  • "skipped" - 测试或测试步骤已跳过。当 Deno 测试的 ignore 选项设置为 true 时,会发生这种情况。
  • "started" - 测试或测试步骤已开始。
  • "passed" - 测试或测试步骤已通过。
  • "failed" - 测试或测试步骤已失败。这旨在指示测试工具而不是测试本身出错,但 Deno 目前不支持这种区分。
  • "errored" - 测试或测试步骤已出错。有关错误的更多信息将在 .message.messages 属性中。
  • "end" - 测试运行已结束。
interface TestIdentifier {
  /** The test module the message is related to. */
  textDocument: TextDocumentIdentifier;

  /** The optional ID of the test. If not present, then the message applies to
   * all tests in the test module. */
  id?: string;

  /** The optional ID of the step. If not present, then the message only applies
   * to the test. */
  stepId?: string;
}

interface TestMessage {
  /** The content of the message. */
  message: MarkupContent;

  /** An optional string which represents the expected output. */
  expectedOutput?: string;

  /** An optional string which represents the actual output. */
  actualOutput?: string;

  /** An optional location related to the message. */
  location?: Location;
}

interface TestEnqueuedStartedSkipped {
  /** The state change that has occurred to a specific test or test step.
   *
   * - `"enqueued"` - the test is now enqueued to be tested
   * - `"started"` - the test has started
   * - `"skipped"` - the test was skipped
   */
  type: "enqueued" | "started" | "skipped";

  /** The test or test step relating to the state change. */
  test: TestIdentifier;
}

interface TestFailedErrored {
  /** The state change that has occurred to a specific test or test step.
   *
   * - `"failed"` - The test failed to run properly, versus the test erroring.
   *   currently the Deno language server does not support this.
   * - `"errored"` - The test errored.
   */
  type: "failed" | "errored";

  /** The test or test step relating to the state change. */
  test: TestIdentifier;

  /** Messages related to the state change. */
  messages: TestMessage[];

  /** An optional duration, in milliseconds from the start to the current
   * state. */
  duration?: number;
}

interface TestPassed {
  /** The state change that has occurred to a specific test or test step. */
  type: "passed";

  /** The test or test step relating to the state change. */
  test: TestIdentifier;

  /** An optional duration, in milliseconds from the start to the current
   * state. */
  duration?: number;
}

interface TestOutput {
  /** The test or test step has output information / logged information. */
  type: "output";

  /** The value of the output. */
  value: string;

  /** The associated test or test step if there was one. */
  test?: TestIdentifier;

  /** An optional location associated with the output. */
  location?: Location;
}

interface TestEnd {
  /** The test run has ended. */
  type: "end";
}

type TestRunProgressMessage =
  | TestEnqueuedStartedSkipped
  | TestFailedErrored
  | TestPassed
  | TestOutput
  | TestEnd;

interface TestRunProgressParams {
  /** The test run ID that the progress message applies to. */
  id: number;

  /** The message*/
  message: TestRunProgressMessage;
}

测试请求 跳转到标题

服务器处理两个不同的请求

deno/testRun 跳转到标题

要请求语言服务器执行一组测试,客户端发送 deno/testRun 请求,其中包括要在未来对客户端的响应中使用的测试运行 ID、测试运行的类型以及要包含或排除的任何测试模块或测试。

目前 Deno 仅支持 "run" 类型的测试运行。"debug""coverage" 计划在未来支持。

当没有包含测试模块或测试时,这意味着应执行所有发现的测试模块和测试。当包含测试模块但未包含任何测试 ID 时,这意味着应包含该测试模块中的所有测试。一旦识别出所有测试,任何排除的测试都将被删除,并且已解析的测试集将在响应中作为 "enqueued" 返回。

由于测试步骤的声明和运行方式的动态性,因此无法通过此 API 包含或排除测试步骤。

interface TestRunRequestParams {
  /** The id of the test run to be used for future messages. */
  id: number;

  /** The run kind. Currently Deno only supports `"run"` */
  kind: "run" | "coverage" | "debug";

  /** Test modules or tests to exclude from the test run. */
  exclude?: TestIdentifier[];

  /** Test modules or tests to include in the test run. */
  include?: TestIdentifier[];
}

interface EnqueuedTestModule {
  /** The test module the enqueued test IDs relate to */
  textDocument: TextDocumentIdentifier;

  /** The test IDs which are now enqueued for testing */
  ids: string[];
}

interface TestRunResponseParams {
  /** Test modules and test IDs that are now enqueued for testing. */
  enqueued: EnqueuedTestModule[];
}

deno/testRunCancel 跳转到标题

如果客户端希望取消当前正在运行的测试运行,它会发送带有要取消的测试 ID 的 deno/testRunCancel 请求。如果测试被取消,则响应将为布尔值 true,如果不可能,则为 false。当测试被取消时,仍将发送适当的测试进度通知。

interface TestRunCancelParams {
  /** The test id to be cancelled. */
  id: number;
}

您找到所需的信息了吗?

隐私政策