-
Notifications
You must be signed in to change notification settings - Fork 34
Home
You will find documentation and adapter installation details in the README.org.
Dape integrates with repeat-mode
by default but if hydra
is your preferred way the following might be useful:
(defun ccpp/post-init-hydra ()
(defhydra dape-hydra (:hint nil)
"
^Stepping^ ^Breakpoints^ ^Info
^^^^^^^^-----------------------------------------------------------
_n_: Next _bb_: Toggle (add/remove) _si_: Info
_i_/_o_: Step in/out _bd_: Delete _sm_: Memory
_<_/_>_: Stack up/down _bD_: Delete all _ss_: Select Stack
_c_: Continue _bl_: Set log message _R_: Repl
_r_: Restart
_d_: Init _k_: Kill _q_: Quit
"
("n" dape-next)
("i" dape-step-in)
("o" dape-step-out)
("<" dape-stack-select-down)
(">" dape-stack-select-up)
("c" dape-continue)
("r" dape-restart)
("ba" dape-breakpoint-toggle)
("bb" dape-breakpoint-toggle)
("be" dape-breakpoint-expression)
("bd" dape-breakpoint-remove-at-point)
("bD" dape-breakpoint-remove-all)
("bl" dape-breakpoint-log)
("si" dape-info)
("sm" dape-read-memory)
("ss" dape-select-stack)
("R" dape-repl)
("d" dape)
("k" dape-kill :color blue)
("q" dape-quit :color blue)))
Thanks to @vibrys for contributing.
On this page you will find useful dape configurations.
Feel free to add useful configurations!
NB: Once you have the configuration implemented as defined below, you can trigger dape from within the container within the context of a TRAMP connection. Use C-x C-f /docker:<container_name>:/path/to/project
to enter the container, then run M-x dape
.
Ensure your target ruby service is setup like so in your docker-compose.yml
:
rails-app:
image: rails-app:latest
command: rdbg --port 5678 -c -- rails server -b 0.0.0.0
environment:
- RUBY_DEBUG_OPEN=true
- RUBY_DEBUG_HOST=0.0.0.0
# Allows rails to initialise, only stopping when a breakpoint is hit
- RUBY_DEBUG_NONSTOP=true
# Needed to stop puma making workers which all attempt to open rdbg
# on the same port
- WEB_CONCURRENCY=0
ports:
- "5678:5678" # For remote debugging RAILS with debug.rb
Use the following dape-config to attach to the process:
(add-to-list 'dape-configs
`(rdbg-attach-local-source
prefix-local "~/code/ruby-app/"
prefix-remote "/usr/app/"
port 5678
:request "attach"
:localfs t))
In order to setup rspec-mode
correctly, it is necessary to run rdbg on a different port to the rails server instance. By using a custom wrapper function, we can add in the necessary environment variables, and spin up a fresh instance for the Rspec run:
(defun jjh/rspec--compose-default-wrapper (_compose compose-service command)
"Function for wrapping a command for execution inside a compose
environment. By adding the port manually here, we keep it out of the
rails service - keeping it free for just rspec. We also name it so
it's easy to find."
(format "docker-compose -f %s run -it --rm --name ruby-app-rspec -e 'RUBY_DEBUG_PORT=5680' -p 5680:5680 %s sh -c \"%s\""
rspec-docker-file-name compose-service command))
(setq rspec-docker-wrapper-fn #'jjh/rspec--compose-default-wrapper)
It’s important to set the debug gem to require: false
so we can control when the port is opened. Update the Gemfile:
gem "debug", require: false
In the spec_helper.rb
, require the debug
gem:
# For debugging
require "debug/open_nonstop"
You can then trigger the rspec tests with a custom dape-config entry:
(add-to-list 'dape-configs
`(rdbg-attach-rspec
prefix-local "~/code/app/"
prefix-remote "/usr/app/"
port 5680
:request "attach"
:localfs t))
Make sure that remote application imports and starts debugpy
.
import debugpy
# Port does not matter just needs to match port in config
# dape debugpy-remote-attach
debugpy.listen(("0.0.0.0", 5678))
(add-to-list 'dape-configs
`(debugpy-remote-attach
modes (python-mode python-ts-mode)
host (lambda () (read-string "Host: " "localhost"))
port (lambda () (read-number "Port: "))
:request "attach"
:type "python"
:pathMappings [(:localRoot (lambda ()
(read-directory-name "Local source directory: "
(funcall dape-cwd-fn)))
:remoteRoot (lambda ()
(read-string "Remote source directory: ")))]
:justMyCode nil
:showReturnValue t))
Thanks to @Gavinok for contributing.
Debug single test.
debugpy-module :module "pytest" :args ["test_file_relative_path_to_base_project::test_method_name"]
Contributed by @Peter-Chou
(add-to-list 'dape-configs
`(delve
modes (go-mode go-ts-mode)
ensure dape-ensure-command
fn (dape-config-autoport dape-config-tramp)
command "dlv"
command-insert-stderr t
command-args ("dap" "--listen" "127.0.0.1::autoport")
command-cwd (lambda()(if (string-suffix-p "_test.go" (buffer-name))
default-directory (dape-cwd)))
port :autoport
:type "debug"
:request "launch"
:mode (lambda() (if (string-suffix-p "_test.go" (buffer-name)) "test" "debug"))
:program "."
:cwd "."
:args (lambda()
(require 'which-func)
(if (string-suffix-p "_test.go" (buffer-name))
(when-let* ((test-name (which-function))
(test-regexp (concat "^" test-name "$")))
(if test-name `["-test.run" ,test-regexp]
(error "No test selected")))
[]))))
The point can be anywhere in function TestDemo, then call dape
and “Run adapter: delve-unit-test
” it will execute go test -test.run TestDemo
.
func TestDemo(t *testing.T) {
t.Error("hello")
}
Thanks to @jixiuf for contributing.
dape already support working with JDTLS + Java Debug Server but it doesn’t support junit.
need eglot-java
with dape-dwim it would auto select the unit test mthod or main to debug
(add-to-list 'dape-configs
`(junit
modes (java-mode java-ts-mode)
ensure (lambda (config)
(save-excursion
(unless (eglot-current-server)
(user-error "No eglot instance active in buffer %s" (current-buffer)))
(when (equal ':json-false
(eglot-execute-command
(eglot-java--find-server)
"java.project.isTestFile"
(vector (eglot--path-to-uri (buffer-file-name)))))
(user-error "Not in a java test file"))
t))
fn (lambda (config)
(let ((file (expand-file-name (plist-get config :program)
(project-root (project-current)))))
(with-current-buffer (find-file-noselect file)
(save-excursion (eglot-java-run-test t))
(thread-first
config
(plist-put 'hostname "localhost")
(plist-put 'port (eglot-execute-command (eglot-current-server)
"vscode.java.startDebugSession" nil))
(plist-put :projectName (project-name (project-current)))))))
:program dape-buffer-default
:request "attach"
:hostname "localhost"
:port 8000))
(setq eglot-java-user-init-opts-fn 'custom-eglot-java-init-opts)
(defun custom-eglot-java-init-opts ( &optional server eglot-java-eclipse-jdt)
"Custom options that will be merged with any default settings."
;; :bundles ["/home/me/.emacs.d/lsp-bundles/com.microsoft.java.debug.plugin-0.50.0.jar"]
`(:bundles [,(download-java-debug-plugin)]))
(defun download-java-debug-plugin ()
(let ((cache-dir (expand-file-name "~/.cache/emacs/"))
(url "https://repo1.maven.org/maven2/com/microsoft/java/com.microsoft.java.debug.plugin/maven-metadata.xml")
(version nil)
(jar-file-name nil)
(jar-file nil))
(unless (file-directory-p cache-dir)
(make-directory cache-dir t))
(setq jar-file (car (directory-files cache-dir nil "com\\.microsoft\\.java\\.debug\\.plugin-\\([0-9]+\\.[0-9]+\\.[0-9]+\\)\\.jar" t)))
(if jar-file
(expand-file-name jar-file cache-dir)
(with-temp-buffer
(url-insert-file-contents url)
(when (re-search-forward "<latest>\\(.*?\\)</latest>" nil t)
(setq version (match-string 1))
(setq jar-file-name (format "com.microsoft.java.debug.plugin-%s.jar" version))
(setq jar-file (expand-file-name jar-file-name cache-dir))
(unless (file-exists-p jar-file)
(setq url (format "https://repo1.maven.org/maven2/com/microsoft/java/com.microsoft.java.debug.plugin/%s/%s"
version jar-file-name))
(message url)
(url-copy-file url jar-file))
jar-file)))))
Follow the steps in the README.org
on how to install codelldb in section “C, C++ and Rust - codelldb”
Add the following configuration to your init.el
:
(add-to-list 'dape-configs
`(ios
modes (swift-mode)
command-cwd dape-command-cwd
command ,(file-name-concat dape-adapter-dir
"codelldb"
"extension"
"adapter"
"codelldb")
command-args ("--port" :autoport
"--settings" "{\"sourceLanguages\":[\"swift\"]}"
"--liblldb" "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/A/LLDB")
port :autoport
simulator-id "iPhone 15 Pro"
app-bundle-id "com.yourcompany.ProductName"
fn (dape-config-autoport
,(lambda (config)
(with-temp-buffer
(let* ((command
(format "xcrun simctl launch --wait-for-debugger --terminate-running-process %S %S"
(plist-get config 'simulator-id)
(plist-get config 'app-bundle-id)))
(code (call-process-shell-command command nil (current-buffer))))
(dape--message (format "* Running: %S *" command))
(dape--message (buffer-string))
(save-match-data
(if (and (zerop code)
(progn (goto-char (point-min))
(search-forward-regexp "[[:digit:]]+" nil t)))
(plist-put config :pid (string-to-number (match-string 0)))
(dape--message (format "* Running: %S *" command))
(dape--message (format "Failed to start simulator:\n%s" (buffer-string)))
(user-error "Failed to start simulator")))))
config))
:type "lldb"
:request "attach"
:cwd "."))
Start simulator:
open -n "Simulator"
Compile program, see xcodebuild (could use compile flag in dape
)
NodeJS (vscode-js-debug)
(contributed by @timcharper)
The following configuration can be used to run an entire file of jest tests (works as of dape
0.5.0).
(defun dape-jest/find-file-buffer-default ()
"Read filename at project root, defaulting to current buffer. Return vector of jest args to run said file"
(let ((file (dape-buffer-default)))
(if file
`["--runInBand" "--no-coverage" ,file]
(user-error "No file found"))))
(defun dape-jest/ensure (config)
"Ensure node is available, jest is installed, that the dapDebugServer is installed"
(dape-ensure-command config)
(let ((cwd (dape-cwd))
(js-debug-file (expand-file-name
(dape--config-eval-value (car (plist-get config 'command-args)))
(dape--config-eval-value (plist-get config 'command-cwd))))
(node-jest-file (expand-file-name
(dape--config-eval-value (plist-get config :program))
(dape--config-eval-value (plist-get config :cwd)))))
(unless (file-exists-p js-debug-file)
(user-error "Debug server file %S does not exist" js-debug-file))
(unless (file-exists-p node-jest-file)
(user-error "Jest executable not found at %S" node-jest-file))))
(add-to-list 'dape-configs
`(jest
modes (js-mode js-ts-mode typescript-mode)
ensure dape-jest/ensure
command "node"
command-cwd dape-command-cwd
command-args (,(expand-file-name
(file-name-concat dape-adapter-dir
"js-debug"
"src"
"dapDebugServer.js"))
:autoport)
port :autoport
fn dape-config-autoport
:type "pwa-node"
:cwd dape-cwd
:env (:VAR1 "some value" :VAR2 "another value")
:program "node_modules/.bin/jest"
:args dape-jest/find-file-buffer-default
:outputCapture "console"
:sourceMapRenames t
:pauseForSourceMap nil
:autoAttachChildProcesses t
:console "internalConsole"
:outputCapture "std"
:killBehavior "forceful"))
https://github.com/svaante/dape-cortex-debug
Very specialized function contributed by @jixiuf
(defun compare-vectors-prefix (vec1 vec2)
(let ((min-length (min (length vec1) (length vec2))))
(cl-loop for i below min-length
always (equal (aref vec1 i) (aref vec2 i)))))
;;;###autoload
(defun dape-dwim()
"If a DAP (Debug Adapter Protocol) session is active, terminate the session.
If there's no active DAP session, start a new session with default configuration.
When prefix argument is given, invoke `dape' interactively instead.
This function uses `dape' related functions to manage debug sessions for Emacs.
It also handles session configuration by looking up the appropriate settings
based on the current context and previous history."
(interactive)
(require 'dape)
(if (dape--live-connection 'parent t)
(progn
(call-interactively #'dape-quit)
(message "dape quit now!"))
(if current-prefix-arg
(call-interactively #'dape)
(let* ((cfg (car (cl-loop for (key . config) in dape-configs
when (and (dape--config-mode-p config)
(dape--config-ensure config))
collect (dape--config-eval key config))))
(suggested-configs
(cl-loop for (key . config) in dape-configs
when (and (dape--config-mode-p config)
(dape--config-ensure config))
collect (dape--config-to-string key nil)))
(hist (seq-find (lambda (str)
(ignore-errors
(member (thread-first (dape--config-from-string str)
(car)
(dape--config-to-string nil))
suggested-configs)))
dape-history)))
(when hist
(setq hist (nth 1 (dape--config-from-string hist)))
(when (and
(equal (plist-get hist 'command-cwd) (plist-get cfg 'command-cwd))
(equal (plist-get hist 'command) (plist-get cfg 'command))
(compare-vectors-prefix (plist-get hist ':args) (plist-get cfg ':args))
(equal (plist-get hist ':program) (plist-get cfg ':program))
(equal (plist-get hist ':mainClass) (plist-get cfg ':mainClass))
)
(setq cfg hist))
)
(when (plist-get cfg 'command-cwd)
(call-process "find" nil nil nil (plist-get cfg 'command-cwd)
"-maxdepth" "1" "-type" "f" "-name" "__debug_bin*" "-exec" "rm" "{}" ";"))
(when cfg (dape cfg)))
)))