Detailed changes
@@ -265,13 +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 = base_path.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();
@@ -285,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
@@ -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"] }
+ }
+ }
+ }
+ ]
+}
@@ -2,47 +2,22 @@
"allOf": [
{
"if": {
- "properties": {
- "type": {
- "const": "pwa-node"
- },
- "request": {
- "const": "launch"
- }
- },
- "required": [
- "type",
- "request"
- ]
+ "properties": { "type": { "const": "pwa-node" }, "request": { "const": "launch" } },
+ "required": ["type", "request"]
},
"then": {
"properties": {
"args": {
"default": [],
"description": "Command line arguments passed to the program.\n\nCan be an array of strings or a single string. When the program is launched in a terminal, setting this property to a single string will result in the arguments not being escaped for the shell.",
- "items": {
- "type": "string"
- },
- "tags": [
- "setup"
- ],
- "type": [
- "array",
- "string"
- ]
+ "items": { "type": "string" },
+ "tags": ["setup"],
+ "type": ["array", "string"]
},
"attachSimplePort": {
"default": 9229,
"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.",
- "oneOf": [
- {
- "type": "integer"
- },
- {
- "pattern": "^\\${.*}$",
- "type": "string"
- }
- ]
+ "oneOf": [{ "type": "integer" }, { "pattern": "^\\${.*}$", "type": "string" }]
},
"autoAttachChildProcesses": {
"default": true,
@@ -52,20 +27,13 @@
"cascadeTerminateToConfigurations": {
"default": [],
"description": "A list of debug sessions which, when this debug session is terminated, will also be stopped.",
- "items": {
- "type": "string",
- "uniqueItems": true
- },
+ "items": { "type": "string", "uniqueItems": true },
"type": "array"
},
"console": {
"default": "internalConsole",
"description": "Where to launch the debug target.",
- "enum": [
- "internalConsole",
- "integratedTerminal",
- "externalTerminal"
- ],
+ "enum": ["internalConsole", "integratedTerminal", "externalTerminal"],
"enumDescriptions": [
"VS Code Debug Console (which doesn't support to read input from a program)",
"VS Code's integrated terminal",
@@ -85,9 +53,7 @@
"cwd": {
"default": "${ZED_WORKTREE_ROOT}",
"description": "Absolute path to the working directory of the program being debugged. If you've set localRoot then cwd will match that value otherwise it falls back to your workspaceFolder",
- "tags": [
- "setup"
- ],
+ "tags": ["setup"],
"type": "string"
},
"enableContentValidation": {
@@ -101,17 +67,10 @@
"type": "boolean"
},
"env": {
- "additionalProperties": {
- "type": [
- "string",
- "null"
- ]
- },
+ "additionalProperties": { "type": ["string", "null"] },
"default": {},
"markdownDescription": "Environment variables passed to the program. The value `null` removes the variable from the environment.",
- "tags": [
- "setup"
- ],
+ "tags": ["setup"],
"type": "object"
},
"envFile": {
@@ -122,30 +81,19 @@
"experimentalNetworking": {
"default": "auto",
"description": "Enable experimental inspection in Node.js. When set to `auto` this is enabled for versions of Node.js that support it. It can be set to `on` or `off` to enable or disable it explicitly.",
- "enum": [
- "auto",
- "on",
- "off"
- ],
+ "enum": ["auto", "on", "off"],
"type": "string"
},
"killBehavior": {
"default": "forceful",
- "enum": [
- "forceful",
- "polite",
- "none"
- ],
+ "enum": ["forceful", "polite", "none"],
"markdownDescription": "Configures how debug processes are killed when stopping the session. Can be:\n\n- forceful (default): forcefully tears down the process tree. Sends SIGKILL on posix, or `taskkill.exe /F` on Windows.\n- polite: gracefully tears down the process tree. It's possible that misbehaving processes continue to run after shutdown in this way. Sends SIGTERM on posix, or `taskkill.exe` with no `/F` (force) flag on Windows.\n- none: no termination will happen.",
"type": "string"
},
"localRoot": {
"default": null,
"description": "Path to the local directory containing the program.",
- "type": [
- "string",
- "null"
- ]
+ "type": ["string", "null"]
},
"nodeVersionHint": {
"default": 12,
@@ -154,27 +102,15 @@
"type": "number"
},
"outFiles": {
- "default": [
- "${ZED_WORKTREE_ROOT}/**/*.(m|c|)js",
- "!**/node_modules/**"
- ],
+ "default": ["${ZED_WORKTREE_ROOT}/**/*.(m|c|)js", "!**/node_modules/**"],
"description": "If source maps are enabled, these glob patterns specify the generated JavaScript files. If a pattern starts with `!` the files are excluded. If not specified, the generated code is expected in the same directory as its source.",
- "items": {
- "type": "string"
- },
- "tags": [
- "setup"
- ],
- "type": [
- "array"
- ]
+ "items": { "type": "string" },
+ "tags": ["setup"],
+ "type": ["array"]
},
"outputCapture": {
"default": "console",
- "enum": [
- "console",
- "std"
- ],
+ "enum": ["console", "std"],
"markdownDescription": "From where to capture output messages: the default debug API if set to `console`, or stdout/stderr streams if set to `std`."
},
"pauseForSourceMap": {
@@ -190,52 +126,29 @@
"program": {
"default": "",
"description": "Absolute path to the program. Generated value is guessed by looking at package.json and opened files. Edit this attribute.",
- "tags": [
- "setup"
- ],
+ "tags": ["setup"],
"type": "string"
},
"remoteRoot": {
"default": null,
"description": "Absolute path to the remote directory containing the program.",
- "type": [
- "string",
- "null"
- ]
+ "type": ["string", "null"]
},
"resolveSourceMapLocations": {
- "default": [
- "${ZED_WORKTREE_ROOT}/**",
- "!**/node_modules/**"
- ],
+ "default": ["${ZED_WORKTREE_ROOT}/**", "!**/node_modules/**"],
"description": "A list of minimatch patterns for locations (folders and URLs) in which source maps can be used to resolve local files. This can be used to avoid incorrectly breaking in external source mapped code. Patterns can be prefixed with \"!\" to exclude them. May be set to an empty array or null to avoid restriction.",
- "items": {
- "type": "string"
- },
- "type": [
- "array",
- "null"
- ]
+ "items": { "type": "string" },
+ "type": ["array", "null"]
},
"restart": {
"default": true,
"description": "Try to reconnect to the program if we lose connection. If set to `true`, we'll try once a second, forever. You can customize the interval and maximum number of attempts by specifying the `delay` and `maxAttempts` in an object instead.",
"oneOf": [
- {
- "type": "boolean"
- },
+ { "type": "boolean" },
{
"properties": {
- "delay": {
- "default": 1000,
- "minimum": 0,
- "type": "number"
- },
- "maxAttempts": {
- "default": 10,
- "minimum": 0,
- "type": "number"
- }
+ "delay": { "default": 1000, "minimum": 0, "type": "number" },
+ "maxAttempts": { "default": 10, "minimum": 0, "type": "number" }
},
"type": "object"
}
@@ -244,27 +157,18 @@
"runtimeArgs": {
"default": [],
"description": "Optional arguments passed to the runtime executable.",
- "items": {
- "type": "string"
- },
- "tags": [
- "setup"
- ],
+ "items": { "type": "string" },
+ "tags": ["setup"],
"type": "array"
},
"runtimeExecutable": {
"default": "node",
"markdownDescription": "Runtime to use. Either an absolute path or the name of a runtime available on the PATH. If omitted `node` is assumed.",
- "type": [
- "string",
- "null"
- ]
+ "type": ["string", "null"]
},
"runtimeSourcemapPausePatterns": {
"default": [],
- "items": {
- "type": "string"
- },
+ "items": { "type": "string" },
"markdownDescription": "A list of patterns at which to manually insert entrypoint breakpoints. This can be useful to give the debugger an opportunity to set breakpoints when using sourcemaps that don't exist or can't be detected before launch, such as [with the Serverless framework](https://github.com/microsoft/vscode-js-debug/issues/492).",
"type": "array"
},
@@ -277,39 +181,21 @@
"default": true,
"description": "Show the async calls that led to the current call stack.",
"oneOf": [
+ { "type": "boolean" },
{
- "type": "boolean"
- },
- {
- "properties": {
- "onAttach": {
- "default": 32,
- "type": "number"
- }
- },
- "required": [
- "onAttach"
- ],
+ "properties": { "onAttach": { "default": 32, "type": "number" } },
+ "required": ["onAttach"],
"type": "object"
},
{
- "properties": {
- "onceBreakpointResolved": {
- "default": 32,
- "type": "number"
- }
- },
- "required": [
- "onceBreakpointResolved"
- ],
+ "properties": { "onceBreakpointResolved": { "default": 32, "type": "number" } },
+ "required": ["onceBreakpointResolved"],
"type": "object"
}
]
},
"skipFiles": {
- "default": [
- "${/**"
- ],
+ "default": ["${/**"],
"description": "An array of file or folder names, or path globs, to skip when debugging. Star patterns and negations are allowed, for example, `[\"**/node_modules/**\", \"!**/node_modules/my-module/**\"]`",
"type": "array"
},
@@ -340,10 +226,7 @@
"stopOnEntry": {
"default": true,
"description": "Automatically stop program after launch.",
- "type": [
- "boolean",
- "string"
- ]
+ "type": ["boolean", "string"]
},
"timeout": {
"default": 10000,
@@ -378,19 +261,13 @@
"default": true,
"description": "Configures what diagnostic output is produced.",
"oneOf": [
- {
- "description": "Trace may be set to 'true' to write diagnostic logs to the disk.",
- "type": "boolean"
- },
+ { "description": "Trace may be set to 'true' to write diagnostic logs to the disk.", "type": "boolean" },
{
"additionalProperties": false,
"properties": {
"logFile": {
"description": "Configures where on disk logs are written.",
- "type": [
- "string",
- "null"
- ]
+ "type": ["string", "null"]
},
"stdio": {
"description": "Whether to return trace data from the launched application or browser.",
@@ -406,18 +283,8 @@
},
{
"if": {
- "properties": {
- "type": {
- "const": "pwa-node"
- },
- "request": {
- "const": "attach"
- }
- },
- "required": [
- "type",
- "request"
- ]
+ "properties": { "type": { "const": "pwa-node" }, "request": { "const": "attach" } },
+ "required": ["type", "request"]
},
"then": {
"properties": {
@@ -439,10 +306,7 @@
"cascadeTerminateToConfigurations": {
"default": [],
"description": "A list of debug sessions which, when this debug session is terminated, will also be stopped.",
- "items": {
- "type": "string",
- "uniqueItems": true
- },
+ "items": { "type": "string", "uniqueItems": true },
"type": "array"
},
"continueOnAttach": {
@@ -462,9 +326,7 @@
"cwd": {
"default": "${ZED_WORKTREE_ROOT}",
"description": "Absolute path to the working directory of the program being debugged. If you've set localRoot then cwd will match that value otherwise it falls back to your workspaceFolder",
- "tags": [
- "setup"
- ],
+ "tags": ["setup"],
"type": "string"
},
"enableContentValidation": {
@@ -478,17 +340,10 @@
"type": "boolean"
},
"env": {
- "additionalProperties": {
- "type": [
- "string",
- "null"
- ]
- },
+ "additionalProperties": { "type": ["string", "null"] },
"default": {},
"markdownDescription": "Environment variables passed to the program. The value `null` removes the variable from the environment.",
- "tags": [
- "setup"
- ],
+ "tags": ["setup"],
"type": "object"
},
"envFile": {
@@ -499,10 +354,7 @@
"localRoot": {
"default": null,
"description": "Path to the local directory containing the program.",
- "type": [
- "string",
- "null"
- ]
+ "type": ["string", "null"]
},
"nodeVersionHint": {
"default": 12,
@@ -511,27 +363,15 @@
"type": "number"
},
"outFiles": {
- "default": [
- "${ZED_WORKTREE_ROOT}/**/*.(m|c|)js",
- "!**/node_modules/**"
- ],
+ "default": ["${ZED_WORKTREE_ROOT}/**/*.(m|c|)js", "!**/node_modules/**"],
"description": "If source maps are enabled, these glob patterns specify the generated JavaScript files. If a pattern starts with `!` the files are excluded. If not specified, the generated code is expected in the same directory as its source.",
- "items": {
- "type": "string"
- },
- "tags": [
- "setup"
- ],
- "type": [
- "array"
- ]
+ "items": { "type": "string" },
+ "tags": ["setup"],
+ "type": ["array"]
},
"outputCapture": {
"default": "console",
- "enum": [
- "console",
- "std"
- ],
+ "enum": ["console", "std"],
"markdownDescription": "From where to capture output messages: the default debug API if set to `console`, or stdout/stderr streams if set to `std`."
},
"pauseForSourceMap": {
@@ -542,18 +382,8 @@
"port": {
"default": 9229,
"description": "Debug port to attach to. Default is 9229.",
- "oneOf": [
- {
- "type": "integer"
- },
- {
- "pattern": "^\\${.*}$",
- "type": "string"
- }
- ],
- "tags": [
- "setup"
- ]
+ "oneOf": [{ "type": "integer" }, { "pattern": "^\\${.*}$", "type": "string" }],
+ "tags": ["setup"]
},
"processId": {
"default": "${command:PickProcess}",
@@ -567,44 +397,23 @@
"remoteRoot": {
"default": null,
"description": "Absolute path to the remote directory containing the program.",
- "type": [
- "string",
- "null"
- ]
+ "type": ["string", "null"]
},
"resolveSourceMapLocations": {
- "default": [
- "${ZED_WORKTREE_ROOT}/**",
- "!**/node_modules/**"
- ],
+ "default": ["${ZED_WORKTREE_ROOT}/**", "!**/node_modules/**"],
"description": "A list of minimatch patterns for locations (folders and URLs) in which source maps can be used to resolve local files. This can be used to avoid incorrectly breaking in external source mapped code. Patterns can be prefixed with \"!\" to exclude them. May be set to an empty array or null to avoid restriction.",
- "items": {
- "type": "string"
- },
- "type": [
- "array",
- "null"
- ]
+ "items": { "type": "string" },
+ "type": ["array", "null"]
},
"restart": {
"default": true,
"description": "Try to reconnect to the program if we lose connection. If set to `true`, we'll try once a second, forever. You can customize the interval and maximum number of attempts by specifying the `delay` and `maxAttempts` in an object instead.",
"oneOf": [
- {
- "type": "boolean"
- },
+ { "type": "boolean" },
{
"properties": {
- "delay": {
- "default": 1000,
- "minimum": 0,
- "type": "number"
- },
- "maxAttempts": {
- "default": 10,
- "minimum": 0,
- "type": "number"
- }
+ "delay": { "default": 1000, "minimum": 0, "type": "number" },
+ "maxAttempts": { "default": 10, "minimum": 0, "type": "number" }
},
"type": "object"
}
@@ -612,9 +421,7 @@
},
"runtimeSourcemapPausePatterns": {
"default": [],
- "items": {
- "type": "string"
- },
+ "items": { "type": "string" },
"markdownDescription": "A list of patterns at which to manually insert entrypoint breakpoints. This can be useful to give the debugger an opportunity to set breakpoints when using sourcemaps that don't exist or can't be detected before launch, such as [with the Serverless framework](https://github.com/microsoft/vscode-js-debug/issues/492).",
"type": "array"
},
@@ -622,39 +429,21 @@
"default": true,
"description": "Show the async calls that led to the current call stack.",
"oneOf": [
+ { "type": "boolean" },
{
- "type": "boolean"
- },
- {
- "properties": {
- "onAttach": {
- "default": 32,
- "type": "number"
- }
- },
- "required": [
- "onAttach"
- ],
+ "properties": { "onAttach": { "default": 32, "type": "number" } },
+ "required": ["onAttach"],
"type": "object"
},
{
- "properties": {
- "onceBreakpointResolved": {
- "default": 32,
- "type": "number"
- }
- },
- "required": [
- "onceBreakpointResolved"
- ],
+ "properties": { "onceBreakpointResolved": { "default": 32, "type": "number" } },
+ "required": ["onceBreakpointResolved"],
"type": "object"
}
]
},
"skipFiles": {
- "default": [
- "${/**"
- ],
+ "default": ["${/**"],
"description": "An array of file or folder names, or path globs, to skip when debugging. Star patterns and negations are allowed, for example, `[\"**/node_modules/**\", \"!**/node_modules/my-module/**\"]`",
"type": "array"
},
@@ -715,19 +504,13 @@
"default": true,
"description": "Configures what diagnostic output is produced.",
"oneOf": [
- {
- "description": "Trace may be set to 'true' to write diagnostic logs to the disk.",
- "type": "boolean"
- },
+ { "description": "Trace may be set to 'true' to write diagnostic logs to the disk.", "type": "boolean" },
{
"additionalProperties": false,
"properties": {
"logFile": {
"description": "Configures where on disk logs are written.",
- "type": [
- "string",
- "null"
- ]
+ "type": ["string", "null"]
},
"stdio": {
"description": "Whether to return trace data from the launched application or browser.",
@@ -747,47 +530,22 @@
},
{
"if": {
- "properties": {
- "type": {
- "const": "node"
- },
- "request": {
- "const": "launch"
- }
- },
- "required": [
- "type",
- "request"
- ]
+ "properties": { "type": { "const": "node" }, "request": { "const": "launch" } },
+ "required": ["type", "request"]
},
"then": {
"properties": {
"args": {
"default": [],
"description": "Command line arguments passed to the program.\n\nCan be an array of strings or a single string. When the program is launched in a terminal, setting this property to a single string will result in the arguments not being escaped for the shell.",
- "items": {
- "type": "string"
- },
- "tags": [
- "setup"
- ],
- "type": [
- "array",
- "string"
- ]
+ "items": { "type": "string" },
+ "tags": ["setup"],
+ "type": ["array", "string"]
},
"attachSimplePort": {
"default": 9229,
"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.",
- "oneOf": [
- {
- "type": "integer"
- },
- {
- "pattern": "^\\${.*}$",
- "type": "string"
- }
- ]
+ "oneOf": [{ "type": "integer" }, { "pattern": "^\\${.*}$", "type": "string" }]
},
"autoAttachChildProcesses": {
"default": true,
@@ -797,20 +555,13 @@
"cascadeTerminateToConfigurations": {
"default": [],
"description": "A list of debug sessions which, when this debug session is terminated, will also be stopped.",
- "items": {
- "type": "string",
- "uniqueItems": true
- },
+ "items": { "type": "string", "uniqueItems": true },
"type": "array"
},
"console": {
"default": "internalConsole",
"description": "Where to launch the debug target.",
- "enum": [
- "internalConsole",
- "integratedTerminal",
- "externalTerminal"
- ],
+ "enum": ["internalConsole", "integratedTerminal", "externalTerminal"],
"enumDescriptions": [
"VS Code Debug Console (which doesn't support to read input from a program)",
"VS Code's integrated terminal",
@@ -830,9 +581,7 @@
"cwd": {
"default": "${ZED_WORKTREE_ROOT}",
"description": "Absolute path to the working directory of the program being debugged. If you've set localRoot then cwd will match that value otherwise it falls back to your workspaceFolder",
- "tags": [
- "setup"
- ],
+ "tags": ["setup"],
"type": "string"
},
"enableContentValidation": {
@@ -846,17 +595,10 @@
"type": "boolean"
},
"env": {
- "additionalProperties": {
- "type": [
- "string",
- "null"
- ]
- },
+ "additionalProperties": { "type": ["string", "null"] },
"default": {},
"markdownDescription": "Environment variables passed to the program. The value `null` removes the variable from the environment.",
- "tags": [
- "setup"
- ],
+ "tags": ["setup"],
"type": "object"
},
"envFile": {
@@ -867,30 +609,19 @@
"experimentalNetworking": {
"default": "auto",
"description": "Enable experimental inspection in Node.js. When set to `auto` this is enabled for versions of Node.js that support it. It can be set to `on` or `off` to enable or disable it explicitly.",
- "enum": [
- "auto",
- "on",
- "off"
- ],
+ "enum": ["auto", "on", "off"],
"type": "string"
},
"killBehavior": {
"default": "forceful",
- "enum": [
- "forceful",
- "polite",
- "none"
- ],
+ "enum": ["forceful", "polite", "none"],
"markdownDescription": "Configures how debug processes are killed when stopping the session. Can be:\n\n- forceful (default): forcefully tears down the process tree. Sends SIGKILL on posix, or `taskkill.exe /F` on Windows.\n- polite: gracefully tears down the process tree. It's possible that misbehaving processes continue to run after shutdown in this way. Sends SIGTERM on posix, or `taskkill.exe` with no `/F` (force) flag on Windows.\n- none: no termination will happen.",
"type": "string"
},
"localRoot": {
"default": null,
"description": "Path to the local directory containing the program.",
- "type": [
- "string",
- "null"
- ]
+ "type": ["string", "null"]
},
"nodeVersionHint": {
"default": 12,
@@ -899,27 +630,15 @@
"type": "number"
},
"outFiles": {
- "default": [
- "${ZED_WORKTREE_ROOT}/**/*.(m|c|)js",
- "!**/node_modules/**"
- ],
+ "default": ["${ZED_WORKTREE_ROOT}/**/*.(m|c|)js", "!**/node_modules/**"],
"description": "If source maps are enabled, these glob patterns specify the generated JavaScript files. If a pattern starts with `!` the files are excluded. If not specified, the generated code is expected in the same directory as its source.",
- "items": {
- "type": "string"
- },
- "tags": [
- "setup"
- ],
- "type": [
- "array"
- ]
+ "items": { "type": "string" },
+ "tags": ["setup"],
+ "type": ["array"]
},
"outputCapture": {
"default": "console",
- "enum": [
- "console",
- "std"
- ],
+ "enum": ["console", "std"],
"markdownDescription": "From where to capture output messages: the default debug API if set to `console`, or stdout/stderr streams if set to `std`."
},
"pauseForSourceMap": {
@@ -935,52 +654,29 @@
"program": {
"default": "",
"description": "Absolute path to the program. Generated value is guessed by looking at package.json and opened files. Edit this attribute.",
- "tags": [
- "setup"
- ],
+ "tags": ["setup"],
"type": "string"
},
"remoteRoot": {
"default": null,
"description": "Absolute path to the remote directory containing the program.",
- "type": [
- "string",
- "null"
- ]
+ "type": ["string", "null"]
},
"resolveSourceMapLocations": {
- "default": [
- "${ZED_WORKTREE_ROOT}/**",
- "!**/node_modules/**"
- ],
+ "default": ["${ZED_WORKTREE_ROOT}/**", "!**/node_modules/**"],
"description": "A list of minimatch patterns for locations (folders and URLs) in which source maps can be used to resolve local files. This can be used to avoid incorrectly breaking in external source mapped code. Patterns can be prefixed with \"!\" to exclude them. May be set to an empty array or null to avoid restriction.",
- "items": {
- "type": "string"
- },
- "type": [
- "array",
- "null"
- ]
+ "items": { "type": "string" },
+ "type": ["array", "null"]
},
"restart": {
"default": true,
"description": "Try to reconnect to the program if we lose connection. If set to `true`, we'll try once a second, forever. You can customize the interval and maximum number of attempts by specifying the `delay` and `maxAttempts` in an object instead.",
"oneOf": [
- {
- "type": "boolean"
- },
+ { "type": "boolean" },
{
"properties": {
- "delay": {
- "default": 1000,
- "minimum": 0,
- "type": "number"
- },
- "maxAttempts": {
- "default": 10,
- "minimum": 0,
- "type": "number"
- }
+ "delay": { "default": 1000, "minimum": 0, "type": "number" },
+ "maxAttempts": { "default": 10, "minimum": 0, "type": "number" }
},
"type": "object"
}
@@ -989,27 +685,18 @@
"runtimeArgs": {
"default": [],
"description": "Optional arguments passed to the runtime executable.",
- "items": {
- "type": "string"
- },
- "tags": [
- "setup"
- ],
+ "items": { "type": "string" },
+ "tags": ["setup"],
"type": "array"
},
"runtimeExecutable": {
"default": "node",
"markdownDescription": "Runtime to use. Either an absolute path or the name of a runtime available on the PATH. If omitted `node` is assumed.",
- "type": [
- "string",
- "null"
- ]
+ "type": ["string", "null"]
},
"runtimeSourcemapPausePatterns": {
"default": [],
- "items": {
- "type": "string"
- },
+ "items": { "type": "string" },
"markdownDescription": "A list of patterns at which to manually insert entrypoint breakpoints. This can be useful to give the debugger an opportunity to set breakpoints when using sourcemaps that don't exist or can't be detected before launch, such as [with the Serverless framework](https://github.com/microsoft/vscode-js-debug/issues/492).",
"type": "array"
},
@@ -1022,39 +709,21 @@
"default": true,
"description": "Show the async calls that led to the current call stack.",
"oneOf": [
+ { "type": "boolean" },
{
- "type": "boolean"
- },
- {
- "properties": {
- "onAttach": {
- "default": 32,
- "type": "number"
- }
- },
- "required": [
- "onAttach"
- ],
+ "properties": { "onAttach": { "default": 32, "type": "number" } },
+ "required": ["onAttach"],
"type": "object"
},
{
- "properties": {
- "onceBreakpointResolved": {
- "default": 32,
- "type": "number"
- }
- },
- "required": [
- "onceBreakpointResolved"
- ],
+ "properties": { "onceBreakpointResolved": { "default": 32, "type": "number" } },
+ "required": ["onceBreakpointResolved"],
"type": "object"
}
]
},
"skipFiles": {
- "default": [
- "${/**"
- ],
+ "default": ["${/**"],
"description": "An array of file or folder names, or path globs, to skip when debugging. Star patterns and negations are allowed, for example, `[\"**/node_modules/**\", \"!**/node_modules/my-module/**\"]`",
"type": "array"
},
@@ -1085,10 +754,7 @@
"stopOnEntry": {
"default": true,
"description": "Automatically stop program after launch.",
- "type": [
- "boolean",
- "string"
- ]
+ "type": ["boolean", "string"]
},
"timeout": {
"default": 10000,
@@ -1123,19 +789,13 @@
"default": true,
"description": "Configures what diagnostic output is produced.",
"oneOf": [
- {
- "description": "Trace may be set to 'true' to write diagnostic logs to the disk.",
- "type": "boolean"
- },
+ { "description": "Trace may be set to 'true' to write diagnostic logs to the disk.", "type": "boolean" },
{
"additionalProperties": false,
"properties": {
"logFile": {
"description": "Configures where on disk logs are written.",
- "type": [
- "string",
- "null"
- ]
+ "type": ["string", "null"]
},
"stdio": {
"description": "Whether to return trace data from the launched application or browser.",
@@ -1151,18 +811,8 @@
},
{
"if": {
- "properties": {
- "type": {
- "const": "node"
- },
- "request": {
- "const": "attach"
- }
- },
- "required": [
- "type",
- "request"
- ]
+ "properties": { "type": { "const": "node" }, "request": { "const": "attach" } },
+ "required": ["type", "request"]
},
"then": {
"properties": {
@@ -1184,10 +834,7 @@
"cascadeTerminateToConfigurations": {
"default": [],
"description": "A list of debug sessions which, when this debug session is terminated, will also be stopped.",
- "items": {
- "type": "string",
- "uniqueItems": true
- },
+ "items": { "type": "string", "uniqueItems": true },
"type": "array"
},
"continueOnAttach": {
@@ -1207,9 +854,7 @@
"cwd": {
"default": "${ZED_WORKTREE_ROOT}",
"description": "Absolute path to the working directory of the program being debugged. If you've set localRoot then cwd will match that value otherwise it falls back to your workspaceFolder",
- "tags": [
- "setup"
- ],
+ "tags": ["setup"],
"type": "string"
},
"enableContentValidation": {
@@ -341,7 +341,7 @@ 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(),
@@ -7,25 +7,29 @@ mod python;
use std::sync::Arc;
-use anyhow::Result;
+use anyhow::{Context as _, Result};
use async_trait::async_trait;
use codelldb::CodeLldbDebugAdapter;
+use collections::HashMap;
use dap::{
DapRegistry,
adapters::{
self, AdapterVersion, DapDelegate, DebugAdapter, DebugAdapterBinary, DebugAdapterName,
- GithubRepo,
+ DownloadedFileType, GithubRepo,
},
configure_tcp_connection,
};
+use fs::Fs as _;
use gdb::GdbDebugAdapter;
use go::GoDebugAdapter;
-use gpui::{App, BorrowAppContext};
+use gpui::{App, BorrowAppContext, http_client::github::GithubRelease};
pub use javascript::JsDebugAdapter;
use php::PhpDebugAdapter;
-use python::PythonDebugAdapter;
+pub use python::PythonDebugAdapter;
+use serde::{Deserialize, Serialize};
use serde_json::json;
-use task::{DebugScenario, ZedDebugConfig};
+use task::{DebugScenario, EnvVariableReplacer, VariableName, ZedDebugConfig};
+use tempfile::TempDir;
pub fn init(cx: &mut App) {
cx.update_default_global(|registry: &mut DapRegistry, _cx| {
@@ -44,18 +48,25 @@ pub fn init(cx: &mut App) {
}
#[cfg(feature = "update-schemas")]
-struct UpdateSchemasDapDelegate {
+#[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 {
- fn new(executor: gpui::BackgroundExecutor) -> Self {
+ pub fn new() -> Self {
+ let executor = gpui::background_executor();
// FIXME
let client = Arc::new(reqwest_client::ReqwestClient::user_agent("Cole").unwrap());
let fs = Arc::new(fs::RealFs::new(None, executor.clone()));
- Self { client, fs }
+ Self {
+ client,
+ fs,
+ executor,
+ }
}
}
@@ -80,7 +91,9 @@ impl dap::adapters::DapDelegate for UpdateSchemasDapDelegate {
fn fs(&self) -> Arc<dyn fs::Fs> {
self.fs.clone()
}
- fn output_to_console(&self, _msg: String) {}
+ fn output_to_console(&self, msg: String) {
+ eprintln!("{msg}")
+ }
async fn which(&self, _command: &std::ffi::OsStr) -> Option<std::path::PathBuf> {
unreachable!()
}
@@ -91,3 +104,142 @@ impl dap::adapters::DapDelegate for UpdateSchemasDapDelegate {
unreachable!()
}
}
+
+#[cfg(feature = "update-schemas")]
+#[derive(Debug, Serialize, 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, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+struct PackageJsonDebugger {
+ r#type: String,
+ configuration_attributes: PackageJsonConfigurationAttributes,
+}
+
+#[cfg(feature = "update-schemas")]
+#[derive(Debug, Serialize, Deserialize)]
+struct PackageJsonContributes {
+ debuggers: Vec<PackageJsonDebugger>,
+}
+
+#[cfg(feature = "update-schemas")]
+#[derive(Debug, Serialize, Deserialize)]
+struct PackageJson {
+ contributes: PackageJsonContributes,
+}
+
+fn get_vsix_package_json(
+ temp_dir: &TempDir,
+ repo: &str,
+ asset_name: impl FnOnce(&GithubRelease) -> anyhow::Result<String>,
+ delegate: UpdateSchemasDapDelegate,
+) -> anyhow::Result<(String, Option<String>)> {
+ 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))
+ })
+}
+
+fn parse_package_json(
+ package_json: String,
+ package_nls_json: Option<String>,
+) -> anyhow::Result<PackageJson> {
+ 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)
+}
@@ -1,17 +1,15 @@
use adapters::latest_github_release;
use anyhow::Context as _;
use dap::{StartDebuggingRequestArguments, adapters::DebugTaskDefinition};
-use fs::Fs;
-use gpui::{AsyncApp, BackgroundExecutor};
-use serde::{Deserialize, Serialize};
+use gpui::AsyncApp;
use serde_json::Value;
use std::{
borrow::Cow,
collections::HashMap,
- path::{Path, PathBuf},
+ path::PathBuf,
sync::{LazyLock, OnceLock},
};
-use task::{DebugRequest, EnvVariableReplacer, VariableName};
+use task::DebugRequest;
use tempfile::TempDir;
use util::{ResultExt, maybe};
@@ -252,7 +250,7 @@ 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(),
@@ -282,132 +280,23 @@ impl DebugAdapter for JsDebugAdapter {
impl JsDebugAdapter {
pub fn get_schema(
temp_dir: &TempDir,
- output_dir: &Path,
- executor: BackgroundExecutor,
- ) -> anyhow::Result<()> {
- #[derive(Serialize, 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>,
- }
-
- #[derive(Serialize, Deserialize)]
- #[serde(rename_all = "camelCase")]
- struct PackageJsonDebugger {
- r#type: String,
- configuration_attributes: PackageJsonConfigurationAttributes,
- }
-
- #[derive(Serialize, Deserialize)]
- struct PackageJsonContributes {
- debuggers: Vec<PackageJsonDebugger>,
- }
-
- #[derive(Serialize, Deserialize)]
- struct PackageJson {
- contributes: PackageJsonContributes,
- }
-
- let temp_dir = std::fs::canonicalize(temp_dir.path())?;
- let delegate = UpdateSchemasDapDelegate::new(executor.clone());
- let fs = delegate.fs.clone();
- let client = delegate.client.clone();
-
- let (package_json, package_nls_json) = executor.block(async move {
- let release = latest_github_release(
- &format!("microsoft/{}", Self::ADAPTER_NPM_NAME),
- true,
- false,
- client.clone(),
- )
- .await?;
-
- let version = release
- .tag_name
- .strip_prefix("v")
- .context("parse version")?;
- let asset_name = format!("ms-vscode.js-debug.{version}.vsix",);
- 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(
- DebugAdapterName(Self::ADAPTER_NAME.into()),
- version,
- adapters::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?;
- anyhow::Ok((package_json, package_nls_json))
- })?;
-
- let package_nls_json =
- serde_json::from_str::<HashMap<String, serde_json::Value>>(&package_nls_json)?
- .into_iter()
- .filter_map(|(k, v)| {
- let v = v.as_str()?;
- Some((k, v.to_owned()))
- })
- .collect();
-
- 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);
+ 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: PackageJson = serde_json::from_value(package_json)?;
+ let package_json = parse_package_json(package_json, package_nls_json)?;
let types = package_json
.contributes
@@ -461,15 +350,7 @@ impl JsDebugAdapter {
let schema = json!({
"allOf": conjuncts
});
-
- // FIXME figure out what to do about formatting
- let mut schema = serde_json::to_string_pretty(&schema)?;
- schema.push('\n');
- std::fs::write(
- output_dir.join(Self::ADAPTER_NAME).with_extension("json"),
- schema,
- )?;
- Ok(())
+ Ok(schema)
}
}
@@ -348,7 +348,7 @@ 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(),
@@ -8,21 +8,24 @@ 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";
@@ -106,6 +109,7 @@ impl PythonDebugAdapter {
request,
})
}
+
async fn fetch_latest_adapter_version(
&self,
delegate: &Arc<dyn DapDelegate>,
@@ -124,7 +128,7 @@ 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(),
@@ -261,336 +265,11 @@ impl DebugAdapter for PythonDebugAdapter {
}
fn dap_schema(&self) -> Cow<'static, serde_json::Value> {
- Cow::Owned(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"
- }
- }
- }
- }
- ]
- }))
+ 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(
@@ -673,6 +352,86 @@ impl DebugAdapter for PythonDebugAdapter {
}
}
+#[cfg(feature = "update-schemas")]
+impl PythonDebugAdapter {
+ pub fn get_schema(
+ temp_dir: &TempDir,
+ delegate: UpdateSchemasDapDelegate,
+ ) -> anyhow::Result<serde_json::Value> {
+ 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())
+ })?;
+
+ let configuration_attributes = debugger.configuration_attributes;
+ let conjuncts = configuration_attributes
+ .launch
+ .map(|schema| ("launch", schema))
+ .into_iter()
+ .chain(
+ configuration_attributes
+ .attach
+ .map(|schema| ("attach", schema)),
+ )
+ .map(|(request, schema)| {
+ json!({
+ "if": {
+ "properties": {
+ "request": {
+ "const": request
+ }
+ },
+ "required": ["request"]
+ },
+ "then": schema
+ })
+ })
+ .collect::<Vec<_>>();
+
+ let schema = json!({
+ "allOf": conjuncts
+ });
+ Ok(schema)
+ }
+}
+
async fn fetch_latest_adapter_version_from_github(
github_repo: GithubRepo,
delegate: &dyn DapDelegate,
@@ -1,13 +1,32 @@
-use std::path::Path;
+use std::{path::Path, process::Command};
-use dap_adapters::JsDebugAdapter;
-use gpui::background_executor;
+use dap_adapters::{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 executor = background_executor();
- JsDebugAdapter::get_schema(&temp_dir, output_dir, executor.clone())?;
+ 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)?,
+ )?;
+
+ Command::new("npx")
+ .arg("prettier")
+ .arg("--write")
+ .arg(output_dir.join("*"))
+ .status()?;
Ok(())
}