Skip to content
Brenton Ashworth edited this page Jan 4, 2012 · 5 revisions

Emacs

Although you can use any editor you like to edit the ClojureScript One files, the authors (and many Clojure programmers) use emacs. On this page we document some of the things you can do to improve your experience working with ClojureScript One in emacs.

Using clojure-mode to edit .cljs files

By default, ClojureScript files are not associated with clojure-mode in emacs. Put the following lines into your .emacs or .emacs.d/init.el file:

(add-to-list 'auto-mode-alist '("\\.cljs$" . clojure-mode))

Working with two REPLs

Working with ClojureScript One differs from working in Clojure in that you are often simultaneously working with two different REPLs: a ClojureScript REPL where you want to evaluate commands in the browser, and a Clojure REPL where you want to evaluate commands against the server portion of the application. A trick that we've used to pull this off is to run the one of them in an inferior lisp buffer, and the other in shell-mode. We define commands and keys for sending expressions to the shell buffer and use the existing commands to send expressions to the inferior lisp buffer. It's a bit of a hack, but an occasionally handy one.

To make it work, put the following into your .emacs or .emacs.d/init.el file:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Allow input to be sent to somewhere other than inferior-lisp
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; This is a total hack: we're hardcoding the name of the shell buffer
(defun shell-send-input (input)
  "Send INPUT into the *shell* buffer and leave it visible."
  (save-selected-window
    (switch-to-buffer-other-window "*shell*")
    (goto-char (point-max))
    (insert input)
    (comint-send-input)))

(defun defun-at-point ()
  "Return the text of the defun at point."
  (apply #'buffer-substring-no-properties
         (region-for-defun-at-point)))

(defun region-for-defun-at-point ()
  "Return the start and end position of defun at point."
  (save-excursion
    (save-match-data
      (end-of-defun)
      (let ((end (point)))
        (beginning-of-defun)
        (list (point) end)))))

(defun expression-preceding-point ()
  "Return the expression preceding point as a string."
  (buffer-substring-no-properties
   (save-excursion (backward-sexp) (point))
   (point)))

(defun shell-eval-last-expression ()
  "Send the expression preceding point to the *shell* buffer."
  (interactive)
  (shell-send-input (expression-preceding-point)))

(defun shell-eval-defun ()
  "Send the current toplevel expression to the *shell* buffer."
  (interactive)
  (shell-send-input (defun-at-point)))

(add-hook 'clojure-mode-hook
          '(lambda ()
             (define-key clojure-mode-map (kbd "C-c e") 'shell-eval-last-expression)
             (define-key clojure-mode-map (kbd "C-c x") 'shell-eval-defun)))

Once there, you can eval this code by selecting it and typing M-x eval-region. Any open Clojure files will need to be reopened for these changes to take effect.

For this example, we will start the Clojure REPL in the shell mode buffer and the ClojureScript REPL in the inferior lisp buffer. You can reverse these if it suits your preference.

  • Run M-x shell to get a new *shell* buffer
  • In the *shell* buffer, change to the One directory by typing cd /path/to/one
  • Start a Clojure REPL by running script/repl
  • Start the dev server in the REPL by executing (use 'one.sample.dev-server) and then (run-server)
  • Open a new emacs window and switch to it: C-x 2 followed by C-x o
  • Change the default directory of the new window: M-x cd followed by /path/to/one
  • Start another Clojure REPL by typing C-u M-x inferior-lisp followed by script/repl
  • Start a ClojureScript REPL in the new Clojure REPL with the commands (use 'one.sample.dev-server) and (cljs-repl)
  • Connect a browser session to the ClojureScript REPL by opening a browser and visiting http://localhost:8080/.

You're now ready to run commands in either the Clojure REPL or the ClojureScript one. Use the following keys:

  • C-M-x: Send the top-level expression at point to the inferior-lisp buffer (in our example, this is the ClojureScript REPL).
  • C-c C-e: Send the expression that ends just before point to the inferior-lisp buffer (in our example, this is the ClojureScript REPL).
  • C-c x: Send the top-level expression at point to the shell buffer (in our example, this is the Clojure REPL).
  • C-c e: Send the expression that ends just before point to the shell buffer (in our example, this is the Clojure REPL).

Consider the following code, with the cursor positioned at the location indicated by the | character:

(+ 2| 3)

Here is what each of the above keys would result in:

  • C-M-x: Evaluate (+ 2 3) in the ClojureScript REPL.
  • C-c C-e: Evaluate 2 in the ClojureScript REPL.
  • C-c x: Evaluate (+ 2 3) in the Clojure REPL.
  • C-c e: Evaluate 2 in the Clojure REPL.

If the keys don't work, it may be as a result of interference with slime minor mode. Try disabling slime-mode in your Clojure buffer.

Clone this wiki locally