diff --git a/modules/config/default/+evil-bindings.el b/modules/config/default/+evil-bindings.el index 25b310960..3e993473e 100644 --- a/modules/config/default/+evil-bindings.el +++ b/modules/config/default/+evil-bindings.el @@ -436,19 +436,7 @@ :n "gb" #'git-timemachine-blame)) ;;; :tools -(map! (:when (featurep! :tools debugger) - :after realgud - :map realgud:shortkey-mode-map - :n "j" #'evil-next-line - :n "k" #'evil-previous-line - :n "h" #'evil-backward-char - :n "l" #'evil-forward-char - :n "c" #'realgud:cmd-continue - :m "n" #'realgud:cmd-next - :m "b" #'realgud:cmd-break - :m "B" #'realgud:cmd-clear) - - (:when (featurep! :tools eval) +(map! (:when (featurep! :tools eval) :g "M-r" #'+eval/buffer :nv "gr" #'+eval:region :n "gR" #'+eval/buffer @@ -721,7 +709,7 @@ :desc "Tags search" "m" #'org-tags-view :desc "View search" "v" #'org-search-view) :desc "Default browser" "b" #'browse-url-of-file - :desc "Debugger" "d" #'+debug/open + :desc "Start debugger" "d" #'+debugger/start :desc "REPL" "r" #'+eval/open-repl-other-window :desc "REPL (same window)" "R" #'+eval/open-repl-same-window :desc "Dired" "-" #'dired-jump diff --git a/modules/editor/evil/+commands.el b/modules/editor/evil/+commands.el index a110e673d..263dce2db 100644 --- a/modules/editor/evil/+commands.el +++ b/modules/editor/evil/+commands.el @@ -177,7 +177,7 @@ If BANG, search Doom documentation." ;;; Project tools (evil-ex-define-cmd "compile" #'+evil:compile) (evil-ex-define-cmd "mak[e]" #'+evil:make) -;; (evil-ex-define-cmd "debug" #'+debug/run) +(evil-ex-define-cmd "debug" #'+debugger/start) (evil-ex-define-cmd "er[rors]" #'flycheck-list-errors) ;;; File operations diff --git a/modules/tools/debugger/autoload/debug.el b/modules/tools/debugger/autoload/debug.el deleted file mode 100644 index 691ea909c..000000000 --- a/modules/tools/debugger/autoload/debug.el +++ /dev/null @@ -1,11 +0,0 @@ -;;; tools/debugger/autoload/debug.el -*- lexical-binding: t; -*- - -;;;###autoload -(defun +debugger/quit () - "Quit the active debugger, if any." - (interactive) - (ignore-errors (call-interactively #'realgud:cmd-quit)) - (doom/popup-close) - (when (featurep 'evil) - (evil-normal-state))) - diff --git a/modules/tools/debugger/autoload/debugger.el b/modules/tools/debugger/autoload/debugger.el new file mode 100644 index 000000000..24ad342eb --- /dev/null +++ b/modules/tools/debugger/autoload/debugger.el @@ -0,0 +1,82 @@ +;;; tools/debugger/autoload/debugger.el -*- lexical-binding: t; -*- + +(defvar +debugger--last nil) + +(defun +debugger-list-for-dap () + (when (and (bound-and-true-p lsp-mode) + (require 'dap-mode nil t) + dsp-mode) + (mapcar #'car dap--debug-template-configurations))) + +(defun +debugger-list-for-realgud () + (cl-loop for (sym . plist) in +debugger-realgud-alist + for sym-name = (symbol-name sym) + for modes = (plist-get plist :modes) + if (or (null modes) (apply #'derived-mode-p modes)) + collect sym)) + + +(defun +debugger-list-available () + "TODO" + (append (+debugger-list-for-dap) + (+debugger-list-for-realgud) + nil)) + + +;; +;;; Interactive commands + +;;;###autoload +(defun +debugger/start-last () + "Relaunch the last debugger session." + (interactive) + (unless +debugger--last + (user-error "No last debugger to invoke")) + (call-interactively +debugger--last)) + +;;;###autoload +(defun +debugger/start (arg) + "Launch a debugger session. + +Launches the last used debugger, if one exists. Otherwise, you will be prompted +for what debugger to use. If the prefix ARG is set, prompt anyway." + (interactive "P") + (if (or arg (null +debugger--last)) + (let ((debugger (intern-soft (completing-read "Start debugger: " (+debugger-list-available))))) + (unless debugger + (user-error "No debugging session to quit")) + (unless (fboundp debugger) + (user-error "Couldn't find debugger backend %S" debugger)) + (setq-local +debugger--last debugger) + (call-interactively debugger)) + (+debugger/start-last))) + +;;;###autoload +(defun +debugger/quit () + "Quit the active debugger, if any." + (interactive) + (cond ((and (fboundp 'dap--cur-session) (dap--cur-session)) + (dap-disconnect)) + ((and (fboundp 'realgud-get-cmdbuf) (realgud-get-cmdbuf)) + (let ((buf (realgud-get-cmdbuf))) + (ignore-errors + (call-interactively #'realgud:cmd-quit)) + (let (realgud-safe-mode) + (kill-buffer buf)))) + ((user-error "No debugging session to quit")))) + +;; TODO debugger breakpoint commands +;; ;;;###autoload +;; (defun +debugger/toggle-breakpoint () +;; (interactive) +;; (user-error "not implemented yet")) + +;; ;;;###autoload +;; (defun +debugger/next-breakpoint () +;; (interactive) +;; (user-error "not implemented yet")) + +;; ;;;###autoload +;; (defun +debugger/previous-breakpoint () +;; (interactive) +;; (user-error "not implemented yet")) diff --git a/modules/tools/debugger/config.el b/modules/tools/debugger/config.el index 7714f3a19..252cb1745 100644 --- a/modules/tools/debugger/config.el +++ b/modules/tools/debugger/config.el @@ -1,9 +1,31 @@ ;;; tools/debugger/config.el -*- lexical-binding: t; -*- +(defvar +debugger--realgud-alist + '((realgud:zshdb :modes (sh-mode)) + (realgud:kshdb :modes (sh-mode)) + (realgud:rdebug :modes (ruby-mode enh-ruby-mode)) + (realgud:pdb :modes (python-mode)) + (realgud:trepan2 :modes (python-mode)) + (realgud:gub :modes (go-mode)) + (realgud:gdb) + (realgud:trepan :modes (perl-mode perl6-mode)) + (realgud:trepanpl :modes (perl-mode perl6-mode)) + (realgud:trepanjs :modes (javascript-mode js2-mode js3-mode)) + (realgud:remake) + (realgud:trepan3k :modes (python-mode)) + (realgud:bashdb :modes (sh-mode)) + (realgud:perldb :modes (perl-mode perl6-mode)))) + + +;; +;;; Packages + (def-package! dap-mode :when (featurep! :tools lsp) :hook (dap-mode . dap-ui-mode) :after lsp-mode + :init + (setq dap--breakpoints-file (concat doom-etc-dir "dap-breakpoints")) :config (dap-mode 1) (dolist (module '(((:lang . java) lsp-java dap-java) @@ -26,24 +48,35 @@ (require 'dap-node))))) -;; FIXME wildly outdated and untested; rewrite me! (def-package! realgud - :commands (realgud:gdb realgud:trepanjs realgud:bashdb realgud:zshdb) + :defer t + :init + (def-package! realgud-trepan-ni + :defer t + :init (add-to-list '+debugger--realgud-alist + '(realgud:trepan-ni :modes (javascript-mode js2-mode js3-mode) + :package realgud-trepan-ni))) + + ;; Realgud doesn't generate its autoloads properly so we do it ourselves + (dolist (debugger +debugger--realgud-alist) + (autoload (car debugger) + (if-let (sym (plist-get (cdr debugger) :package)) + (symbol-name sym) + "realgud") + nil t)) + :config - (set-popup-rule! "^\\*\\(?:trepanjs:\\(?:g\\|zsh\\|bash\\)db\\)" :size 20) + (set-popup-rule! "^\\*\\(?:trepanjs:\\(?:g\\|zsh\\|bash\\)db\\|pdb \\)" + :size 20 :select nil :quit nil) - (when (featurep! :lang javascript) - (after! js2-mode - (require 'realgud-trepan-ni))) - - ;; TODO Temporary Ex commands for the debugger - ;; (def-tmp-excmd! doom:def-debug-on doom:def-debug-off - ;; ("n[ext]" . realgud:cmd-next) - ;; ("s[tep]" . realgud:cmd-step) - ;; ("b[reak]" . +debug:toggle-breakpoint) - ;; ("c[ontinue]" . realgud:cmd-continue)) - ;; (advice-add #'realgud-cmdbuf-init :after #'doom:def-debug-on) - ;; (advice-add #'realgud:cmd-quit :after #'doom:def-debug-off) + (defun +debugger*cleanup-when-realgud-terminates (&optional buf) + "Kill command buffer when debugging session ends (which closes its popup)." + (when (stringp buf) + (setq buf (get-buffer buf))) + (when-let (cmdbuf (realgud-get-cmdbuf buf)) + (let (kill-buffer-hook) + (kill-buffer buf)))) + (advice-add #'realgud:terminate :after #'+debugger*cleanup-when-realgud-terminates) ;; Monkey-patch `realgud:run-process' to run in a popup. ;; TODO Find a more elegant solution @@ -55,7 +88,7 @@ (process (get-buffer-process cmd-buf))) (cond ((and process (eq 'run (process-status process))) (pop-to-buffer cmd-buf) - (define-key evil-emacs-state-local-map (kbd "ESC ESC") #'+debug/quit) + (define-key evil-emacs-state-local-map (kbd "ESC ESC") #'+debugger/quit) (realgud:track-set-debugger debugger-name) (realgud-cmdbuf-info-in-debugger?= 't) (realgud-cmdbuf-info-cmd-args= cmd-args) @@ -65,8 +98,11 @@ (let* ((info realgud-cmdbuf-info) (cmd-args (realgud-cmdbuf-info-cmd-args info)) (cmd-str (mapconcat #'identity cmd-args " "))) + (if (boundp 'starting-directory) + (realgud-cmdbuf-info-starting-directory= starting-directory)) (set minibuffer-history-var - (list-utils-uniq (cons cmd-str (eval minibuffer-history-var)))))))) + (cl-remove-duplicates + (cons cmd-str (eval minibuffer-history)) :from-end)))))) (t (if cmd-buf (switch-to-buffer cmd-buf)) (message "Error running command: %s" (mapconcat #'identity cmd-args " "))))