Skip to content

Commit a03931a

Browse files
fentasclaude
andauthored
feat: add DAP debugger for argsh scripts (#98)
## Summary Adds a Debug Adapter Protocol (DAP) server (`argsh-dap`) that enables step-through debugging of argsh/bash scripts in VSCode. Uses bash's built-in `DEBUG` trap — no bashdb or external dependencies required. ## Features ### Core DAP - Breakpoints (file:line) with runtime updates - Stepping: step in (F11), step over (F10), step out (Shift+F11), continue (F5) - Stack trace via `FUNCNAME`/`BASH_LINENO`/`BASH_SOURCE` - Named pipe (FIFO) communication between debugger and bash process ### argsh-specific enhancements (#92-#97) | Feature | Issue | Description | |---------|-------|-------------| | Smart breakpoints | #92 | Set breakpoints by subcommand name — resolves through `:usage` namespace chain | | Args inspector | #93 | "argsh Args" scope shows structured `:args` definitions with field types | | Auto-launch configs | #94 | Generate launch configs for all subcommand paths from `:usage` tree | | Import-aware resolution | #95 | Smart breakpoints search imported files via the shared resolver | | Variable tooltips | #96 | Hover shows argsh type annotations (`:~int`, `:+`, etc.) | | Command tree breakpoints | #97 | Function breakpoints use `:usage` resolution | ### VSCode extension - `argsh` debug type registered with launch config schema - Auto-detect `argsh-dap` binary (bundled or PATH) - Default "Debug Current File" config with `stopOnEntry` - Configuration snippet for `launch.json` ### Architecture ``` VSCode ←── DAP (stdin/stdout) ──→ argsh-dap │ ├── analyzes script via argsh_syntax ├── spawns bash with DEBUG trap prelude └── communicates via named pipes (FIFOs) ``` No `dap` crate — hand-rolled DAP types with `serde_json` (both available crates are stale/alpha). ## Files changed | File | Description | |------|-------------| | `crates/argsh-lsp/Cargo.toml` | Add `libc` dep, `[[bin]] argsh-dap` | | `crates/argsh-lsp/src/bin/argsh-dap.rs` | DAP server binary (~600 lines) | | `crates/argsh-lsp/tests/dap_integration.rs` | 8 integration tests | | `vscode-argsh/src/debugProvider.ts` | Debug adapter factory + config provider | | `vscode-argsh/src/extension.ts` | Register debug provider | | `vscode-argsh/package.json` | Debugger contributions, breakpoints, settings | | `docs/development/tools/debugger.mdx` | User documentation | | `docs/sidebars.js` | Sidebar entry under Tools | ## Tests - 8 DAP integration tests: version/help, initialize capabilities, threads, breakpoints, configurationDone, scopes with argsh Args - All 135 existing tests pass (55 LSP + 27 lint + 26 syntax + 19 unit + 8 DAP) - Extension compiles clean ## Test plan - [x] `cargo test --release` — all 135 tests pass - [x] `npm run compile` — extension compiles - [x] `argsh-dap --version` / `--help` works - [ ] Manual testing: F5 in VSCode with a script, breakpoints, stepping 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e629934 commit a03931a

12 files changed

Lines changed: 3050 additions & 21 deletions

File tree

README.md

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ Runtime
185185
| Command | What it does | Backed by |
186186
|---|---|---|
187187
| [`argsh test`](https://arg.sh/development/fundamentals/test) | Run `.bats` tests; auto-discovers tests via `PATH_TESTS` | [bats-core](https://github.com/bats-core/bats-core) |
188-
| [`argsh lint`](https://arg.sh/development/fundamentals/lint) | Lint all shell files in your project | [shellcheck](https://www.shellcheck.net/) |
188+
| [`argsh lint`](https://arg.sh/development/fundamentals/lint) | Lint all shell files (shellcheck + argsh-lint) | [shellcheck](https://www.shellcheck.net/) + [argsh-lint](https://arg.sh/development/fundamentals/lint) |
189189
| [`argsh coverage`](https://arg.sh/development/fundamentals/coverage) | Generate a coverage report with a minimum threshold | [kcov](https://github.com/SimonKagstrom/kcov) |
190190
| [`argsh docs`](https://arg.sh/development/fundamentals/docs) | Generate Markdown docs from `@description` comments | [shdoc](https://github.com/reconquest/shdoc) |
191191
| [`argsh minify`](https://arg.sh/development/fundamentals/minify) | Bundle + minify + obfuscate a multi-file project into a single script | native Rust minifier |
@@ -286,9 +286,9 @@ Run `bash bench/usage-depth.sh` to reproduce.
286286

287287
### 🧩 IDE Support
288288

289-
argsh includes a **Language Server** and **VSCode/Windsurf extension** for rich IDE support:
289+
argsh includes a **Language Server**, **CLI linter**, **debugger**, and **VSCode/Windsurf extension** for a complete development experience:
290290

291-
- **Diagnostics**10 checks (AG001–AG010) with shellcheck-style suppression (`# argsh disable=AG004`)
291+
- **Diagnostics**12 checks (AG001–AG013) with shellcheck-style suppression (`# argsh disable=AG004`)
292292
- **Completions** — modifiers, types (built-in + custom), annotations, library functions (`is::`, `to::`, `string::`, ...)
293293
- **Help preview** — hover over functions to see generated `--help` output
294294
- **Go to definition** — Ctrl+Click on usage entries, `:-` mappings, `:~custom` types, imports
@@ -301,25 +301,35 @@ argsh includes a **Language Server** and **VSCode/Windsurf extension** for rich
301301

302302
Works alongside shellcheck — argsh handles framework-specific validation, shellcheck handles general bash.
303303

304+
**CLI Linter** (`argsh-lint`) — standalone binary with shellcheck-compatible flags for CI pipelines:
305+
304306
```bash
305-
# Build from source
306-
cd crates/argsh-lsp && cargo build --release
307-
cd vscode-argsh && npm install && npm run compile
307+
argsh-lint script.sh # gcc-style output
308+
argsh-lint --format=json --severity=warning # JSON for CI
309+
argsh lint # runs both shellcheck + argsh-lint
310+
argsh lint --only-argsh # argsh-lint only
308311
```
309312

310-
See the [LSP docs](https://arg.sh/development/tools/lsp) for configuration and full feature reference.
311-
312-
&nbsp;
313+
See the [Lint docs](https://arg.sh/development/fundamentals/lint) for the full flag reference.
313314

314-
### 🚧 State of this Project
315+
**Debugger** (`argsh-dap`) — step-through debugging via VSCode with no external dependencies:
315316

316-
> This project is in a very early stage.
317+
- **Breakpoints** — file:line, conditional (`(( i == 3 ))`), and by subcommand name
318+
- **Stepping** — step in (F11), step over (F10), step out (Shift+F11)
319+
- **Call stack** — full `FUNCNAME`/`BASH_SOURCE` trace with argsh namespace resolution
320+
- **Variable inspection** — argsh Args inspector shows `:args` field definitions with types
321+
- **Watch expressions** and **set variable at runtime**
322+
- **Subshell support**`$()`, pipes, `{ ...; } &` don't deadlock
317323

318-
That being said, most of it is quite rough. But it's a start. The best time that you join the conversation and try to refine the concept.
324+
Uses bash's built-in `DEBUG` trap — no `bashdb` required. See the [Debugger docs](https://arg.sh/development/tools/debugger).
319325

320-
#### Short term goals
326+
```bash
327+
# Build from source
328+
cd crates/argsh-lsp && cargo build --release # builds argsh-lsp, argsh-lint, argsh-dap
329+
cd vscode-argsh && npm install && npm run compile
330+
```
321331

322-
- [ ] Bash debugger integration (e.g. with `bashdb`)
332+
See the [LSP docs](https://arg.sh/development/tools/lsp) for configuration and full feature reference.
323333

324334
&nbsp;
325335

crates/argsh-lsp/Cargo.toml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ path = "src/main.rs"
1919
name = "argsh-lint"
2020
path = "src/bin/argsh-lint.rs"
2121

22+
# Debug Adapter Protocol (DAP) server for step-through debugging of argsh
23+
# scripts. Uses bash's DEBUG trap for breakpoints and stepping — no bashdb
24+
# dependency required.
25+
[[bin]]
26+
name = "argsh-dap"
27+
path = "src/bin/argsh-dap.rs"
28+
2229
[dependencies]
2330
argsh-syntax = { path = "../argsh-syntax" }
2431
tower-lsp = "0.20"
@@ -27,7 +34,10 @@ serde = { version = "1", features = ["derive"] }
2734
serde_json = "1"
2835
dashmap = "6"
2936
regex = "1"
37+
tempfile = "3"
38+
39+
[target.'cfg(unix)'.dependencies]
40+
libc = "0.2"
3041

3142
[dev-dependencies]
32-
tempfile = "3"
3343
serde_json = "1"

crates/argsh-lsp/coverage.json

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,20 @@
2121
"total_lines": "401",
2222
"excluded_lines": "0"
2323
},
24+
{
25+
"file": "crates/argsh-lsp/tests/dap_integration.rs",
26+
"percent_covered": "99.31",
27+
"covered_lines": "286",
28+
"total_lines": "288",
29+
"excluded_lines": "0"
30+
},
31+
{
32+
"file": "crates/argsh-lsp/tests/dap_e2e.rs",
33+
"percent_covered": "99.30",
34+
"covered_lines": "426",
35+
"total_lines": "429",
36+
"excluded_lines": "0"
37+
},
2438
{
2539
"file": "crates/argsh-lsp/src/format.rs",
2640
"percent_covered": "97.30",
@@ -84,6 +98,13 @@
8498
"total_lines": "408",
8599
"excluded_lines": "0"
86100
},
101+
{
102+
"file": "crates/argsh-lsp/src/bin/argsh-dap.rs",
103+
"percent_covered": "78.38",
104+
"covered_lines": "667",
105+
"total_lines": "851",
106+
"excluded_lines": "0"
107+
},
87108
{
88109
"file": "crates/argsh-syntax/src/usage.rs",
89110
"percent_covered": "77.78",
@@ -141,12 +162,12 @@
141162
"excluded_lines": "0"
142163
}
143164
],
144-
"percent_covered": "79.45",
145-
"covered_lines": 4915,
146-
"total_lines": 6186,
165+
"percent_covered": "81.17",
166+
"covered_lines": 6294,
167+
"total_lines": 7754,
147168
"excluded_lines": 0,
148169
"percent_low": 25,
149170
"percent_high": 75,
150171
"command": "cargo-test+llvm-cov",
151-
"date": "2026-04-16 21:47:52"
172+
"date": "2026-04-18 18:03:55"
152173
}

0 commit comments

Comments
 (0)