Skip to content

Commit

Permalink
Integrate debugger with interactive evaluation
Browse files Browse the repository at this point in the history
  • Loading branch information
Malabarba committed Jul 1, 2015
1 parent cd4d255 commit 02c4e80
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 11 deletions.
4 changes: 4 additions & 0 deletions README.md
Expand Up @@ -921,6 +921,10 @@ Keyboard shortcut | Description
<kbd>l</kbd> | List local variables
<kbd>q</kbd> | Quit execution

In addition, all the usual evaluation commands (such as <kbd>C-x C-e</kbd> or
<kbd>C-c M-:</kbd>) will use the current lexical context (local variables) while
the debugger is active.

### Managing multiple sessions

You can connect to multiple nREPL servers using <kbd>M-x
Expand Down
17 changes: 17 additions & 0 deletions cider-debug.el
Expand Up @@ -178,6 +178,18 @@ Each element of LOCALS should be a list of at least two elements."
(setq cider--debug-display-locals (not cider--debug-display-locals))
(cider--debug-mode-redisplay))

(defun cider--debug-lexical-eval (key form &optional callback _point)
"Eval FORM in the lexical context of debug session given by KEY.
Do nothing if CALLBACK is provided.
Designed to be used as `cider-interactive-eval-override' and called instead
of `cider-interactive-eval' in debug sessions."
;; The debugger uses its own callback, so if the caller is passing a callback
;; we return nil and let `cider-interactive-eval' do its thing.
(unless callback
(cider-debug-mode-send-reply (format "{:response :eval, :code %s}" form)
key)
t))

(defvar cider--debug-mode-map)

(define-minor-mode cider--debug-mode
Expand All @@ -190,6 +202,10 @@ In order to work properly, this mode must be activated by
(nrepl-dbind-response cider--debug-mode-response (input-type)
(unless (consp input-type)
(error "debug-mode activated on a message not asking for commands: %s" cider--debug-mode-response))
;; Integrate with eval commands.
(setq cider-interactive-eval-override
(apply-partially #'cider--debug-lexical-eval
(nrepl-dict-get cider--debug-mode-response "key")))
;; Set the keymap.
(let ((alist `((?\C-g . ":quit")
,@(mapcar (lambda (k) (cons (string-to-char k) (concat ":" k)))
Expand All @@ -206,6 +222,7 @@ In order to work properly, this mode must be activated by
(setq buffer-read-only nil)
(remove-overlays nil nil 'cider-type 'debug-result)
(remove-overlays nil nil 'cider-type 'debug-code)
(setq cider-interactive-eval-override nil)
(setq cider--debug-mode-commands-alist nil)
(setq cider--debug-mode-response nil)))

Expand Down
33 changes: 22 additions & 11 deletions cider-interaction.el
Expand Up @@ -1640,21 +1640,30 @@ Clears any compilation highlights and kills the error window."
(cider-eval-ns-form)
(cider--cache-ns-form))))

(defvar-local cider-interactive-eval-override nil
"Function to call instead of `cider-interactive-eval'.")

(defun cider-interactive-eval (form &optional callback point)
"Evaluate FORM and dispatch the response to CALLBACK.
This function is the main entry point in CIDER's interactive evaluation
API. Most other interactive eval functions should rely on this function.
If CALLBACK is nil use `cider-interactive-eval-handler'.
POINT, if non-nil, is the position of FORM in its buffer."
(cider--prep-interactive-eval form)
(nrepl-request:eval
form
(or callback (cider-interactive-eval-handler))
;; always eval ns forms in the user namespace
;; otherwise trying to eval ns form for the first time will produce an error
(if (cider-ns-form-p form) "user" (cider-current-ns))
nil
point))
POINT, if non-nil, is the position of FORM in its buffer.
If `cider-interactive-eval-override' is a function, call it with the same
arguments and only proceed with evaluation if it returns nil."
(unless (and cider-interactive-eval-override
(functionp cider-interactive-eval-override)
(funcall cider-interactive-eval-override form callback point))
(cider--prep-interactive-eval form)
(nrepl-request:eval
form
(or callback (cider-interactive-eval-handler))
;; always eval ns forms in the user namespace
;; otherwise trying to eval ns form for the first time will produce an error
(if (cider-ns-form-p form) "user" (cider-current-ns))
nil
point)))

(defun cider-interactive-pprint-eval (form &optional callback right-margin)
"Evaluate FORM and dispatch the response to CALLBACK.
Expand Down Expand Up @@ -1752,14 +1761,16 @@ command `cider-debug-defun-at-point'."
"Read a sexp from the minibuffer and output its result to the echo area."
(interactive)
(let* ((form (cider-read-from-minibuffer "CIDER Eval: "))
(override cider-interactive-eval-override)
(ns-form (if (cider-ns-form-p form) "" (format "(ns %s)" (cider-current-ns)))))
(with-current-buffer (get-buffer-create cider-read-eval-buffer)
(erase-buffer)
(clojure-mode)
(unless (string= "" ns-form)
(insert ns-form "\n\n"))
(insert form)
(cider-interactive-eval form))))
(let ((cider-interactive-eval-override override))
(cider-interactive-eval form)))))


;; Connection and REPL
Expand Down

0 comments on commit 02c4e80

Please sign in to comment.