Skip to content

Instantly share code, notes, and snippets.

@gertverhoog
Created September 15, 2012 00:22
Show Gist options
  • Save gertverhoog/3725749 to your computer and use it in GitHub Desktop.
Save gertverhoog/3725749 to your computer and use it in GitHub Desktop.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Clojure, Paredit and nRepl
;;
;; Sets up nrepl/clojure/paredit with the following features:
;;
;; - enable Paredit mode for clojure files
;;
;; - when there's an nrepl connection, compile and load clojure files
;; automatically after saving
;;
;; - enable Eldoc mode to show function arglists hints when editing clojure files
;;
;; - set up key bindings to work better with Paredit (e.g. make DEL paredit-aware)
;;
;; - M-SPC collapses all whitespace around the cursor into a single space, and
;; re-indents the s-expression around the cursor
;;
;; - after typing a space, calls 'nrepl-eldoc, so function arglists are shown
;; not just when the cursor is directly after a symbol, but elsewhere in an
;; expression as well
;;
;; - binds TAB to a function that indents the expression, completes the symbol
;; and shows arglist documentation (stolen/adapted from the SLIME function
;; slime-indent-and-complete-symbol)
;;
(require 'paredit)
(require 'clojure-mode)
(require 'nrepl)
(defun multi-line-just-one-space (&optional n)
"Multi-line version of `just-one-space': Delete all spaces and tabs
around point, leaving one space (or N spaces). When in clojure or
emacs lisp mode, re-indents the s-expression."
(interactive "*p")
(let ((orig-pos (point)))
(skip-chars-backward " \t\n")
(constrain-to-field nil orig-pos)
(dotimes (i (or n 1))
(if (= (following-char) ?\s)
(forward-char 1)
(insert ?\s)))
(delete-region
(point)
(progn
(skip-chars-forward " \t\n")
(constrain-to-field nil orig-pos t))))
(when (or (eq major-mode 'clojure-mode)
(eq major-mode 'emacs-lisp-mode))
(indent-sexp)))
(global-set-key (kbd "M-SPC") 'multi-line-just-one-space)
(defun nrepl-eldoc-space (n)
"Inserts a space and calls nrepl-eldoc to print arglists"
(interactive "p")
(self-insert-command n)
(when (nrepl-current-session)
(nrepl-eldoc)))
(defun nrepl-indent-and-complete ()
"Indent the current line and perform symbol completion.
First indent the line. If indenting doesn't move point, complete
the symbol. If there's no symbol at the point, show the arglist
for the most recently enclosed macro or function.
adapted from SLIME's slime-indent-and-complete-symbol"
(interactive)
(let ((pos (point)))
(lisp-indent-line)
(when (= pos (point))
(cond ((save-excursion (re-search-backward "[^() \n\t\r]+\\=" nil t))
(nrepl-complete))
((memq (char-before) '(?\t ?\ ))
(nrepl-eldoc))))))
(defun setup-my-clojure-mode ()
"Enables nRepl minor mode, Eldoc and ParEdit. Binds TAB to
'nrepl-indent-and-complete, which re-indents the s-expression, and
either auto-completes the symbol before the cursor, or calls nrepl-eldoc.
Binds space to 'nrepl-eldoc-space, which inserts a space and shows arglists."
(nrepl-interaction-mode)
(nrepl-eldoc-enable-in-current-buffer)
(enable-paredit-mode)
(define-key clojure-mode-map (kbd "TAB") 'nrepl-indent-and-complete)
(define-key clojure-mode-map (kbd "SPC") 'nrepl-eldoc-space))
(add-hook 'clojure-mode-hook 'setup-my-clojure-mode)
(defun setup-clojure-paredit ()
(define-key clojure-mode-map
(kbd "DEL") 'paredit-backward-delete)
(define-key clojure-mode-map
(kbd "{") 'paredit-open-curly)
(define-key clojure-mode-map
(kbd "}") 'paredit-close-curly)
(modify-syntax-entry ?\{ "(}")
(modify-syntax-entry ?\} "){")
(modify-syntax-entry ?\[ "(]")
(modify-syntax-entry ?\] ")[")
(modify-syntax-entry ?~ "' ")
(modify-syntax-entry ?, " ")
(modify-syntax-entry ?^ "'")
(modify-syntax-entry ?= "'"))
(add-hook 'clojure-mode-hook 'setup-clojure-paredit)
(defun clojure-maybe-compile-and-load-file ()
"Call function `nrepl-load-current-buffer' if there's an nrepl session.
Meant to be used in `after-save-hook'."
(when (and (eq major-mode 'clojure-mode)
(not (string= "project.clj" buffer-file-name))
(not (string-match "^.*\.cljs$" buffer-file-name))
(nrepl-current-session))
(nrepl-load-current-buffer)))
(add-hook 'after-save-hook 'clojure-maybe-compile-and-load-file)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment