Skip to content

Commit

Permalink
Merge pull request #903 from vspinu/isolate-nrepl
Browse files Browse the repository at this point in the history
Isolate `nrepl-client` connection logic from CIDER
  • Loading branch information
bbatsov committed Dec 27, 2014
2 parents f24dee0 + f42ef6d commit 6ec5cea
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 41 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
### New features

* Trigger Grimoire doc lookup from doc buffers by pressing <kbd>g</kbd> (in Emacs) and <kbd>G</kbd> (in browser).
* [#903](https://github.com/clojure-emacs/cider/pull/903): Isolate
`nrepl-client` connection logic from CIDER. New hooks `cider-connected-hook`
and `cider-disconnected-hook`.

## 0.8.2 / 2014-12-21

Expand Down
4 changes: 0 additions & 4 deletions cider-interaction.el
Original file line number Diff line number Diff line change
Expand Up @@ -1801,10 +1801,6 @@ restart the server."
(cider-jack-in prompt-project))
(error "Can't restart CIDER for unknown project"))))

(add-hook 'nrepl-connected-hook 'cider-enable-on-existing-clojure-buffers)
(add-hook 'nrepl-disconnected-hook
'cider-possibly-disable-on-existing-clojure-buffers)

(provide 'cider-interaction)

;;; cider-interaction.el ends here
13 changes: 8 additions & 5 deletions cider-repl.el
Original file line number Diff line number Diff line change
Expand Up @@ -162,16 +162,19 @@ PROJECT-DIR, PORT and HOST are as in `nrepl-make-buffer-name'."
(current-buffer))
(nrepl-make-buffer-name nrepl-repl-buffer-name-template project-dir host port)))

(defun cider-repl-create (&optional project-dir host port)
(defun cider-repl-create (endpoint)
"Create a REPL buffer and install `cider-repl-mode'.
PROJECT-DIR, PORT and HOST are as in `nrepl-make-buffer-name'."
ENDPOINT is a plist as returned by `nrepl-connect'."
;; Connection might not have been set as yet. Please don't send requests here.
(let ((buf (nrepl-make-buffer-name nrepl-repl-buffer-name-template
project-dir host port)))
(let ((buf (nrepl-make-buffer-name nrepl-repl-buffer-name-template nil
(plist-get endpoint :host)
(plist-get endpoint :port))))
(with-current-buffer (get-buffer-create buf)
(unless (derived-mode-p 'cider-repl-mode)
(cider-repl-mode))
(cider-repl-reset-markers))
(cider-repl-reset-markers)
(add-hook 'nrepl-connected-hook 'cider--connected-handler nil 'local)
(add-hook 'nrepl-disconnected-hook 'cider--disconnected-handler nil 'local))
buf))

(defun cider-repl-require-repl-utils ()
Expand Down
37 changes: 35 additions & 2 deletions cider.el
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,18 @@ This variable is used by `cider-connect'."
:type 'list
:group 'cider)

(defcustom cider-connected-hook nil
"List of functions to call when connected to Clojure nREPL server."
:type 'hook
:group 'cider
:version "0.9.0")

(defcustom cider-disconnected-hook nil
"List of functions to call when disconnected from the Clojure nREPL server."
:type 'hook
:group 'cider
:version "0.9.0")

(defvar cider-ps-running-nrepls-command "ps u | grep leiningen"
"Process snapshot command used in `cider-locate-running-nrepl-ports'.")

Expand All @@ -118,7 +130,8 @@ start the server."
(interactive "P")
(setq cider-current-clojure-buffer (current-buffer))
(if (cider--lein-present-p)
(let* ((project (when prompt-project
(let* ((nrepl-create-client-buffer-function #'cider-repl-create)
(project (when prompt-project
(read-directory-name "Project: ")))
(project-dir (nrepl-project-directory-for
(or project (nrepl-current-dir))))
Expand All @@ -140,7 +153,8 @@ Create REPL buffer and start an nREPL client connection."
(interactive (cider-select-endpoint))
(setq cider-current-clojure-buffer (current-buffer))
(when (nrepl-check-for-repl-buffer `(,host ,port) nil)
(nrepl-start-client-process host port t)))
(let ((nrepl-create-client-buffer-function #'cider-repl-create))
(nrepl-start-client-process host port))))

(defun cider-select-endpoint ()
"Interactively select the host and port to connect to."
Expand Down Expand Up @@ -234,6 +248,25 @@ In case `default-directory' is non-local we assume the command is available."
(executable-find cider-lein-command)
(executable-find (concat cider-lein-command ".bat"))))

(defun cider--connected-handler ()
"Handle cider initialization after nREPL connection has been established.
This function is appended to `nrepl-connected-hook' in the client process
buffer."
;; `nrepl-connected-hook' is run in connection buffer
(cider-repl-init (current-buffer))
(cider--check-required-nrepl-ops)
(cider--check-middleware-compatibility)
(cider-enable-on-existing-clojure-buffers)
(run-hooks 'cider-connected-hook))

(defun cider--disconnected-handler ()
"Cleanup after nREPL connection has been lost or closed.
This function is appended to `nrepl-disconnected-hook' in the client
process buffer."
;; `nrepl-connected-hook' is run in connection buffer
(cider-possibly-disable-on-existing-clojure-buffers)
(run-hooks 'cider-disconnected-hook))

;;;###autoload
(eval-after-load 'clojure-mode
'(progn
Expand Down
62 changes: 32 additions & 30 deletions nrepl-client.el
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ buffer will be hidden."
:type 'boolean
:group 'nrepl)

(defvar nrepl-create-client-buffer-function 'nrepl-create-client-buffer-default
"Name of a function that returns a client process buffer.
It is called with one argument, a plist containing :host, :port and :proc
as returned by `nrepl-connect'. ")


;;; nREPL Buffer Names

Expand Down Expand Up @@ -683,20 +688,18 @@ If NO-ERROR is non-nil, show messages instead of throwing an error."
;; `nrepl-start-client-process' is called from `nrepl-server-filter'. It
;; starts the client process described by `nrepl-client-filter' and
;; `nrepl-client-sentinel'.
(defun nrepl-start-client-process (&optional host port replp server-proc)
(defun nrepl-start-client-process (&optional host port server-proc)
"Create new client process identified by HOST and PORT.
If eitehr HOST or PORT are nil, pick them from the value returned by
`nrepl-connection-endpoint'. If REPLP is non-nil create a client
connection which is associated with a repl buffer. When non-nil,
SERVER-PROC must be a running nrepl server process within Emacs. Return
the newly created client connection process."
In remote buffers, HOST and PORT are taken from the current tramp
connection. SERVER-PROC must be a running nREPL server process within
Emacs. This function creates connection buffer by a call to
`nrepl-create-client-buffer-function'. Return newly created client
process."
(let* ((endpoint (nrepl-connect host port))
(client-proc (plist-get endpoint :proc))
(host (plist-get endpoint :host))
(port (plist-get endpoint :port))
(client-buf (if replp
(cider-repl-create default-directory host port)
(nrepl-create-connection-buffer default-directory host port))))
(client-buf (funcall nrepl-create-client-buffer-function endpoint)))

(set-process-buffer client-proc (get-buffer client-buf))

Expand All @@ -712,20 +715,19 @@ the newly created client connection process."
(setq nrepl-project-dir (buffer-local-value 'nrepl-project-dir server-buf)
nrepl-server-buffer server-buf))
(setq nrepl-endpoint `(,host ,port)
;; FIXME: REPL and connection buffers are the same thing
nrepl-connection-buffer client-buf
nrepl-repl-buffer (when replp client-buf)
nrepl-repl-buffer client-buf
nrepl-tunnel-buffer (-when-let (tunnel (plist-get endpoint :tunnel))
(process-buffer tunnel))
nrepl-pending-requests (make-hash-table :test 'equal)
nrepl-completed-requests (make-hash-table :test 'equal)))

(nrepl-make-connection-default client-buf)
(nrepl--init-client-sessions client-proc)
(nrepl--init-connection-buffer client-buf replp)
(cider--check-required-nrepl-ops)
(cider--check-middleware-compatibility)
(run-hooks 'nrepl-connected-hook)
(nrepl--init-capabilities client-buf)

(with-current-buffer client-buf
(run-hooks 'nrepl-connected-hook))

client-proc))

Expand All @@ -750,19 +752,13 @@ for functionality like pretty-printing won't clobber the values of *1, *2, etc."
(setq nrepl-tooling-session new-session))
(error "Could not create new tooling session (%s)" err)))))

(defun nrepl--init-connection-buffer (conn-buffer replp)
"Initialize CONN-BUFFER as a connection buffer.
If REPLP is non-nil, initialize as a REPL buffer.
Here we determine the main session's capabilities using the \"describe\" op
and store that information as buffer-local data in the connection buffer."
(defun nrepl--init-capabilities (conn-buffer)
"Store locally in CONN-BUFFER the capabilities of nREPL server."
(let ((description (nrepl-sync-request:describe)))
(nrepl-dbind-response description (ops versions)
(with-current-buffer conn-buffer
(setq nrepl-ops ops)
(setq nrepl-versions versions)))
(when replp
(cider-repl-init conn-buffer))))
(setq nrepl-versions versions)))))

(defun nrepl-close-client-sessions ()
"Close the nREPL sessions for the active connection."
Expand Down Expand Up @@ -993,7 +989,10 @@ Return a newly created process."
(set-process-sentinel serv-proc 'nrepl-server-sentinel)
(set-process-coding-system serv-proc 'utf-8-unix 'utf-8-unix)
(with-current-buffer serv-buf
(setq nrepl-project-dir directory))
(setq nrepl-project-dir directory)
;; ensure that `nrepl-start-client-process' sees right function
(setq-local nrepl-create-client-buffer-function
nrepl-create-client-buffer-function))
(message "Starting nREPL server via %s..."
(propertize cmd 'face 'font-lock-keyword-face))
serv-proc))
Expand All @@ -1008,7 +1007,7 @@ Return a newly created process."
(let ((port (string-to-number (match-string 1 output))))
(message (format "nREPL server started on %s" port))
(with-current-buffer (process-buffer process)
(let ((client-proc (nrepl-start-client-process nil port t process)))
(let ((client-proc (nrepl-start-client-process nil port process)))
;; FIXME: Bad connection tracking system. There can be multiple client
;; connections per server
(setq nrepl-connection-buffer (buffer-name (process-buffer client-proc))))))))
Expand Down Expand Up @@ -1138,10 +1137,13 @@ The default buffer name is *nrepl-messages*."
tramp-current-host
nrepl-host))

(defun nrepl-create-connection-buffer (&optional project-dir host port)
"Create an nREPL connection buffer.
PROJECT-DIR, HOST and PORT are as in `nrepl-make-buffer-name'."
(let ((buffer (generate-new-buffer (nrepl-connection-buffer-name project-dir host port))))
(defun nrepl-create-client-buffer-default (endpoint)
"Create an nREPL client process buffer.
ENDPOINT is a plist returned by `nrepl-connect'."
(let ((buffer (generate-new-buffer
(nrepl-connection-buffer-name default-directory
(plist-get endpoint :host)
(plist-get endpoint :port)))))
(with-current-buffer buffer
(buffer-disable-undo)
(setq-local kill-buffer-query-functions nil))
Expand Down

0 comments on commit 6ec5cea

Please sign in to comment.