1
1
Fork
You've already forked debugadapter
0
Debug Adapter Protocol implementation for R
  • R 100%
2025年11月21日 17:35:55 -05:00
.github chore: adding github readme 2025年02月16日 11:57:31 -05:00
.woodpecker add woodpecker ci 2025年02月16日 17:04:32 +00:00
inst/debugme adding usage instructions 2023年01月21日 12:43:47 -05:00
man clean up user-facing API 2024年07月20日 14:57:39 -04:00
R clean up user-facing API 2024年07月20日 14:57:39 -04:00
tests/fixtures/containers chore: update test container neovim config 2025年11月21日 17:35:55 -05:00
.Rbuildignore wip: initial refactor 2024年07月01日 12:55:03 -04:00
DESCRIPTION wip: improving debug prompt 2024年07月09日 00:37:04 -04:00
LICENSE.md wip: initial refactor 2024年07月01日 12:55:03 -04:00
NAMESPACE wip: support launch-mode 2024年07月12日 18:15:11 -04:00
NOTES.md initial commit 2022年08月27日 09:51:20 -07:00
README.md adding setup instructions for neovim 2024年07月01日 16:25:25 -04:00
SETUP.md chore: update test container neovim config 2025年11月21日 17:35:55 -05:00

debugadapter

developing

An implementation of the Debug Adapter Protocol for R

Status: Reincarnated! 🧟

It recently came to my attention that R received an experimentel feature in devel that would make this project much more realistic.

Current work focuses on this feature to test the viability for this purpose.

debugadapter operates in one of two ways:

  1. execute mode, where A file is used as a script for execution, in which case debugadapter will launch a new debug server, register breakpoints and provide a debug REPL within your client if it provides the capability and allow you to step through the script (not currently implemented).

  2. attach mode, where your client will attach to a running server, running as a background process to an interactive session.

    # start a server in the background
    debugadapter::run() 
    # execute some code which will hit a breakpoint and debug as usual
    my_code_to_debug()
    # debugging at my_nested_fn_call(...) #123
    # Browse[0]> 
    # ...
    

Getting Started

Follow the instructions below to launch your debug server, then follow the instructions for your client of choice.

1. Installation

pak::pkg_install("dgkf/debugadapter")

2. Starting the Server

Regardless of your client, running a server is always the same. In R, run:

debugadapter::run()

For testing or development, you may consider setting the option debugadapter.log to configure the log level. One of 1 (trace), 2 (debug) or 3 (info - default).

3. Set a Breakpoint

From your IDE's DAP client, set a breakpoint. See a list of client instructions below to configure your IDE.

Not that debugging breakpoints aren't recognized from the R session until after the next top-level command finishes (see #4 for details).

4. Debug!

🚧 Work-in-progress 🚧

Currently, nothing will happen. Communication about the current debugger state back to the client is in early development.

The intention is that debugging within the running R session relays information about the current state of the debugger back to your debug client so that the current scope and environment are communicated back to your client as you step through your code.

Likewise, using your IDE's debug controls to step through code progress debugging on the R session.

Clients

See SETUP.md for client-specific configuration details.

Architecture

Attaching an interactive R session relies on the coordination of multiple R processes:

  1. DAP Server
    A socket-based server used for communicating with the debug client. When run in the background, the debugger state is synchronized after each top-level task and before entering a REPL-based debugger.

  2. R Session
    The interactive R session serves as the parent to the DAP server and the browser() REPL, allowing for iterative debugging in a persistent R session.

  3. forked browser() process
    When browser() would be called, it is instead launched in a forked process, which allows the interactive R session to step through the debugger while also querying for various debugger context required by the debug client. Unfortunately, this means that this approach is currently not supported on Windows.

Debugging Loop

sequenceDiagram
participant ide as Client (IDE)
participant dap as DAP Server
participant r as REPL
alt Attach Mode
 r->>dap: debugadapter::run()
 Note over ide: Set breakpoint
 ide->>dap: attach DAP
 ide-->>dap: listen for updates
 alt REPL taskCallback
 r->>+dap: request sync debug state
 dap->>-r: reply sync debug state
 else browser() browser.hook
 r->>dap: send debug state
 dap->>ide: update client state
 r->>+dap: request sync debug state
 dap->>-r: reply sync debug state
 end
else Launch Mode
 Note over ide: Set breakpoint
 Note over ide: Debug
 ide->>dap: launch DAP
 ide-->>dap: listen for updates
 dap->>r: launch R in background
 ide->>+dap: send state
 dap->>+r: send updates
 r->>-dap: send state
 dap->>-ide: update client state
end

This is all orchestrated using a web of connections between each of the processes. The exact layout is in flux as the project matures.

Attach Mode

flowchart LR
repl[fa:fa-terminal R Session]
server[DAP Server]
client[DAP Client]
subgraph Attached R Session
 server <-->|<i>stdio</i>| repl
 subgraph bg[Background <br> Process]
 server
 end
end
subgraph IDE
 client
end
client <-->|<i>tcp</i>| server

Launch Mode

flowchart LR
repl[fa:fa-terminal R Session]
server[DAP Server]
client[DAP Client]
subgraph Launched R Session
 server <-->|<i>stdio</i>| repl
 subgraph bg[Subprocess]
 repl
 end
end
subgraph IDE
 client
end
client <-->|<i>tcp</i>| server

Prior Art

vscDebugger

An existing implementation that originated as a VSCode extension. While that package seems to work well in VSCode, it has been on a long path to being more editor agnostic. debugadapter deviates from the design choices of this package in two key ways:

  • A pure R package for simpler portability
  • Prioritzing a use case where an arbitrary terminal can be attached to the debug client and integrate with an interactive R session.