Skip to content

Commit

Permalink
[Fix #920] Implement boot support for cider-jack-in
Browse files Browse the repository at this point in the history
  • Loading branch information
pandeiro committed Jan 14, 2015
1 parent c1c527a commit f01b6f9
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 31 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* [#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`.
* [#920](https://github.com/clojure-emacs/cider/issues/920): Support `cider-jack-in` for boot-based projects.

### Changes

Expand Down
36 changes: 22 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -531,22 +531,24 @@ enable `paredit` in the REPL buffer as well:
## Basic Usage

The only requirement to use CIDER is to have a nREPL server to
which it may connect. Many Clojurians favour the use of the Leiningen tool
to start a nREPL server, but the use of Leiningen is not a prerequisite to use
CIDER (but it's required if you want to use the `cider-jack-in` command).
which it may connect. Many Clojurians favour the use of the Leiningen or Boot tools
to start an nREPL server, but the use of Leiningen or Boot is not a prerequisite to use
CIDER (but it *is* required if you want to use the `cider-jack-in` command).

### Setting up a Leiningen project (optional)
### Setting up a Leiningen or Boot project (optional)

[Leiningen](http://leiningen.org/) is the de facto standard
build/project management tool for Clojure. It has a similar scope to
the Maven build tool favoured by Java developers (Leiningen actually
reuses many things from the Maven ecosystem).
[Leiningen](http://leiningen.org/) is the de facto standard build/project
management tool for Clojure. [Boot](http://boot-clj.com/) is a newer build tool
offering abstractions and libraries to construct more complex build
scenarios. Both have a similar scope to the Maven build tool favoured by Java
developers (and they actually reuse many things from the Maven ecosystem).

CIDER features a command called `cider-jack-in` that will start an nREPL server
for a particular Leiningen project and connect to it automatically. This
functionality depends on Leiningen 2.x (preferably 2.5+). Older versions are not
supported. Follow the installation instructions on Leiningen's web site to get
it up and running and afterwards create a project like this:
for a particular Leiningen or Boot project and connect to it automatically.
This functionality depends on Leiningen 2.x (preferably 2.5+) or Boot
2.0.0+. Older versions are not supported. For Leiningen, follow the installation
instructions on its web site to get it up and running and afterwards create a
project like this:

```
$ lein new demo
Expand All @@ -556,12 +558,12 @@ The two main ways to obtain an nREPL connection are discussed in the following s

### Launch a nREPL server and client from Emacs

Simply open in Emacs a file belonging to your `lein` project (like
Simply open in Emacs a file belonging to your `lein` or `boot` project (like
`foo.clj`) and type <kbd>M-x cider-jack-in</kbd>. This will start a nREPL with
all the deps loaded in, plus an `CIDER` client connected to it.

Alternative you can use <kbd>C-u M-x cider-jack-in</kbd> to specify the name of
a lein project, without having to visit any file in it.
a `lein` or `boot` project, without having to visit any file in it.

### Connect to a running nREPL server

Expand All @@ -572,6 +574,12 @@ You can go to your project's dir in a terminal and type there
$ lein repl
```

Or with Boot:

```
$ boot repl wait
```

Alternatively you can start nREPL either manually or by the facilities provided by your
project build tool (Maven, etc).

Expand Down
82 changes: 66 additions & 16 deletions cider.el
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,20 @@ version from the CIDER package or library.")
:type 'string
:group 'cider)

(defcustom cider-boot-command
"boot"
"The command used to execute Boot."
:type 'string
:group 'cider
:package-version '(cider . "0.9.0"))

(defcustom cider-boot-parameters
"repl -s wait"
"Params passed to boot to start an nREPL server via `cider-jack-in'."
:type 'string
:group 'cider
:package-version '(cider . "0.9.0"))

(defcustom cider-known-endpoints nil
"Specify a list of custom endpoints where each endpoint is a list.
For example: '((\"label\" \"host\" \"port\")).
Expand Down Expand Up @@ -122,29 +136,45 @@ Sub-match 1 must be the project path.")
(interactive)
(message "CIDER %s" (cider--version)))

(defun cider-command-present-p (project-type)
(pcase project-type
("lein" 'cider--lein-present-p)
("boot" 'cider--boot-present-p)))

(defun cider-jack-in-command (project-type)
(pcase project-type
("lein" cider-lein-command)
("boot" cider-boot-command)))

(defun cider-jack-in-params (project-type)
(pcase project-type
("lein" cider-lein-parameters)
("boot" cider-boot-parameters)))

;;;###autoload
(defun cider-jack-in (&optional prompt-project)
"Start a nREPL server for the current project and connect to it.
If PROMPT-PROJECT is t, then prompt for the project for which to
start the server."
(interactive "P")
(setq cider-current-clojure-buffer (current-buffer))
(if (cider--lein-present-p)
(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))))
(lein-params (if prompt-project
(read-string (format "nREPL server command: %s "
cider-lein-command)
cider-lein-parameters)
cider-lein-parameters))
(cmd (format "%s %s" cider-lein-command lein-params)))
(when (nrepl-check-for-repl-buffer nil project-dir)
(nrepl-start-server-process project-dir cmd)))
(message "The %s executable (specified by `cider-lein-command') isn't on your exec-path"
cider-lein-command)))
(let ((project-type (cider-project-type)))
(if (funcall (cider-command-present-p project-type))
(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))))
(params (if prompt-project
(read-string (format "nREPL server command: %s "
(cider-jack-in-params project-type))
(cider-jack-in-params project-type))
(cider-jack-in-params project-type)))
(cmd (format "%s %s" (cider-jack-in-command project-type) params)))
(when (nrepl-check-for-repl-buffer nil project-dir)
(nrepl-start-server-process project-dir cmd)))
(message "The %s executable (specified by `cider-lein-command' or `cider-boot-command') isn't on your exec-path"
(cider-jack-in-command project-type)))))

;;;###autoload
(defun cider-connect (host port)
Expand Down Expand Up @@ -239,6 +269,18 @@ use `cider-ps-running-nrepls-command' and `cider-ps-running-nrepl-path-regexp-li
(setq paths (cons (match-string 1) paths)))))
(-distinct paths)))

(defun cider-project-type ()
"Determine the type, either leiningen or boot, of the current project.
If both project file types are present, prompt the user to choose."
(let* ((default-directory (nrepl-project-directory-for (nrepl-current-dir)))
(lein-project-exists (file-exists-p "project.clj"))
(boot-project-exists (file-exists-p "build.boot")))
(cond ((and lein-project-exists boot-project-exists)
(completing-read "Which command should be used? " '("lein" "boot") nil
t "lein"))
(lein-project-exists "lein")
(boot-project-exists "boot"))))

;; TODO: Implement a check for `cider-lein-command' over tramp
(defun cider--lein-present-p ()
"Check if `cider-lein-command' is on the `exec-path'.
Expand All @@ -248,6 +290,14 @@ 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--boot-present-p ()
"Check if `cider-boot-command' is on the `exec-path'.
In case `default-directory' is non-local we assume the command is available."
(or (file-remote-p default-directory)
(executable-find cider-boot-command)
(executable-find (concat cider-boot-command ".exe"))))

(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
Expand Down
3 changes: 2 additions & 1 deletion nrepl-client.el
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,8 @@ Bind the value of the provided KEYS and execute BODY."
(defun nrepl-project-directory-for (dir-name)
"Return the project directory for the specified DIR-NAME."
(when dir-name
(locate-dominating-file dir-name "project.clj")))
(or (locate-dominating-file dir-name "project.clj")
(locate-dominating-file dir-name "build.boot"))))

(defun nrepl-check-for-repl-buffer (endpoint project-directory)
"Check whether a matching connection buffer already exists.
Expand Down

0 comments on commit f01b6f9

Please sign in to comment.