Better translation here: https://kvantos.github.io/#articles_en/emacs-slime/
Emacs works quite well with Common Lisp.
We can use REPL and autocompletion feature connecting to new Common Lisp implementation or working implementation; SLIME server booted on implementation holds communicaiton between implementation and Emacs.
Though frequently we connect into working implementation on local environment with SLIME and that is well-documented on the Web, there is few documents that describes a way to connect Emacs into working implementation and enjoy productive development in modern environment -- Docker compose environment.
Thus I try to:
- Connect emacs into living typical Common Lisp application (Caveman 2) booted on docker-compose.
- Interact with living code and interfare with its behavior.
I assume you have already done with basic SLIME configuration on Emacs.
Motivation
My hobby program written in Common Lisp is dockerized and able to boot with docker-compose, except "editor and its environment". So situation is this: I connected Emacs into the local-booted implementation with SLIME for syntax highlight and autocompletion, not into the docker-compose-booted implementation. It raised many probrems such that malfunction of autocompletion and loading library, and burdened developer of maintaining develop environment.
Now I am going to harmonize coding environment and server environment to develop with genuine living code.
Environment
cat /proc/version
Linux version 4.4.104-39-default (geeko@buildhost) (gcc version 4.8.5 (SUSE Linux) ) #1 SMP Thu Jan 4 08:11:03 UTC 2018 (7db1912)
lsb_release -a
- LSB Version: n/a
- Distributor ID: openSUSE project
- Description: openSUSE Leap 42.3
- Release: 42.3
- Codename: n/a
ros version
build with gcc (SUSE Linux) 4.8.5 libcurl=7.37.0 Quicklisp=2017-03-06 Dist=2017-08-30 lispdir='/usr/local/etc/roswell/' homedir='/home/windymelt/.roswell/' configdir='/home/windymelt/.roswell/'
ros run -- -version
SBCL 1.4.0
Sample application
I prepared the sample application. You can try to connect into the application with SWANK.
Let docker-compose
expose SWANK port
SWANK server should be booted on an implementation to communicate with Emacs.
We expose port used for SWANK server through host to allow connect from Emacs.
Here we suppose that the implementation is working on app
service built from following Dockerfile
.
Web application (caveman 2) and SWANK server use 5000
port and 6005
port respectively.
You can choose arbitary port number for SWANK server because Emacs always asks for SWANK host and port number.
# docker-compose.yml version: '3' services: app: build: . ports: - "6005:6005" # For development; SWANK port. cf. Dockerfile - "5000:5000"
Dockerfile
In Dockerfile
we command CMD
to boot SWANK server first, preceding application server booting.
We look at bottom part of Dockerfile
because many part of Dockerfile have no buissiness with SWANK:
CMD [ \ "qlot", "exec", "ros", \ "-e", "(ql:quickload :swank)", \ "-e", "(setf swank::*loopback-interface* \"0.0.0.0\")", \ "-e", "(swank:create-server :port 6005 :dont-close t :style :spawn)", \ "-l", "bundle-libs/bundle.lisp", \ "-S", ".", "~/.roswell/bin/clackup", "--server", ":woo", "--address", "0.0.0.0", "--port", "5000", "app.lisp" \ ]
The container boots qlot
, library localiser. It makes loading libraries under quicklisp/
.
qlot
has responsibility to pass configuration about project-local libraries to implementation and the implementation is booted by ros
.
ros
processes dangling options in written order:
First swank
is loaded by -e (ql:quickload :swank)
to prepare booting SWANK server. You may declare dependency into qlfile
and write -e (asdf:load-system :swank)
here.
Then we overwrite the address which SWANK server listens by -e (setf swank::*loopback-interface* "0.0.0.0")
.
This is because docker environment often makes turbulance of IP addresses. We ensure connecting to implementation by fixing listening address to 0.0.0.0
.
By the way SWANK has no authentication mechanism so everyone can connect to socket of SWANK server. You should use SSH if you have to secure connection, but it's okay because this is development purpose.
Next we boot SWANK server listening 6005
port by -e (swank:create-server :port 6005 :dont-close t :style :spawn)
.
:dont-close
should keep connection but I'm not sure. :style :spawn
designates type of connection: one spawned process per connection. It is not needed if you connect SWANK server from exactly one client.
Following processes have no business with SWANK.
-l bundle-libs/bundle.lisp
is to load dependent local library. qlot
can freeze all dependent libraries into bundle-libs
executing qlot bundle
and bootstrapping file to load libraries is bundle.lisp
. It should be used by ros -l
option. -l
simply loads and executes specified file.
-S .
configures ASDF default system repository (asdf:*central-registry*
) into current directory (this time it's project-root).
ASDF can find system such that its ASD file is placed at specified directory.
At last we boot clack application by ~/.roswell/bin/clackup --server :woo --address 0.0.0.0 --port 5000 app.lisp
.
app.lisp
is called clack aplication alike perl's app.psgi
. This file is created automatically when Caveman project is created.
Connecting from Emacs
It's time to flight. Boot project with docker-compose
and connect from Emacs.
docker-compose up
After M-x slime-connect
you will get the prompt Host:
to specify localhost
.
Then you will get the prompt Port:
to specify 6005
configured above.
After all following output are made into minibuffer and you can see working REPL window.
Connecting to Swank on port 6005.. Connected. Take this REPL, brother, and may it serve you well.
You can move into your package because living codes are already loaded.
;; there is Caveman 2 project named :hogeapplication CL-USER> (in-package :hogeapplication.web) #<PACKAGE "HOGEAPPLICATION.WEB"> HOGEAPPLICATION.WEB> *web* #<<WEB> {12345678}> HOGEAPPLICATION.WEB> (render #P"index.html") ;; -- Template is rendered exactly same as you coded in hogeapplication.web package -- HOGEAPPLICATION.WEB> (clear-routing-rules *web*) ;; -- All of routing information is gone, application is made to say 404. try this! --
Conclusion
Now we can read/modify symbols inside living application because:
- We booted SWANK server at
Dockerfile
and configured potr exposure setting - We connected into the implementation running over container orchestrated by docker-compose, from Emacs on host machine
We can use precise autocompletion along living application because package information is provided to SLIME from SWANK.
This post is self-translation of: