codelldb

Cole Miller created

Change summary

crates/dap_adapters/schemas/CodeLLDB.json | 253 +++++++++++++++++++++++++
crates/dap_adapters/src/codelldb.rs       | 232 ++++------------------
crates/dap_adapters/src/dap_adapters.rs   |  30 ++
crates/dap_adapters/src/go.rs             |  32 --
crates/dap_adapters/src/python.rs         |  32 --
crates/dap_adapters/src/update_schemas.rs |  15 +
6 files changed, 343 insertions(+), 251 deletions(-)

Detailed changes

crates/dap_adapters/schemas/CodeLLDB.json 🔗

@@ -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."
+            ]
+          }
+        }
+      }
+    }
+  ]
+}

crates/dap_adapters/src/codelldb.rs 🔗

@@ -1,4 +1,9 @@
-use std::{borrow::Cow, 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;
@@ -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: &TempDir,
+        delegate: UpdateSchemasDapDelegate,
+    ) -> anyhow::Result<serde_json::Value> {
+        let (package_json, package_nls_json) = get_vsix_package_json(
+            temp_dir,
+            "vadimcn/codelldb",
+            |_| Ok(format!("codelldb-bootstrap.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 codelldb debuggers: {}",
+                    debuggers.len()
+                )
+            })?;
+
+        Ok(schema_for_configuration_attributes(
+            debugger.configuration_attributes,
+        ))
+    }
+}
+
 #[async_trait(?Send)]
 impl DebugAdapter for CodeLldbDebugAdapter {
     fn name(&self) -> DebugAdapterName {
@@ -133,194 +166,11 @@ impl DebugAdapter for CodeLldbDebugAdapter {
     }
 
     fn dap_schema(&self) -> Cow<'static, serde_json::Value> {
-        Cow::Owned(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"]
-                            }
-                        ]
-                    }
-                }
-            ]
-        }))
+        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(

crates/dap_adapters/src/dap_adapters.rs 🔗

@@ -9,7 +9,7 @@ use std::sync::Arc;
 
 use anyhow::{Context as _, Result};
 use async_trait::async_trait;
-use codelldb::CodeLldbDebugAdapter;
+pub use codelldb::CodeLldbDebugAdapter;
 use collections::HashMap;
 use dap::{
     DapRegistry,
@@ -243,3 +243,31 @@ fn parse_package_json(
     let package_json: PackageJson = serde_json::from_value(package_json)?;
     Ok(package_json)
 }
+
+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
+    })
+}

crates/dap_adapters/src/go.rs 🔗

@@ -122,35 +122,9 @@ impl GoDebugAdapter {
                 anyhow::anyhow!("unexpected number of go 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)
+        Ok(schema_for_configuration_attributes(
+            debugger.configuration_attributes,
+        ))
     }
 }
 

crates/dap_adapters/src/python.rs 🔗

@@ -400,35 +400,9 @@ impl PythonDebugAdapter {
                 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)
+        Ok(schema_for_configuration_attributes(
+            debugger.configuration_attributes,
+        ))
     }
 }
 

crates/dap_adapters/src/update_schemas.rs 🔗

@@ -1,6 +1,10 @@
 use std::{path::Path, process::Command};
 
-use dap_adapters::{GoDebugAdapter, JsDebugAdapter, PythonDebugAdapter, UpdateSchemasDapDelegate};
+use dap::adapters::DapDelegate as _;
+use dap_adapters::{
+    CodeLldbDebugAdapter, GoDebugAdapter, JsDebugAdapter, PythonDebugAdapter,
+    UpdateSchemasDapDelegate,
+};
 use tempfile::TempDir;
 
 fn main() -> anyhow::Result<()> {
@@ -32,6 +36,15 @@ fn main() -> anyhow::Result<()> {
         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")