An elegant weapon, for a more civilized age.

In which we assemble a portable, Emacs based LISP development environment under Windows.  This being good for the soul.

For Carlos, happy birthday.  You will come to understand... they all do.
For Josh, you were right about Lisp.

Before we begin, let me say if you are new to Lisp, you should check out Quicklisp.  Quicklisp provides a convenient way to setup and maintain a Lisp development environment with a large set of libraries.  However, if you would like a portable Lisp development environment and/or would like to have more control over (or a better understanding of) your Emacs based setup, please read on.

What you will need:

  1. The latest version of Emacs for Windows.  Download the zip.
  2. The latest CVS snapshot of SLIME.  Download the tar archive.
  3. One or more of the following Lisp implementations:
  • CCL: Checkout the latest release version from SVN.
  • CLISP
  • ECL: You will have to compile from source.

Optional:

  • Par Edit: helps **keep parentheses balanced**

And we are off!

  1. Extract Emacs to a location of your choice, e.g. emacs-24.3 (tip include the version in the directory names so you can tell which version you are running.)
  2. Create a directory named 'home' in the root of your emacs directory, e.g. emacs-24.3/home
  3. Create a directory named 'bin' in the root of 'home', e.g. emacs-24.3/home/bin
  4. Deploy Lisp implementation(s)
    • CLISP
      • Extract to a directory in bin, e.g. emacs-24.3/home/bin/clisp-2.49
    • ECL
      • Compile from source and install to a directory in bin, e.g. emacs-24.3/home/bin/ecl-13.5.1
    • CCL
      • Checkout from SVN to a directory in bin, e.g. emacs-24.3/home/bin/ccl
      • Tip: keep CCL up to date between version releases with SVN's update command.
      • Modify ccl/level-1/linux-files.lisp line 939 #+windows-target to set HOME from the 'HOME' environment variable.  This allows us to control where CCL writes files reducing debris and making it portable.
        #+windows-target
        ;; Matthew Witherwax (lemoneer) 01MAY2013
        ;; Modified the Windows target to use the value of the HOME environment
        ;; variable if it exists; otherwise, it falls back to the OS user database.
        ;; This allows CCL to be run portably under Windows without leaving debris
        ;; behind.
        (or
         (getenv "HOME")
         (dolist (k '(#||"HOME"||# "USERPROFILE"))
           (with-native-utf-16-cstrs ((key k))
             (let* ((p (#__wgetenv key)))
           (unless (%null-ptr-p p)
             (return (get-foreign-namestring p)))))))
        
  5. Create the file site-start.el in site-lisp in the root of your Emacs directory, e.g. emacs-24.3/, and insert the code below. This allows us to set the ‘HOME’ environment variable when we launch Emacs.
    ; remove etc from the path
        (defvar %~dp0
            (substring data-directory 0
            (- (length data-directory) 4)))
        ; create appened home/
        (defvar home-dir (concat %~dp0 "home/"))
        (setenv "HOME" home-dir)
    
  6. Extract the latest slime csv snapshot to site-lisp, e.g. emacs-24.3/site-lisp/slime-2013-12-12
  7. Optional: Copy paredit to /lisp in the root of your Emacs directory, e.g. emacs-24.3/lisp
  8. Launch Emacs by double clicking runemacs.exe in the bin directory of the Emacs directory, e.g. emacs-24.3/bin, and type C-x C-f ~/.emacs to open the Emacs config file.   Insert the following:
    (set-language-environment "utf-8")
    
    ;;; Add slime
    (add-to-list 'load-path "~/site-lisp/slime-2013-12-12")  ;or wherever you put it
    
    ;;; CCL Note that if you save a heap image, the character
    ;;; encoding specified on the command line will be preserved,
    ;;; and you won't have to specify the -K utf-8 any more.
    
    ;; SLIME and CLISP will complain about a missing temp directory without this
    (setq temporary-file-directory (expand-file-name "~/temp"))
    
    ;; Path to clisp full so we can build the call
    (setq path-clisp (expand-file-name "~/bin/clisp-2.49/full/"))
    
    ;;; Configure available Lisp
    ;;; Leave out the one(s) you did not install
    (setq slime-lisp-implementations
    	`(
    		(ccl (,(expand-file-name "~/bin/ccl/wx86cl64.exe") "-K utf-8"))
    		(clisp (,(replace-regexp-in-string "@" path-clisp "@lisp.exe") 
    			,(replace-regexp-in-string "@" path-clisp "-B@") 
    			,(replace-regexp-in-string "@" path-clisp "-M@lispinit.mem")
    			"-ansi"))
    		(ecl (,(expand-file-name "~/bin/ecl-13.5.1/ecl.exe")))))
    
    ;;; setup slime
    (require 'slime)
    (setq slime-net-coding-system 'utf-8-unix)
    (slime-setup '(slime-fancy))
    
    ;;; setup paredit if you installed it
    (autoload 'paredit-mode "paredit"
      "Minor mode for pseudo-structurally editing Lisp code." t)
    (add-hook 'emacs-lisp-mode-hook       (lambda () (paredit-mode +1)))
    (add-hook 'lisp-mode-hook             (lambda () (paredit-mode +1)))
    (add-hook 'lisp-interaction-mode-hook (lambda () (paredit-mode +1)))
    (add-hook 'scheme-mode-hook           (lambda () (paredit-mode +1)))
    
    ;;; This is disabled to stop paredit from running in the REPL
    ;;; Feel free to uncomment this to turn it back on
    
    ;;;; (add-hook 'slime-repl-mode-hook (lambda () (paredit-mode +1)))
    ;;;; ;; Stop SLIME's REPL from grabbing DEL,
    ;;;; ;; which is annoying when backspacing over a '('
    ;;;; (defun override-slime-repl-bindings-with-paredit ()
    ;;;; (define-key slime-repl-mode-map
    ;;;; 	(read-kbd-macro paredit-backward-delete-key) nil))
    ;;;; (add-hook 'slime-repl-mode-hook 'override-slime-repl-bindings-with-paredit)
    
    ;;; bonus split the screen in to two side by side windows
    (defun 2-windows-vertical-to-horizontal ()
      (if (and
           (= (length (window-list)) 2) ; only split if there are 2 windows
           (window-combined-p)) ; and they are vertical
          (progn
    	(delete-window)
    	(split-window-horizontally))))
    
    (add-hook 'emacs-startup-hook '2-windows-vertical-to-horizontal)
    
    (when (display-graphic-p)
      (add-to-list 'default-frame-alist '(left . 0))
      (add-to-list 'default-frame-alist '(top . 0))
    )
    
    (w32-send-sys-command 61488)
    
  9. Create a batch file called runslime.bat and insert the following command.  This will allow us to launch Emacs with slime and your default Lisp running.
    @ECHO OFF
    C:\emacs-24.3\bin\runemacs.exe --eval=(slime)

 If you followed all the steps, when you run runslime.bat, you should see something like this

Take this REPL, brother, and may it serve you well.