diff --git a/Cask b/Cask index 78a06513f..7e6bfea39 100644 --- a/Cask +++ b/Cask @@ -112,7 +112,10 @@ (depends-on "quickrun") (depends-on "repl-toggle") -;; Workgroups --- core/core-workgroups.el +;; Debugging -- core/core-debug.el +(depends-on "realgud") + +;; Sessions --- core/core-sessions.el (depends-on "workgroups2") diff --git a/core/core-debug.el b/core/core-debug.el new file mode 100644 index 000000000..da5faeebb --- /dev/null +++ b/core/core-debug.el @@ -0,0 +1,39 @@ +;;; core-debug.el + +(after! debug + ;; For elisp debugging + (map! :map debugger-mode-map + :n "RET" 'debug-help-follow + :n "n" 'debugger-step-through + :n "c" 'debugger-continue)) + +(use-package realgud + :commands (realgud:gdb realgud:trepanjs realgud:bashdb realgud:zshdb) + :config + (map! :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 + :m "n" 'realgud:cmd-next + :m "b" 'realgud:cmd-break + :m "B" 'realgud:cmd-clear + :n "c" 'realgud:cmd-continue) + + ;; Temporary Ex commands for the debugger + ;; TODO Turn temporary ex commands into macro + (defun narf*debug-init (&rest _) + (exmap "n[ext]" 'realgud:cmd-next) + (exmap "s[tep]" 'realgud:cmd-step) + (exmap "b[reak]" 'narf:debug-toggle-breakpoint) + (exmap "c[ontinue]" 'realgud:cmd-continue)) + (defun narf*debug-quit (&rest _) + (narf/evil-ex-undefine-cmd "n[ext]") + (narf/evil-ex-undefine-cmd "s[tep]") + (narf/evil-ex-undefine-cmd "b[reak]") + (narf/evil-ex-undefine-cmd "c[ontinue]")) + (advice-add 'realgud-cmdbuf-init :after 'narf*debug-init) + (advice-add 'realgud:cmd-quit :after 'narf*debug-quit)) + +(provide 'core-debug) +;;; core-debug.el ends here diff --git a/core/core-popup.el b/core/core-popup.el index b328b85aa..1f76b6ce2 100644 --- a/core/core-popup.el +++ b/core/core-popup.el @@ -10,7 +10,11 @@ :config (shackle-mode 1) (setq shackle-rules - '(;; Plugins + '(;; Debuggers + ("\\`\\*\\(g\\|zsh\\|bash\\)db.*?\\*\\'" :regexp t :align below :size 20) + ("\\`\\*trepanjs.*?\\*\\'" :regexp t :align below :size 20) + + ;; Plugins ("*helm bookmarks*" :align below :size 7 :select t) ("\\` ?\\*[hH]elm.*?\\*\\'" :regexp t :align below :size 20 :select t) (" ?\\*Flycheck.+\\*" :regexp t :align below :size 15 :noselect t) @@ -210,6 +214,37 @@ "q" 'narf/org-agenda-quit "Q" 'narf/org-agenda-quit)) + (after! realgud + ;; This allows realgud debuggers to run in a popup. + ;; TODO Find a more elegant advice-based solution + ;; FIXME Causes realgud:cmd-* to focus popup on every invocation + (defun realgud:run-process(debugger-name script-filename cmd-args minibuffer-history &optional no-reset) + (let ((cmd-buf)) + (setq cmd-buf + (apply 'realgud-exec-shell debugger-name script-filename + (car cmd-args) no-reset (cdr cmd-args))) + (let ((process (get-buffer-process cmd-buf))) + (if (and process (eq 'run (process-status process))) + (progn + (pop-to-buffer cmd-buf) + (define-key evil-emacs-state-local-map (kbd "ESC ESC") 'narf/debug-quit) + (realgud:track-set-debugger debugger-name) + (realgud-cmdbuf-info-in-debugger?= 't) + (realgud-cmdbuf-info-cmd-args= cmd-args) + (when cmd-buf + (switch-to-buffer cmd-buf) + (when realgud-cmdbuf-info + (let* ((info realgud-cmdbuf-info) + (cmd-args (realgud-cmdbuf-info-cmd-args info)) + (cmd-str (mapconcat 'identity cmd-args " "))) + (set minibuffer-history + (list-utils-uniq (cons cmd-str (eval minibuffer-history)))))))) + ;; else + (progn + (if cmd-buf (switch-to-buffer cmd-buf)) + (message "Error running command: %s" (mapconcat 'identity cmd-args " "))))) + cmd-buf))) + (after! flycheck (map! :map flycheck-error-list-mode-map :n "q" 'narf/popup-close diff --git a/core/defuns/defuns-debug.el b/core/defuns/defuns-debug.el index 18ac637a8..3f981ff0a 100644 --- a/core/defuns/defuns-debug.el +++ b/core/defuns/defuns-debug.el @@ -35,5 +35,40 @@ (let (message-log-max) (message "%s%s" (if bang ">> " "") message))) +;;;###autoload (autoload 'narf:debug "defuns-debug" nil t) +(evil-define-command narf:debug (&optional path) + "Initiate debugger for current major mode" + (interactive "") + (let ((default-directory (narf/project-root))) + (cond ((memq major-mode '(c-mode c++-mode)) + (realgud:gdb (if path (concat "gdb " path)))) + ((memq major-mode '(ruby-mode enh-ruby-mode)) + (narf:repl nil (format "run '%s'" (f-filename (or path buffer-file-name))))) + ((eq major-mode 'sh-mode) + (let ((shell sh-shell)) + (when (string= shell "sh") + (setq shell "bash")) + (cond ((string= shell "bash") + (realgud:bashdb (if path (concat "bashdb " path)))) + ((string= shell "zsh") + (realgud:zshdb (if path (concat "zshdb " path)))) + (t (user-error "No shell debugger for %s" shell))))) + ;; TODO Add python debugging + ((memq major-mode '(js-mode js2-mode js3-mode)) + (realgud:trepanjs)) + (t (user-error "No debugger for %s" major-mode))))) + +;;;###autoload (autoload 'narf:debug-toggle-breakpoint "defuns-debug" nil t) +(evil-define-command narf:debug-toggle-breakpoint (&optional bang) + (interactive "") + (call-interactively (if bang 'realgud:cmd-clear 'realgud:cmd-break))) + +;;;###autoload +(defun narf/debug-quit () + (interactive) + (ignore-errors (call-interactively 'realgud:cmd-quit)) + (narf/popup-close) + (evil-normal-state)) + (provide 'defuns-debug) ;;; defuns-debug.el ends here diff --git a/core/defuns/defuns-evil.el b/core/defuns/defuns-evil.el index f71062abc..9f94250bb 100644 --- a/core/defuns/defuns-evil.el +++ b/core/defuns/defuns-evil.el @@ -125,5 +125,14 @@ (user-error (evil-ex-pattern-update-ex-info nil (format "?%s" lossage)))))) +;;;###autoload +(defun narf/evil-ex-undefine-cmd (cmd) + (if (string-match "^[^][]*\\(\\[\\(.*\\)\\]\\)[^][]*$" cmd) + (let ((abbrev (replace-match "" nil t cmd 1)) + (full (replace-match "\\2" nil nil cmd 1))) + (setq evil-ex-commands (delq (assoc full evil-ex-commands) evil-ex-commands)) + (setq evil-ex-commands (delq (assoc abbrev evil-ex-commands) evil-ex-commands))) + (setq evil-ex-commands (delq (assoc cmd evil-ex-commands) evil-ex-commands)))) + (provide 'defuns-evil) ;;; defuns-evil.el ends here diff --git a/init.el b/init.el index 4f6e45f78..6179babef 100644 --- a/init.el +++ b/init.el @@ -61,6 +61,7 @@ core-vcs ; remember remember, that commit in November core-helm ; a search engine for life and love core-eval ; run code, run. + core-debug ; emacs as a universal debugger core-sessions ; cure Emacs alzheimers + tab emulation ;; Environments diff --git a/private/my-commands.el b/private/my-commands.el index 3977ddc36..a56fd04bc 100644 --- a/private/my-commands.el +++ b/private/my-commands.el @@ -79,5 +79,8 @@ (after! flycheck (exmap "er[rors]" (λ! (flycheck-buffer) (flycheck-list-errors)))) +;; Debuggers +(exmap "debug" 'narf:debug) + (provide 'my-commands) ;;; my-commands.el ends here