Skip to content

Instantly share code, notes, and snippets.

@baruchel
Last active October 6, 2021 13:49
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save baruchel/c05048699ed36a27770bb295552a2f3b to your computer and use it in GitHub Desktop.
Save baruchel/c05048699ed36a27770bb295552a2f3b to your computer and use it in GitHub Desktop.
Complete integration of Maxima into Vim with Slimv

I previously wrote a plugin called vim-notebook for using Maxima in a Vim buffer. But since Maxima is written in Lisp and intended to be usable from Lisp code, I finally figured out a very nice way to achieve a similar result by using the existing Slimv.

In this post, I explain how to:

  • install a Lisp implementation (Clozure CL);
  • install the Quicklisp library manager;
  • install the Swank server;
  • fetch the latest version of Maxima and compile the interpreter only;
  • integrate Maxima to Vim with Slimv.

Assuming we work with some Linux distribution, we have to choose a directory for the whole installation described here; I choose ~/Documents/Thomas/lisp; of course, any other location will be fine:

cd ~/Documents/Thomas
mkdir lisp
cd lisp

Installing the current release of Clozure CL

Now we have to download Clozure CL and uncompress it:

wget ftp://ftp.clozure.com/pub/release/1.11/ccl-1.11-linuxx86.tar.gz
tar -xzf ccl-1.11-linuxx86.tar.gz
rm ccl-1.11-linuxx86.tar.gz

We can check the Lisp interpreter works (the 64-bit version is chosen here):

ccl/lx86cl64

A simple operation can be tried:

(+ 1 1)
(quit)

Installing the Quicklisp library manager

Being in the same directory:

curl -O https://beta.quicklisp.org/quicklisp.lisp
ccl/lx86cl64 --load quicklisp.lisp

Now the two following commands have to be typed from the Lisp interpreter:

(quicklisp-quickstart:install)
(quit)

The installer puts the quicklisp directory in the home directory; I don't like that, thus I move it in the same directory:

mv ~/quicklisp .
rm quicklisp.lisp

The new location has to be fixed in the init file of Clozure CL:

vim ~/.ccl-init.lisp

The following piece of code has to be written in the file (with the right path):

#-quicklisp
(defun load-quicklisp ()
    (let ((quicklisp-init
              (merge-pathnames
                "Documents/Thomas/lisp/quicklisp/setup.lisp" (user-homedir-pathname))))
         (when (probe-file quicklisp-init)
               (load quicklisp-init))))

Installing the Swank server

With Quicklisp, it is very easy to install the Swank server; a first Lisp image containing the server can also be dumped:

ccl/lx86cl64

The three following commands must be typed:

(load-quicklisp)
(ql:quickload "swank")
(swank-loader:dump-image "ccl-with-swank")

Now a new file, called ccl-with-swank should be in the lisp/ working directory; let's try it:

ccl/lx86cl64 -I ccl-with-swank -e "(swank:create-server :port 4005 :style :spawn :dont-close t)"

which should display a line ;; Swank started at port: 4005.; furthermore, the following command (typed from another terminal window) should show the process lx86cl64 listening on prt 4005:

netstat -tulpn

I usually add the following line in my ~/.bashrc in order to be able to launch the Swank server more easely:

alias swank='~/Documents/Thomas/lisp/ccl/lx86cl64 -I ~/Documents/Thomas/lisp/ccl-with-swank -e "(swank:create-server :port 4005 :style :spawn :dont-close t)"'

Installing the Slimv plugin

Now, the slimv plugin for Vim can be installed with some Plugin manager. In my ~/.vimrc, I add the following lines:

let g:slimv_repl_split=4
let g:paredit_mode=0
let g:slimv_disable_scheme=1
let g:slimv_swank_cmd='! xfce4-terminal -T "Swank" -x ~/Documents/Thomas/lisp/ccl/lx86cl64 -I ~/Documents/Thomas/lisp/ccl-with-swank -e "(swank:create-server :port 4005 :style :spawn :dont-close t)" &'

A first test can be performed:

vim test.lisp

Then, we can type ,c (which should start the Swank server and connect to it); then a simple operation can be tried; type (+ 1 1) in the Vim buffer, switch to normal mode, keep the cursor on this expression and type ,e; the result should be displayed in the other buffer. Close Vim; and kill the Swank server (typing (quit) in the other window is the best way for doing it).

Compile Maxima

We are still in the directory lisp/; we have to install git if it is not installed yet:

sudo apt-get install git

Then:

git clone git://git.code.sf.net/p/maxima/code maxima-code
cd maxima-code/
../ccl/lx86cl64

Type the three following commands:

(load "configure.lisp")
(configure :interactive nil)
(quit)

Then:

cd src
../../ccl/lx86cl64

Type the three following commands:

(load "maxima-build.lisp")
(maxima-compile)
(quit)

Finally we can dump another image containing both Maxima and the Swank server:

../../ccl/lx86cl64

with the following commands:

(load "maxima-build.lisp")
(maxima-load)
(load-quicklisp)
(ql:quickload "swank")
(save-application "../../ccl-with-maxima-and-swank") 

The new image should be in the lisp/ directory:

cd ../..
ls

A low-level test with Vim can already be performed; in the same terminal, type:

ccl/lx86cl64 -I ccl-with-maxima-and-swank -e "(swank:create-server :port 4005 :style :spawn :dont-close t)"

and in another window, type:

vim test.lisp

Then, type ,c for connecting to this already running server; in the Vim buffer, type: #$1+1;$ and then (in normal mode, with the cursor being on this expression): "zyy for yanking the line into the z register; then "z,r for sending the content of the z register to the running Swank server; the result should appear in the second Vim buffer. After that, close Vim and kill the Swank server.

A second alias may be added in the ~/.bashrc file for sending this special Swank server:

alias maxima-swank='~/Documents/Thomas/lisp/ccl/lx86cl64 -I ~/Documents/Thomas/lisp/ccl-with-maxima-and-swank -e "(swank:create-server :port 4005 :style :spawn :dont-close t)"'

Final Vim configuration

First, we have to find the right command for opening a new terminal emulator with this second Swank server running in it; I use:

xfce4-terminal -x ~/Documents/Thomas/lisp/ccl/lx86cl64 -I ~/Documents/Thomas/lisp/ccl-with-maxima-and-swank -e "(swank:create-server :port 4005 :style :spawn :dont-close t)" &

or (with the right title for the window):

xfce4-terminal -T "Maxima/Swank" -x ~/Documents/Thomas/lisp/ccl/lx86cl64 -I ~/Documents/Thomas/lisp/ccl-with-maxima-and-swank -e "(swank:create-server :port 4005 :style :spawn :dont-close t)" &

Now, I want to run Maxima from various documents type (even txt or markdown md files); thus, I add the following command in my ~/.vimrc:

function! MaximaSwank()                                                        
    let g:slimv_swank_cmd='!xfce4-terminal -T "Maxima/Swank" -x ~/Documents/Thomas/lisp/ccl/lx86cl64 -I ~/Documents/Thomas/lisp/ccl-with-maxima-and-swank -e "(swank:create-server :port 4005 :style :spawn :dont-close t)" &'
    " Temporary change the filetype to 'lisp' in order to start slimv          
    let l:b=&filetype                                                          
    set filetype=lisp                                                          
    execute "normal ,c"                                                        
    execute "set filetype=" . l:b    
    let @z="(cl-user::run)"
    execute "normal \"z,r"
endfunc                                                                        
map ,M :call MaximaSwank()<cr>           

which will map the ,M shortcut to a command starting the special Maxima/Swank Lisp image from any document.

The final step is write some macros for Vim allowing to evaluate Maxima expressions.

As a first attempt, the following macro (mapped to my µ key) sends the selected block (in visual mode) to the Maxima interpreter:

map µ "zy"z,r

Another attempt defines the following function:

function! MaximaEvaluate() range                                               
    execute a:firstline . "," . a:lastline . "yank z"                                                          
    execute "normal \"z,r"
endfunc

The functionMaximaEvaluate takes a range of lines for evaluating them:

:1call MaximaEvaluate()
:3,7call MaximaEvaluate()

Of course, more convenient macros can embed MaximaEvaluate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment