textual-debugger 0.2.2__tar.gz → 0.2.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/PKG-INFO +199 -35
  2. {textual_debugger-0.2.2/src/tdb → textual_debugger-0.2.4}/README.md +193 -31
  3. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/pyproject.toml +6 -4
  4. {textual_debugger-0.2.2 → textual_debugger-0.2.4/src/tdb}/README.md +193 -31
  5. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/__init__.py +1 -1
  6. textual_debugger-0.2.4/src/tdb/adapters/bash/__main__.py +23 -0
  7. textual_debugger-0.2.4/src/tdb/adapters/bash/declares.py +92 -0
  8. textual_debugger-0.2.4/src/tdb/adapters/bash/server.py +360 -0
  9. textual_debugger-0.2.4/src/tdb/adapters/bash/session.py +489 -0
  10. textual_debugger-0.2.4/src/tdb/adapters/bash/tdb_harness.sh +230 -0
  11. textual_debugger-0.2.4/src/tdb/adapters/perl/Devel/TdbCompile.pm +68 -0
  12. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/adapters/perl/helpers.pl +42 -1
  13. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/adapters/perl/server.py +373 -17
  14. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/adapters/perl/session.py +74 -4
  15. textual_debugger-0.2.4/src/tdb/adapters/tcsh/__init__.py +7 -0
  16. textual_debugger-0.2.4/src/tdb/adapters/tcsh/__main__.py +3 -0
  17. textual_debugger-0.2.4/src/tdb/adapters/tcsh/breakpoints.py +44 -0
  18. textual_debugger-0.2.4/src/tdb/adapters/tcsh/cli.py +163 -0
  19. textual_debugger-0.2.4/src/tdb/adapters/tcsh/guardian.py +718 -0
  20. textual_debugger-0.2.4/src/tdb/adapters/tcsh/inspect.py +187 -0
  21. textual_debugger-0.2.4/src/tdb/adapters/tcsh/instrumenter.py +354 -0
  22. textual_debugger-0.2.4/src/tdb/adapters/tcsh/models.py +61 -0
  23. textual_debugger-0.2.4/src/tdb/adapters/tcsh/protocol.py +68 -0
  24. textual_debugger-0.2.4/src/tdb/adapters/tcsh/runtime.py +304 -0
  25. textual_debugger-0.2.4/src/tdb/adapters/tcsh/scanner.py +225 -0
  26. textual_debugger-0.2.4/src/tdb/adapters/tcsh/server.py +553 -0
  27. textual_debugger-0.2.4/src/tdb/adapters/tcsh/session.py +1221 -0
  28. textual_debugger-0.2.4/src/tdb/adapters/tcsh/transport.py +914 -0
  29. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/app.py +5 -19
  30. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/app_handlers/dap_events.py +61 -64
  31. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/app_handlers/ui_panels.py +2 -0
  32. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/dap/types.py +19 -0
  33. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/languages/base.py +46 -0
  34. textual_debugger-0.2.4/src/tdb/languages/bash.py +83 -0
  35. textual_debugger-0.2.4/src/tdb/languages/errors.py +235 -0
  36. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/languages/perl.py +4 -1
  37. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/languages/python.py +2 -1
  38. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/languages/registry.py +18 -0
  39. textual_debugger-0.2.4/src/tdb/languages/tcsh.py +101 -0
  40. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/server/event_handler.py +0 -3
  41. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/session/controller.py +56 -8
  42. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/session/state.py +7 -0
  43. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/session/textual_handler.py +0 -1
  44. textual_debugger-0.2.4/src/tdb/widgets/__init__.py +0 -0
  45. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/widgets/async_tasks_modal.py +1 -1
  46. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/widgets/code_view.py +0 -1
  47. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/widgets/evaluate_console.py +2 -3
  48. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/widgets/modals.py +11 -1
  49. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/textual_debugger.egg-info/PKG-INFO +199 -35
  50. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/textual_debugger.egg-info/SOURCES.txt +24 -0
  51. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/LICENSE +0 -0
  52. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/setup.cfg +0 -0
  53. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/__main__.py +0 -0
  54. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/_timeouts.py +0 -0
  55. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/adapters/__init__.py +0 -0
  56. {textual_debugger-0.2.2/src/tdb/adapters/perl → textual_debugger-0.2.4/src/tdb/adapters/bash}/__init__.py +0 -0
  57. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/adapters/perl/Devel/TdbRemote.pm +0 -0
  58. {textual_debugger-0.2.2/src/tdb/dap → textual_debugger-0.2.4/src/tdb/adapters/perl}/__init__.py +0 -0
  59. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/adapters/perl/__main__.py +0 -0
  60. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/adapters/perl/protocol.py +0 -0
  61. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/adapters/perl/refs.py +0 -0
  62. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/app_handlers/__init__.py +0 -0
  63. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/app_handlers/inspection.py +0 -0
  64. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/app_handlers/routing.py +0 -0
  65. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/app_helpers.py +0 -0
  66. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/breakpoint_hook.py +0 -0
  67. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/cli.py +0 -0
  68. {textual_debugger-0.2.2/src/tdb/server → textual_debugger-0.2.4/src/tdb/dap}/__init__.py +0 -0
  69. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/dap/client.py +0 -0
  70. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/dap/messages.py +0 -0
  71. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/dap/protocol.py +0 -0
  72. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/inspection.py +0 -0
  73. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/inspection_full.py +0 -0
  74. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/keybindings/__init__.py +0 -0
  75. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/languages/__init__.py +0 -0
  76. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/languages/cpp.py +0 -0
  77. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/mcp/__init__.py +0 -0
  78. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/mcp/__main__.py +0 -0
  79. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/mcp/server.py +0 -0
  80. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/mcp/session.py +0 -0
  81. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/persist.py +0 -0
  82. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/post_mortem.py +0 -0
  83. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/processes_cache.py +0 -0
  84. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/replay.py +0 -0
  85. {textual_debugger-0.2.2/src/tdb/session → textual_debugger-0.2.4/src/tdb/server}/__init__.py +0 -0
  86. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/server/app.py +0 -0
  87. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/server/handlers.py +0 -0
  88. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/server/rpc_types.py +0 -0
  89. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/server/runner.py +0 -0
  90. {textual_debugger-0.2.2/src/tdb/widgets → textual_debugger-0.2.4/src/tdb/session}/__init__.py +0 -0
  91. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/session/child_processes.py +0 -0
  92. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/session/event_bus.py +0 -0
  93. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/session/inspect_service.py +0 -0
  94. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/session/messages.py +0 -0
  95. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/session/post_mortem_loader.py +0 -0
  96. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/session/recorder.py +0 -0
  97. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/session/statement_stepper.py +0 -0
  98. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/session/terminal.py +0 -0
  99. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/source_analysis.py +0 -0
  100. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/widgets/_inspection_modal.py +0 -0
  101. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/widgets/breakpoint_view.py +0 -0
  102. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/widgets/console_view.py +0 -0
  103. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/widgets/full_contents_modal.py +0 -0
  104. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/widgets/menu_bar.py +0 -0
  105. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/widgets/processes_modal.py +0 -0
  106. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/widgets/stack_view.py +0 -0
  107. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/widgets/status_bar.py +0 -0
  108. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/widgets/threads_modal.py +0 -0
  109. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/tdb/widgets/variable_view.py +0 -0
  110. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/textual_debugger.egg-info/dependency_links.txt +0 -0
  111. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/textual_debugger.egg-info/entry_points.txt +0 -0
  112. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/textual_debugger.egg-info/requires.txt +0 -0
  113. {textual_debugger-0.2.2 → textual_debugger-0.2.4}/src/textual_debugger.egg-info/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: textual-debugger
3
- Version: 0.2.2
4
- Summary: A TUI Python debugger based on textual and debugpy
3
+ Version: 0.2.4
4
+ Summary: A TUI debugger for Python, Perl, and other languages. Based on textual.
5
5
  Author-email: Al Danial <al.danial@gmail.com>
6
6
  License: textual-debugger is licensed to you under the MIT/X Consortium license:
7
7
 
@@ -39,11 +39,13 @@ Classifier: Intended Audience :: Developers
39
39
  Classifier: License :: OSI Approved :: MIT License
40
40
  Classifier: Operating System :: POSIX :: Linux
41
41
  Classifier: Programming Language :: Python :: 3
42
- Classifier: Programming Language :: Python :: 3.10
43
42
  Classifier: Programming Language :: Python :: 3.11
44
43
  Classifier: Programming Language :: Python :: 3.12
44
+ Classifier: Programming Language :: Python :: 3.13
45
+ Classifier: Programming Language :: Python :: 3.14
46
+ Classifier: Programming Language :: Python :: 3.15
45
47
  Classifier: Topic :: Software Development :: Debuggers
46
- Requires-Python: >=3.10
48
+ Requires-Python: >=3.11
47
49
  Description-Content-Type: text/markdown
48
50
  License-File: LICENSE
49
51
  Requires-Dist: textual>=8.0.0
@@ -68,8 +70,12 @@ Dynamic: license-file
68
70
 
69
71
  `textual-debugger` (the package) provides `tdb` (the command-line tool and module),
70
72
  a full-featured terminal-based debugger for Python and other languages
71
- with a Debug Adapter Protocol (DAP) implementation. C and C++ support (via
72
- `gdb` or `lldb-dap`) is built in.
73
+ with a Debug Adapter Protocol (DAP) implementation. In addition to Python,
74
+ `tdb` comes with built-in support for
75
+ - C and C++ (via `gdb` or `lldb-dap`)
76
+ - Perl (via `perl -d`)
77
+ - Bash (via bash's own `DEBUG` trap; bash ≥ 4.4)
78
+ - Tcsh (via source instrumentation of a stock `tcsh`)
73
79
 
74
80
  `tdb` is built with [textual](https://github.com/Textualize/textual) and speaks
75
81
  DAP to a pluggable debug adapter: [debugpy](https://github.com/microsoft/debugpy)
@@ -90,7 +96,9 @@ MIT License. Copyright 2026 by Al Danial.
90
96
  `tdb`:
91
97
 
92
98
  - debugs multiple languages through the Debug Adapter Protocol: Python (via `debugpy`,
93
- the richest feature set) and C/C++ (via `gdb -i dap` or `lldb-dap`), with the language
99
+ the richest feature set), C/C++ (via `gdb -i dap` or `lldb-dap`), Perl (via `perl -d`),
100
+ Bash (via bash's own `DEBUG` trap), and Tcsh (via source instrumentation of a
101
+ stock `tcsh`), with the language
94
102
  auto-detected from the target (ref. [Multi-Language Debugging](#multi-language-debugging)).
95
103
 
96
104
  - supports debugging of synchronous, asynchronous, multi-threaded, and multi-process Python code.
@@ -236,22 +244,26 @@ python -m tdb my_program.py
236
244
 
237
245
  ## Multi-Language Debugging
238
246
 
239
- `tdb` debugs any language that has a Debug Adapter Protocol backend. Two
247
+ `tdb` debugs any language that has a Debug Adapter Protocol backend. Five
240
248
  languages are supported out of the box:
241
249
 
242
- | Language | Adapter(s) | How to get the adapter | Feature level |
250
+ | Language | Adapter(s) | Dependencies | Feature level |
243
251
  |----------|------------|------------------------|---------------|
244
- | Python | `debugpy` (default) | installed with `textual-debugger` | everything in this README |
252
+ | Python | `debugpy` (default) | Python ≥ 3.11 | everything in this README |
245
253
  | C / C++ (any native binary) | `gdb` (default), `lldb-dap` (alternate) | `gdb -i dap` requires GDB ≥ 14; `lldb-dap` ships with LLVM ≥ 17 (e.g. `apt install lldb`) | core debugging: breakpoints, stepping, stack, variables, evaluate console |
246
- | Perl | perl-tdb (bundled) | needs perl ≥ 5.18 on PATH (or `{"adapters": {"perl": ...}}`) | core debugging + remote attach |
254
+ | Perl | perl-tdb (bundled) | perl ≥ 5.18 on PATH | core debugging + remote attach |
255
+ | Bash | bash-tdb (bundled) | bash ≥ 4.4 on PATH | core debugging (no remote attach) |
256
+ | Tcsh | tcsh-tdb (bundled) | tcsh on PATH | core debugging (no remote attach, no conditional breakpoints, no pause) |
247
257
 
248
258
  ### Language detection and selection
249
259
 
250
260
  The language is auto-detected from the debug target:
251
261
 
252
- 1. File extension: `.py` → Python; `.pl` / `.pm` / `.t` → Perl.
262
+ 1. File extension: `.py` → Python; `.pl` / `.pm` / `.t` → Perl; `.sh` / `.bash`
263
+ → Bash; `.csh` / `.tcsh` → Tcsh.
253
264
  2. Native executables (ELF, Mach-O, PE magic bytes) → C/C++.
254
- 3. A `#!...python` or `#!...perl` shebang → Python / Perl respectively.
265
+ 3. A `#!...python`, `#!...perl`, `#!...bash`, or `#!...csh`/`#!...tcsh`
266
+ shebang → Python / Perl / Bash / Tcsh respectively.
255
267
  4. C/C++/Rust *source* files (`.c`, `.cpp`, `.rs`, …) produce an error with a
256
268
  hint: compile with debug info (`g++ -g -O0`) and debug the binary.
257
269
  5. Anything else produces an error naming the `--lang` override.
@@ -283,17 +295,62 @@ conditions and persistence), stepping, continue/pause, run-to-cursor, stack
283
295
  navigation, variable inspection, the evaluate console, syntax highlighting,
284
296
  and the JSON-RPC / MCP programmatic modes.
285
297
 
286
- Python-specific features are hidden or return a clear "not supported for this
298
+ Python-specific features are hidden or return "not supported for this
287
299
  language" message when debugging other languages: statement-granularity
288
300
  stepping (non-Python languages always step per line), the async task /
289
301
  process inspectors and wait graph, the evaluate console's trailing-`?` help,
290
302
  `--python`/`--pv`, `--no-subprocess`, automatic child-process attachment, and
291
303
  the post-mortem / `tdb.breakpoint()` hooks (those hooks live inside Python
292
304
  programs by nature). Remote attach (`-r`) also works for Perl (see
293
- [Perl](#perl) — `Devel::TdbRemote` in place of `debugpy.listen()`), but not
294
- for C/C++. `--terminal` is
305
+ [Perl](#perl), `Devel::TdbRemote` in place of `debugpy.listen()`), but not
306
+ for C/C++, Bash, or Tcsh. `--terminal` is
295
307
  currently ignored for non-Python targets.
296
308
 
309
+ **Bash limitations (v1):** the bash adapter uses bash's own `DEBUG` trap and
310
+ has a smaller feature envelope than Python/Perl:
311
+
312
+ - Debuggee code that installs its own `DEBUG` trap clobbers the harness;
313
+ debugging silently degrades to free-running.
314
+ - No stopping inside subshells `(...)`, `$(...)`, or pipeline segments; they
315
+ execute normally.
316
+ - Child bash processes run uninstrumented.
317
+ - Outer-frame locals not inspectable (innermost frame only).
318
+ - Pause is deferred while blocked in an external command.
319
+ - `.sh` files that aren't bash are only diagnosed at launch, by bash itself
320
+ or the harness version check.
321
+ - The `DEBUG` trap never fires on a function-definition line, so a
322
+ breakpoint on a `func() {` line never hits; entry and step-in stops land
323
+ on the first executable line of the function body instead.
324
+ - The debug control channel occupies two inherited file descriptors
325
+ (typically high-numbered). A script that execs redirections onto those
326
+ exact fds (e.g. `exec 63>&-` or reusing them for its own I/O) will
327
+ silently break debugging.
328
+
329
+ See [Bash](#bash) below for launch details.
330
+
331
+ **Tcsh limitations (v1):** tcsh has no debug hooks at all, so the tcsh
332
+ adapter debugs an instrumented temporary *copy* of the script (original
333
+ paths and line numbers are preserved in everything tdb displays):
334
+
335
+ - Conditional breakpoints are not supported; a condition set in the
336
+ Breakpoint View is ignored for tcsh (the breakpoint always stops).
337
+ - No asynchronous pause: a free-running script stops only at the next
338
+ breakpoint (or when it exits).
339
+ - A breakpoint binds to the nearest safe statement at or after the
340
+ requested line; unplaceable breakpoints are reported unverified.
341
+ - Stack frames represent `source`d files, not native call frames, and only
342
+ literal `source` targets resolvable at launch are instrumented (computed
343
+ or `cd`-dependent sources run normally but are atomic to the debugger).
344
+ - All frames show the same live shell state (Shell Variables, Environment,
345
+ Aliases, Arguments). Stock tcsh keeps no per-frame history.
346
+ - Multiple commands on one physical line (`a ; b`), command substitutions,
347
+ and external commands are atomic stepping units.
348
+ - `$0` inside dynamically generated or evaluated text can expose the
349
+ generated copy's path (ordinary lexical `$0` is rewritten correctly).
350
+ - Requires Python ≥ 3.11.
351
+
352
+ See [Tcsh](#tcsh) below for launch details.
353
+
297
354
  ### C/C++ tips
298
355
 
299
356
  - Compile with `-g` (ideally `-g -O0`). If no breakpoint in a file can be
@@ -304,7 +361,7 @@ currently ignored for non-Python targets.
304
361
  variables, and evaluate console remain fully usable.
305
362
  - GDB (the default adapter) has the most complete libstdc++
306
363
  pretty-printing. `lldb-dap` (via `--adapter lldb-dap`) also debugs
307
- GCC-built binaries fine — DWARF is compiler-neutral.
364
+ GCC-built binaries fine. DWARF is compiler-neutral.
308
365
  - **GDB evaluate-console quirk:** GDB's DAP treats REPL input as CLI
309
366
  commands, so evaluate expressions with an explicit `print`, e.g.
310
367
  `print x` rather than bare `x` (bare `x` collides with GDB's
@@ -312,8 +369,8 @@ currently ignored for non-Python targets.
312
369
 
313
370
  ### Perl
314
371
 
315
- `tdb` bundles its own Perl adapter (`perl-tdb`) — no separate adapter install
316
- needed, just a `perl` ≥ 5.18 on `PATH`. It drives stock `perl5db` under the
372
+ `tdb` bundles its own Perl adapter (`perl-tdb`) so only need
373
+ `perl` ≥ 5.18 on `PATH`. It drives stock `perl5db` under the
317
374
  hood, so it works with any Perl already on the system.
318
375
 
319
376
  **Launching a script:**
@@ -322,15 +379,61 @@ hood, so it works with any Perl already on the system.
322
379
  tdb script.pl
323
380
  ```
324
381
 
382
+ **Compile-time code (`BEGIN` blocks):** Perl runs `BEGIN` blocks and the
383
+ `use` statements that are themselves `BEGIN` blocks while it is still
384
+ *compiling* your program, before stock `perl5db` ever stops. `tdb` arms the
385
+ debugger ahead of compilation so that code is debuggable too, which means the
386
+ first stop is the first **compile-time** statement of your file (typically
387
+ `use strict;` near the top) rather than the first runtime statement. Step from
388
+ there and you land inside your `BEGIN` blocks, with the stack and evaluate
389
+ views working normally (local variable listing is limited at a compile-time
390
+ stop); the `Stack` view shows the frame as `main::BEGIN`. Stepping through a
391
+ `use` line takes a few steps (the pragma's
392
+ own compile-time work happens in between) but you are never dragged into
393
+ another module's internals.
394
+
395
+ Two consequences worth knowing:
396
+
397
+ - **Breakpoints are deferred while your program compiles.** During the compile
398
+ phase Perl has only parsed part of your file, so its line table is
399
+ incomplete and a breakpoint can't be verified yet. `tdb` holds such requests
400
+ and, while it single-steps through the rest of compilation, checks each
401
+ compile-time statement it lands on against them. A breakpoint placed
402
+ *inside* a `BEGIN` block fires there directly, on the first run, without
403
+ needing to be stepped into by hand. Conditional breakpoints work the same
404
+ way at compile time; a condition that itself errors behaves exactly like a
405
+ bad condition at runtime in that it does not fire. Two residual caveats: a
406
+ breakpoint on a non-statement line (the `BEGIN {` line itself, or a blank
407
+ line) never fires during the compile phase, since it's never actually
408
+ trapped as a statement; and `hitCondition` (break on the Nth hit) isn't
409
+ honored for a compile-time stop, only a plain `condition`.
410
+ - **Startup is slower for large dependency graphs**, because the debugger is
411
+ active throughout compilation. A script with a big `use` tree takes
412
+ noticeably longer to reach its first stop under `tdb`.
413
+
414
+ **`END` blocks** are entered with **step-in** (`s`). `next` and `continue` run
415
+ straight past them to program termination, which is standard `perl5db`
416
+ behavior, not a `tdb` limitation.
417
+
418
+ **When your program dies:** an uncaught Perl error (`die`, or a fatal runtime
419
+ error such as division by zero) opens the same error modal Python tracebacks
420
+ get: the message, the call stack parsed from Perl's `at FILE line N.` /
421
+ `... called at FILE line N` output, and Code View navigated to the failing
422
+ line. This works for compile-time failures too, including a `die` inside a
423
+ `BEGIN` block that aborts compilation. Press `e` in Code View to re-summon the
424
+ last error. `tdb` also reports the debuggee's real exit status rather than
425
+ assuming success.
426
+
325
427
  **Remote attach:** useful when the Perl process is already running (a long-
326
428
  lived service, a process started by something other than `tdb`) or lives on
327
429
  another host/container. Add three lines to the target program, with the
328
430
  `use` line first so the debugger is armed before any of your code compiles:
329
431
 
330
432
  ```perl
331
- use Devel::TdbRemote; # FIRST line of your program
433
+ use Devel::TdbRemote; # first line of your program
332
434
  ...
333
435
  Devel::TdbRemote::listen(5678); # non-blocking
436
+ print "Waiting for tdb to attach on port 5678\n";
334
437
  Devel::TdbRemote::wait_for_client(); # blocks until tdb connects
335
438
  ```
336
439
 
@@ -349,8 +452,8 @@ script controls startup), arm it before Perl even parses your file instead:
349
452
  environment that launches the debuggee.
350
453
 
351
454
  **Copying the adapter to a remote host:** `Devel::TdbRemote` and its helper
352
- script are plain files, not a CPAN install — copy both onto the remote
353
- machine and point `PERL5LIB` at the directory that contains them:
455
+ script are plain files, not a CPAN install. Copy both onto the remote
456
+ machine and point `PERL5LIB` at the directory that contains them, for example:
354
457
 
355
458
  ```bash
356
459
  # From a checkout or an installed wheel's site-packages/tdb/adapters/perl:
@@ -360,7 +463,7 @@ export PERL5LIB=/opt/tdb-perl:$PERL5LIB
360
463
  ```
361
464
 
362
465
  (`Devel/TdbRemote.pm` locates `helpers.pl` next to itself at runtime, so keep
363
- the two files in the same relative layout shown above — `helpers.pl` is a
466
+ the two files in the same relative layout shown above; `helpers.pl` is a
364
467
  sibling of the `Devel/` directory, not inside it.)
365
468
 
366
469
  **PadWalker (optional but recommended):** inspecting lexical (`my`)
@@ -372,9 +475,68 @@ Install with `cpanm PadWalker` (or your distro's package) for full fidelity.
372
475
 
373
476
  **Pause is unavailable in attach mode.** Launch-mode sessions (`tdb
374
477
  script.pl`) support pausing a running program at any time. Remote-attach
375
- sessions don't — debugpy-style asynchronous pause needs a control channel
478
+ sessions don't. Asynchronous pause (as Python gets via `debugpy`) needs a control channel
376
479
  `Devel::TdbRemote` doesn't implement yet; `pause` in attach mode returns a
377
- clear "not available" error instead of hanging.
480
+ "not available" error instead of hanging.
481
+
482
+ ### Bash
483
+
484
+ `tdb` bundles its own bash adapter (`bash-tdb`) so no separate adapter install
485
+ needed, just a `bash` ≥ 4.4 on `PATH`. It drives stock bash's own `DEBUG`
486
+ trap (with `extdebug` for return-value control) under the hood via a small
487
+ harness script sourced through `BASH_ENV`, so it works with any bash already
488
+ on the system.
489
+
490
+ **Launching a script:**
491
+
492
+ ```bash
493
+ tdb script.sh
494
+ ```
495
+
496
+ Core debugging works as described above (breakpoints, stepping,
497
+ continue/pause, stack, variables, evaluate console), with the v1 caveats
498
+ listed in [What works for non-Python languages](#what-works-for-non-python-languages).
499
+ Most notably, a breakpoint can't be set on a `func() {` line itself (the
500
+ `DEBUG` trap never fires there), stops never land inside subshells or
501
+ pipeline segments, child bash processes run uninstrumented, and only the
502
+ innermost frame's locals are inspectable. There is no remote-attach mode for
503
+ Bash.
504
+
505
+ The Variables view shows three scopes for bash: Locals (innermost frame
506
+ only), Globals (unexported shell variables), and Environment (exported
507
+ variables, both inherited and script-`export`ed).
508
+
509
+ ### Tcsh
510
+
511
+ `tdb` bundles its own tcsh adapter (`tcsh-tdb`) so no separate adapter
512
+ is needed, just a stock `tcsh` on `PATH` (or
513
+ `{"adapters": {"tcsh": "/path/to/tcsh"}}` in `config.json`). Stock tcsh has
514
+ no debugger hooks, so the adapter instruments a temporary copy of the script
515
+ (and of any literal `source`d files), runs it with `tcsh -f`, and
516
+ coordinates stops through private FIFOs. tdb always shows the original
517
+ source paths and line numbers; the generated copies are private adapter
518
+ details and are cleaned up when the session ends.
519
+
520
+ **Launching a script:**
521
+
522
+ ```bash
523
+ tdb script.csh
524
+ ```
525
+
526
+ Core debugging works as described above: line breakpoints, stepping
527
+ (`next` steps over `source`d files, `stepIn` steps into instrumented ones),
528
+ stack navigation across `source` nesting, variable inspection, and the
529
+ evaluate console with the v1 caveats listed in
530
+ [What works for non-Python languages](#what-works-for-non-python-languages),
531
+ most notably: no conditional breakpoints, no pause of a free-running
532
+ script, and stepping is per logical source line.
533
+
534
+ The Variables view shows four scopes for tcsh: Shell Variables (`set`),
535
+ Environment (`setenv`), Aliases, and Arguments (`argv`). All of them show
536
+ the live state of the single tcsh process. The evaluate console executes
537
+ text directly in the paused shell. It can inspect *and mutate* state
538
+ (`set name = value` takes effect immediately), and a syntax error in
539
+ evaluated text can terminate the debuggee; there is no isolation.
378
540
 
379
541
  ## Layout
380
542
 
@@ -519,8 +681,10 @@ Breakpoints persist across session restarts.
519
681
 
520
682
  ### Variable Inspection
521
683
 
522
- The Variable View shows a tree of scopes (Locals, Globals) with all variables in the current
523
- frame. Expand nodes to drill into complex objects. Children are loaded lazily on demand.
684
+ The Variable View shows a tree of scopes with all variables in the current frame. The scopes
685
+ themselves are language-dependent: Locals, Globals, plus Environment for bash; Lexicals,
686
+ Globals, Specials for Perl (see the [Bash](#bash) and [Perl](#perl) sections above for
687
+ details). Expand nodes to drill into complex objects. Children are loaded lazily on demand.
524
688
  Variable values can be changed in the Evaluate Console.
525
689
 
526
690
  Double-click a variable, or highlight the variable with the text cursor in
@@ -969,23 +1133,23 @@ Each is JSON with `event`, `data`, and `timestamp` fields.
969
1133
  ## Recording and replaying sessions
970
1134
 
971
1135
  `tdb --record session.jsonl prog.py` runs a normal TUI session and captures
972
- your debugging actions — breakpoints (including `-k`/`-t` and persisted
1136
+ your debugging actions including breakpoints (including `-k`/`-t` and persisted
973
1137
  ones), stepping, continue/pause, Evaluate-console entries, stack-frame
974
- navigation, variable expansion, restart, quit — to `session.jsonl` as
1138
+ navigation, variable expansion, restart, quit. The session is
1139
+ written to `session.jsonl` as
975
1140
  JSON-RPC commands. Works with launch mode (any language) and `-r`
976
1141
  remote attach.
977
1142
 
978
1143
  Replay it two ways:
979
1144
 
980
- - `tdb --replay session.jsonl` — one command: launches the recorded
1145
+ - `tdb --replay session.jsonl` launches the recorded
981
1146
  program headless, feeds every recorded command through the same RPC
982
1147
  dispatch `tdb --server` uses, and prints a transcript (recorded time,
983
1148
  command, verbatim result, interleaved program output). Exit code 0 iff
984
1149
  every command succeeded. Add `--timing` to reproduce the original
985
1150
  pacing, `--replay-timeout S` to bound each stop-wait (default 30 s).
986
1151
  - Against a live server: start `tdb --server prog.py`, then feed line 2
987
- onward of the file to `POST /rpc` — each line is already a valid
988
- request body:
1152
+ onward of the file to `POST /rpc` . Each line is a valid request body:
989
1153
 
990
1154
  tail -n +2 session.jsonl | while read line; do
991
1155
  curl -s -X POST -H 'Content-Type: application/json' \
@@ -1039,7 +1203,7 @@ client expects to launch servers.
1039
1203
  | Cluster | Tools |
1040
1204
  |---------|-------|
1041
1205
  | Lifecycle | `debug_launch`, `debug_attach`, `quit` |
1042
- | Control | `control(action, timeout_s=30)` — `action ∈ {continue, next, step_in, step_out, pause, wait_for_stop}` |
1206
+ | Control | `control(action, timeout_s=30)` where `action ∈ {continue, next, step_in, step_out, pause, wait_for_stop}` |
1043
1207
  | Inspection | `inspect(expressions)`, `read_source(file_path)`, `stack_trace()`, `status()`, `get_output()` |
1044
1208
  | Breakpoints | `set_breakpoint(spec, condition?, hit_condition?)`, `remove_breakpoint(spec)`, `list_breakpoints()` |
1045
1209
  | Differentiators | `threads(thread_id?)`, `tasks(task_name?)`, `processes(name_or_pid?)`, `wait_graph()` |
@@ -1109,7 +1273,7 @@ usage: tdb [-h] [-v] [-r [HOST:]PORT] [--cwd CWD] [--no-stop-on-entry]
1109
1273
  | `--local-root PATH` | Local directory containing a copy of remote code (repeat to mirror multiple trees). Pair with `--remote-root`; counts must match. Required when `-k` sets a breakpoint against a remote debuggee whose code lives at a different path. |
1110
1274
  | `--remote-root PATH` | Remote directory matched to `--local-root` (same CLI position via `zip()`). |
1111
1275
  | `-k`, `--breakpoint FILE:LINE|LINE` | Set a breakpoint (may be repeated). Passing `-k` implies `--no-stop-on-entry` so the program runs straight to the first breakpoint. |
1112
- | `-t`, `--to-line FILE:LINE|LINE` | Like `-k`, but the breakpoint is not saved to the breakpoints file — it just takes you to that spot in the code for this session (may be repeated). |
1276
+ | `-t`, `--to-line FILE:LINE|LINE` | Like `-k`, but the breakpoint is not saved to the breakpoints file, it just takes you to that spot in the code for this session (may be repeated). |
1113
1277
  | `--no-stop-on-entry` | Do not pause at the first line (default: stop on entry; automatic when `-k` is given) |
1114
1278
  | `--cwd DIR` | Working directory for the debuggee |
1115
1279
  | `--python PATH` | Python interpreter for the debuggee (Python targets only) |
@@ -1144,7 +1308,7 @@ executable path (`{"adapters": {"lldb-dap": "/opt/llvm/bin/lldb-dap"}}`), and
1144
1308
  (`{"default_adapters": {"cpp": "lldb-dap"}}`).
1145
1309
 
1146
1310
  **Perl is a special case:** `perl-tdb` is tdb's own bundled adapter (always
1147
- found — it's Python code, not an external executable), so
1311
+ found; it's Python code, not an external executable), so
1148
1312
  `adapters.perl` doesn't select an adapter binary. Instead it names the
1149
1313
  *Perl interpreter* tdb should spawn to run the debuggee:
1150
1314
  `{"adapters": {"perl": "/path/to/perl"}}`. Use this when the `perl` on