Introduction

Following are some settings used to edit Scheme file with VIM.

Coloring

VIM's default syntax file for Scheme already has some CHICKEN-specific settings, we can enable those by adding the following line into ~/.vim/ftplugin/scheme.vim .

let b:is_chicken=1

But still some annoyances remain.

The following code is a patch to syntax/scheme.vim , you can patch the system-side file, or you can copy it to ~/.vim/syntax , and then patch it. This patch adds S-expression comment and Unix hash-bang support.

--- old-scheme.vim 2008-08-16 09:35:17.000000000 +0800 +++ scheme.vim 2008-08-16 09:34:38.000000000 +0800 @@ -29,6 +29,11 @@ syn match schemeError oneline ![^ \t()\[\]";]*! syn match schemeError oneline ")" +" Add TempStruc before Struc and Quoted. +" although TempStruc will be overwritten by them when do hightlighting, +" it still can be used to delimit a sexp. +syn region schemeTempStruc start="(" end=")" contained transparent contains=schemeTempStruc + " Quoted and backquoted stuff syn region schemeQuoted matchgroup=Delimiter start="['`]" end=![ \t()\[\]";]!me=e-1 contains=ALLBUT,schemeStruc,schemeSyntax,schemeFunc @@ -231,8 +236,13 @@ if exists("b:is_chicken") || exists("is_chicken") + syn match schemeChar oneline "#\\return" + syn match schemeChar oneline "#!eof" + " multiline comment syntax region schemeMultilineComment start=/#|/ end=/|#/ contains=schemeMultilineComment + syn region schemeSexpComment start="#;(" end=")" contains=schemeComment,schemeTempStruc + hi def link schemeSexpComment Comment syn match schemeOther oneline "##[-a-z!$%&*/:<=>?^_~0-9+.@#%]\+" syn match schemeExtSyntax oneline "#:[-a-z!$%&*/:<=>?^_~0-9+.@#%]\+" @@ -268,6 +278,9 @@ " suggested by Alex Queiroz syn match schemeExtSyntax oneline "#![-a-z!$%&*/:<=>?^_~0-9+.@#%]\+" syn region schemeString start=+#<#\s*\z(.*\)+ end=+^\z1$+ + + syn match schemeShebang "^#!/.*csi.*$" + hi def link schemeShebang Comment endif " Synchronization and the wrapping up...

Editing

Completion

VIM's completion functionality can be configured by 'complete' option. There are several useful settings for Scheme editing.

First is the k flag, we can supply a dict file to it. The following code can be used to generate a Scheme dict file.

#!/usr/local/bin/csi -script ( import apropos regex ( chicken sort ) ) ( call-with-output-file "scheme-word-list" ( lambda ( port ) ( for-each ( lambda ( x ) ( display x port ) ( newline port ) ) ( sort ( apropos-list ( regexp ".*" ) #:macros? #t ) ( lambda ( a b ) ( string<? ( symbol->string a ) ( symbol->string b ) ) ) ) ) ) )

Then add the following line to ~/.vim/ftplugin/scheme.vim , and we will be able to complete identifier names using CTRL-P and CTRL-N.

setl complete+=,k~/scheme-word-list

Also when we edit c files, VIM finds words in not only opened buffers, but also included files. These are controlled by the following options.

Likewise, VIM can be configured to find words in files which are mentioned in use or require-extension. In the example below, change the path to match your setup. The follwing lines go into ~/.vim/ftplugin/scheme.vim :

setl include=\^\(\\(use\\\|require-extension\\)\\s\\+ setl includeexpr=substitute(v:fname,'$','.scm','') setl path+=/usr/local/lib/chicken/3 setl suffixesadd=.scm

Indentation

VIM already indents Scheme file well, except it can't recognise some CHICKEN keywords. We just have to add them.

setl lispwords+=let-values,condition-case,with-input-from-string setl lispwords+=with-output-to-string,handle-exceptions,call/cc,rec,receive setl lispwords+=call-with-output-file

Also, put those lines in to scheme.vim .

nmap <silent> == :call Scheme_indent_top_sexp()<cr> " Indent a toplevel sexp. fun! Scheme_indent_top_sexp() let pos = getpos('.') silent! exec "normal! 99[(=%" call setpos('.', pos) endfun

Then we can use == to indent a toplevel S-expression.

Interaction

Vim lacks a cross-platform facility to spawn shells and other commandline programs and interact with them, therefore various methods—or workarounds—have been invented and re-invented over time to address the issue. Each has its own advantages and drawbacks.

Using VimSh

This is a Vim extension written in Python that approximates what most users would consider the "ideal" shell interaction from within a text editor. It can spawn any interactive program from inside Vim, display their output in a new buffer (a Vim window) and receive input on the bottom line of the same buffer. Since it's a Vim buffer you can go into normal mode and move around the buffer, yank, paste, use word completion, etc. (Do understand that changing text and typing newlines in places other than the bottom line will give weird results.)

You will need a Vim built with Python support (:version must contain +python) and an OS with pty support (Windows users are SOL.)

Instructions:

download VimSh

put vimsh.py into ~/.vim

into I prefer to discard the vimsh.vim provided, as it is mostly comments and instructions, and instead put the following in my .vimrc

let g:vimsh_sh="/bin/bash" let g:vimsh_pty_prompt_override=0 let g:vimsh_show_workaround_msgs=0 function! VimShRedraw() redraw endf function! VimShNew() if ! exists("g:vimsh_loaded_python_file") pyfile ~/.vim/vimsh.py let g:vimsh_loaded_python_file=1 endif python spawn_buf('_vimsh_') endf function! VimShRun(text) " Called on a string or on a list of lines " Executes the lines in the VimSh window, one by one " (to allow for secondary prompts and/or incremental evaluation) " Parse argument let t = type(a:text) if t == 1 let lines = split(a:text, '

') elseif t == 3 let lines = a:text else echoerr 'Argument is neither a list nor a string' return endif " Find VimSh window let win = bufwinnr('_vimsh_') if win == -1 echohl WarningMsg echomsg 'Cannot find vimsh window' echohl None return endif " Execute commands exec win . 'wincmd w' for line in lines call setline('$', getline('$') . line) python lookup_buf('_vimsh_').execute_cmd() redraw sleep 1m "why do I need a sleep to apply the redraw? endfor stopinsert wincmd p echo endf function! VimShRunOp(type, ...) " Helper function (copied verbatim from Vim help) let sel_save = &selection let &selection = "inclusive" let reg_save = @@ if a:0 silent exe "normal! `<" . a:type . "`>y" elseif a:type == 'line' silent exe "normal! '[V']y" elseif a:type == 'block' silent exe "normal! `[\<C-V>`]y" else silent exe "normal! `[v`]y" endif call VimShRun(@@) let &selection = sel_save let @@ = reg_save endf nmap Sn :call VimShNew()<CR> nnoremap S :set opfunc=VimShRunOp<CR>g@ vnoremap S :<C-U>call VimShRunOp(visualmode(), 1)<CR> nnoremap SS :call VimShRun(getline('.'))<CR> nnoremap Sf :call VimShRun(getline(1,'$'))<CR> nmap St :norm 99[(<CR>vabS

The code above includes work from various sources and contains a few weird tricks (in other words: here be dragons) It provides several features under the S leading character. Redefining S as Shell (or Send) shouldn't cause problems for most users, as the default Substitute function is just a synonym for Change, but you can alter the mappings if you don't like it.

Sn open a new shell SS or count SS send the current line (or count lines) to the shell S motion send the text over motion to the shell (eg. S3w sends 3 words to the shell) visual mode S send the selected text (either char-, line-, or block-wise selection) Sf send the entire file to the shell St send the current top-level form to the shell

A newline is always added at the end of the text being sent, so as to make the shell execute it. If for some reason you don't want to send a complete command, you will have to use Vim's standard yank & pull (copy & paste) from your editing buffer to the shell buffer.

Care is taken to make the shell react to each individual line as if it was typed interactively. As a result, pasting huge chunks will be a slow operation. You are advised to use a source command in this case: source (or dot) for bash, include for CHICKEN.

Important notice: because of a limitation in Vim, when a line takes more than a given timeout (1/10 of a second) to execute, VimSh returns the command to the editor without waiting for the shell to complete the operation. You will have to manually go to the VimSh buffer every once in a while and hit F5 to refresh the view. This is probably the most annoying drawback of this whole method, but it's not that bad in actuality.

The config block above spawns bash, instead of csi, for several reasons:

to have bash initialize the environment properly

to be able to read any csi fatal errors

to use this framework for other languages / interpreters.

One last thing, you might like this if you're not using it already:

set mousefocus

Using GNU Screen

Another way to add interaction facility to Vim is to use GNU Screen.

With this method the csi process is completely independent (detached) from Vim. It must be started manually, in a Screen session with a specific window title, and remains running after quitting the editor. This can be either an advantage or a disadvantage, depending on your requirements.

Source: Jonathan Palardy.

Put following lines into ftplugin/scheme.vim (make sure that there is no trailing whitespace, especially in the "nmap" lines):

nmap <silent> <leader>es :call Scheme_eval_defun()<cr> nmap <silent> <leader>ef :call Scheme_send_sexp("(load \"" . expand("%:p") . "\")

")<cr> fun! Scheme_send_sexp(sexp) let ss = escape(a:sexp, '\"') call system("screen -p csi -X stuff \"" . ss . "

\"") "(or for tmux users) "call system("tmux send-keys -t csi \"" . ss . "

\"") endfun fun! Scheme_eval_defun() let pos = getpos('.') silent! exec "normal! 99[(yab" call Scheme_send_sexp(@") call setpos('.', pos) endfun

First we create a window in screen with the name of csi and start csi in it. Then open a scheme file, using <leader>es to evaluate a sexp and using <leader>ef to load a file.

Another minimalistic approach is described in the Endoscreen Cut&Paster blogpost.

SWANK / SLIMV

There is a slime client for vim called slimv.

A tutorial screencast on setting it up can be found at vimeo.

REPL : Minimalistic REPL

A vim extension which provides a REPL.