Compare commits

...

14 Commits

Author SHA1 Message Date
Cole Miller
cbe071a9e9 Merge remote-tracking branch 'origin/main' into auto-extract-dap-schemas 2025-07-07 14:28:37 -04:00
Cole Miller
50fbc05e1a Merge remote-tracking branch 'origin/main' into auto-extract-dap-schemas 2025-07-05 19:01:05 -04:00
Cole Miller
8869d77286 clippy 2025-07-05 18:43:26 -04:00
Cole Miller
8150cae6f3 clean up 2025-07-05 18:36:55 -04:00
Cole Miller
7fafe92564 add a script 2025-07-05 18:25:07 -04:00
Cole Miller
d8406230a1 gdb 2025-07-05 18:20:46 -04:00
Cole Miller
9254fa04a5 codelldb 2025-07-05 18:15:23 -04:00
Cole Miller
7f0ee3f1f4 go 2025-07-05 17:58:03 -04:00
Cole Miller
0088201ca9 python 2025-07-05 17:48:09 -04:00
Cole Miller
078756a2ac reorganize in preparation for more adapters 2025-07-05 00:58:11 -04:00
Cole Miller
0ac3cc25e5 serde(remote) 2025-07-05 00:01:29 -04:00
Cole Miller
fe94d0feb7 fix tcp_connection 2025-07-04 21:55:23 -04:00
Cole Miller
e1a7869938 wip 2025-07-04 21:39:57 -04:00
Cole Miller
8c32fdf5e7 wip
Co-authored-by: Remco Smits <djsmits12@gmail.com>
2025-07-04 19:40:25 -04:00
26 changed files with 10852 additions and 1297 deletions

5
Cargo.lock generated
View File

@@ -4112,7 +4112,6 @@ dependencies = [
"log",
"node_runtime",
"parking_lot",
"paths",
"proto",
"schemars",
"serde",
@@ -4154,11 +4153,15 @@ dependencies = [
"json_dotpath",
"language",
"log",
"node_runtime",
"paths",
"reqwest_client",
"serde",
"serde_json",
"settings",
"shlex",
"task",
"tempfile",
"util",
"workspace-hack",
]

View File

@@ -38,7 +38,6 @@ language.workspace = true
log.workspace = true
node_runtime.workspace = true
parking_lot.workspace = true
paths.workspace = true
proto.workspace = true
schemars.workspace = true
serde.workspace = true

View File

@@ -15,7 +15,7 @@ use serde::{Deserialize, Serialize};
use settings::WorktreeId;
use smol::fs::File;
use std::{
borrow::Borrow,
borrow::{Borrow, Cow},
ffi::OsStr,
fmt::Debug,
net::Ipv4Addr,
@@ -265,12 +265,13 @@ pub struct GithubRepo {
}
pub async fn download_adapter_from_github(
adapter_name: DebugAdapterName,
adapter_name: &str,
github_version: AdapterVersion,
file_type: DownloadedFileType,
base_path: &Path,
delegate: &dyn DapDelegate,
) -> Result<PathBuf> {
let adapter_path = paths::debug_adapters_dir().join(&adapter_name.as_ref());
let adapter_path = base_path.join(adapter_name);
let version_path = adapter_path.join(format!("{}_{}", adapter_name, github_version.tag_name));
let fs = delegate.fs();
@@ -284,11 +285,7 @@ pub async fn download_adapter_from_github(
.context("Failed creating adapter path")?;
}
log::debug!(
"Downloading adapter {} from {}",
adapter_name,
&github_version.url,
);
log::debug!("Downloading {} from {}", adapter_name, &github_version.url);
delegate.output_to_console(format!("Downloading from {}...", github_version.url));
let mut response = delegate
@@ -373,7 +370,7 @@ pub trait DebugAdapter: 'static + Send + Sync {
}
}
fn dap_schema(&self) -> serde_json::Value;
fn dap_schema(&self) -> Cow<'static, serde_json::Value>;
fn label_for_child_session(&self, _args: &StartDebuggingRequestArguments) -> Option<String> {
None
@@ -399,8 +396,8 @@ impl DebugAdapter for FakeAdapter {
DebugAdapterName(Self::ADAPTER_NAME.into())
}
fn dap_schema(&self) -> serde_json::Value {
serde_json::Value::Null
fn dap_schema(&self) -> Cow<'static, serde_json::Value> {
Cow::Owned(serde_json::Value::Null)
}
async fn request_kind(

View File

@@ -4,12 +4,10 @@ use collections::FxHashMap;
use gpui::{App, Global, SharedString};
use language::LanguageName;
use parking_lot::RwLock;
use task::{
AdapterSchema, AdapterSchemas, DebugRequest, DebugScenario, SpawnInTerminal, TaskTemplate,
};
use task::{DebugRequest, DebugScenario, SpawnInTerminal, TaskTemplate};
use crate::adapters::{DebugAdapter, DebugAdapterName};
use std::{collections::BTreeMap, sync::Arc};
use std::{borrow::Cow, collections::BTreeMap, sync::Arc};
/// Given a user build configuration, locator creates a fill-in debug target ([DebugScenario]) on behalf of the user.
#[async_trait]
@@ -63,19 +61,13 @@ impl DapRegistry {
.and_then(|adapter| adapter.adapter_language_name())
}
pub async fn adapters_schema(&self) -> task::AdapterSchemas {
let mut schemas = AdapterSchemas(vec![]);
let adapters = self.0.read().adapters.clone();
for (name, adapter) in adapters.into_iter() {
schemas.0.push(AdapterSchema {
adapter: name.into(),
schema: adapter.dap_schema(),
});
}
schemas
pub async fn adapter_schemas(&self) -> Vec<(SharedString, Cow<'static, serde_json::Value>)> {
self.0
.read()
.adapters
.iter()
.map(|(name, adapter)| (name.0.clone(), adapter.dap_schema()))
.collect()
}
pub fn locators(&self) -> FxHashMap<SharedString, Arc<dyn DapLocator>> {

View File

@@ -12,6 +12,12 @@ test-support = [
"task/test-support",
"util/test-support",
]
update-schemas = [
"dep:node_runtime",
"dep:reqwest_client",
"dep:settings",
"dep:tempfile",
]
[lints]
workspace = true
@@ -20,6 +26,11 @@ workspace = true
path = "src/dap_adapters.rs"
doctest = false
[[bin]]
name = "update-schemas"
path = "src/update_schemas.rs"
required-features = ["update-schemas"]
[dependencies]
anyhow.workspace = true
async-trait.workspace = true
@@ -40,6 +51,11 @@ task.workspace = true
util.workspace = true
workspace-hack.workspace = true
node_runtime = { workspace = true, optional = true }
reqwest_client = { workspace = true, optional = true }
settings = { workspace = true, optional = true }
tempfile = { workspace = true, optional = true }
[dev-dependencies]
dap = { workspace = true, features = ["test-support"] }
gpui = { workspace = true, features = ["test-support"] }

View File

@@ -0,0 +1,253 @@
{
"allOf": [
{
"if": { "properties": { "request": { "const": "launch" } }, "required": ["request"] },
"then": {
"properties": {
"program": { "description": "Path to the program to debug.", "type": "string" },
"cargo": {
"description": "Cargo invocation parameters.",
"type": "object",
"properties": {
"args": { "description": "Cargo command line arguments.", "type": "array", "default": [] },
"env": {
"description": "Additional environment variables passed to Cargo.",
"type": "object",
"patternProperties": { ".*": { "type": "string" } },
"default": {}
},
"cwd": { "description": "Cargo working directory.", "type": "string" },
"problemMatcher": {
"description": "Problem matcher(s) to apply to Cargo output.",
"type": ["string", "array"]
},
"filter": {
"description": "Filter applied to compilation artifacts.",
"type": "object",
"properties": { "name": { "type": "string" }, "kind": { "type": "string" } }
}
},
"required": ["args"],
"additionalProperties": false,
"defaultSnippets": [
{
"label": "Library unit tests",
"body": { "args": ["test", "--no-run", "--lib"], "filter": { "kind": "lib" } }
},
{ "label": "Executable", "body": { "args": ["build", "--bin=${1:<name>}"], "filter": { "kind": "bin" } } }
]
},
"args": { "description": "Program arguments.", "type": ["array", "string"] },
"cwd": { "description": "Program working directory.", "type": "string" },
"env": {
"description": "Additional environment variables.",
"type": "object",
"patternProperties": { ".*": { "type": "string" } }
},
"envFile": { "description": "File to read the environment variables from.", "type": "string" },
"stdio": {
"description": "Destination for stdio streams: null = send to debugger console or a terminal, \"<path>\" = attach to a file/tty/fifo.",
"type": ["null", "string", "array", "object"],
"default": null
},
"terminal": {
"description": "Terminal type to use.",
"type": "string",
"enum": ["integrated", "external", "console"],
"enumDescriptions": [
"Use integrated terminal in VSCode.",
"Use external terminal window.",
"Use VScode Debug Console for stdout and stderr. Stdin will be unavailable."
],
"default": "integrated"
},
"console": {
"description": "Terminal type to use. (This setting is a compatibility alias of 'terminal'.)",
"type": "string",
"enum": ["integratedTerminal", "externalTerminal", "internalConsole"],
"enumDescriptions": [
"Use integrated terminal in VSCode.",
"Use external terminal window.",
"Use VScode Debug Console for stdout and stderr. Stdin will be unavailable."
]
},
"stopOnEntry": {
"description": "Automatically stop debuggee after launch.",
"type": "boolean",
"default": false
},
"initCommands": {
"description": "Initialization commands executed upon debugger startup.",
"type": "array",
"items": { "type": "string" },
"default": []
},
"targetCreateCommands": {
"description": "Commands that create the debug target.",
"type": "array",
"items": { "type": "string" },
"default": []
},
"preRunCommands": {
"description": "Commands executed just before the program is launched.",
"type": "array",
"items": { "type": "string" },
"default": []
},
"processCreateCommands": {
"description": "Commands that create the debuggee process.",
"type": "array",
"items": { "type": "string" },
"default": []
},
"postRunCommands": {
"description": "Commands executed just after the program has been launched.",
"type": "array",
"items": { "type": "string" },
"default": []
},
"preTerminateCommands": {
"description": "Commands executed just before the debuggee is terminated or disconnected from.",
"type": "array",
"items": { "type": "string" },
"default": []
},
"exitCommands": {
"description": "Commands executed at the end of debugging session.",
"type": "array",
"items": { "type": "string" },
"default": []
},
"expressions": {
"description": "The default evaluator type used for expressions.",
"type": "string",
"enum": ["simple", "python", "native"]
},
"sourceMap": {
"description": "Source path remapping between the build machine and the local machine. Each item is a pair of remote and local path prefixes.",
"type": "object",
"patternProperties": { ".*": { "type": ["string", "null"] } },
"default": {}
},
"relativePathBase": {
"description": "Base directory used for resolution of relative source paths. Defaults to \"${ZED_WORKTREE_ROOT}\".",
"type": "string"
},
"sourceLanguages": {
"description": "A list of source languages to enable language-specific features for.",
"type": "array",
"default": []
},
"reverseDebugging": {
"description": "Enable reverse debugging (Requires reverse execution support in the debug server, see User's Manual for details).",
"type": "boolean",
"default": false
},
"breakpointMode": {
"description": "Specifies how source breakpoints should be set.",
"type": "string",
"enum": ["path", "file"],
"enumDescriptions": [
"Resolve locations using full source file path.",
"Resolve locations using file name only."
]
}
},
"anyOf": [{ "required": ["program"] }, { "required": ["targetCreateCommands"] }, { "required": ["cargo"] }]
}
},
{
"if": { "properties": { "request": { "const": "attach" } }, "required": ["request"] },
"then": {
"properties": {
"program": { "description": "Path to the program to attach to.", "type": "string" },
"pid": {
"description": "Process id to attach to.",
"type": ["integer", "string"],
"default": "${command:pickMyProcess}"
},
"stopOnEntry": {
"description": "Automatically stop debuggee after attach.",
"type": "boolean",
"default": false
},
"waitFor": {
"description": "Wait for the process to launch (MacOS only).",
"type": "boolean",
"default": false
},
"initCommands": {
"description": "Initialization commands executed upon debugger startup.",
"type": "array",
"items": { "type": "string" },
"default": []
},
"targetCreateCommands": {
"description": "Commands that create the debug target.",
"type": "array",
"items": { "type": "string" },
"default": []
},
"preRunCommands": {
"description": "Commands executed just before the program is launched.",
"type": "array",
"items": { "type": "string" },
"default": []
},
"processCreateCommands": {
"description": "Commands that create the debuggee process.",
"type": "array",
"items": { "type": "string" },
"default": []
},
"postRunCommands": {
"description": "Commands executed just after the program has been launched.",
"type": "array",
"items": { "type": "string" },
"default": []
},
"exitCommands": {
"description": "Commands executed at the end of debugging session.",
"type": "array",
"items": { "type": "string" },
"default": []
},
"expressions": {
"description": "The default evaluator type used for expressions.",
"type": "string",
"enum": ["simple", "python", "native"]
},
"sourceMap": {
"description": "Source path remapping between the build machine and the local machine. Each item is a pair of remote and local path prefixes.",
"type": "object",
"patternProperties": { ".*": { "type": ["string", "null"] } },
"default": {}
},
"relativePathBase": {
"description": "Base directory used for resolution of relative source paths. Defaults to \"${ZED_WORKTREE_ROOT}\".",
"type": "string"
},
"sourceLanguages": {
"description": "A list of source languages to enable language-specific features for.",
"type": "array",
"default": []
},
"reverseDebugging": {
"description": "Enable reverse debugging (Requires reverse execution support in the debug server, see User's Manual for details).",
"type": "boolean",
"default": false
},
"breakpointMode": {
"description": "Specifies how source breakpoints should be set.",
"type": "string",
"enum": ["path", "file"],
"enumDescriptions": [
"Resolve locations using full source file path.",
"Resolve locations using file name only."
]
}
}
}
}
]
}

View File

@@ -0,0 +1,281 @@
{
"allOf": [
{
"if": { "properties": { "request": { "const": "launch" } }, "required": ["request"] },
"then": {
"properties": {
"args": {
"default": [],
"description": "Command line arguments passed to the program. For string type arguments, it will pass through the shell as is, and therefore all shell variable expansions will apply. But for the array type, the values will be shell-escaped.",
"items": { "type": "string" },
"anyOf": [
{ "default": "${command:pickArgs}", "enum": ["${command:pickArgs}"] },
{ "type": ["array", "string"] }
]
},
"autoReload": {
"default": {},
"description": "Configures automatic reload of code on edit.",
"properties": {
"enable": { "default": false, "description": "Automatically reload code on edit.", "type": "boolean" },
"exclude": {
"default": [
"**/.git/**",
"**/.metadata/**",
"**/__pycache__/**",
"**/node_modules/**",
"**/site-packages/**"
],
"description": "Glob patterns of paths to exclude from auto reload.",
"items": { "type": "string" },
"type": "array"
},
"include": {
"default": ["**/*.py", "**/*.pyw"],
"description": "Glob patterns of paths to include in auto reload.",
"items": { "type": "string" },
"type": "array"
}
},
"type": "object"
},
"console": {
"default": "integratedTerminal",
"description": "Where to launch the debug target: internal console, integrated terminal, or external terminal.",
"enum": ["externalTerminal", "integratedTerminal", "internalConsole"]
},
"cwd": {
"default": "${ZED_WORKTREE_ROOT}",
"description": "Absolute path to the working directory of the program being debugged. Default is the root directory of the file (leave empty).",
"type": "string"
},
"debugAdapterPath": {
"description": "Path (fully qualified) to the Python debug adapter executable.",
"type": "string"
},
"autoStartBrowser": {
"default": false,
"description": "Open external browser to launch the application",
"type": "boolean"
},
"django": { "default": false, "description": "Django debugging.", "type": "boolean" },
"env": {
"additionalProperties": { "type": "string" },
"default": {},
"description": "Environment variables defined as a key value pair. Property ends up being the Environment Variable and the value of the property ends up being the value of the Env Variable.",
"type": "object"
},
"envFile": {
"default": "${ZED_WORKTREE_ROOT}/.env",
"description": "Absolute path to a file containing environment variable definitions.",
"type": "string"
},
"gevent": {
"default": false,
"description": "Enable debugging of gevent monkey-patched code.",
"type": "boolean"
},
"jinja": {
"default": null,
"description": "Jinja template debugging (e.g. Flask).",
"enum": [false, null, true]
},
"justMyCode": { "default": true, "description": "Debug only user-written code.", "type": "boolean" },
"logToFile": {
"default": false,
"description": "Enable logging of debugger events to a log file. This file can be found in the debugpy extension install folder.",
"type": "boolean"
},
"module": { "default": "", "description": "Name of the module to be debugged.", "type": "string" },
"pathMappings": {
"default": [],
"items": {
"label": "Path mapping",
"properties": {
"localRoot": { "default": "${ZED_WORKTREE_ROOT}", "label": "Local source root.", "type": "string" },
"remoteRoot": { "default": "", "label": "Remote source root.", "type": "string" }
},
"required": ["localRoot", "remoteRoot"],
"type": "object"
},
"label": "Path mappings.",
"type": "array"
},
"program": { "default": "${file}", "description": "Absolute path to the program.", "type": "string" },
"purpose": {
"default": [],
"description": "Tells extension to use this configuration for test debugging, or when using debug-in-terminal command.",
"items": {
"enum": ["debug-test", "debug-in-terminal"],
"enumDescriptions": [
"Use this configuration while debugging tests using test view or test debug commands.",
"Use this configuration while debugging a file using debug in terminal button in the editor."
]
},
"type": "array"
},
"pyramid": { "default": false, "description": "Whether debugging Pyramid applications.", "type": "boolean" },
"python": {
"default": "${command:python.interpreterPath}",
"description": "Absolute path to the Python interpreter executable; overrides workspace configuration if set.",
"type": "string"
},
"pythonArgs": {
"default": [],
"description": "Command-line arguments passed to the Python interpreter. To pass arguments to the debug target, use \"args\".",
"items": { "type": "string" },
"type": "array"
},
"redirectOutput": { "default": true, "description": "Redirect output.", "type": "boolean" },
"showReturnValue": {
"default": true,
"description": "Show return value of functions when stepping.",
"type": "boolean"
},
"stopOnEntry": { "default": false, "description": "Automatically stop after launch.", "type": "boolean" },
"subProcess": {
"default": false,
"description": "Whether to enable Sub Process debugging.",
"type": "boolean"
},
"sudo": {
"default": false,
"description": "Running debug program under elevated permissions (on Unix).",
"type": "boolean"
},
"guiEventLoop": {
"default": "matplotlib",
"description": "The GUI event loop that's going to run. Possible values: \"matplotlib\", \"wx\", \"qt\", \"none\", or a custom function that'll be imported and run.",
"type": "string"
},
"consoleName": {
"default": "Python Debug Console",
"description": "Display name of the debug console or terminal",
"type": "string"
},
"clientOS": { "default": null, "description": "OS that VS code is using.", "enum": ["windows", null, "unix"] }
}
}
},
{
"if": { "properties": { "request": { "const": "attach" } }, "required": ["request"] },
"then": {
"properties": {
"autoReload": {
"default": {},
"description": "Configures automatic reload of code on edit.",
"properties": {
"enable": { "default": false, "description": "Automatically reload code on edit.", "type": "boolean" },
"exclude": {
"default": [
"**/.git/**",
"**/.metadata/**",
"**/__pycache__/**",
"**/node_modules/**",
"**/site-packages/**"
],
"description": "Glob patterns of paths to exclude from auto reload.",
"items": { "type": "string" },
"type": "array"
},
"include": {
"default": ["**/*.py", "**/*.pyw"],
"description": "Glob patterns of paths to include in auto reload.",
"items": { "type": "string" },
"type": "array"
}
},
"type": "object"
},
"connect": {
"label": "Attach by connecting to debugpy over a socket.",
"properties": {
"host": {
"default": "127.0.0.1",
"description": "Hostname or IP address to connect to.",
"type": "string"
},
"port": { "description": "Port to connect to.", "type": ["number", "string"] }
},
"required": ["port"],
"type": "object"
},
"debugAdapterPath": {
"description": "Path (fully qualified) to the python debug adapter executable.",
"type": "string"
},
"django": { "default": false, "description": "Django debugging.", "type": "boolean" },
"jinja": {
"default": null,
"description": "Jinja template debugging (e.g. Flask).",
"enum": [false, null, true]
},
"justMyCode": {
"default": true,
"description": "If true, show and debug only user-written code. If false, show and debug all code, including library calls.",
"type": "boolean"
},
"listen": {
"label": "Attach by listening for incoming socket connection from debugpy",
"properties": {
"host": {
"default": "127.0.0.1",
"description": "Hostname or IP address of the interface to listen on.",
"type": "string"
},
"port": { "description": "Port to listen on.", "type": ["number", "string"] }
},
"required": ["port"],
"type": "object"
},
"logToFile": {
"default": false,
"description": "Enable logging of debugger events to a log file. This file can be found in the debugpy extension install folder.",
"type": "boolean"
},
"pathMappings": {
"default": [],
"items": {
"label": "Path mapping",
"properties": {
"localRoot": { "default": "${ZED_WORKTREE_ROOT}", "label": "Local source root.", "type": "string" },
"remoteRoot": { "default": "", "label": "Remote source root.", "type": "string" }
},
"required": ["localRoot", "remoteRoot"],
"type": "object"
},
"label": "Path mappings.",
"type": "array"
},
"processId": {
"anyOf": [
{
"default": "${command:pickProcess}",
"description": "Use process picker to select a process to attach, or Process ID as integer.",
"enum": ["${command:pickProcess}"]
},
{ "description": "ID of the local process to attach to.", "type": "integer" }
]
},
"redirectOutput": { "default": true, "description": "Redirect output.", "type": "boolean" },
"showReturnValue": {
"default": true,
"description": "Show return value of functions when stepping.",
"type": "boolean"
},
"subProcess": {
"default": false,
"description": "Whether to enable Sub Process debugging",
"type": "boolean"
},
"consoleName": {
"default": "Python Debug Console",
"description": "Display name of the debug console or terminal",
"type": "string"
},
"clientOS": { "default": null, "description": "OS that VS code is using.", "enum": ["windows", null, "unix"] }
}
}
}
]
}

View File

@@ -0,0 +1,398 @@
{
"allOf": [
{
"if": { "properties": { "request": { "const": "launch" } }, "required": ["request"] },
"then": {
"required": [],
"properties": {
"debugAdapter": {
"enum": ["legacy", "dlv-dap"],
"description": "Select which debug adapter to use with this launch configuration.",
"default": "dlv-dap"
},
"program": {
"type": "string",
"description": "Path to the program folder (or any go file within that folder) when in `debug` or `test` mode, and to the pre-built binary file to debug in `exec` mode. If it is not an absolute path, the extension interprets it as a workspace relative path.",
"default": "${ZED_WORKTREE_ROOT}"
},
"mode": {
"enum": ["auto", "debug", "test", "exec", "replay", "core"],
"description": "One of `auto`, `debug`, `test`, `exec`, `replay`, `core`. In `auto` mode, the extension will choose either `debug` or `test` depending on active editor window.",
"default": "auto"
},
"traceDirPath": {
"type": "string",
"description": "Directory in which the record trace is located or to be created for a new output trace. For use on 'replay' mode only",
"default": ""
},
"coreFilePath": {
"type": "string",
"description": "Path to the core dump file to open. For use on 'core' mode only",
"default": ""
},
"stopOnEntry": {
"type": "boolean",
"description": "Automatically stop program after launch.",
"default": false
},
"args": {
"type": ["array", "string"],
"description": "Command line arguments passed to the debugged program.",
"items": { "type": "string" },
"default": []
},
"showLog": {
"type": "boolean",
"description": "Show log output from the delve debugger. Maps to dlv's `--log` flag.",
"default": false
},
"cwd": {
"type": "string",
"description": "Workspace relative or absolute path to the working directory of the program being debugged if a non-empty value is specified. The `program` folder is used as the working directory if `cwd` is omitted or empty.",
"default": ""
},
"env": {
"type": "object",
"description": "Environment variables passed to the launched debuggee program. Format as string key:value pairs. Merged with `envFile` and `go.toolsEnvVars` with precedence `env` > `envFile` > `go.toolsEnvVars`.",
"default": {}
},
"substitutePath": {
"type": "array",
"items": {
"type": "object",
"properties": {
"from": {
"type": "string",
"description": "The absolute local path to be replaced when passing paths to the debugger.",
"default": ""
},
"to": {
"type": "string",
"description": "The absolute remote path to be replaced when passing paths back to the client.",
"default": ""
}
}
},
"description": "An array of mappings from a local path (editor) to the remote path (debugee). This setting is useful when working in a file system with symbolic links, running remote debugging, or debugging an executable compiled externally. The debug adapter will replace the local path with the remote path in all of the calls.",
"default": []
},
"buildFlags": {
"type": ["string", "array"],
"items": { "type": "string" },
"description": "Build flags, to be passed to the Go compiler. Maps to dlv's `--build-flags` flag.",
"default": []
},
"dlvFlags": {
"type": "array",
"description": "Extra flags for `dlv`. See `dlv help` for the full list of supported. Flags such as `--log-output`, `--log`, `--log-dest`, `--api-version`, `--output`, `--backend` already have corresponding properties in the debug configuration, and flags such as `--listen` and `--headless` are used internally. If they are specified in `dlvFlags`, they may be ignored or cause an error.",
"items": { "type": "string" },
"default": []
},
"port": {
"type": "number",
"description": "When applied to remote-attach configurations, will look for \"dlv ... --headless --listen=<host>:<port>\" server started externally. In dlv-dap mode this will apply to all other configurations as well. The extension will try to connect to an external server started with \"dlv dap --listen=<host>:<port>\" to ask it to launch/attach to the target process.",
"default": 2345
},
"host": {
"type": "string",
"description": "When applied to remote-attach configurations, will look for \"dlv ... --headless --listen=<host>:<port>\" server started externally. In dlv-dap mode this will apply to all other configurations as well. The extension will try to connect to an external server started with \"dlv dap --listen=<host>:<port>\" to ask it to launch/attach to the target process.",
"default": "127.0.0.1"
},
"trace": {
"type": "string",
"enum": ["verbose", "trace", "log", "info", "warn", "error"],
"default": "error",
"description": "Various levels of logging shown in the debug console & 'Go Debug' output channel. When using the `legacy` debug adapter, the logs will also be written to a file if it is set to a value other than `error`."
},
"envFile": {
"type": ["string", "array"],
"items": { "type": "string" },
"description": "Absolute path to a file containing environment variable definitions, formatted as string key=value pairs. Multiple files can be specified by provided an array of absolute paths. Merged with `env` and `go.toolsEnvVars` with precedence `env` > `envFile` > `go.toolsEnvVars`. ",
"default": ""
},
"backend": {
"type": "string",
"enum": ["default", "native", "lldb", "rr"],
"description": "Backend used by delve. Maps to `dlv`'s `--backend` flag."
},
"output": {
"type": "string",
"description": "Output path for the binary of the debugee.",
"default": "debug"
},
"logOutput": {
"type": "string",
"enum": ["debugger", "gdbwire", "lldbout", "debuglineerr", "rpc", "dap"],
"description": "Comma separated list of components that should produce debug output. Maps to dlv's `--log-output` flag. Check `dlv log` for details.",
"default": "debugger"
},
"logDest": {
"type": "string",
"description": "dlv's `--log-dest` flag. See `dlv log` for details. Number argument is not allowed. Supported only in `dlv-dap` mode, and on Linux and Mac OS."
},
"dlvLoadConfig": {
"type": "object",
"properties": {
"followPointers": {
"type": "boolean",
"description": "FollowPointers requests pointers to be automatically dereferenced.",
"default": true
},
"maxVariableRecurse": {
"type": "number",
"description": "MaxVariableRecurse is how far to recurse when evaluating nested types.",
"default": 1
},
"maxStringLen": {
"type": "number",
"description": "MaxStringLen is the maximum number of bytes read from a string.",
"default": 64
},
"maxArrayValues": {
"type": "number",
"description": "MaxArrayValues is the maximum number of elements read from an array, a slice or a map.",
"default": 64
},
"maxStructFields": {
"type": "number",
"description": "MaxStructFields is the maximum number of fields read from a struct, -1 will read all fields.",
"default": -1
}
},
"description": "LoadConfig describes to delve, how to load values from target's memory. Not applicable when using `dlv-dap` mode.",
"default": {
"followPointers": true,
"maxVariableRecurse": 1,
"maxStringLen": 64,
"maxArrayValues": 64,
"maxStructFields": -1
}
},
"apiVersion": {
"type": "number",
"enum": [1, 2],
"description": "Delve Api Version to use. Default value is 2. Maps to dlv's `--api-version` flag. Not applicable when using `dlv-dap` mode.",
"default": 2
},
"stackTraceDepth": {
"type": "number",
"description": "Maximum depth of stack trace collected from Delve.",
"default": 50
},
"showGlobalVariables": {
"type": "boolean",
"default": false,
"description": "Boolean value to indicate whether global package variables should be shown in the variables pane or not."
},
"showRegisters": {
"type": "boolean",
"default": false,
"description": "Boolean value to indicate whether register variables should be shown in the variables pane or not."
},
"hideSystemGoroutines": {
"type": "boolean",
"default": false,
"description": "Boolean value to indicate whether system goroutines should be hidden from call stack view."
},
"console": {
"default": "internalConsole",
"description": "(Experimental) Where to launch the debugger and the debug target: internal console, integrated terminal, or external terminal. It is ignored in remote debugging.",
"enum": ["internalConsole", "integratedTerminal", "externalTerminal"]
},
"asRoot": {
"default": false,
"description": "(Experimental) Debug with elevated permissions (on Unix). It requires `integrated` or `external` console modes and is ignored in remote debugging.",
"type": "boolean"
}
}
}
},
{
"if": { "properties": { "request": { "const": "attach" } }, "required": ["request"] },
"then": {
"required": [],
"properties": {
"debugAdapter": {
"enum": ["legacy", "dlv-dap"],
"description": "Select which debug adapter to use with this launch configuration.",
"default": "dlv-dap"
},
"processId": {
"anyOf": [
{
"enum": ["${command:pickProcess}", "${command:pickGoProcess}"],
"description": "Use process picker to select a process to attach, or Process ID as integer."
},
{
"type": "string",
"description": "Attach to a process by name. If more than one process matches the name, use the process picker to select a process."
},
{
"type": "number",
"description": "The numeric ID of the process to be debugged. If 0, use the process picker to select a process."
}
],
"default": 0
},
"mode": {
"enum": ["local", "remote"],
"description": "Indicates local or remote debugging. Local is similar to the `dlv attach` command, remote - to `dlv connect`",
"default": "local"
},
"stopOnEntry": {
"type": "boolean",
"description": "Automatically stop program after attach.",
"default": false
},
"dlvFlags": {
"type": "array",
"description": "Extra flags for `dlv`. See `dlv help` for the full list of supported. Flags such as `--log-output`, `--log`, `--log-dest`, `--api-version`, `--output`, `--backend` already have corresponding properties in the debug configuration, and flags such as `--listen` and `--headless` are used internally. If they are specified in `dlvFlags`, they may be ignored or cause an error.",
"items": { "type": "string" },
"default": []
},
"showLog": {
"type": "boolean",
"description": "Show log output from the delve debugger. Maps to dlv's `--log` flag.",
"default": false
},
"cwd": {
"type": "string",
"description": "Workspace relative or absolute path to the working directory of the program being debugged. Default is the current workspace.",
"default": "${ZED_WORKTREE_ROOT}"
},
"remotePath": {
"type": "string",
"description": "The path to the source code on the remote machine, when the remote path is different from the local machine. If specified, becomes the first entry in substitutePath. Not supported with `dlv-dap`.",
"markdownDeprecationMessage": "Use `substitutePath` instead.",
"default": ""
},
"port": {
"type": "number",
"description": "When applied to remote-attach configurations, will look for \"dlv ... --headless --listen=<host>:<port>\" server started externally. In dlv-dap mode, this will apply to all other configurations as well. The extension will try to connect to an external server started with \"dlv dap --listen=<host>:<port>\" to ask it to launch/attach to the target process.",
"default": 2345
},
"host": {
"type": "string",
"description": "When applied to remote-attach configurations, will look for \"dlv ... --headless --listen=<host>:<port>\" server started externally. In dlv-dap mode, this will apply to all other configurations as well. The extension will try to connect to an external server started with \"dlv dap --listen=<host>:<port>\" to ask it to launch/attach to the target process.",
"default": "127.0.0.1"
},
"substitutePath": {
"type": "array",
"items": {
"type": "object",
"properties": {
"from": {
"type": "string",
"description": "The absolute local path to be replaced when passing paths to the debugger.",
"default": ""
},
"to": {
"type": "string",
"description": "The absolute remote path to be replaced when passing paths back to the client.",
"default": ""
}
}
},
"description": "An array of mappings from a local path (editor) to the remote path (debugee). This setting is useful when working in a file system with symbolic links, running remote debugging, or debugging an executable compiled externally. The debug adapter will replace the local path with the remote path in all of the calls. Overridden by `remotePath`.",
"default": []
},
"trace": {
"type": "string",
"enum": ["verbose", "trace", "log", "info", "warn", "error"],
"default": "error",
"description": "Various levels of logging shown in the debug console & 'Go Debug' output channel. When using the `legacy` debug adapter, the logs will also be written to a file if it is set to a value other than `error`."
},
"backend": {
"type": "string",
"enum": ["default", "native", "lldb", "rr"],
"description": "Backend used by delve. Maps to `dlv`'s `--backend` flag."
},
"logOutput": {
"type": "string",
"enum": ["debugger", "gdbwire", "lldbout", "debuglineerr", "rpc", "dap"],
"description": "Comma separated list of components that should produce debug output. Maps to dlv's `--log-output` flag. Check `dlv log` for details.",
"default": "debugger"
},
"logDest": {
"type": "string",
"description": "dlv's `--log-dest` flag. See `dlv log` for details. Number argument is not allowed. Supported only in `dlv-dap` mode and on Linux and Mac OS."
},
"dlvLoadConfig": {
"type": "object",
"properties": {
"followPointers": {
"type": "boolean",
"description": "FollowPointers requests pointers to be automatically dereferenced",
"default": true
},
"maxVariableRecurse": {
"type": "number",
"description": "MaxVariableRecurse is how far to recurse when evaluating nested types",
"default": 1
},
"maxStringLen": {
"type": "number",
"description": "MaxStringLen is the maximum number of bytes read from a string",
"default": 64
},
"maxArrayValues": {
"type": "number",
"description": "MaxArrayValues is the maximum number of elements read from an array, a slice or a map",
"default": 64
},
"maxStructFields": {
"type": "number",
"description": "MaxStructFields is the maximum number of fields read from a struct, -1 will read all fields",
"default": -1
}
},
"description": "LoadConfig describes to delve, how to load values from target's memory. Not applicable when using `dlv-dap` mode.",
"default": {
"followPointers": true,
"maxVariableRecurse": 1,
"maxStringLen": 64,
"maxArrayValues": 64,
"maxStructFields": -1
}
},
"apiVersion": {
"type": "number",
"enum": [1, 2],
"description": "Delve Api Version to use. Default value is 2. Not applicable when using `dlv-dap` mode.",
"default": 2
},
"stackTraceDepth": {
"type": "number",
"description": "Maximum depth of stack trace collected from Delve.",
"default": 50
},
"showGlobalVariables": {
"type": "boolean",
"default": false,
"description": "Boolean value to indicate whether global package variables should be shown in the variables pane or not."
},
"showRegisters": {
"type": "boolean",
"default": false,
"description": "Boolean value to indicate whether register variables should be shown in the variables pane or not."
},
"hideSystemGoroutines": {
"type": "boolean",
"default": false,
"description": "Boolean value to indicate whether system goroutines should be hidden from call stack view."
},
"console": {
"default": "internalConsole",
"description": "(Experimental) Where to launch the debugger: internal console, integrated terminal, or external terminal. This does not affect tty of the running program. It is ignored in remote debugging.",
"enum": ["internalConsole", "integratedTerminal", "externalTerminal"]
},
"asRoot": {
"default": false,
"description": "(Experimental) Debug with elevated permissions (on Unix). This requires `integrated` or `external` console modes and is ignored in remote debugging.",
"type": "boolean"
}
}
}
}
]
}

View File

@@ -0,0 +1,88 @@
{
"oneOf": [
{
"allOf": [
{
"type": "object",
"required": ["request"],
"properties": {
"request": {
"type": "string",
"enum": ["launch"],
"description": "Request to launch a new process"
}
}
},
{
"type": "object",
"properties": {
"program": {
"type": "string",
"description": "The program to debug. This corresponds to the GDB 'file' command."
},
"args": {
"type": "array",
"items": {
"type": "string"
},
"description": "Command line arguments passed to the program. These strings are provided as command-line arguments to the inferior.",
"default": []
},
"cwd": {
"type": "string",
"description": "Working directory for the debugged program. GDB will change its working directory to this directory."
},
"env": {
"type": "object",
"description": "Environment variables for the debugged program. Each key is the name of an environment variable; each value is the value of that variable."
},
"stopAtBeginningOfMainSubprogram": {
"type": "boolean",
"description": "When true, GDB will set a temporary breakpoint at the program's main procedure, like the 'start' command.",
"default": false
},
"stopOnEntry": {
"type": "boolean",
"description": "When true, GDB will set a temporary breakpoint at the program's first instruction, like the 'starti' command.",
"default": false
}
},
"required": ["program"]
}
]
},
{
"allOf": [
{
"type": "object",
"required": ["request"],
"properties": {
"request": {
"type": "string",
"enum": ["attach"],
"description": "Request to attach to an existing process"
}
}
},
{
"type": "object",
"properties": {
"pid": {
"type": "number",
"description": "The process ID to which GDB should attach."
},
"program": {
"type": "string",
"description": "The program to debug (optional). This corresponds to the GDB 'file' command. In many cases, GDB can determine which program is running automatically."
},
"target": {
"type": "string",
"description": "The target to which GDB should connect. This is passed to the 'target remote' command."
}
},
"required": ["pid"]
}
]
}
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,13 @@
use std::{collections::HashMap, path::PathBuf, sync::OnceLock};
use std::{
borrow::Cow,
collections::HashMap,
path::PathBuf,
sync::{LazyLock, OnceLock},
};
use anyhow::{Context as _, Result};
use async_trait::async_trait;
use dap::adapters::{DebugTaskDefinition, latest_github_release};
use dap::adapters::{DapDelegate, DebugTaskDefinition, latest_github_release};
use futures::StreamExt;
use gpui::AsyncApp;
use serde_json::Value;
@@ -12,12 +17,12 @@ use util::fs::remove_matching;
use crate::*;
#[derive(Default)]
pub(crate) struct CodeLldbDebugAdapter {
pub struct CodeLldbDebugAdapter {
path_to_codelldb: OnceLock<String>,
}
impl CodeLldbDebugAdapter {
const ADAPTER_NAME: &'static str = "CodeLLDB";
pub const ADAPTER_NAME: &'static str = "CodeLLDB";
async fn request_args(
&self,
@@ -82,6 +87,34 @@ impl CodeLldbDebugAdapter {
}
}
#[cfg(feature = "update-schemas")]
impl CodeLldbDebugAdapter {
pub fn get_schema(
temp_dir: &tempfile::TempDir,
delegate: UpdateSchemasDapDelegate,
) -> anyhow::Result<serde_json::Value> {
let (package_json, package_nls_json) = get_vsix_package_json(
temp_dir,
"vadimcn/codelldb",
|_| Ok("codelldb-bootstrap.vsix".into()),
delegate,
)?;
let package_json = parse_package_json(package_json, package_nls_json)?;
let [debugger] =
<[_; 1]>::try_from(package_json.contributes.debuggers).map_err(|debuggers| {
anyhow::anyhow!(
"unexpected number of codelldb debuggers: {}",
debuggers.len()
)
})?;
Ok(schema_for_configuration_attributes(
debugger.configuration_attributes,
))
}
}
#[async_trait(?Send)]
impl DebugAdapter for CodeLldbDebugAdapter {
fn name(&self) -> DebugAdapterName {
@@ -132,195 +165,12 @@ impl DebugAdapter for CodeLldbDebugAdapter {
})
}
fn dap_schema(&self) -> serde_json::Value {
json!({
"properties": {
"request": {
"type": "string",
"enum": ["attach", "launch"],
"description": "Debug adapter request type"
},
"program": {
"type": "string",
"description": "Path to the program to debug or attach to"
},
"args": {
"type": ["array", "string"],
"description": "Program arguments"
},
"cwd": {
"type": "string",
"description": "Program working directory"
},
"env": {
"type": "object",
"description": "Additional environment variables",
"patternProperties": {
".*": {
"type": "string"
}
}
},
"envFile": {
"type": "string",
"description": "File to read the environment variables from"
},
"stdio": {
"type": ["null", "string", "array", "object"],
"description": "Destination for stdio streams: null = send to debugger console or a terminal, \"<path>\" = attach to a file/tty/fifo"
},
"terminal": {
"type": "string",
"enum": ["integrated", "console"],
"description": "Terminal type to use",
"default": "integrated"
},
"console": {
"type": "string",
"enum": ["integratedTerminal", "internalConsole"],
"description": "Terminal type to use (compatibility alias of 'terminal')"
},
"stopOnEntry": {
"type": "boolean",
"description": "Automatically stop debuggee after launch",
"default": false
},
"initCommands": {
"type": "array",
"description": "Initialization commands executed upon debugger startup",
"items": {
"type": "string"
}
},
"targetCreateCommands": {
"type": "array",
"description": "Commands that create the debug target",
"items": {
"type": "string"
}
},
"preRunCommands": {
"type": "array",
"description": "Commands executed just before the program is launched",
"items": {
"type": "string"
}
},
"processCreateCommands": {
"type": "array",
"description": "Commands that create the debuggee process",
"items": {
"type": "string"
}
},
"postRunCommands": {
"type": "array",
"description": "Commands executed just after the program has been launched",
"items": {
"type": "string"
}
},
"preTerminateCommands": {
"type": "array",
"description": "Commands executed just before the debuggee is terminated or disconnected from",
"items": {
"type": "string"
}
},
"exitCommands": {
"type": "array",
"description": "Commands executed at the end of debugging session",
"items": {
"type": "string"
}
},
"expressions": {
"type": "string",
"enum": ["simple", "python", "native"],
"description": "The default evaluator type used for expressions"
},
"sourceMap": {
"type": "object",
"description": "Source path remapping between the build machine and the local machine",
"patternProperties": {
".*": {
"type": ["string", "null"]
}
}
},
"relativePathBase": {
"type": "string",
"description": "Base directory used for resolution of relative source paths. Defaults to the workspace folder"
},
"sourceLanguages": {
"type": "array",
"description": "A list of source languages to enable language-specific features for",
"items": {
"type": "string"
}
},
"reverseDebugging": {
"type": "boolean",
"description": "Enable reverse debugging",
"default": false
},
"breakpointMode": {
"type": "string",
"enum": ["path", "file"],
"description": "Specifies how source breakpoints should be set"
},
"pid": {
"type": ["integer", "string"],
"description": "Process id to attach to"
},
"waitFor": {
"type": "boolean",
"description": "Wait for the process to launch (MacOS only)",
"default": false
}
},
"required": ["request"],
"allOf": [
{
"if": {
"properties": {
"request": {
"enum": ["launch"]
}
}
},
"then": {
"oneOf": [
{
"required": ["program"]
},
{
"required": ["targetCreateCommands"]
}
]
}
},
{
"if": {
"properties": {
"request": {
"enum": ["attach"]
}
}
},
"then": {
"oneOf": [
{
"required": ["pid"]
},
{
"required": ["program"]
}
]
}
}
]
})
fn dap_schema(&self) -> Cow<'static, serde_json::Value> {
static SCHEMA: LazyLock<serde_json::Value> = LazyLock::new(|| {
const RAW_SCHEMA: &str = include_str!("../schemas/CodeLLDB.json");
serde_json::from_str(RAW_SCHEMA).unwrap()
});
Cow::Borrowed(&*SCHEMA)
}
async fn get_binary(
@@ -341,9 +191,10 @@ impl DebugAdapter for CodeLldbDebugAdapter {
let version_path =
if let Ok(version) = self.fetch_latest_adapter_version(delegate).await {
adapters::download_adapter_from_github(
self.name(),
Self::ADAPTER_NAME,
version.clone(),
adapters::DownloadedFileType::Vsix,
paths::debug_adapters_dir(),
delegate.as_ref(),
)
.await?;

View File

@@ -9,7 +9,7 @@ use std::sync::Arc;
use anyhow::Result;
use async_trait::async_trait;
use codelldb::CodeLldbDebugAdapter;
pub use codelldb::CodeLldbDebugAdapter;
use dap::{
DapRegistry,
adapters::{
@@ -19,11 +19,11 @@ use dap::{
configure_tcp_connection,
};
use gdb::GdbDebugAdapter;
use go::GoDebugAdapter;
pub use go::GoDebugAdapter;
use gpui::{App, BorrowAppContext};
use javascript::JsDebugAdapter;
pub use javascript::JsDebugAdapter;
use php::PhpDebugAdapter;
use python::PythonDebugAdapter;
pub use python::PythonDebugAdapter;
use serde_json::json;
use task::{DebugScenario, ZedDebugConfig};
@@ -42,3 +42,238 @@ pub fn init(cx: &mut App) {
}
})
}
#[cfg(feature = "update-schemas")]
#[derive(Clone)]
pub struct UpdateSchemasDapDelegate {
client: std::sync::Arc<reqwest_client::ReqwestClient>,
fs: std::sync::Arc<fs::RealFs>,
executor: gpui::BackgroundExecutor,
}
#[cfg(feature = "update-schemas")]
impl UpdateSchemasDapDelegate {
pub fn new() -> Self {
let executor = gpui::background_executor();
let client =
Arc::new(reqwest_client::ReqwestClient::user_agent("Zed DAP schema updater").unwrap());
let fs = Arc::new(fs::RealFs::new(None, executor.clone()));
Self {
client,
fs,
executor,
}
}
}
#[cfg(feature = "update-schemas")]
#[async_trait]
impl dap::adapters::DapDelegate for UpdateSchemasDapDelegate {
fn worktree_id(&self) -> settings::WorktreeId {
unreachable!()
}
fn worktree_root_path(&self) -> &std::path::Path {
unreachable!()
}
fn http_client(&self) -> Arc<dyn dap::adapters::HttpClient> {
self.client.clone()
}
fn node_runtime(&self) -> node_runtime::NodeRuntime {
unreachable!()
}
fn toolchain_store(&self) -> Arc<dyn language::LanguageToolchainStore> {
unreachable!()
}
fn fs(&self) -> Arc<dyn fs::Fs> {
self.fs.clone()
}
fn output_to_console(&self, msg: String) {
eprintln!("{msg}")
}
async fn which(&self, _command: &std::ffi::OsStr) -> Option<std::path::PathBuf> {
unreachable!()
}
async fn read_text_file(&self, _path: std::path::PathBuf) -> Result<String> {
unreachable!()
}
async fn shell_env(&self) -> collections::HashMap<String, String> {
unreachable!()
}
}
#[cfg(feature = "update-schemas")]
#[derive(Debug, serde::Serialize, serde::Deserialize)]
struct PackageJsonConfigurationAttributes {
#[serde(default, skip_serializing_if = "Option::is_none")]
launch: Option<serde_json::Value>,
#[serde(default, skip_serializing_if = "Option::is_none")]
attach: Option<serde_json::Value>,
}
#[cfg(feature = "update-schemas")]
#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
struct PackageJsonDebugger {
r#type: String,
configuration_attributes: PackageJsonConfigurationAttributes,
}
#[cfg(feature = "update-schemas")]
#[derive(Debug, serde::Serialize, serde::Deserialize)]
struct PackageJsonContributes {
debuggers: Vec<PackageJsonDebugger>,
}
#[cfg(feature = "update-schemas")]
#[derive(Debug, serde::Serialize, serde::Deserialize)]
struct PackageJson {
contributes: PackageJsonContributes,
}
#[cfg(feature = "update-schemas")]
fn get_vsix_package_json(
temp_dir: &tempfile::TempDir,
repo: &str,
asset_name: impl FnOnce(&gpui::http_client::github::GithubRelease) -> anyhow::Result<String>,
delegate: UpdateSchemasDapDelegate,
) -> anyhow::Result<(String, Option<String>)> {
use anyhow::Context as _;
use dap::adapters::DownloadedFileType;
use fs::Fs as _;
let temp_dir = std::fs::canonicalize(temp_dir.path())?;
let fs = delegate.fs.clone();
let client = delegate.client.clone();
let executor = delegate.executor.clone();
executor.block(async move {
let release = adapters::latest_github_release(repo, true, false, client.clone()).await?;
let asset_name = asset_name(&release)?;
let version = AdapterVersion {
tag_name: release.tag_name,
url: release
.assets
.iter()
.find(|asset| asset.name == asset_name)
.with_context(|| format!("no asset found matching {asset_name:?}"))?
.browser_download_url
.clone(),
};
let path = adapters::download_adapter_from_github(
"schemas",
version,
DownloadedFileType::Vsix,
&temp_dir,
&delegate,
)
.await?;
let package_json = fs
.load(&path.join("extension").join("package.json"))
.await?;
let package_nls_json = fs
.load(&path.join("extension").join("package.nls.json"))
.await
.ok();
anyhow::Ok((package_json, package_nls_json))
})
}
#[cfg(feature = "update-schemas")]
fn parse_package_json(
package_json: String,
package_nls_json: Option<String>,
) -> anyhow::Result<PackageJson> {
use collections::HashMap;
use task::{EnvVariableReplacer, VariableName};
let package_nls_json = package_nls_json
.map(|package_nls_json| {
let package_nls_json =
serde_json::from_str::<HashMap<String, serde_json::Value>>(&package_nls_json)?;
let package_nls_json = package_nls_json
.into_iter()
.filter_map(|(k, v)| {
let v = v.as_str()?;
Some((k, v.to_owned()))
})
.collect();
anyhow::Ok(package_nls_json)
})
.transpose()?
.unwrap_or_default();
let package_json: serde_json::Value = serde_json::from_str(&package_json)?;
struct Replacer {
package_nls_json: HashMap<String, String>,
env: EnvVariableReplacer,
}
impl Replacer {
fn replace(&self, input: serde_json::Value) -> serde_json::Value {
match input {
serde_json::Value::String(s) => {
if s.starts_with("%") && s.ends_with("%") {
self.package_nls_json
.get(s.trim_matches('%'))
.map(|s| s.as_str().into())
.unwrap_or("(missing)".into())
} else {
self.env.replace(&s).into()
}
}
serde_json::Value::Array(arr) => {
serde_json::Value::Array(arr.into_iter().map(|v| self.replace(v)).collect())
}
serde_json::Value::Object(obj) => serde_json::Value::Object(
obj.into_iter().map(|(k, v)| (k, self.replace(v))).collect(),
),
_ => input,
}
}
}
let env = EnvVariableReplacer::new(HashMap::from_iter([(
"workspaceFolder".to_owned(),
VariableName::WorktreeRoot.to_string(),
)]));
let replacer = Replacer {
env,
package_nls_json,
};
let package_json = replacer.replace(package_json);
let package_json: PackageJson = serde_json::from_value(package_json)?;
Ok(package_json)
}
#[cfg(feature = "update-schemas")]
fn schema_for_configuration_attributes(
attrs: PackageJsonConfigurationAttributes,
) -> serde_json::Value {
let conjuncts = attrs
.launch
.map(|schema| ("launch", schema))
.into_iter()
.chain(attrs.attach.map(|schema| ("attach", schema)))
.map(|(request, schema)| {
json!({
"if": {
"properties": {
"request": {
"const": request
}
},
"required": ["request"]
},
"then": schema
})
})
.collect::<Vec<_>>();
json!({
"allOf": conjuncts
})
}

View File

@@ -1,4 +1,4 @@
use std::{collections::HashMap, ffi::OsStr};
use std::{borrow::Cow, collections::HashMap, ffi::OsStr, sync::LazyLock};
use anyhow::{Context as _, Result, bail};
use async_trait::async_trait;
@@ -63,95 +63,12 @@ impl DebugAdapter for GdbDebugAdapter {
})
}
fn dap_schema(&self) -> serde_json::Value {
json!({
"oneOf": [
{
"allOf": [
{
"type": "object",
"required": ["request"],
"properties": {
"request": {
"type": "string",
"enum": ["launch"],
"description": "Request to launch a new process"
}
}
},
{
"type": "object",
"properties": {
"program": {
"type": "string",
"description": "The program to debug. This corresponds to the GDB 'file' command."
},
"args": {
"type": "array",
"items": {
"type": "string"
},
"description": "Command line arguments passed to the program. These strings are provided as command-line arguments to the inferior.",
"default": []
},
"cwd": {
"type": "string",
"description": "Working directory for the debugged program. GDB will change its working directory to this directory."
},
"env": {
"type": "object",
"description": "Environment variables for the debugged program. Each key is the name of an environment variable; each value is the value of that variable."
},
"stopAtBeginningOfMainSubprogram": {
"type": "boolean",
"description": "When true, GDB will set a temporary breakpoint at the program's main procedure, like the 'start' command.",
"default": false
},
"stopOnEntry": {
"type": "boolean",
"description": "When true, GDB will set a temporary breakpoint at the program's first instruction, like the 'starti' command.",
"default": false
}
},
"required": ["program"]
}
]
},
{
"allOf": [
{
"type": "object",
"required": ["request"],
"properties": {
"request": {
"type": "string",
"enum": ["attach"],
"description": "Request to attach to an existing process"
}
}
},
{
"type": "object",
"properties": {
"pid": {
"type": "number",
"description": "The process ID to which GDB should attach."
},
"program": {
"type": "string",
"description": "The program to debug (optional). This corresponds to the GDB 'file' command. In many cases, GDB can determine which program is running automatically."
},
"target": {
"type": "string",
"description": "The target to which GDB should connect. This is passed to the 'target remote' command."
}
},
"required": ["pid"]
}
]
}
]
})
fn dap_schema(&self) -> Cow<'static, serde_json::Value> {
static SCHEMA: LazyLock<serde_json::Value> = LazyLock::new(|| {
const RAW_SCHEMA: &str = include_str!("../schemas/GDB.json");
serde_json::from_str(RAW_SCHEMA).unwrap()
});
Cow::Borrowed(&*SCHEMA)
}
async fn get_binary(

View File

@@ -16,22 +16,23 @@ use task::TcpArgumentsTemplate;
use util;
use std::{
borrow::Cow,
env::consts,
ffi::OsStr,
path::{Path, PathBuf},
str::FromStr,
sync::OnceLock,
sync::{LazyLock, OnceLock},
};
use crate::*;
#[derive(Default, Debug)]
pub(crate) struct GoDebugAdapter {
pub struct GoDebugAdapter {
shim_path: OnceLock<PathBuf>,
}
impl GoDebugAdapter {
const ADAPTER_NAME: &'static str = "Delve";
pub const ADAPTER_NAME: &'static str = "Delve";
async fn fetch_latest_adapter_version(
delegate: &Arc<dyn DapDelegate>,
) -> Result<AdapterVersion> {
@@ -78,9 +79,10 @@ impl GoDebugAdapter {
DownloadedFileType::GzipTar
};
download_adapter_from_github(
"delve-shim-dap".into(),
"delve-shim-dap",
asset.clone(),
ty,
paths::debug_adapters_dir(),
delegate.as_ref(),
)
.await?;
@@ -95,6 +97,37 @@ impl GoDebugAdapter {
}
}
#[cfg(feature = "update-schemas")]
impl GoDebugAdapter {
pub fn get_schema(
temp_dir: &tempfile::TempDir,
delegate: UpdateSchemasDapDelegate,
) -> anyhow::Result<serde_json::Value> {
let (package_json, package_nls_json) = get_vsix_package_json(
temp_dir,
"golang/vscode-go",
|version| {
let version = version
.tag_name
.strip_prefix("v")
.context("parse tag name")?;
Ok(format!("go-{version}.vsix"))
},
delegate,
)?;
let package_json = parse_package_json(package_json, package_nls_json)?;
let [debugger] =
<[_; 1]>::try_from(package_json.contributes.debuggers).map_err(|debuggers| {
anyhow::anyhow!("unexpected number of go debuggers: {}", debuggers.len())
})?;
Ok(schema_for_configuration_attributes(
debugger.configuration_attributes,
))
}
}
#[async_trait(?Send)]
impl DebugAdapter for GoDebugAdapter {
fn name(&self) -> DebugAdapterName {
@@ -105,260 +138,12 @@ impl DebugAdapter for GoDebugAdapter {
Some(SharedString::new_static("Go").into())
}
fn dap_schema(&self) -> serde_json::Value {
// Create common properties shared between launch and attach
let common_properties = json!({
"debugAdapter": {
"enum": ["legacy", "dlv-dap"],
"description": "Select which debug adapter to use with this configuration.",
"default": "dlv-dap"
},
"stopOnEntry": {
"type": "boolean",
"description": "Automatically stop program after launch or attach.",
"default": false
},
"showLog": {
"type": "boolean",
"description": "Show log output from the delve debugger. Maps to dlv's `--log` flag.",
"default": false
},
"cwd": {
"type": "string",
"description": "Workspace relative or absolute path to the working directory of the program being debugged.",
"default": "${ZED_WORKTREE_ROOT}"
},
"dlvFlags": {
"type": "array",
"description": "Extra flags for `dlv`. See `dlv help` for the full list of supported flags.",
"items": {
"type": "string"
},
"default": []
},
"port": {
"type": "number",
"description": "Debug server port. For remote configurations, this is where to connect.",
"default": 2345
},
"host": {
"type": "string",
"description": "Debug server host. For remote configurations, this is where to connect.",
"default": "127.0.0.1"
},
"substitutePath": {
"type": "array",
"items": {
"type": "object",
"properties": {
"from": {
"type": "string",
"description": "The absolute local path to be replaced."
},
"to": {
"type": "string",
"description": "The absolute remote path to replace with."
}
}
},
"description": "Mappings from local to remote paths for debugging.",
"default": []
},
"trace": {
"type": "string",
"enum": ["verbose", "trace", "log", "info", "warn", "error"],
"default": "error",
"description": "Debug logging level."
},
"backend": {
"type": "string",
"enum": ["default", "native", "lldb", "rr"],
"description": "Backend used by delve. Maps to `dlv`'s `--backend` flag."
},
"logOutput": {
"type": "string",
"enum": ["debugger", "gdbwire", "lldbout", "debuglineerr", "rpc", "dap"],
"description": "Components that should produce debug output.",
"default": "debugger"
},
"logDest": {
"type": "string",
"description": "Log destination for delve."
},
"stackTraceDepth": {
"type": "number",
"description": "Maximum depth of stack traces.",
"default": 50
},
"showGlobalVariables": {
"type": "boolean",
"default": false,
"description": "Show global package variables in variables pane."
},
"showRegisters": {
"type": "boolean",
"default": false,
"description": "Show register variables in variables pane."
},
"hideSystemGoroutines": {
"type": "boolean",
"default": false,
"description": "Hide system goroutines from call stack view."
},
"console": {
"default": "internalConsole",
"description": "Where to launch the debugger.",
"enum": ["internalConsole", "integratedTerminal"]
},
"asRoot": {
"default": false,
"description": "Debug with elevated permissions (on Unix).",
"type": "boolean"
}
fn dap_schema(&self) -> Cow<'static, serde_json::Value> {
static SCHEMA: LazyLock<serde_json::Value> = LazyLock::new(|| {
const RAW_SCHEMA: &str = include_str!("../schemas/Delve.json");
serde_json::from_str(RAW_SCHEMA).unwrap()
});
// Create launch-specific properties
let launch_properties = json!({
"program": {
"type": "string",
"description": "Path to the program folder or file to debug.",
"default": "${ZED_WORKTREE_ROOT}"
},
"args": {
"type": ["array", "string"],
"description": "Command line arguments for the program.",
"items": {
"type": "string"
},
"default": []
},
"env": {
"type": "object",
"description": "Environment variables for the debugged program.",
"default": {}
},
"envFile": {
"type": ["string", "array"],
"items": {
"type": "string"
},
"description": "Path(s) to files with environment variables.",
"default": ""
},
"buildFlags": {
"type": ["string", "array"],
"items": {
"type": "string"
},
"description": "Flags for the Go compiler.",
"default": []
},
"output": {
"type": "string",
"description": "Output path for the binary.",
"default": "debug"
},
"mode": {
"enum": [ "debug", "test", "exec", "replay", "core"],
"description": "Debug mode for launch configuration.",
},
"traceDirPath": {
"type": "string",
"description": "Directory for record trace (for 'replay' mode).",
"default": ""
},
"coreFilePath": {
"type": "string",
"description": "Path to core dump file (for 'core' mode).",
"default": ""
}
});
// Create attach-specific properties
let attach_properties = json!({
"processId": {
"anyOf": [
{
"enum": ["${command:pickProcess}", "${command:pickGoProcess}"],
"description": "Use process picker to select a process."
},
{
"type": "string",
"description": "Process name to attach to."
},
{
"type": "number",
"description": "Process ID to attach to."
}
],
"default": 0
},
"mode": {
"enum": ["local", "remote"],
"description": "Local or remote debugging.",
"default": "local"
},
"remotePath": {
"type": "string",
"description": "Path to source on remote machine.",
"markdownDeprecationMessage": "Use `substitutePath` instead.",
"default": ""
}
});
// Create the final schema
json!({
"oneOf": [
{
"allOf": [
{
"type": "object",
"required": ["request"],
"properties": {
"request": {
"type": "string",
"enum": ["launch"],
"description": "Request to launch a new process"
}
}
},
{
"type": "object",
"properties": common_properties
},
{
"type": "object",
"required": ["program", "mode"],
"properties": launch_properties
}
]
},
{
"allOf": [
{
"type": "object",
"required": ["request"],
"properties": {
"request": {
"type": "string",
"enum": ["attach"],
"description": "Request to attach to an existing process"
}
}
},
{
"type": "object",
"properties": common_properties
},
{
"type": "object",
"required": ["mode"],
"properties": attach_properties
}
]
}
]
})
Cow::Borrowed(&*SCHEMA)
}
async fn config_from_zed_format(&self, zed_scenario: ZedDebugConfig) -> Result<DebugScenario> {

View File

@@ -4,19 +4,23 @@ use collections::HashMap;
use dap::{StartDebuggingRequestArguments, adapters::DebugTaskDefinition};
use gpui::AsyncApp;
use serde_json::Value;
use std::{path::PathBuf, sync::OnceLock};
use std::{
borrow::Cow,
path::PathBuf,
sync::{LazyLock, OnceLock},
};
use task::DebugRequest;
use util::{ResultExt, maybe};
use crate::*;
#[derive(Debug, Default)]
pub(crate) struct JsDebugAdapter {
pub struct JsDebugAdapter {
checked: OnceLock<()>,
}
impl JsDebugAdapter {
const ADAPTER_NAME: &'static str = "JavaScript";
pub const ADAPTER_NAME: &'static str = "JavaScript";
const ADAPTER_NPM_NAME: &'static str = "vscode-js-debug";
const ADAPTER_PATH: &'static str = "js-debug/src/dapDebugServer.js";
@@ -233,270 +237,12 @@ impl DebugAdapter for JsDebugAdapter {
})
}
fn dap_schema(&self) -> serde_json::Value {
json!({
"oneOf": [
{
"allOf": [
{
"type": "object",
"required": ["request"],
"properties": {
"request": {
"type": "string",
"enum": ["launch"],
"description": "Request to launch a new process"
}
}
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["pwa-node", "node", "chrome", "pwa-chrome", "msedge", "pwa-msedge", "node-terminal"],
"description": "The type of debug session",
"default": "pwa-node"
},
"program": {
"type": "string",
"description": "Path to the program or file to debug"
},
"cwd": {
"type": "string",
"description": "Absolute path to the working directory of the program being debugged"
},
"args": {
"type": ["array", "string"],
"description": "Command line arguments passed to the program",
"items": {
"type": "string"
},
"default": []
},
"env": {
"type": "object",
"description": "Environment variables passed to the program",
"default": {}
},
"envFile": {
"type": ["string", "array"],
"description": "Path to a file containing environment variable definitions",
"items": {
"type": "string"
}
},
"stopOnEntry": {
"type": "boolean",
"description": "Automatically stop program after launch",
"default": false
},
"attachSimplePort": {
"type": "number",
"description": "If set, attaches to the process via the given port. This is generally no longer necessary for Node.js programs and loses the ability to debug child processes, but can be useful in more esoteric scenarios such as with Deno and Docker launches. If set to 0, a random port will be chosen and --inspect-brk added to the launch arguments automatically."
},
"runtimeExecutable": {
"type": ["string", "null"],
"description": "Runtime to use, an absolute path or the name of a runtime available on PATH",
"default": "node"
},
"runtimeArgs": {
"type": ["array", "null"],
"description": "Arguments passed to the runtime executable",
"items": {
"type": "string"
},
"default": []
},
"outFiles": {
"type": "array",
"description": "Glob patterns for locating generated JavaScript files",
"items": {
"type": "string"
},
"default": ["${ZED_WORKTREE_ROOT}/**/*.js", "!**/node_modules/**"]
},
"sourceMaps": {
"type": "boolean",
"description": "Use JavaScript source maps if they exist",
"default": true
},
"pauseForSourceMap": {
"type": "boolean",
"description": "Wait for source maps to load before setting breakpoints.",
"default": true
},
"sourceMapRenames": {
"type": "boolean",
"description": "Whether to use the \"names\" mapping in sourcemaps.",
"default": true
},
"sourceMapPathOverrides": {
"type": "object",
"description": "Rewrites the locations of source files from what the sourcemap says to their locations on disk",
"default": {}
},
"restart": {
"type": ["boolean", "object"],
"description": "Restart session after Node.js has terminated",
"default": false
},
"trace": {
"type": ["boolean", "object"],
"description": "Enables logging of the Debug Adapter",
"default": false
},
"console": {
"type": "string",
"enum": ["internalConsole", "integratedTerminal"],
"description": "Where to launch the debug target",
"default": "internalConsole"
},
// Browser-specific
"url": {
"type": ["string", "null"],
"description": "Will navigate to this URL and attach to it (browser debugging)"
},
"webRoot": {
"type": "string",
"description": "Workspace absolute path to the webserver root",
"default": "${ZED_WORKTREE_ROOT}"
},
"userDataDir": {
"type": ["string", "boolean"],
"description": "Path to a custom Chrome user profile (browser debugging)",
"default": true
},
"skipFiles": {
"type": "array",
"description": "An array of glob patterns for files to skip when debugging",
"items": {
"type": "string"
},
"default": ["<node_internals>/**"]
},
"timeout": {
"type": "number",
"description": "Retry for this number of milliseconds to connect to the debug adapter",
"default": 10000
},
"resolveSourceMapLocations": {
"type": ["array", "null"],
"description": "A list of minimatch patterns for source map resolution",
"items": {
"type": "string"
}
}
},
}
]
},
{
"allOf": [
{
"type": "object",
"required": ["request"],
"properties": {
"request": {
"type": "string",
"enum": ["attach"],
"description": "Request to attach to an existing process"
}
}
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["pwa-node", "node", "chrome", "pwa-chrome", "edge", "pwa-edge"],
"description": "The type of debug session",
"default": "pwa-node"
},
"processId": {
"type": ["string", "number"],
"description": "ID of process to attach to (Node.js debugging)"
},
"port": {
"type": "number",
"description": "Debug port to attach to",
"default": 9229
},
"address": {
"type": "string",
"description": "TCP/IP address of the process to be debugged",
"default": "localhost"
},
"restart": {
"type": ["boolean", "object"],
"description": "Restart session after Node.js has terminated",
"default": false
},
"sourceMaps": {
"type": "boolean",
"description": "Use JavaScript source maps if they exist",
"default": true
},
"sourceMapPathOverrides": {
"type": "object",
"description": "Rewrites the locations of source files from what the sourcemap says to their locations on disk",
"default": {}
},
"outFiles": {
"type": "array",
"description": "Glob patterns for locating generated JavaScript files",
"items": {
"type": "string"
},
"default": ["${ZED_WORKTREE_ROOT}/**/*.js", "!**/node_modules/**"]
},
"url": {
"type": "string",
"description": "Will search for a page with this URL and attach to it (browser debugging)"
},
"webRoot": {
"type": "string",
"description": "Workspace absolute path to the webserver root",
"default": "${ZED_WORKTREE_ROOT}"
},
"skipFiles": {
"type": "array",
"description": "An array of glob patterns for files to skip when debugging",
"items": {
"type": "string"
},
"default": ["<node_internals>/**"]
},
"timeout": {
"type": "number",
"description": "Retry for this number of milliseconds to connect to the debug adapter",
"default": 10000
},
"resolveSourceMapLocations": {
"type": ["array", "null"],
"description": "A list of minimatch patterns for source map resolution",
"items": {
"type": "string"
}
},
"remoteRoot": {
"type": ["string", "null"],
"description": "Path to the remote directory containing the program"
},
"localRoot": {
"type": ["string", "null"],
"description": "Path to the local directory containing the program"
}
},
"oneOf": [
{ "required": ["processId"] },
{ "required": ["port"] }
]
}
]
}
]
})
fn dap_schema(&self) -> Cow<'static, serde_json::Value> {
static SCHEMA: LazyLock<serde_json::Value> = LazyLock::new(|| {
const RAW_SCHEMA: &str = include_str!("../schemas/JavaScript.json");
serde_json::from_str(RAW_SCHEMA).unwrap()
});
Cow::Borrowed(&*SCHEMA)
}
async fn get_binary(
@@ -511,9 +257,10 @@ impl DebugAdapter for JsDebugAdapter {
delegate.output_to_console(format!("Checking latest version of {}...", self.name()));
if let Some(version) = self.fetch_latest_adapter_version(delegate).await.log_err() {
adapters::download_adapter_from_github(
self.name(),
Self::ADAPTER_NAME,
version,
adapters::DownloadedFileType::GzipTar,
paths::debug_adapters_dir(),
delegate.as_ref(),
)
.await?;
@@ -536,6 +283,84 @@ impl DebugAdapter for JsDebugAdapter {
}
}
#[cfg(feature = "update-schemas")]
impl JsDebugAdapter {
pub fn get_schema(
temp_dir: &tempfile::TempDir,
delegate: UpdateSchemasDapDelegate,
) -> anyhow::Result<serde_json::Value> {
let (package_json, package_nls_json) = get_vsix_package_json(
temp_dir,
&format!("microsoft/{}", Self::ADAPTER_NPM_NAME),
|release| {
let version = release
.tag_name
.strip_prefix("v")
.context("parse version")?;
let asset_name = format!("ms-vscode.js-debug.{version}.vsix");
Ok(asset_name)
},
delegate,
)?;
let package_json = parse_package_json(package_json, package_nls_json)?;
let types = package_json
.contributes
.debuggers
.iter()
.map(|debugger| debugger.r#type.clone())
.collect::<Vec<_>>();
let mut conjuncts = package_json
.contributes
.debuggers
.into_iter()
.flat_map(|debugger| {
let r#type = debugger.r#type;
let configuration_attributes = debugger.configuration_attributes;
configuration_attributes
.launch
.map(|schema| ("launch", schema))
.into_iter()
.chain(
configuration_attributes
.attach
.map(|schema| ("attach", schema)),
)
.map(|(request, schema)| {
json!({
"if": {
"properties": {
"type": {
"const": r#type
},
"request": {
"const": request
}
},
"required": ["type", "request"]
},
"then": schema
})
})
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
conjuncts.push(json!({
"properties": {
"type": {
"enum": types
}
},
"required": ["type"]
}));
let schema = json!({
"allOf": conjuncts
});
Ok(schema)
}
}
fn normalize_task_type(task_type: &mut Value) {
let Some(task_type_str) = task_type.as_str() else {
return;

View File

@@ -6,6 +6,7 @@ use dap::StartDebuggingRequestArgumentsRequest;
use dap::adapters::{DebugTaskDefinition, TcpArguments};
use gpui::{AsyncApp, SharedString};
use language::LanguageName;
use std::borrow::Cow;
use std::{collections::HashMap, path::PathBuf, sync::OnceLock};
use util::ResultExt;
@@ -125,8 +126,8 @@ impl PhpDebugAdapter {
#[async_trait(?Send)]
impl DebugAdapter for PhpDebugAdapter {
fn dap_schema(&self) -> serde_json::Value {
json!({
fn dap_schema(&self) -> Cow<'static, serde_json::Value> {
Cow::Owned(json!({
"properties": {
"request": {
"type": "string",
@@ -294,7 +295,7 @@ impl DebugAdapter for PhpDebugAdapter {
}
},
"required": ["request", "program"]
})
}))
}
fn name(&self) -> DebugAdapterName {
@@ -347,9 +348,10 @@ impl DebugAdapter for PhpDebugAdapter {
delegate.output_to_console(format!("Checking latest version of {}...", self.name()));
if let Some(version) = self.fetch_latest_adapter_version(delegate).await.log_err() {
adapters::download_adapter_from_github(
self.name(),
Self::ADAPTER_NAME,
version,
adapters::DownloadedFileType::Vsix,
paths::debug_adapters_dir(),
delegate.as_ref(),
)
.await?;

View File

@@ -6,22 +6,26 @@ use gpui::{AppContext, AsyncApp, SharedString};
use json_dotpath::DotPaths;
use language::{LanguageName, Toolchain};
use serde_json::Value;
use std::borrow::Cow;
use std::net::Ipv4Addr;
use std::sync::LazyLock;
use std::{
collections::HashMap,
ffi::OsStr,
path::{Path, PathBuf},
sync::OnceLock,
};
#[cfg(feature = "update-schemas")]
use tempfile::TempDir;
use util::ResultExt;
#[derive(Default)]
pub(crate) struct PythonDebugAdapter {
pub struct PythonDebugAdapter {
checked: OnceLock<()>,
}
impl PythonDebugAdapter {
const ADAPTER_NAME: &'static str = "Debugpy";
pub const ADAPTER_NAME: &'static str = "Debugpy";
const DEBUG_ADAPTER_NAME: DebugAdapterName =
DebugAdapterName(SharedString::new_static(Self::ADAPTER_NAME));
const ADAPTER_PACKAGE_NAME: &'static str = "debugpy";
@@ -105,6 +109,7 @@ impl PythonDebugAdapter {
request,
})
}
async fn fetch_latest_adapter_version(
&self,
delegate: &Arc<dyn DapDelegate>,
@@ -123,9 +128,10 @@ impl PythonDebugAdapter {
delegate: Arc<dyn DapDelegate>,
) -> Result<()> {
let version_path = adapters::download_adapter_from_github(
adapter_name,
adapter_name.as_ref(),
version,
adapters::DownloadedFileType::GzipTar,
paths::debug_adapters_dir(),
delegate.as_ref(),
)
.await?;
@@ -258,337 +264,12 @@ impl DebugAdapter for PythonDebugAdapter {
})
}
fn dap_schema(&self) -> serde_json::Value {
json!({
"properties": {
"request": {
"type": "string",
"enum": ["attach", "launch"],
"description": "Debug adapter request type"
},
"autoReload": {
"default": {},
"description": "Configures automatic reload of code on edit.",
"properties": {
"enable": {
"default": false,
"description": "Automatically reload code on edit.",
"type": "boolean"
},
"exclude": {
"default": [
"**/.git/**",
"**/.metadata/**",
"**/__pycache__/**",
"**/node_modules/**",
"**/site-packages/**"
],
"description": "Glob patterns of paths to exclude from auto reload.",
"items": {
"type": "string"
},
"type": "array"
},
"include": {
"default": [
"**/*.py",
"**/*.pyw"
],
"description": "Glob patterns of paths to include in auto reload.",
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"debugAdapterPath": {
"description": "Path (fully qualified) to the python debug adapter executable.",
"type": "string"
},
"django": {
"default": false,
"description": "Django debugging.",
"type": "boolean"
},
"jinja": {
"default": null,
"description": "Jinja template debugging (e.g. Flask).",
"enum": [
false,
null,
true
]
},
"justMyCode": {
"default": true,
"description": "If true, show and debug only user-written code. If false, show and debug all code, including library calls.",
"type": "boolean"
},
"logToFile": {
"default": false,
"description": "Enable logging of debugger events to a log file. This file can be found in the debugpy extension install folder.",
"type": "boolean"
},
"pathMappings": {
"default": [],
"items": {
"label": "Path mapping",
"properties": {
"localRoot": {
"default": "${ZED_WORKTREE_ROOT}",
"label": "Local source root.",
"type": "string"
},
"remoteRoot": {
"default": "",
"label": "Remote source root.",
"type": "string"
}
},
"required": [
"localRoot",
"remoteRoot"
],
"type": "object"
},
"label": "Path mappings.",
"type": "array"
},
"redirectOutput": {
"default": true,
"description": "Redirect output.",
"type": "boolean"
},
"showReturnValue": {
"default": true,
"description": "Show return value of functions when stepping.",
"type": "boolean"
},
"subProcess": {
"default": false,
"description": "Whether to enable Sub Process debugging",
"type": "boolean"
},
"consoleName": {
"default": "Python Debug Console",
"description": "Display name of the debug console or terminal",
"type": "string"
},
"clientOS": {
"default": null,
"description": "OS that VS code is using.",
"enum": [
"windows",
null,
"unix"
]
}
},
"required": ["request"],
"allOf": [
{
"if": {
"properties": {
"request": {
"enum": ["attach"]
}
}
},
"then": {
"properties": {
"connect": {
"label": "Attach by connecting to debugpy over a socket.",
"properties": {
"host": {
"default": "127.0.0.1",
"description": "Hostname or IP address to connect to.",
"type": "string"
},
"port": {
"description": "Port to connect to.",
"type": [
"number",
"string"
]
}
},
"required": [
"port"
],
"type": "object"
},
"listen": {
"label": "Attach by listening for incoming socket connection from debugpy",
"properties": {
"host": {
"default": "127.0.0.1",
"description": "Hostname or IP address of the interface to listen on.",
"type": "string"
},
"port": {
"description": "Port to listen on.",
"type": [
"number",
"string"
]
}
},
"required": [
"port"
],
"type": "object"
},
"processId": {
"anyOf": [
{
"default": "${command:pickProcess}",
"description": "Use process picker to select a process to attach, or Process ID as integer.",
"enum": [
"${command:pickProcess}"
]
},
{
"description": "ID of the local process to attach to.",
"type": "integer"
}
]
}
}
}
},
{
"if": {
"properties": {
"request": {
"enum": ["launch"]
}
}
},
"then": {
"properties": {
"args": {
"default": [],
"description": "Command line arguments passed to the program. For string type arguments, it will pass through the shell as is, and therefore all shell variable expansions will apply. But for the array type, the values will be shell-escaped.",
"items": {
"type": "string"
},
"anyOf": [
{
"default": "${command:pickArgs}",
"enum": [
"${command:pickArgs}"
]
},
{
"type": [
"array",
"string"
]
}
]
},
"console": {
"default": "integratedTerminal",
"description": "Where to launch the debug target: internal console, integrated terminal, or external terminal.",
"enum": [
"externalTerminal",
"integratedTerminal",
"internalConsole"
]
},
"cwd": {
"default": "${ZED_WORKTREE_ROOT}",
"description": "Absolute path to the working directory of the program being debugged. Default is the root directory of the file (leave empty).",
"type": "string"
},
"autoStartBrowser": {
"default": false,
"description": "Open external browser to launch the application",
"type": "boolean"
},
"env": {
"additionalProperties": {
"type": "string"
},
"default": {},
"description": "Environment variables defined as a key value pair. Property ends up being the Environment Variable and the value of the property ends up being the value of the Env Variable.",
"type": "object"
},
"envFile": {
"default": "${ZED_WORKTREE_ROOT}/.env",
"description": "Absolute path to a file containing environment variable definitions.",
"type": "string"
},
"gevent": {
"default": false,
"description": "Enable debugging of gevent monkey-patched code.",
"type": "boolean"
},
"module": {
"default": "",
"description": "Name of the module to be debugged.",
"type": "string"
},
"program": {
"default": "${ZED_FILE}",
"description": "Absolute path to the program.",
"type": "string"
},
"purpose": {
"default": [],
"description": "Tells extension to use this configuration for test debugging, or when using debug-in-terminal command.",
"items": {
"enum": [
"debug-test",
"debug-in-terminal"
],
"enumDescriptions": [
"Use this configuration while debugging tests using test view or test debug commands.",
"Use this configuration while debugging a file using debug in terminal button in the editor."
]
},
"type": "array"
},
"pyramid": {
"default": false,
"description": "Whether debugging Pyramid applications.",
"type": "boolean"
},
"python": {
"default": "${command:python.interpreterPath}",
"description": "Absolute path to the Python interpreter executable; overrides workspace configuration if set.",
"type": "string"
},
"pythonArgs": {
"default": [],
"description": "Command-line arguments passed to the Python interpreter. To pass arguments to the debug target, use \"args\".",
"items": {
"type": "string"
},
"type": "array"
},
"stopOnEntry": {
"default": false,
"description": "Automatically stop after launch.",
"type": "boolean"
},
"sudo": {
"default": false,
"description": "Running debug program under elevated permissions (on Unix).",
"type": "boolean"
},
"guiEventLoop": {
"default": "matplotlib",
"description": "The GUI event loop that's going to run. Possible values: \"matplotlib\", \"wx\", \"qt\", \"none\", or a custom function that'll be imported and run.",
"type": "string"
}
}
}
}
]
})
fn dap_schema(&self) -> Cow<'static, serde_json::Value> {
static SCHEMA: LazyLock<serde_json::Value> = LazyLock::new(|| {
const RAW_SCHEMA: &str = include_str!("../schemas/Debugpy.json");
serde_json::from_str(RAW_SCHEMA).unwrap()
});
Cow::Borrowed(&*SCHEMA)
}
async fn get_binary(
@@ -671,6 +352,62 @@ impl DebugAdapter for PythonDebugAdapter {
}
}
#[cfg(feature = "update-schemas")]
impl PythonDebugAdapter {
pub fn get_schema(
temp_dir: &TempDir,
delegate: UpdateSchemasDapDelegate,
) -> anyhow::Result<serde_json::Value> {
use fs::Fs as _;
let temp_dir = std::fs::canonicalize(temp_dir.path())?;
let fs = delegate.fs.clone();
let executor = delegate.executor.clone();
let (package_json, package_nls_json) = executor.block(async move {
let version = fetch_latest_adapter_version_from_github(
GithubRepo {
repo_name: "vscode-python-debugger".into(),
repo_owner: "microsoft".into(),
},
&delegate,
)
.await?;
let path = adapters::download_adapter_from_github(
"schemas",
version,
adapters::DownloadedFileType::GzipTar,
&temp_dir,
&delegate,
)
.await?;
let path = util::fs::find_file_name_in_dir(path.as_path(), |file_name| {
file_name.starts_with("microsoft-vscode-python-debugger-")
})
.await
.context("find python debugger extension in download")?;
let package_json = fs.load(&path.join("package.json")).await?;
let package_nls_json = fs.load(&path.join("package.nls.json")).await.ok();
anyhow::Ok((package_json, package_nls_json))
})?;
let package_json = parse_package_json(package_json, package_nls_json)?;
let [debugger] =
<[_; 1]>::try_from(package_json.contributes.debuggers).map_err(|debuggers| {
anyhow::anyhow!("unexpected number of python debuggers: {}", debuggers.len())
})?;
Ok(schema_for_configuration_attributes(
debugger.configuration_attributes,
))
}
}
async fn fetch_latest_adapter_version_from_github(
github_repo: GithubRepo,
delegate: &dyn DapDelegate,

View File

@@ -0,0 +1,54 @@
use std::{path::Path, process::Command};
use dap::adapters::DapDelegate as _;
use dap_adapters::{
CodeLldbDebugAdapter, GoDebugAdapter, JsDebugAdapter, PythonDebugAdapter,
UpdateSchemasDapDelegate,
};
use tempfile::TempDir;
fn main() -> anyhow::Result<()> {
let temp_dir = TempDir::new()?;
let output_dir = Path::new("crates/dap_adapters/schemas");
let delegate = UpdateSchemasDapDelegate::new();
let schema = JsDebugAdapter::get_schema(&temp_dir, delegate.clone())?;
std::fs::write(
&output_dir
.join(JsDebugAdapter::ADAPTER_NAME)
.with_extension("json"),
serde_json::to_string(&schema)?,
)?;
let schema = PythonDebugAdapter::get_schema(&temp_dir, delegate.clone())?;
std::fs::write(
&output_dir
.join(PythonDebugAdapter::ADAPTER_NAME)
.with_extension("json"),
serde_json::to_string(&schema)?,
)?;
let schema = GoDebugAdapter::get_schema(&temp_dir, delegate.clone())?;
std::fs::write(
&output_dir
.join(GoDebugAdapter::ADAPTER_NAME)
.with_extension("json"),
serde_json::to_string(&schema)?,
)?;
let schema = CodeLldbDebugAdapter::get_schema(&temp_dir, delegate.clone())?;
std::fs::write(
&output_dir
.join(CodeLldbDebugAdapter::ADAPTER_NAME)
.with_extension("json"),
serde_json::to_string(&schema)?,
)?;
delegate.output_to_console("Formatting schemas with prettier...".into());
Command::new("npx")
.arg("prettier")
.arg("--write")
.arg(output_dir.join("*"))
.status()?;
Ok(())
}

View File

@@ -1,4 +1,5 @@
use std::{
borrow::Cow,
path::{Path, PathBuf},
str::FromStr,
sync::Arc,
@@ -79,8 +80,8 @@ impl DebugAdapter for ExtensionDapAdapter {
self.debug_adapter_name.as_ref().into()
}
fn dap_schema(&self) -> serde_json::Value {
self.schema.clone()
fn dap_schema(&self) -> Cow<'static, serde_json::Value> {
Cow::Owned(self.schema.clone())
}
async fn get_binary(

View File

@@ -5,7 +5,7 @@ use async_trait::async_trait;
use collections::HashMap;
use dap::DapRegistry;
use futures::StreamExt;
use gpui::{App, AsyncApp, Task};
use gpui::{App, AsyncApp, SharedString, Task};
use http_client::github::{GitHubLspBinaryVersion, latest_github_release};
use language::{
ContextProvider, LanguageRegistry, LanguageToolchainStore, LocalFile as _, LspAdapter,
@@ -23,13 +23,14 @@ use smol::{
};
use std::{
any::Any,
borrow::Cow,
env::consts,
ffi::OsString,
path::{Path, PathBuf},
str::FromStr,
sync::Arc,
};
use task::{AdapterSchemas, TaskTemplate, TaskTemplates, VariableName};
use task::{TaskTemplate, TaskTemplates, VariableName};
use util::{ResultExt, archive::extract_zip, fs::remove_matching, maybe, merge_json_value_into};
use crate::PackageJsonData;
@@ -153,7 +154,7 @@ impl JsonLspAdapter {
fn get_workspace_config(
language_names: Vec<String>,
adapter_schemas: AdapterSchemas,
adapter_schemas: Vec<(SharedString, Cow<'static, serde_json::Value>)>,
cx: &mut App,
) -> Value {
let keymap_schema = KeymapFile::generate_json_schema_for_registered_actions(cx);
@@ -167,7 +168,7 @@ impl JsonLspAdapter {
);
let tasks_schema = task::TaskTemplates::generate_json_schema();
let debug_schema = task::DebugTaskFile::generate_json_schema(&adapter_schemas);
let debug_schema = task::DebugTaskFile::generate_json_schema(adapter_schemas);
let snippets_schema = snippet_provider::format::VsSnippetsFile::generate_json_schema();
let tsconfig_schema = serde_json::Value::from_str(TSCONFIG_SCHEMA).unwrap();
let package_json_schema = serde_json::Value::from_str(PACKAGE_JSON_SCHEMA).unwrap();
@@ -258,7 +259,7 @@ impl JsonLspAdapter {
let adapter_schemas = cx
.read_global::<DapRegistry, _>(|dap_registry, _| dap_registry.to_owned())?
.adapters_schema()
.adapter_schemas()
.await;
let config = cx.update(|cx| {

View File

@@ -1,16 +0,0 @@
use gpui::SharedString;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
/// JSON schema for a specific adapter
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
pub struct AdapterSchema {
/// The adapter name identifier
pub adapter: SharedString,
/// The JSON schema for this adapter's configuration
pub schema: serde_json::Value,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(transparent)]
pub struct AdapterSchemas(pub Vec<AdapterSchema>);

View File

@@ -1,29 +1,27 @@
use crate::serde_helpers::non_empty_string_vec;
use anyhow::{Context as _, Result};
use collections::FxHashMap;
use collections::{FxHashMap, HashMap};
use gpui::SharedString;
use log as _;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::net::Ipv4Addr;
use std::path::PathBuf;
use util::{debug_panic, schemars::add_new_subschema};
use std::{borrow::Cow, net::Ipv4Addr};
use util::schemars::add_new_subschema;
use util::serde::default_true;
use zed_actions::RevealTarget;
use crate::{TaskTemplate, adapter_schema::AdapterSchemas};
use crate::{HideStrategy, RevealStrategy, Shell, TaskTemplate};
/// Represents the host information of the debug adapter
#[derive(Default, Deserialize, Serialize, PartialEq, Eq, JsonSchema, Clone, Debug)]
/// Optional TCP connection information for connecting to an already running debug adapter
pub struct TcpArgumentsTemplate {
/// The port that the debug adapter is listening on
///
/// Default: We will try to find an open port
/// The port that the debug adapter is listening on (default: auto-find open port)
pub port: Option<u16>,
/// The host that the debug adapter is listening too
///
/// Default: 127.0.0.1
/// The host that the debug adapter is listening to (default: 127.0.0.1)
#[garde(ipv4)]
pub host: Option<Ipv4Addr>,
/// The max amount of time in milliseconds to connect to a tcp DAP before returning an error
///
/// Default: 2000ms
/// The max amount of time in milliseconds to connect to a tcp DAP before returning an error (default: 2000ms)
pub timeout: Option<u64>,
}
@@ -184,12 +182,75 @@ impl From<AttachRequest> for DebugRequest {
}
}
fn build_task_template_default_label() -> String {
"debug-build".to_owned()
}
/// Copy of TaskTemplate for which label is optional, for use in build tasks.
///
/// The serde(remote) helper checks at compile time that this is in sync with the original TaskTemplate.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(remote = "TaskTemplate")]
struct BuildTaskTemplate {
/// Human readable name of the task to display in the UI.
#[serde(default = "build_task_template_default_label")]
pub label: String,
/// Executable command to spawn.
pub command: String,
/// Arguments to the command.
#[serde(default)]
pub args: Vec<String>,
/// Env overrides for the command, will be appended to the terminal's environment from the settings.
#[serde(default)]
pub env: HashMap<String, String>,
/// Current working directory to spawn the command into, defaults to current project root.
#[serde(default)]
pub cwd: Option<String>,
/// Whether to use a new terminal tab or reuse the existing one to spawn the process.
#[serde(default)]
pub use_new_terminal: bool,
/// Whether to allow multiple instances of the same task to be run, or rather wait for the existing ones to finish.
#[serde(default)]
pub allow_concurrent_runs: bool,
/// What to do with the terminal pane and tab, after the command was started:
/// * `always` — always show the task's pane, and focus the corresponding tab in it (default)
/// * `no_focus` — always show the task's pane, add the task's tab in it, but don't focus it
/// * `never` — do not alter focus, but still add/reuse the task's tab in its pane
#[serde(default)]
pub reveal: RevealStrategy,
/// Where to place the task's terminal item after starting the task.
/// * `dock` — in the terminal dock, "regular" terminal items' place (default).
/// * `center` — in the central pane group, "main" editor area.
#[serde(default)]
pub reveal_target: RevealTarget,
/// What to do with the terminal pane and tab, after the command had finished:
/// * `never` — do nothing when the command finishes (default)
/// * `always` — always hide the terminal tab, hide the pane also if it was the last tab in it
/// * `on_success` — hide the terminal tab on task success only, otherwise behaves similar to `always`.
#[serde(default)]
pub hide: HideStrategy,
/// Represents the tags which this template attaches to.
/// Adding this removes this task from other UI and gives you ability to run it by tag.
#[serde(default, deserialize_with = "non_empty_string_vec")]
#[schemars(length(min = 1))]
pub tags: Vec<String>,
/// Which shell to use when spawning the task.
#[serde(default)]
pub shell: Shell,
/// Whether to show the task line in the task output.
#[serde(default = "default_true")]
pub show_summary: bool,
/// Whether to show the command line in the task output.
#[serde(default = "default_true")]
pub show_command: bool,
}
#[derive(Serialize, PartialEq, Eq, JsonSchema, Clone, Debug)]
#[serde(untagged)]
pub enum BuildTaskDefinition {
ByName(SharedString),
Template {
#[serde(flatten)]
#[serde(flatten, with = "BuildTaskTemplate")]
task_template: TaskTemplate,
#[serde(skip)]
locator_name: Option<SharedString>,
@@ -281,51 +342,23 @@ pub struct DebugScenario {
}
/// A group of Debug Tasks defined in a JSON file.
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(transparent)]
pub struct DebugTaskFile(pub Vec<DebugScenario>);
impl DebugTaskFile {
pub fn generate_json_schema(schemas: &AdapterSchemas) -> serde_json::Value {
pub fn generate_json_schema(
adapter_schemas: Vec<(SharedString, Cow<'static, serde_json::Value>)>,
) -> serde_json::Value {
let mut generator = schemars::generate::SchemaSettings::draft2019_09().into_generator();
let mut build_task_value = BuildTaskDefinition::json_schema(&mut generator).to_value();
if let Some(template_object) = build_task_value
.get_mut("anyOf")
.and_then(|array| array.as_array_mut())
.and_then(|array| array.get_mut(1))
{
if let Some(properties) = template_object
.get_mut("properties")
.and_then(|value| value.as_object_mut())
{
if properties.remove("label").is_none() {
debug_panic!(
"Generated TaskTemplate json schema did not have expected 'label' field. \
Schema of 2nd alternative is: {template_object:?}"
);
}
}
if let Some(arr) = template_object
.get_mut("required")
.and_then(|array| array.as_array_mut())
{
arr.retain(|v| v.as_str() != Some("label"));
}
} else {
debug_panic!(
"Generated TaskTemplate json schema did not match expectations. \
Schema is: {build_task_value:?}"
);
}
let adapter_conditions = schemas
.0
let adapter_names = adapter_schemas
.iter()
.map(|adapter_schema| {
let adapter_name = adapter_schema.adapter.to_string();
.map(|(adapter_name, _)| adapter_name.clone())
.collect::<Vec<_>>();
let adapter_conditions = adapter_schemas
.iter()
.map(|(adapter_name, schema)| {
add_new_subschema(
&mut generator,
&format!("{adapter_name}DebugSettings"),
@@ -335,16 +368,23 @@ impl DebugTaskFile {
"adapter": { "const": adapter_name }
}
},
"then": adapter_schema.schema
"then": schema
}),
)
})
.collect::<Vec<_>>();
let build_task_schema = BuildTaskDefinition::json_schema(&mut generator).to_value();
let build_task_definition_ref = add_new_subschema(
&mut generator,
BuildTaskDefinition::schema_name().as_ref(),
build_task_value,
build_task_schema,
);
let tcp_connection_schema = TcpArgumentsTemplate::json_schema(&mut generator).to_value();
let tcp_connection_definition_ref = add_new_subschema(
&mut generator,
TcpArgumentsTemplate::schema_name().as_ref(),
tcp_connection_schema,
);
let meta_schema = generator
@@ -362,16 +402,10 @@ impl DebugTaskFile {
"items": {
"type": "object",
"required": ["adapter", "label"],
// TODO: Uncommenting this will cause json-language-server to provide warnings for
// unrecognized properties. It should be enabled if/when there's an adapter JSON
// schema that's comprehensive. In order to not get warnings for the other schemas,
// `additionalProperties` or `unevaluatedProperties` (to handle "allOf" etc style
// schema combinations) could be set to `true` for that schema.
//
// "unevaluatedProperties": false,
"unevaluatedProperties": false,
"properties": {
"adapter": {
"type": "string",
"enum": adapter_names,
"description": "The name of the debug adapter"
},
"label": {
@@ -379,25 +413,7 @@ impl DebugTaskFile {
"description": "The name of the debug configuration"
},
"build": build_task_definition_ref,
"tcp_connection": {
"type": "object",
"description": "Optional TCP connection information for connecting to an already running debug adapter",
"properties": {
"port": {
"type": "integer",
"description": "The port that the debug adapter is listening on (default: auto-find open port)"
},
"host": {
"type": "string",
"pattern": "^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}$",
"description": "The host that the debug adapter is listening to (default: 127.0.0.1)"
},
"timeout": {
"type": "integer",
"description": "The max amount of time in milliseconds to connect to a tcp DAP before returning an error (default: 2000ms)"
}
}
}
"tcp_connection": tcp_connection_definition_ref,
},
"allOf": adapter_conditions
},

View File

@@ -1,6 +1,5 @@
//! Baseline interface of Tasks in Zed: all tasks in Zed are intended to use those for implementing their own logic.
mod adapter_schema;
mod debug_format;
mod serde_helpers;
mod shell_builder;
@@ -17,7 +16,6 @@ use std::borrow::Cow;
use std::path::PathBuf;
use std::str::FromStr;
pub use adapter_schema::{AdapterSchema, AdapterSchemas};
pub use debug_format::{
AttachRequest, BuildTaskDefinition, DebugRequest, DebugScenario, DebugTaskFile, LaunchRequest,
Request, TcpArgumentsTemplate, ZedDebugConfig,
@@ -336,19 +334,19 @@ pub enum Shell {
},
}
type VsCodeEnvVariable = String;
type ZedEnvVariable = String;
pub type VsCodeEnvVariable = String;
pub type ZedEnvVariable = String;
struct EnvVariableReplacer {
pub struct EnvVariableReplacer {
variables: HashMap<VsCodeEnvVariable, ZedEnvVariable>,
}
impl EnvVariableReplacer {
fn new(variables: HashMap<VsCodeEnvVariable, ZedEnvVariable>) -> Self {
pub fn new(variables: HashMap<VsCodeEnvVariable, ZedEnvVariable>) -> Self {
Self { variables }
}
fn replace_value(&self, input: serde_json::Value) -> serde_json::Value {
pub fn replace_value(&self, input: serde_json::Value) -> serde_json::Value {
match input {
serde_json::Value::String(s) => serde_json::Value::String(self.replace(&s)),
serde_json::Value::Array(arr) => {
@@ -363,7 +361,7 @@ impl EnvVariableReplacer {
}
}
// Replaces occurrences of VsCode-specific environment variables with Zed equivalents.
fn replace(&self, input: &str) -> String {
pub fn replace(&self, input: &str) -> String {
shellexpand::env_with_context_no_errors(&input, |var: &str| {
// Colons denote a default value in case the variable is not set. We want to preserve that default, as otherwise shellexpand will substitute it for us.
let colon_position = var.find(':').unwrap_or(var.len());

View File

@@ -43,8 +43,8 @@ pub struct TaskTemplate {
pub allow_concurrent_runs: bool,
/// What to do with the terminal pane and tab, after the command was started:
/// * `always` — always show the task's pane, and focus the corresponding tab in it (default)
// * `no_focus` — always show the task's pane, add the task's tab in it, but don't focus it
// * `never` — do not alter focus, but still add/reuse the task's tab in its pane
/// * `no_focus` — always show the task's pane, add the task's tab in it, but don't focus it
/// * `never` — do not alter focus, but still add/reuse the task's tab in its pane
#[serde(default)]
pub reveal: RevealStrategy,
/// Where to place the task's terminal item after starting the task.

3
script/update-dap-schemas Executable file
View File

@@ -0,0 +1,3 @@
#!/usr/bin/env bash
cargo run --package dap_adapters --features update-schemas --bin update-schemas

View File

@@ -49,7 +49,9 @@ extend-exclude = [
# typos-cli doesn't understand our `vˇariable` markup
"crates/editor/src/hover_links.rs",
# typos-cli doesn't understand `setis` is intentional test case
"crates/editor/src/code_completion_tests.rs"
"crates/editor/src/code_completion_tests.rs",
# schemas come from upstream, not worth it to maintain a patch in our copies to fix typos
"crates/dap_adapters/schemas/",
]
[default]