Clojure has been my primary programming language for a couple of years now. During this period, I have relied on my trusty Vim text editor as the development environment. Coding Clojure in Vim had been an enjoyable experience with these excellent Vim plugins:
- vim-clojure-static
- fireplace.vim
- paredit.vim
- Rainbow Parentheses Improved
- vim-clojure-highlight
- vim-cljfmt
So, why am I switching? Well, Clojure is, after all, a LISP. The tooling coverage for Clojure in the LISP's natural habitat, Emacs, is simply more complete than in Vim. I did not realize the extent of the discrepancy until last week, when some guys in the Clojure meetup demonstrated impressive refactoring features of their Emacs Clojure development environment.
To be fair, fireplace is doing an adequate job of supporting the most of dynamic features necessary for Clojure programming: code evaluation, documents lookup, tests and so on. I have been productive with it in the last couple of years. On the other hand, as my projects grow bigger and more complex, better support for debugging and refactoring seems to become desirable. These capabilities exist in Emacs.
Of course, I am not about to give up the Vim style text editing. As a HCI researcher in my previous life, I know that theoretically, Vim style text editing is simply better than text editing with GUI and a mouse, because Fitts' Law is real and it hurts. In addition, the superiority of modal editor vi over non-modal editor emacs for text editing has been empirically established as far back as 19831.
For my case, an ideal situation would be to keep the text editing style of Vim, but use it in Emacs to get the benefit of extensive Clojure support. Not surprisingly, plenty of people have worked towards such solutions. The latest effort is in the form of spacemacs, a fantastic open source project that is enjoying an outpouring enthusiasm from the community, earning more than 3000 github stars in a very short time.
I had to try it. Try as I did. And I can say that I am not disappointed.
To be honest, the on-boarding process left a lot to be desired. First, on OSX, there's already a default installation of emacs, which would not work with spacemacs. The recommended homebrew installation of emacs is simple enough, but one needs to rename the default emacs and make the homebrew one the default. This is not mentioned in the guide.
I found configuring the editor to be surprisingly easy, considering I knew nothing about emacs before (other than the key combination to quit from one). The majority of the Vim key bindings I tried work as desired. The ones that did not work are not hard to change. Within a couple of hours, I have managed to create a configuration that replicates most of the key bindings of paredit.vim, which I need to be productive coding Clojure. Here are my dotspacemacs/config
to achieve these and more.
(defun remove-background-color ()
"Useful for transparent terminal."
(unless (display-graphic-p (selected-frame))
(set-face-background 'default "unspecified-bg" (selected-frame))))
(defun dotspacemacs/config ()
"Configuration function.
This function is called at the very end of Spacemacs initialization after
layers configuration."
;; Make evil-mode up/down operate in screen lines instead of logical lines
(define-key evil-motion-state-map "j" 'evil-next-visual-line)
(define-key evil-motion-state-map "k" 'evil-previous-visual-line)
;; Also in visual mode
(define-key evil-visual-state-map "j" 'evil-next-visual-line)
(define-key evil-visual-state-map "k" 'evil-previous-visual-line)
;; clojure mode config
(require 'clojure-mode-extra-font-locking)
(add-hook 'clojure-mode-hook #'smartparens-strict-mode)
(add-hook 'clojure-mode-hook #'evil-smartparens-mode)
(add-hook 'clojure-mode-hook #'rainbow-delimiters-mode)
;; start a light theme when launched as GUI
(when (display-graphic-p)
(progn
(disable-theme 'darkburn)
(load-theme 'leuven t)
(enable-theme 'leuven)))
;; remove background color for both server and client
(add-hook 'window-setup-hook 'remove-background-color)
(add-hook 'server-visit-hook 'remove-background-color)
;; remove trailing whitespace when saving
(add-hook 'before-save-hook 'delete-trailing-whitespace)
;; toggle comments
(define-key evil-normal-state-map ",c " " cl")
;; match paredit.vim key-binding
(define-key evil-normal-state-map ",W" " kw") ; wrap with ()
(define-key evil-normal-state-map ",w[" ; wrap with []
(lambda (&optional arg) (interactive "P") (sp-wrap-with-pair "[")))
(define-key evil-normal-state-map ",w{" ; wrap with {}
(lambda (&optional arg) (interactive "P") (sp-wrap-with-pair "{")))
(define-key evil-normal-state-map ",S" " kW") ; splice, i.e unwrap an sexp
(define-key evil-normal-state-map ",J" " kJ") ; join two sexps
(define-key evil-normal-state-map ",O" 'sp-split-sexp) ; split an sexp
(define-key evil-normal-state-map ",I" " kr") ; raise current symbol
(define-key evil-normal-state-map (kbd ", <up>") " kE") ; splice kill backward
(define-key evil-normal-state-map (kbd ", <down>") " ke") ; forward
;; These are different from vim, here cursor should NOT be on delimits
(define-key evil-normal-state-map ",>" " ks") ; forward slurp
(define-key evil-normal-state-map ",<" " kS") ; backward slurp
)
As can be seen, all these functionality of Vim have already been coded up by someone and included in spacemacs as functions, all I did was changing their key-bindings. That was easy :-). I am looking forward to the journey ahead with spacemacs.
- 1. Poller, M.F., Garter, S.K. A Comparative Study of Moded and Modeless Text Editing by Experienced Editor Users. In Proceedings of CHI '83, pp 166-170
Comments
comments powered by Disqus