(λmacs)
Emacs for Clojure development on macOS X.

Table of Contents

(λmacs) is Emacs for Clojure development on macOS X.

lambdamacs_600.png

Intro

Motivation

For a number of years I've been using Emacs as my primary/only IDE. I used a number of "distributions" readily available on internet such as emacs-live and Prelude of which I made my own extension Preludex, and I watched the birth of Spacemacs and the new challenger doom-emacs.

Over time each of these distributions grew larger and larger and it became hard to keep the configuration up-to-date but still minimal (just what you need).

So I decided to build my own out of the best pieces of all of them.

If you are new to Emacs, it is probably best if you start with one of the more popular distributions so that you get enough community support. If only you need is to develop Clojure, and have enough tooling support feel free to use my configuration.

Installation

Alternatively you can install it via:


sudo mkdir /usr/local/Frameworks
sudo chown $(whoami):admin /usr/local/Frameworks
brew tap d12frosted/emacs-plus
brew install emacs-plus@29 --with-no-frame-refocus --with-xwidgets --with-imagemagick --with-native-comp --with-elrumo2-icon

You can check github://d12frosted/homebrew-emacs-plus what each option does.

NOTE: you can choose your icon here and replace the last argument with the one you want

  • Backup your previous installation:

mv ~/.emacs.d ~/.emacs.d-backup

  • Clone (λmacs)

git clone https://github.com/BrunoBonacci/lambdamacs.git ~/.emacs.d

  • Install platform tools

Some platform tools are used to enhance the user experience and to support some features.


brew install the_silver_searcher aspell fd

  • That's all, start hacking!

If you want you can customize your configuration (see next section).

Configuration

There are a number of configurable options to setup (λmacs) just right for your environment.

To change the configuration file edit config/user-config.el.

  • First configure your name and email:

;; add your name and email address
(setq user-full-name    "Firstname Lastname"
      user-mail-address "your-email@email.org")

  • Install a nice looking font and pick a size:

Here some suggestions:


(setq lambdamacs/default-font "Roboto Mono Thin for Powerline")
(setq lambdamacs/default-font-size 150)

  • Select your favorite theme

There are a number a themes already installed see the full list and see theme screenshots. I'd recommend to pick your favorite as default and use a light theme as alternative. It can be useful sometimes to switch to the alternative for example if you make a presentation. Light themes work better with projectors.


(setq lambdamacs/default-theme 'doom-moonlight)
(setq lambdamacs/alternative-theme 'doom-one-light)

You can switch between themes by typing M-x lambdamacs/switch-theme-to-alternative and switch back to the default theme with M-x lambdamacs/switch-theme-to-default

Structure

(λmacs) has the following project structure:

.emacs.d
├── init.el    - main emacs init file
├── config/    - user configuration and other settings
├── modules/   - packages which are not available in MELPA
├── src/       - packages installation and configuration
├── assets/    - Assets for this project (images, css, etc)
├── yas/       - Custom Yasnippets
└── .save/     - Locally saved items (history, items etc.)

Packages installed

Package Purpose
avy Jump where you want (like ace-jump)
bm Bookmarks management
bookmarks Code bookmarks
browse-at-remote Browse selected files or lines on Github (and other repos)
carbon-now-sh Generate images from code snippets, useful for presentations.
cider CIDER the best IDE for Clojude development
clj-refactor Cider companion for refactoring
command-log Displays a buffer with the keys and commands you type
doom-modeline cool minimalistic modeline
doom-theme a collection of well curated themes
flycheck Run checks on the fly
flyspell Spell checking
forge Magit extension for Pull Requests and Issues
google-this Quickly Google something at point
magit Git controls
markdown Markdown mode support with TOC and Live preview (via flymd)
multiple-cursors Multiple cursors for editing
outline-presentation Use org-mode to make a presentation
paradox A package manager which makes very easy to update your installation
paredit Can't develop Clojure without structural editing
password-generator Generate strong random passwords
prodigy Local process management
projectile Useful functions for working with projecs
restclient Turn simple text buffer into HTTP REST calls
sticky-windows Stick windows in place (no auto close)
switch-java Enables to select the JVM version while inside emacs
undo-tree Powerful multi-state undo
wgrep Editable search buffers
witespace To clean trailing whitespaces in the code
wsd WebSequenceDiagrams
yas-snippet Code snippets
  • TODO:
  • [ ] wsd
  • [ ] workgroups / persp-mode / toggle-zoom ??
  • [ ] code rtf pygments
  • [ ] repl image hack

Keybindings

Here is the list of keybindings which are added by this configuration. All standard keybindings are valid, plus the default keybindings of the pacakge installed.

Here is how to read the keybindings:

  • C-x - means Ctrl + x
  • C-x 1 - means Ctrl + x followed by 1
  • M-x - means Meta + x or Alt + x or Option + x
  • s-x - means Super + x or Command ⌘ + x
  • SPC - is space bar
  • RET - is reutrn key

Here the keybindings added/defined by (λmacs):

Mode or group Key Action Module
clojure-mode M-SPC Removes all the blanks between two forms except one (λmacs)
clojure-mode s-b Adds a nice comment box with current line. (λmacs)
clojure-mode C-c C-r Prefix for Clojure refactoring functions clj-refactor
cider-mode C-c C-{ Decompiles the previous form (into Java code) clj-decompiler
editor M-y Browse the content of the kill-ring browse-kill-ring
editor C-a Smart beginning of the line (non blank) crux
editor ⌘-c Copy selected region (like macOS - more natural) cua-mode
editor ⌘-v Paste selected region (like macOS - more natural) cua-mode
editor C-RET Toggle rectangular selection cua-mode
editor C-= Expands the selection to the larger surrounding form. expand-region
editor M-/ or s-/ Hippie expansion (completion) hippie
editor C-> multi-cursor mark next like this multiple-cursors
editor C-< multi-cursor mark previous like this multiple-cursors
editor C-c C-< multi-cursor mark all like this multiple-cursors
editor C-M-s-. C-M-s-. Adds a cursor on each line of a multi-line selection multiple-cursors
editor C-x j Jump to section in buffer (depends on current mode) counsel
editor s-j + char Jumps to the word starting with the given char avy
editor s-. + char Jumps to the location selected with the given char avy
editor s-w + char Jumps to the window selected with the given char avy
editor C-c C-w Opens the selected file in Github browse-at-remote
editor C-c C-S-w Copy the link of the selected file in Github in kill-ring browse-at-remote
editor ⌘-← Restore previous window layout winner
editor ⌘-→ Redo previous window layout winner
editor M-s-c Calls carbon-now-sh and generate an image with your code carbon-now-sh
bookmarks s-1 Toggle bookmark bm
bookmarks s-2 Cycle previous bookmarks bm
bookmarks s-3 Cycle next bookmarks bm
bookmarks s-5 Create bookmarks by regex bm
bookmarks s-0 Clear all bookmarks in this buffer bm
bookmarks s-S-0 Clear all bookmarks in all buffers bm
files/buffers C-x C-/ Open dired explorer for the current file. (λmacs)
files/buffers C-c t Open a shell terminal crux
files/buffers s-r Open a recently opened file crux
files/buffers C-u C-x 0 Closes a locked window (via C-x 9) sticky-windows
files/buffers M-s- + ← → ↑ ↓ Move between windows (same keys as iTerm) (λmacs)
windows C-S- + ← → ↑ ↓ Resize current window using keybindings windsize
processes C-x p Open Prodigy's status buffer (start/stop processes) prodigy
project C-x g Open Magit status magit
project C-x M-g Minibuffer popup with Magit dispatch functions magit
project C-x g + C-o Open the current project in Github magit
project C-c p or s-p Projectile's prefix projectile
project C-x 9 Locks the window in place so that it can't be closed. sticky-windows
all s-g Google word or region at point google-this

Features

Here some features implemented/available in (λmacs)

Switch Java version

(λmacs) focus is on Clojure development. Clojure is a JVM hosted language. JVM release process has been traditionally quite slow, but in the recent years Oracle and OpenJDK have speed up the release process to roughly every 6 months.

For this reason it is common to having the need to use/try different version of the underlying JVM while working on a Clojure project.

Emacs doesn't have a facility to do this and, to my knowledge, there is package that handles this. For this reason I wrote a module that offers this possibility and described the solution in this blog post: Switching between multiple Java JDK versions in Emacs.

You can read more about the solution in the blog post but here I will only describe how it works.

Firstly you need to tell (λmacs) where your JDKs are installed. Typically on a macOS the default location is: /Library/Java/JavaVirtualMachines.

If this is the location where are your JDK versions are installed then you don't need to change the configuration, otherwise select the appropriate folder in the config/user-config.el file.


;; base directory where all the JDK versions are installed
;; use `M-x switch-java' to select the JVM to use
(setq JAVA_BASE "/Library/Java/JavaVirtualMachines")

Once you set the base directory where all your JDKs are installed and evaluated the form, to select a JVM to use you can just run: M-x switch-java which will show the list of available JVMs. Once you select one JDK, it will update the $JVM_HOME environment variable and use it whenever you start a new REPL or java application.

Here other commands you can run:

  • M-x switch-java select a JDK from a list of available ones
  • M-x switch-java-default will select the system default JDK (the one in use prior any selection)
  • M-x switch-java-which-version? displays the JDK currently in use.

You can see a usage demo here:

switch-java.gif

Custom yasnippets

yasnippets is a templating minor-mode with allows to define code templates and complete them with a few keystrokes. Think about the repetitve structures in your code. Check out this demo on Youtube. It works across languages and there are plenty of predefine templates Here the is a list of all most of the boundled snippets.

However if you want to define your own snippets you can drop them in ~/.emacs.d/yas folder divided by major-mode. If you are unfamiliar with the templating language used by yasnippet you can check the official online documentation.

Restclient

If you do RESTful services development restclient is going to be your best companion.

restclient turns normal text buffers into executable HTTP requests ideal to tests your webservices.

For example, create an empty buffer, activate the move via M-x restclient-mode then write your HTTP requests like:

#
# retrieve your current IP address
#
GET http://ifconfig.co/ip


#
# retrieve the geolocation city info
#
GET http://ifconfig.co/city
Accept: text/plain


#
# retrieve all as json
#
GET http://ifconfig.co/json
Content-Type: application/json

After each request try to press C-c C-v to execute the request and see the response.

All *.rest files are in restclient-mode by default.

Here a list of all the keybindings for this mode:

  • C-c C-c : runs the query under the cursor, tries to pretty-print the response (if possible)
  • C-c C-r : same, but doesn't do anything with the response, just shows the buffer
  • C-c C-v : same as C-c C-c, but doesn't switch focus to other window
  • C-c C-p : jump to the previous query
  • C-c C-n : jump to the next query
  • C-c C-. : mark the query under the cursor
  • C-c C-u : copy query under the cursor as a curl command
  • C-c C-g : start a [helm](https://emacs-helm.github.io/helm/) session with sources for variables and requests (if helm is available, of course)
  • C-c n n : narrow to region of current request (including headers)
  • TAB : hide/show current request body, only if
  • C-c C-a : show all collapsed regions
  • C-c C-i : show information on resclient variables at point

cljfmt auto-format

The way Cider formats the code isn't particularly nice. To format the code properly you need to have a repl running and the code needs to be loaded. Because of this the formatting changes depending on which state your IDE is. I think it is a bad idea. I rather have a less appealing formatting, but which can be done without having to load/compile the code.

(λmacs) performs a reformatting of the code on save with a definition which doesn't take into account which particular form you are in. However, there are times this is not convenient, like when working on someone else code. To disable the code-reformat set the variable lambdamacs/cljfmt-reformat-on-save to nil in the configuration.


(setq lambdamacs/cljfmt-reformat-on-save nil)

You can toggle the value with M-x cljfmt-toggle-reformat.

Get involved

Contribution

This is my personal setup, I don't mind you using it and I'd appreciate feedbacks and suggestions on how to improve it! Issue a PR, and if it works for me, I'll merge it!

References

The code in this repo has is the sum of my personal experience and the following references:

Thank you to all of you!

License

Copyright © 2020 Bruno Bonacci and contributors. Distributed under the GNU General Public License, version 3.