Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save robert-stuttaford/6255383 to your computer and use it in GitHub Desktop.
Save robert-stuttaford/6255383 to your computer and use it in GitHub Desktop.

Editing Clojure with Emacs

This gist will guide you to setting up a basic emacs-starter-kit-based Emacs configuration for editing Clojure.

This gist was put together by Ryan Neufeld @rkneufeld - original here. I added the Clojure Cheatsheet - https://github.com/krisajenkins/clojure-cheatsheet by Kris Jenkins @krisajenkins. I also updated the clone url in the instructions. Otherwise, the gist is unmodified.

Contents:

Getting Emacs

The first step is to get Emacs. Whatever you do, just make sure you get Emacs 24.

To paraphrase Install the right Emacs:

Once you've installed Emacs verify you have the correct version with emacs --version

▸ emacs --version
GNU Emacs 24.2.1
Copyright (C) 2012 Free Software Foundation, Inc.
GNU Emacs comes with ABSOLUTELY NO WARRANTY.
You may redistribute copies of Emacs
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING.

Now, for the config...

Installing the config

Prerequisite: Install Leiningen. Installation instructions.

To follow along with the contents of the presentation I would suggest you download and install the Emacs configuration bundled in this gist like so:

  1. Clean out any existing Emacs configurations you have.

  2. Clone this gist to your ~/.emacs.d folder with the command

     $ git clone https://gist.github.com/6255383.git ~/.emacs.d
    
  3. Launch emacs without any arguments like $ emacs. You'll see a number of package fetch and compilation messages fly by as Emacs installs all of the packages specified in init.el.

If you didn't encounter any errors you've likely arrived at a simple, stable Emacs configuration. The configuration is annotated, so feel free to read and edit as you see fit.

Enjoy

A special note for Mac users

If you try to follow along into the Paredit sections you'll be sorely disappointed when you start trying to do things like C-→. The problem is this: every Mac terminal sends the incorrect key codes to your terminal, and by-proxy, Emacs.

Fix this by following the excellent instructions of Cosmin Stejerean's Emacs + paredit under terminal. His instructions address how to fix Terminal.app, iTerm and iTerm2 to send the proper key codes for using Paredit.

Keyboard Shortcuts

Protip: To find out what any keybinding does use C-h k followed by the keybinding in question to discover what it does.

REPL-driven Development with nREPL:

Keybinding Result
M-x nrepl-jack-in, C-c M-j (when in Clojure file) Open an nREPL session. Intelligently loads project context if launched from any file within a Leiningen project.
C-↑, C-↓ Browse up or down through nREPL's history of commands.
C-x 3 Split window vertically
C-x f Open file
C-M-x Evaluate expression at cursor. This command evaluates whatever top-level expression is under your cursor.
C-c M-n Change the namespace of your nREPL REPL to match the command was issued from.
C-c C-k Evaluate an entire file.
C-c C-e Evaluate the expression preceding your cursor.
C-c C-r Evaluate a selected region. Start selecting text with the keybinding C-Space.
M-. Jump to the definition of the symbol under your cursor.
M-, Jump back one level (after jumping with M-.).

Paredit

Keybinding Result
C-→ Absorb one expression from the right of the current expression
Also try C-←, C-M-→ and C-M-←

Example: (+ 1 2) 3(+ 1 2 3)
M-↑ "Splice sexp killing backwards". A utility-knife of a command that unwraps an expression, deleting anything before the cursor.
Example: (filter :completed? (map (fn [[_ v]] v)▋todos))(filter :completed? todos)

Clojure Cheatsheet

Read about how to use the incredibly handy Clojure Cheatsheet, updated for Clojure 1.5 and packaged into an easy, fast, searchable, offline form:

https://github.com/krisajenkins/clojure-cheatsheet

;; General
(setq initial-scratch-message nil) ; *scratch* starts empty
(when (locate-library "clojure-mode") ; Set *scratch* to Clojure mode
(setq initial-major-mode 'clojure-mode))
(projectile-global-mode) ; Quickly navigate projects using Projectile (C-c p C-h for available commands)
(setq projectile-show-paths-function 'projectile-hashify-with-relative-paths) ; Projectile shows full relative paths
;; Visual
(load-theme 'twilight t) ; Load my preferred theme, twilight
(add-hook 'prog-mode-hook 'rainbow-delimiters-mode) ; Enable rainbow delimiters when programming
(remove-hook 'prog-mode-hook 'esk-turn-on-hl-line-mode) ; Disable emacs-starter-kits line highlighting
(global-linum-mode t) ; Always show line numbers on left
(setq linum-format "%4d ") ; Line numbers gutter should be four characters wide
(line-number-mode 1) ; Mode line shows line numbers
(column-number-mode 1) ; Mode line shows column numbers
(setq-default tab-width 2) ; Tab width of 2
(fset 'yes-or-no-p 'y-or-n-p) ; Emacs prompts should accept "y" or "n" instead of the full word
(setq visible-bell nil) ; No more Mr. Visual Bell Guy.
;; Clojure
(setq auto-mode-alist (cons '("\\.edn$" . clojure-mode) auto-mode-alist)) ; *.edn are Clojure files
(setq auto-mode-alist (cons '("\\.cljs$" . clojure-mode) auto-mode-alist)) ; *.cljs are Clojure files
;; nREPL customizations
(setq nrepl-hide-special-buffers t) ; Don't show buffers like connection or server
(setq nrepl-popup-on-error nil) ; Don't popup new buffer for errors (show in nrepl buffer)
(setq nrepl-popup-stacktraces-in-repl t) ; Display stacktrace inline
(add-hook 'nrepl-interaction-mode-hook 'nrepl-turn-on-eldoc-mode) ; Enable eldoc - shows fn argument list in echo area
(add-hook 'nrepl-mode-hook 'paredit-mode) ; Use paredit in *nrepl* buffer
(add-to-list 'same-window-buffer-names "*nrepl*") ; Make C-c C-z switch to *nrepl*
;; Ido-mode customizations
(setq ido-decorations ; Make ido-mode display vertically
(quote
("\n-> " ; Opening bracket around prospect list
"" ; Closing bracket around prospect list
"\n " ; separator between prospects
"\n ..." ; appears at end of truncated list of prospects
"[" ; opening bracket around common match string
"]" ; closing bracket around common match string
" [No match]" ; displayed when there is no match
" [Matched]" ; displayed if there is a single match
" [Not readable]" ; current diretory is not readable
" [Too big]" ; directory too big
" [Confirm]"))) ; confirm creation of new file or buffer
(add-hook 'ido-setup-hook ; Navigate ido-mode vertically
(lambda ()
(define-key ido-completion-map [down] 'ido-next-match)
(define-key ido-completion-map [up] 'ido-prev-match)
(define-key ido-completion-map (kbd "C-n") 'ido-next-match)
(define-key ido-completion-map (kbd "C-p") 'ido-prev-match)))
Check out README.md to get started editing Clojure with Emacs.
(require 'package)
(add-to-list 'package-archives
'("melpa" . "http://melpa.milkbox.net/packages/") t)
(package-initialize)
(when (not package-archive-contents)
(package-refresh-contents))
;; Add in your own as you wish:
(defvar my-packages '(starter-kit
starter-kit-bindings
starter-kit-js
starter-kit-lisp
;; Clojure & friends
clojure-mode
nrepl
rainbow-delimiters
clojure-cheatsheet
;; Project navigation
projectile
ack-and-a-half
;; Misc.
markdown-mode
twilight-theme
hlinum)
"A list of packages to ensure are installed at launch.")
;; Automaticaly install any missing packages
(dolist (p my-packages)
(when (not (package-installed-p p))
(package-install p)))
;; Load the provided Clojure start kit configurations
(load (concat user-emacs-directory "clojure-starter-kit.el"))
(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(font-lock-warning-face ((t (:inherit nil :foreground "red" :background nil))))
'(linum-highlight-face ((t (:inherit default :background "color-238" :foreground "white"))))
'(show-paren-match ((((class color) (background dark)) (:inherit nil :foreground "red")))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment