textual-debugger 0.1.5__tar.gz → 0.2.2__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.
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/PKG-INFO +260 -22
- {textual_debugger-0.1.5/src/tdb → textual_debugger-0.2.2}/README.md +258 -20
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/pyproject.toml +2 -2
- {textual_debugger-0.1.5 → textual_debugger-0.2.2/src/tdb}/README.md +258 -20
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/__init__.py +1 -1
- textual_debugger-0.2.2/src/tdb/adapters/perl/Devel/TdbRemote.pm +93 -0
- textual_debugger-0.2.2/src/tdb/adapters/perl/__main__.py +23 -0
- textual_debugger-0.2.2/src/tdb/adapters/perl/helpers.pl +384 -0
- textual_debugger-0.2.2/src/tdb/adapters/perl/protocol.py +110 -0
- textual_debugger-0.2.2/src/tdb/adapters/perl/refs.py +34 -0
- textual_debugger-0.2.2/src/tdb/adapters/perl/server.py +593 -0
- textual_debugger-0.2.2/src/tdb/adapters/perl/session.py +247 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/app.py +231 -27
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/app_handlers/dap_events.py +2 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/app_handlers/inspection.py +56 -8
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/cli.py +216 -57
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/dap/client.py +45 -75
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/dap/messages.py +20 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/dap/types.py +3 -0
- textual_debugger-0.2.2/src/tdb/languages/__init__.py +21 -0
- textual_debugger-0.2.2/src/tdb/languages/base.py +144 -0
- textual_debugger-0.2.2/src/tdb/languages/cpp.py +150 -0
- textual_debugger-0.2.2/src/tdb/languages/perl.py +98 -0
- textual_debugger-0.2.2/src/tdb/languages/python.py +116 -0
- textual_debugger-0.2.2/src/tdb/languages/registry.py +119 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/mcp/server.py +12 -2
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/mcp/session.py +51 -10
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/persist.py +27 -11
- textual_debugger-0.2.2/src/tdb/replay.py +202 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/server/handlers.py +23 -5
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/server/runner.py +76 -27
- textual_debugger-0.2.2/src/tdb/session/__init__.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/session/child_processes.py +7 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/session/controller.py +75 -20
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/session/inspect_service.py +14 -2
- textual_debugger-0.2.2/src/tdb/session/recorder.py +106 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/session/state.py +15 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/session/statement_stepper.py +16 -3
- textual_debugger-0.2.2/src/tdb/widgets/__init__.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/widgets/code_view.py +94 -54
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/textual_debugger.egg-info/PKG-INFO +260 -22
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/textual_debugger.egg-info/SOURCES.txt +17 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/textual_debugger.egg-info/requires.txt +1 -1
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/LICENSE +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/setup.cfg +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/__main__.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/_timeouts.py +0 -0
- {textual_debugger-0.1.5/src/tdb/dap → textual_debugger-0.2.2/src/tdb/adapters}/__init__.py +0 -0
- {textual_debugger-0.1.5/src/tdb/server → textual_debugger-0.2.2/src/tdb/adapters/perl}/__init__.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/app_handlers/__init__.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/app_handlers/routing.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/app_handlers/ui_panels.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/app_helpers.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/breakpoint_hook.py +0 -0
- {textual_debugger-0.1.5/src/tdb/session → textual_debugger-0.2.2/src/tdb/dap}/__init__.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/dap/protocol.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/inspection.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/inspection_full.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/keybindings/__init__.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/mcp/__init__.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/mcp/__main__.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/post_mortem.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/processes_cache.py +0 -0
- {textual_debugger-0.1.5/src/tdb/widgets → textual_debugger-0.2.2/src/tdb/server}/__init__.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/server/app.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/server/event_handler.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/server/rpc_types.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/session/event_bus.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/session/messages.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/session/post_mortem_loader.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/session/terminal.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/session/textual_handler.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/source_analysis.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/widgets/_inspection_modal.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/widgets/async_tasks_modal.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/widgets/breakpoint_view.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/widgets/console_view.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/widgets/evaluate_console.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/widgets/full_contents_modal.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/widgets/menu_bar.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/widgets/modals.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/widgets/processes_modal.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/widgets/stack_view.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/widgets/status_bar.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/widgets/threads_modal.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/tdb/widgets/variable_view.py +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/textual_debugger.egg-info/dependency_links.txt +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/textual_debugger.egg-info/entry_points.txt +0 -0
- {textual_debugger-0.1.5 → textual_debugger-0.2.2}/src/textual_debugger.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: textual-debugger
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: A TUI Python debugger based on textual and debugpy
|
|
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:
|
|
@@ -51,7 +51,7 @@ Requires-Dist: debugpy>=1.8.0
|
|
|
51
51
|
Requires-Dist: pygments>=2.17.0
|
|
52
52
|
Requires-Dist: fastapi>=0.115.0
|
|
53
53
|
Requires-Dist: uvicorn>=0.30.0
|
|
54
|
-
Requires-Dist: mcp
|
|
54
|
+
Requires-Dist: mcp<2.0.0,>=1.28.0
|
|
55
55
|
Provides-Extra: dev
|
|
56
56
|
Requires-Dist: pytest; extra == "dev"
|
|
57
57
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
@@ -67,12 +67,18 @@ Dynamic: license-file
|
|
|
67
67
|
# `textual-debugger`
|
|
68
68
|
|
|
69
69
|
`textual-debugger` (the package) provides `tdb` (the command-line tool and module),
|
|
70
|
-
a full-featured terminal-based Python
|
|
71
|
-
|
|
72
|
-
`
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
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
|
+
|
|
74
|
+
`tdb` is built with [textual](https://github.com/Textualize/textual) and speaks
|
|
75
|
+
DAP to a pluggable debug adapter: [debugpy](https://github.com/microsoft/debugpy)
|
|
76
|
+
(the engine behind VS Code's Python debugger) for Python,
|
|
77
|
+
[GDB's DAP mode](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Debugger-Adapter-Protocol.html) or
|
|
78
|
+
[lldb-dap](https://lldb.llvm.org/resources/lldbdap.html)
|
|
79
|
+
for compiled code. It provides a rich interactive interface for stepping through
|
|
80
|
+
code, inspecting variables, managing breakpoints, and evaluating expressions in
|
|
81
|
+
complex programs.
|
|
76
82
|
|
|
77
83
|
- PyPI: https://pypi.org/project/textual-debugger/
|
|
78
84
|
- GitHub: https://github.com/AlDanial/tdb
|
|
@@ -83,6 +89,10 @@ MIT License. Copyright 2026 by Al Danial.
|
|
|
83
89
|
|
|
84
90
|
`tdb`:
|
|
85
91
|
|
|
92
|
+
- 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
|
|
94
|
+
auto-detected from the target (ref. [Multi-Language Debugging](#multi-language-debugging)).
|
|
95
|
+
|
|
86
96
|
- supports debugging of synchronous, asynchronous, multi-threaded, and multi-process Python code.
|
|
87
97
|
It specifically supports modules
|
|
88
98
|
- `asyncio` (with a built-in async task inspector and task wait graph)
|
|
@@ -169,11 +179,25 @@ tdb my_program.py
|
|
|
169
179
|
# debug with arguments
|
|
170
180
|
tdb my_program.py arg1 arg2
|
|
171
181
|
|
|
182
|
+
# debug a C/C++ (or other native) executable built with -g. The ELF/Mach-O/PE
|
|
183
|
+
# binary is auto-detected and debugged through GDB's DAP mode (GDB >= 14)
|
|
184
|
+
tdb ./myprog arg1 arg2
|
|
185
|
+
|
|
186
|
+
# same, but using lldb-dap (LLVM >= 17) instead of gdb
|
|
187
|
+
tdb --adapter lldb-dap ./myprog
|
|
188
|
+
|
|
189
|
+
# force the language when auto-detection can't tell (e.g. an extensionless script)
|
|
190
|
+
tdb --lang python ./mytool
|
|
191
|
+
|
|
172
192
|
# add breakpoints at lines 20 and 35 of `my_program.py` and line 14
|
|
173
193
|
# of `module.py` (when -k is given, --no-stop-on-entry is set and the
|
|
174
194
|
# program runs to the first breakpoint)
|
|
175
195
|
tdb -k 20 -k 35 -k module.py:14 my_program.py arg1 arg2
|
|
176
196
|
|
|
197
|
+
# run straight to line 20 without saving the breakpoint for future
|
|
198
|
+
# sessions (-t is -k minus the persistence)
|
|
199
|
+
tdb -t 20 my_program.py
|
|
200
|
+
|
|
177
201
|
# use a specific virtualenv
|
|
178
202
|
tdb --python /path/to/venv/bin/python my_program.py
|
|
179
203
|
|
|
@@ -210,6 +234,148 @@ Alternatively, use the module entry point:
|
|
|
210
234
|
python -m tdb my_program.py
|
|
211
235
|
```
|
|
212
236
|
|
|
237
|
+
## Multi-Language Debugging
|
|
238
|
+
|
|
239
|
+
`tdb` debugs any language that has a Debug Adapter Protocol backend. Two
|
|
240
|
+
languages are supported out of the box:
|
|
241
|
+
|
|
242
|
+
| Language | Adapter(s) | How to get the adapter | Feature level |
|
|
243
|
+
|----------|------------|------------------------|---------------|
|
|
244
|
+
| Python | `debugpy` (default) | installed with `textual-debugger` | everything in this README |
|
|
245
|
+
| 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 |
|
|
247
|
+
|
|
248
|
+
### Language detection and selection
|
|
249
|
+
|
|
250
|
+
The language is auto-detected from the debug target:
|
|
251
|
+
|
|
252
|
+
1. File extension: `.py` → Python; `.pl` / `.pm` / `.t` → Perl.
|
|
253
|
+
2. Native executables (ELF, Mach-O, PE magic bytes) → C/C++.
|
|
254
|
+
3. A `#!...python` or `#!...perl` shebang → Python / Perl respectively.
|
|
255
|
+
4. C/C++/Rust *source* files (`.c`, `.cpp`, `.rs`, …) produce an error with a
|
|
256
|
+
hint: compile with debug info (`g++ -g -O0`) and debug the binary.
|
|
257
|
+
5. Anything else produces an error naming the `--lang` override.
|
|
258
|
+
|
|
259
|
+
`--lang` forces the language; `--adapter` picks a non-default adapter within
|
|
260
|
+
it (`tdb --lang cpp --adapter lldb-dap ./myprog`).
|
|
261
|
+
|
|
262
|
+
> **Migration note:** extensionless Python scripts without a `python` shebang
|
|
263
|
+
> were previously assumed to be Python; they now require `--lang python`.
|
|
264
|
+
|
|
265
|
+
### Adapters are found on `PATH`
|
|
266
|
+
|
|
267
|
+
`tdb` does not download or bundle adapters. If the adapter executable isn't
|
|
268
|
+
found, the error names the package to install. To use an adapter from a
|
|
269
|
+
non-standard location, or change a language's default adapter, add to
|
|
270
|
+
`config.json` (see [Configuration](#configuration)):
|
|
271
|
+
|
|
272
|
+
```json
|
|
273
|
+
{
|
|
274
|
+
"adapters": {"lldb-dap": "/opt/llvm/bin/lldb-dap"},
|
|
275
|
+
"default_adapters": {"cpp": "lldb-dap"}
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### What works for non-Python languages
|
|
280
|
+
|
|
281
|
+
Core debugging works identically for every language: breakpoints (incl.
|
|
282
|
+
conditions and persistence), stepping, continue/pause, run-to-cursor, stack
|
|
283
|
+
navigation, variable inspection, the evaluate console, syntax highlighting,
|
|
284
|
+
and the JSON-RPC / MCP programmatic modes.
|
|
285
|
+
|
|
286
|
+
Python-specific features are hidden or return a clear "not supported for this
|
|
287
|
+
language" message when debugging other languages: statement-granularity
|
|
288
|
+
stepping (non-Python languages always step per line), the async task /
|
|
289
|
+
process inspectors and wait graph, the evaluate console's trailing-`?` help,
|
|
290
|
+
`--python`/`--pv`, `--no-subprocess`, automatic child-process attachment, and
|
|
291
|
+
the post-mortem / `tdb.breakpoint()` hooks (those hooks live inside Python
|
|
292
|
+
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
|
|
295
|
+
currently ignored for non-Python targets.
|
|
296
|
+
|
|
297
|
+
### C/C++ tips
|
|
298
|
+
|
|
299
|
+
- Compile with `-g` (ideally `-g -O0`). If no breakpoint in a file can be
|
|
300
|
+
bound, `tdb` prints a console warning suggesting the program may lack
|
|
301
|
+
debug info.
|
|
302
|
+
- Stack frames pointing into system libraries often have no source on disk;
|
|
303
|
+
the Code View shows a `<Could not read …>` placeholder while the stack,
|
|
304
|
+
variables, and evaluate console remain fully usable.
|
|
305
|
+
- GDB (the default adapter) has the most complete libstdc++
|
|
306
|
+
pretty-printing. `lldb-dap` (via `--adapter lldb-dap`) also debugs
|
|
307
|
+
GCC-built binaries fine — DWARF is compiler-neutral.
|
|
308
|
+
- **GDB evaluate-console quirk:** GDB's DAP treats REPL input as CLI
|
|
309
|
+
commands, so evaluate expressions with an explicit `print`, e.g.
|
|
310
|
+
`print x` rather than bare `x` (bare `x` collides with GDB's
|
|
311
|
+
examine-memory command). `lldb-dap` evaluates bare expressions directly.
|
|
312
|
+
|
|
313
|
+
### Perl
|
|
314
|
+
|
|
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
|
|
317
|
+
hood, so it works with any Perl already on the system.
|
|
318
|
+
|
|
319
|
+
**Launching a script:**
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
tdb script.pl
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
**Remote attach:** useful when the Perl process is already running (a long-
|
|
326
|
+
lived service, a process started by something other than `tdb`) or lives on
|
|
327
|
+
another host/container. Add three lines to the target program, with the
|
|
328
|
+
`use` line first so the debugger is armed before any of your code compiles:
|
|
329
|
+
|
|
330
|
+
```perl
|
|
331
|
+
use Devel::TdbRemote; # FIRST line of your program
|
|
332
|
+
...
|
|
333
|
+
Devel::TdbRemote::listen(5678); # non-blocking
|
|
334
|
+
Devel::TdbRemote::wait_for_client(); # blocks until tdb connects
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Then attach from `tdb`, forcing the language since there's no local `program`
|
|
338
|
+
argument for `tdb` to detect it from:
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
tdb --lang perl -r host:5678
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
**Arming caveat:** only code *compiled after* the debugger is armed can be
|
|
345
|
+
stepped into or breakpointed. That's why `use Devel::TdbRemote;` must be the
|
|
346
|
+
first line of the program. If you can't edit the first line (e.g. a wrapper
|
|
347
|
+
script controls startup), arm it before Perl even parses your file instead:
|
|
348
|
+
`perl -d:TdbRemote prog.pl`, or set `PERL5OPT=-d:TdbRemote` in the
|
|
349
|
+
environment that launches the debuggee.
|
|
350
|
+
|
|
351
|
+
**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:
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
# From a checkout or an installed wheel's site-packages/tdb/adapters/perl:
|
|
357
|
+
scp -r Devel/TdbRemote.pm helpers.pl remote-host:/opt/tdb-perl/
|
|
358
|
+
# On the remote host:
|
|
359
|
+
export PERL5LIB=/opt/tdb-perl:$PERL5LIB
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
(`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
|
|
364
|
+
sibling of the `Devel/` directory, not inside it.)
|
|
365
|
+
|
|
366
|
+
**PadWalker (optional but recommended):** inspecting lexical (`my`)
|
|
367
|
+
variables in the *current* frame always works. Lexicals in outer/caller
|
|
368
|
+
frames need the `PadWalker` module installed on the debuggee's Perl; without
|
|
369
|
+
it, tdb falls back to a read-only pad walk that can't reach fully into
|
|
370
|
+
enclosing scopes, and outer-frame variable listings degrade accordingly.
|
|
371
|
+
Install with `cpanm PadWalker` (or your distro's package) for full fidelity.
|
|
372
|
+
|
|
373
|
+
**Pause is unavailable in attach mode.** Launch-mode sessions (`tdb
|
|
374
|
+
script.pl`) support pausing a running program at any time. Remote-attach
|
|
375
|
+
sessions don't — debugpy-style asynchronous pause needs a control channel
|
|
376
|
+
`Devel::TdbRemote` doesn't implement yet; `pause` in attach mode returns a
|
|
377
|
+
clear "not available" error instead of hanging.
|
|
378
|
+
|
|
213
379
|
## Layout
|
|
214
380
|
|
|
215
381
|
```
|
|
@@ -238,7 +404,7 @@ The footer shows the most relevant keybindings for the current mode.
|
|
|
238
404
|
### Navigation and Keybindings
|
|
239
405
|
|
|
240
406
|
|
|
241
|
-
The Code View shows syntax-highlighted
|
|
407
|
+
The Code View shows syntax-highlighted source (lexer chosen per language) with line numbers.
|
|
242
408
|
A cursor line (blue) tracks your position; the current execution line is highlighted in gold.
|
|
243
409
|
|
|
244
410
|
**View focus shortcuts (global):**
|
|
@@ -330,6 +496,9 @@ lands on `print(results)`, not on each interior sub-line of the `gather` call. S
|
|
|
330
496
|
stops on each physical line--useful for inspecting how a complex expression is built up.
|
|
331
497
|
The choice is saved to `~/.config/tdb/config.json`.
|
|
332
498
|
|
|
499
|
+
Statement mode requires a source-language model and is currently Python-only;
|
|
500
|
+
other languages always step per line (the Step Mode menu says so if you try).
|
|
501
|
+
|
|
333
502
|
### Breakpoints
|
|
334
503
|
|
|
335
504
|
Click the gutter in the Code View to toggle a breakpoint, or press `b` in Debug mode.
|
|
@@ -387,6 +556,15 @@ interactive evaluation of expressions in the current scope:
|
|
|
387
556
|
|
|
388
557
|
Variable values set here are reflected in the running code.
|
|
389
558
|
|
|
559
|
+
### Cut / Paste
|
|
560
|
+
|
|
561
|
+
Expression for the Evaluate Console are often copied from the Code View.
|
|
562
|
+
Doing this in `tdb` differs from traditional terminal behavior, because `textual` applications
|
|
563
|
+
capture mouse events for their own use.
|
|
564
|
+
|
|
565
|
+
Instead, hold the `Shift` key while performing your conventional cut/paste keystrokes or mouse
|
|
566
|
+
operation to get the expected behavior.
|
|
567
|
+
|
|
390
568
|
### Console Output
|
|
391
569
|
|
|
392
570
|
The Console View captures stdout (normal text) and stderr (red text) from the debuggee
|
|
@@ -754,7 +932,7 @@ curl -s -X POST http://127.0.0.1:8150/rpc \
|
|
|
754
932
|
| `set_breakpoint` | `["file:line"]` or `["file:line", "condition", "hit_condition"]` | Set a breakpoint |
|
|
755
933
|
| `remove_breakpoint` | `["file:line"]` | Remove a breakpoint |
|
|
756
934
|
| `list_breakpoints` | `[]` | Show all breakpoints |
|
|
757
|
-
| `continue` | `[]` or `[timeout_s]` | Resume execution; on timeout returns `"still running
|
|
935
|
+
| `continue` | `[]` or `[timeout_s]` | Resume execution; on timeout returns `"still running--call pause or wait again"` (success) |
|
|
758
936
|
| `next` | `[]` or `[timeout_s]` | Step over |
|
|
759
937
|
| `step_in` | `[]` or `[timeout_s]` | Step into |
|
|
760
938
|
| `step_out` | `[]` or `[timeout_s]` | Step out |
|
|
@@ -788,12 +966,46 @@ curl -N http://127.0.0.1:8150/events
|
|
|
788
966
|
Events: `initialized`, `stopped`, `continued`, `terminated`, `exited`, `output`.
|
|
789
967
|
Each is JSON with `event`, `data`, and `timestamp` fields.
|
|
790
968
|
|
|
969
|
+
## Recording and replaying sessions
|
|
970
|
+
|
|
971
|
+
`tdb --record session.jsonl prog.py` runs a normal TUI session and captures
|
|
972
|
+
your debugging actions — breakpoints (including `-k`/`-t` and persisted
|
|
973
|
+
ones), stepping, continue/pause, Evaluate-console entries, stack-frame
|
|
974
|
+
navigation, variable expansion, restart, quit — to `session.jsonl` as
|
|
975
|
+
JSON-RPC commands. Works with launch mode (any language) and `-r`
|
|
976
|
+
remote attach.
|
|
977
|
+
|
|
978
|
+
Replay it two ways:
|
|
979
|
+
|
|
980
|
+
- `tdb --replay session.jsonl` — one command: launches the recorded
|
|
981
|
+
program headless, feeds every recorded command through the same RPC
|
|
982
|
+
dispatch `tdb --server` uses, and prints a transcript (recorded time,
|
|
983
|
+
command, verbatim result, interleaved program output). Exit code 0 iff
|
|
984
|
+
every command succeeded. Add `--timing` to reproduce the original
|
|
985
|
+
pacing, `--replay-timeout S` to bound each stop-wait (default 30 s).
|
|
986
|
+
- 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:
|
|
989
|
+
|
|
990
|
+
tail -n +2 session.jsonl | while read line; do
|
|
991
|
+
curl -s -X POST -H 'Content-Type: application/json' \
|
|
992
|
+
-d "$line" http://127.0.0.1:8150/rpc
|
|
993
|
+
done
|
|
994
|
+
|
|
995
|
+
(On Windows, an equivalent loop in Python: read the file, skip the
|
|
996
|
+
first line, `requests.post` each remaining line.)
|
|
997
|
+
|
|
998
|
+
Not captured: pure viewing (scrolling, search, modals, thread/task
|
|
999
|
+
lists), breakpoint enable/disable toggles, variable expansions when the
|
|
1000
|
+
adapter reports no `evaluateName` (currently the Perl adapter), and
|
|
1001
|
+
File > Open program switches.
|
|
1002
|
+
|
|
791
1003
|
## MCP Integration
|
|
792
1004
|
|
|
793
1005
|
tdb ships a Model Context Protocol (MCP) server (`tdb-mcp`) that exposes
|
|
794
1006
|
the debugger as a curated set of tools an AI agent can call. The MCP
|
|
795
1007
|
server is a third in-process consumer of the same dispatch handlers the
|
|
796
|
-
TUI and the HTTP server use
|
|
1008
|
+
TUI and the HTTP server use so an agent gets the same lock semantics,
|
|
797
1009
|
including the pause-during-continue bypass, and the same DAP-backed
|
|
798
1010
|
inspection surface.
|
|
799
1011
|
|
|
@@ -832,17 +1044,24 @@ client expects to launch servers.
|
|
|
832
1044
|
| Breakpoints | `set_breakpoint(spec, condition?, hit_condition?)`, `remove_breakpoint(spec)`, `list_breakpoints()` |
|
|
833
1045
|
| Differentiators | `threads(thread_id?)`, `tasks(task_name?)`, `processes(name_or_pid?)`, `wait_graph()` |
|
|
834
1046
|
|
|
835
|
-
`control` is intentionally one tool that takes an action enum
|
|
1047
|
+
`control` is intentionally one tool that takes an action enum. The six
|
|
836
1048
|
underlying RPC actions share a return shape, and agents perform
|
|
837
1049
|
measurably better with a small surface than with one tool per action.
|
|
838
1050
|
`threads` / `tasks` / `processes` overload list-vs-inspect via a
|
|
839
1051
|
single optional argument for the same reason.
|
|
840
1052
|
|
|
1053
|
+
`debug_launch` accepts optional `lang` and `adapter` parameters mirroring the
|
|
1054
|
+
CLI's `--lang`/`--adapter`; when omitted, the language is auto-detected from
|
|
1055
|
+
`program`, so an agent can hand it a compiled binary directly. The
|
|
1056
|
+
`tasks`/`processes`/`wait_graph` tools stay registered for every language but
|
|
1057
|
+
return a structured "not supported when debugging C/C++"-style error for
|
|
1058
|
+
non-Python debuggees.
|
|
1059
|
+
|
|
841
1060
|
### Agent flow for a long-running step
|
|
842
1061
|
|
|
843
1062
|
```
|
|
844
1063
|
agent → control(action="continue", timeout_s=30)
|
|
845
|
-
mcp → "still running
|
|
1064
|
+
mcp → "still running, call pause or wait again"
|
|
846
1065
|
agent → control(action="pause") # OR: control(action="wait_for_stop", timeout_s=30)
|
|
847
1066
|
mcp → "<file>:<line>"
|
|
848
1067
|
agent → inspect(["x", "len(buf)"])
|
|
@@ -851,7 +1070,7 @@ mcp → "x = 7\nlen(buf) = 1024"
|
|
|
851
1070
|
|
|
852
1071
|
`pause` bypasses the dispatch lock so it can interrupt a `continue`
|
|
853
1072
|
that's still mid-flight (HTTP and MCP share the same `NO_LOCK_ACTIONS`
|
|
854
|
-
policy
|
|
1073
|
+
policy; see `tdb/server/app.py`).
|
|
855
1074
|
|
|
856
1075
|
### Security caveat
|
|
857
1076
|
|
|
@@ -860,22 +1079,23 @@ execution in the debuggee process**. This is inherent to a debugger and
|
|
|
860
1079
|
not a tdb-specific concern, but MCP clients (and the humans running
|
|
861
1080
|
them) should apply appropriate permission models: don't auto-approve
|
|
862
1081
|
`inspect` against untrusted expressions, and don't expose `tdb-mcp` on
|
|
863
|
-
a network
|
|
1082
|
+
a network (stdio transport only by design).
|
|
864
1083
|
|
|
865
1084
|
### Deferred / out of scope (v1)
|
|
866
1085
|
|
|
867
|
-
- SSE-style event push
|
|
1086
|
+
- SSE-style event push: `control` and `wait_for_stop` make polling
|
|
868
1087
|
efficient enough; events would also need uneven MCP-client support.
|
|
869
|
-
- HTTP / streamable-HTTP transports
|
|
1088
|
+
- HTTP / streamable-HTTP transports: would require auth (which the
|
|
870
1089
|
HTTP RPC server also currently lacks); stdio inherits the trust of
|
|
871
1090
|
the process that spawned it.
|
|
872
|
-
- Multi-session
|
|
1091
|
+
- Multi-session: one debug session per MCP process.
|
|
873
1092
|
|
|
874
1093
|
## CLI Reference
|
|
875
1094
|
|
|
876
1095
|
```
|
|
877
1096
|
usage: tdb [-h] [-v] [-r [HOST:]PORT] [--cwd CWD] [--no-stop-on-entry]
|
|
878
1097
|
[--no-just-my-code] [--no-subprocess] [--python PYTHON] [--pv]
|
|
1098
|
+
[--lang LANGUAGE] [--adapter ADAPTER]
|
|
879
1099
|
[--keybindings {default,vim,emacs}]
|
|
880
1100
|
[--terminal {xterm,konsole,gnome-terminal,ghostty,kitty,iterm2,warp,wezterm,terminator}]
|
|
881
1101
|
[--local-root PATH] [--remote-root PATH]
|
|
@@ -889,10 +1109,13 @@ usage: tdb [-h] [-v] [-r [HOST:]PORT] [--cwd CWD] [--no-stop-on-entry]
|
|
|
889
1109
|
| `--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. |
|
|
890
1110
|
| `--remote-root PATH` | Remote directory matched to `--local-root` (same CLI position via `zip()`). |
|
|
891
1111
|
| `-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). |
|
|
892
1113
|
| `--no-stop-on-entry` | Do not pause at the first line (default: stop on entry; automatic when `-k` is given) |
|
|
893
1114
|
| `--cwd DIR` | Working directory for the debuggee |
|
|
894
|
-
| `--python PATH` | Python interpreter for the debuggee |
|
|
1115
|
+
| `--python PATH` | Python interpreter for the debuggee (Python targets only) |
|
|
895
1116
|
| `--pv` | Shorthand for --python .venv/bin/python |
|
|
1117
|
+
| `--lang LANGUAGE` | Debuggee language (`python`, `cpp`, `perl`); default: auto-detect from the target |
|
|
1118
|
+
| `--adapter ADAPTER` | Debug adapter within the language (e.g. `--lang cpp --adapter lldb-dap`); default: the language's standard adapter |
|
|
896
1119
|
| `--no-just-my-code` | Step into stdlib/site-packages code instead of skipping it
|
|
897
1120
|
(default: skipped). On uncaught exceptions, the crash modal always shows the full traceback
|
|
898
1121
|
including library frames, regardless of this flag. |
|
|
@@ -912,11 +1135,25 @@ On Windows, it uses `%APPDATA%\tdb\`.
|
|
|
912
1135
|
|
|
913
1136
|
| File | Contents |
|
|
914
1137
|
|------|----------|
|
|
915
|
-
| `config.json` | User preferences (keybinding scheme, color theme, step mode) |
|
|
1138
|
+
| `config.json` | User preferences (keybinding scheme, color theme, step mode, adapter overrides) |
|
|
916
1139
|
| `breakpoints.json` | Breakpoints from previous sessions, keyed by project directory |
|
|
917
1140
|
|
|
1141
|
+
Adapter-related keys in `config.json`: `adapters` maps an adapter id to an
|
|
1142
|
+
executable path (`{"adapters": {"lldb-dap": "/opt/llvm/bin/lldb-dap"}}`), and
|
|
1143
|
+
`default_adapters` picks a language's default adapter
|
|
1144
|
+
(`{"default_adapters": {"cpp": "lldb-dap"}}`).
|
|
1145
|
+
|
|
1146
|
+
**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
|
|
1148
|
+
`adapters.perl` doesn't select an adapter binary. Instead it names the
|
|
1149
|
+
*Perl interpreter* tdb should spawn to run the debuggee:
|
|
1150
|
+
`{"adapters": {"perl": "/path/to/perl"}}`. Use this when the `perl` on
|
|
1151
|
+
`PATH` is too old (< 5.18) or you need a specific `perlbrew`/`plenv` version.
|
|
1152
|
+
|
|
918
1153
|
Breakpoints are saved on exit and restored when debugging a program in the same
|
|
919
|
-
directory. Each project's breakpoints are independent.
|
|
1154
|
+
directory. Each project's breakpoints are independent. Breakpoints set with
|
|
1155
|
+
`-t`/`--to-line` are the exception: they behave like `-k` breakpoints during
|
|
1156
|
+
the session but are never saved.
|
|
920
1157
|
|
|
921
1158
|
**Step mode** (`step_mode` in `config.json`) controls how `n` (step over) and `s` (step
|
|
922
1159
|
into) handle multi-line source statements:
|
|
@@ -934,7 +1171,8 @@ fires as expected.
|
|
|
934
1171
|
## Tech Stack
|
|
935
1172
|
|
|
936
1173
|
- [textual](https://github.com/Textualize/textual) : TUI framework
|
|
937
|
-
- [debugpy](https://github.com/microsoft/debugpy) : Debug Adapter Protocol implementation
|
|
1174
|
+
- [debugpy](https://github.com/microsoft/debugpy) : Debug Adapter Protocol implementation for Python
|
|
1175
|
+
- [gdb](https://sourceware.org/gdb/) / [lldb-dap](https://lldb.llvm.org/resources/lldbdap.html) : optional, user-installed DAP adapters for C/C++
|
|
938
1176
|
- [pygments](https://pygments.org/) : Syntax highlighting
|
|
939
1177
|
- [FastAPI](https://fastapi.tiangolo.com/) + [uvicorn](https://www.uvicorn.org/) : JSON-RPC server
|
|
940
1178
|
|