第132章 调试器扩展
Debug Adapter Protocol Server 可以以扩展的形式暴露,供调试器使用。
定义调试器扩展
单个扩展可以提供一至多个 DAP Server。每个 DAP Server 都必须在 extension.toml 中注册:
[debug_adapters.my-debug-adapter]
# 调试适配器配置架构的 JSON Schema 的可选相对路径。默认为 `debug_adapter_schemas/$DEBUG_ADAPTER_NAME_ID.json`。
# 注意,虽然此字段是可选的,但架构(Schema)是必需的。
schema_path = "relative/path/to/schema.json"
接下来,在扩展的 Rust 代码中,实现 get_dap_binary 方法:
impl zed::Extension for MyExtension {
fn get_dap_binary(
&mut self,
adapter_name: String,
config: DebugTaskDefinition,
user_provided_debug_adapter_path: Option<String>,
worktree: &Worktree,
) -> Result<DebugAdapterBinary, String>;
}
该方法应返回启动 debug adapter protocol server 的命令,以及使其正常运行所需的任何参数或环境变量。
如果需要从外部源(如 GitHub Releases、npm 等)下载 DAP Server,也可以在此函数中完成。请确保仅在定期更新时进行检查,因为每当用户通过该调试适配器启动新的调试会话时,此函数都会被调用。
还必须实现 dap_request_kind。此函数用于确定给定的调试场景是启动新的被调试程序,还是附加到现有的被调试程序上。我们还用它来判断某个调试场景是否需要运行定位器(locator)。
impl zed::Extension for MyExtension {
fn dap_request_kind(
&mut self,
_adapter_name: String,
_config: Value,
) -> Result<StartDebuggingRequestArgumentsRequest, String>;
}
这两个函数足以将你的调试适配器暴露给基于 debug.json 的用户工作流,但你应强烈考虑同时实现 dap_config_to_scenario。
impl zed::Extension for MyExtension {
fn dap_config_to_scenario(
&mut self,
_adapter_name: DebugConfig,
) -> Result<DebugScenario, String>;
}
当用户通过新建进程的弹窗界面发起调试会话时,会调用 dap_config_to_scenario。简单来说,它接收一个通用的调试配置(不针对任何特定 debug adapter),并尝试将其转换为适用于你的 adapter 的具体调试场景。换句话说,它要回答的问题是:“给定一个程序、一组参数、当前工作目录和环境变量,启动这个 debug adapter 的配置应该是什么样的?”
定义 Debug Locator
Zed 提供了一种自动创建调试场景的方式,即 debug locator(调试定位器)。Locator 负责定位调试目标,并确定如何为它启动调试会话。多亏了 locator,我们可以把用户现有的任务(比如 cargo run)自动转换成调试场景(比如先执行 cargo build,再启动调试器,以 target/debug/my_program 作为待调试的程序)。
即使你的扩展不提供 debug adapter,也可以定义自己的 debug locator。如果扩展已经提供了语言任务,我们强烈建议这样做——这样用户无需手动配置 debug adapter 就能直接启动调试会话。
Locator 可以做到与所使用的 debug adapter 无关(但并非必须)。它们负责定位调试目标并确定如何为它启动调试会话,这让多个扩展可以在不同 adapter 之间复用 locator 逻辑。
你的扩展可以定义一个或多个 debug locator,每个 locator 都必须在 extension.toml 中注册:
[debug_locators.my-debug-locator]
Locator 由两部分组成。首先,每个 locator 会在每个可用任务上运行,以判断是否有 locator 能为给定任务提供调试场景。这一步通过调用 dap_locator_create_scenario 完成。
impl zed::Extension for MyExtension {
fn dap_locator_create_scenario(
&mut self,
_locator_name: String,
_build_task: TaskTemplate,
_resolved_label: String,
_debug_adapter_name: String,
) -> Option<DebugScenario>;
}
当某个调试场景为给定的用户任务定义了相应的调试对等项时,该函数应返回 Some 调试场景。
注意,DebugScenario 可以包含一个构建任务。如果存在该任务,构建成功后我们将执行 run_dap_locator。
impl zed::Extension for MyExtension {
fn run_dap_locator(
&mut self,
_locator_name: String,
_build_task: TaskTemplate,
) -> Result<DebugRequest, String>;
}
如果无法确定性地确定构建目标,run_dap_locator 会很有用。某些构建系统产生的工件名称可能事先未知。
但请注意,你不需要进行两阶段解析;如果仅通过 dap_locator_create_scenario 就能确定完整的调试配置,你可以省略返回的 DebugScenario 中的 build 属性。还要注意,你的 locator 将会被那些它不太可能接受的任务调用;因此,在执行任何昂贵操作之前,你应该尽早返回 None。
可用扩展
请参阅以扩展形式发布的 DAP 服务器在 Zed 网站上的列表。
查看它们的仓库,了解常见的实现模式和结构。
测试
要测试你的新 Debug Adapter Protocol 服务器扩展,你可以将其安装为开发扩展。