Commits

Tamas Kovacs committed 97e610b

Version 0.9.4

Added highlighting of square and curly brackets for Clojure. Added options to disable Slimv for specific filetypes: g:slimv_disable_clojure, g:slimv_disable_lisp, g:slimv_disable_scheme. Added option g:slimv_indent_keylists (thanks to Andrew Smirnoff). Added "set hidden" for safe switching of modified buffers. Added Help to Inspect and Threads buffers. Evaluate register contents if Eval-Region prefixed by ["x]. Store form in register if Eval-Defun or Eval-Exp prefixed by ["x]. Increased timeout for :create-repl. Stay in REPL buffer if Macroexpand performed in REPL. Search for either (in-ns) or (ns) for Clojure, remove quote character from namespace name. Added SlimvEvalTestDefun() and SlimvEvalTestExp() for immediate testing of the form(s) being evaluated. Bugfixes: Various indentation issues (function name is a subform, let, let*, do, defpackage, defsystem, and [] for Clojure). Eval-Range problem in visual mode. SLDB parsing problem with newlines in description of restarts. REPL autoscroll incidentally stopping (thanks to Andrew Lyon). Added some index out of range checks (thanks to Philipp Marek).

Comments (0)

Files changed (7)

-*slimv.txt*                    Slimv                 Last Change: 22 Dec 2011
+*slimv.txt*                    Slimv                 Last Change: 23 Jan 2012
 
 Slimv                                                                  *slimv*
-                               Version 0.9.3
+                               Version 0.9.4
 
 The Superior Lisp Interaction Mode for Vim.
 This plugin is aimed to help Lisp development by interfacing between Vim and
 
 |g:slimv_ctags|              OS command to generate tags file.
 
+|g:slimv_disable_clojure|    Disable Slimv for Clojure files.
+
+|g:slimv_disable_lisp|       Disable Slimv for Lisp files.
+
+|g:slimv_disable_scheme|     Disable Slimv for Scheme files.
+
 |g:slimv_echolines|          Echo only this number of lines from the form
                              being evaluated.
 
 |g:slimv_impl|               The Lisp implementation. Defaults to 'clisp'.
 
+|g:slimv_indent_keylists|    Enable special indentation for keyword lists.
+
 |g:slimv_indent_maxlines|    Maximum number of lines searched backwards for
                              indenting special forms
 
 This means that Slimv will use clisp even if both sbcl and clisp are installed
 and the autodetection would choose sbcl.
 
+                                                      *g:slimv_disable_clojure*
+                                                         *g:slimv_disable_lisp*
+                                                       *g:slimv_disable_scheme*
+If any of these options are set then the Slimv will not be loaded and enabled
+for the corresponding filetype.
+
+Example:
+You want to use Slimv for Lisp but don't want to use it for Scheme:
+    let g:slimv_disable_scheme = 1
+
                                                             *g:slimv_swank_cmd*
                                                         *g:slimv_swank_clojure*
                                                          *g:slimv_swank_scheme*
 If this option is set to zero then no line is echoed at all, if set to -1
 then all lines are always echoed.
 
+                                                      *g:slimv_indent_keylists*
+If nonzero then Slimv indents keyword lists like that:
+
+(:foo :bar
+ :baz :boo)
+
+instead of the function-style indentation:
+
+(:foo :bar
+      :baz :boo)
+
+This option is switched on by default. There are however some special forms
+(defpackage, defsystem) that are always indented in the function-style, e.g.:
+
+(defpackage :my-package
+  (:use :cl
+        :my-utils))
+
                                                       *g:slimv_indent_maxlines*
 Maximum number of lines searched backwards for indenting special forms, like
 flet, labels, macrolet. Setting it to a high value may slow down indenting.
     ,(      ,(t      Paredit Toggle
 
     Evaluation commands:
-    ,d      ,ed      Eval Defun (current top level form)
-    ,e      ,ee      Eval Current Expression (current subform)
-    ,r      ,er      Eval Region (visual selection)
+["x],d  ["x],ed      Eval Defun (current top level form) [put in register x]
+["x],e  ["x],ee      Eval Current Expression (current subform) [put in reg. x]
+["x],r  ["x],er      Eval Region (visual selection) [or text from register x]
     ,b      ,eb      Eval Buffer
     ,v      ,ei      Interactive Eval (evaluates in frame when in SLDB)
     ,u      ,eu      Undefine Function
     ,D      ,cd      Compile Defun
     ,L      ,cl      Compile and Load File
     ,F      ,cf      Compile File
-    ,R      ,cr      Compile Region
+["x],R  ["x],cr      Compile Region [or text from register x]
 
     Cross Reference commands
     ,xc     ,xc      Who Calls
     ,<Down> ,rn      Next Input
     ,z      ,rr      Refresh REPL Buffer
 
+Note:
+Some mappings accept an optional "x prefix (where x is a register name)
+similarly to Vim's p (put) and y (yank) commands. These commands may
+additionally use the given Vim register to store or retrieve text.
+
+Commands "Eval Defun" and "Eval Current Expression" also store the form being
+evaluated in the given register. When using uppercase register name, the
+current form is appended to the contents of the register.
+
+Commands "Eval Region" and "Compile Region" use the contents of the given
+register (instead of the selected region) for evaluation or compilation.
+
+This feature may be used for remembering and recalling a test form used for
+testing parts of the code.
+
+Sample workflow:
+    1. place the cursor on the test form
+    2. "a,d stores the test form in register 'a' and evaluates it
+    3. test fails, bug is in other parts of code, try to fix it
+    4. send fixed code to the swank server the usual way
+    5. "a,r recalls the test form from register 'a' and evaluates it
+    7. repeat steps 3.-5.
+
 
 Also see |slimv-repl| for additional keybindings valid only in the REPL buffer.
 Some menu items or Slimv commands may differ in case Slimv uses the SWANK
 ===============================================================================
 CHANGE LOG                                                    *slimv-changelog*
 
+0.9.4  - Added highlighting of [] and {} for Clojure.
+       - Added options to disable Slimv for specific filetypes:
+         g:slimv_disable_clojure, g:slimv_disable_lisp, g:slimv_disable_scheme.
+       - Added option g:slimv_indent_keylists (thanks to Andrew Smirnoff).
+       - Added "set hidden" for safe switching of modified buffers.
+       - Added Help to Inspect and Threads buffers.
+       - Evaluate register contents if Eval-Region prefixed by ["x].
+       - Store form in register if Eval-Defun or Eval-Exp prefixed by ["x].
+       - Increased timeout for :create-repl.
+       - Stay in REPL buffer if Macroexpand performed in REPL.
+       - Search for either (in-ns) or (ns) for Clojure, remove quote character
+         from namespace name.
+       - Added SlimvEvalTestDefun() and SlimvEvalTestExp() for immediate testing
+         of the form(s) being evaluated.
+       - Bugfix: various indentation issues (function name is a subform,
+         let, let*, do, defpackage, defsystem, and [] for Clojure).
+       - Bugfix: Eval-Range problem in visual mode.
+       - Bugfix: SLDB parsing problem with newlines in description of restarts.
+       - Bugfix: REPL autoscroll incidentally stopping (thanks to Andrew Lyon).
+       - Bugfix: added some index out of range checks (thanks to Philipp Marek).
+
 0.9.3  - Start Swank server in virtual terminal when running in GNU screen
          on Linux (thanks to Oleg Terenchuk).
        - Reuse a window for slimv also when there are three or more windows open.
 Also thanks to Vlad Hanciuta, Marcin Fatyga, Dmitry Petukhov,
 Daniel Solano G�mez, Brian Kropf, Len Weincier, Andreas Salwasser,
 Jon Thacker, Andrew Hills, Jerome Baum, John Obbele, Andreas Fredriksson,
-�mer Sinan Agacan, Tobias Pflug, Chris Cahoon, Mats Rauhala, Oleg Terenchuk
-for additional notes and contributions.
+�mer Sinan Agacan, Tobias Pflug, Chris Cahoon, Mats Rauhala, Oleg Terenchuk,
+Andrew Lyon, Andrew Smirnoff for additional notes and contributions.
 
 I would also like to say a big thank you to everyone donating to support
 development. This is a one-element list at the moment: :)

ftplugin/clojure/slimv-clojure.vim

 " slimv-clojure.vim:
 "               Clojure filetype plugin for Slimv
-" Version:      0.9.3
-" Last Change:  06 Dec 2011
+" Version:      0.9.4
+" Last Change:  07 Jan 2012
 " Maintainer:   Tamas Kovacs <kovisoft at gmail dot com>
 " License:      This file is placed in the public domain.
 "               No warranty, express or implied.
 " =====================================================================
 "
 "  Load Once:
-if exists("b:did_ftplugin")
+if exists("b:did_ftplugin") || exists("g:slimv_disable_clojure")
     finish
 endif
 

ftplugin/lisp/slimv-lisp.vim

 " slimv-lisp.vim:
 "               Lisp filetype plugin for Slimv
-" Version:      0.9.3
-" Last Change:  06 Dec 2011
+" Version:      0.9.4
+" Last Change:  07 Jan 2012
 " Maintainer:   Tamas Kovacs <kovisoft at gmail dot com>
 " License:      This file is placed in the public domain.
 "               No warranty, express or implied.
 " =====================================================================
 "
 "  Load Once:
-if exists("b:did_ftplugin")
+if exists("b:did_ftplugin") || exists("g:slimv_disable_lisp")
+    finish
+endif
+
+" Handle cases when lisp dialects explicitly use the lisp filetype plugins
+if &ft == "clojure" && exists("g:slimv_disable_clojure")
+    finish
+endif
+
+if &ft == "scheme" && exists("g:slimv_disable_scheme")
     finish
 endif
 

ftplugin/scheme/slimv-scheme.vim

 " slimv-scheme.vim:
 "               Scheme filetype plugin for Slimv
-" Version:      0.9.3
-" Last Change:  06 Dec 2011
+" Version:      0.9.4
+" Last Change:  07 Jan 2012
 " Maintainer:   Tamas Kovacs <kovisoft at gmail dot com>
 " License:      This file is placed in the public domain.
 "               No warranty, express or implied.
 " =====================================================================
 "
 "  Load Once:
-if exists("b:did_ftplugin")
+if exists("b:did_ftplugin") || exists("g:slimv_disable_scheme")
     finish
 endif
 

ftplugin/slimv.vim

 " slimv.vim:    The Superior Lisp Interaction Mode for VIM
-" Version:      0.9.3
-" Last Change:  22 Dec 2011
+" Version:      0.9.4
+" Last Change:  22 Jan 2012
 " Maintainer:   Tamas Kovacs <kovisoft at gmail dot com>
 " License:      This file is placed in the public domain.
 "               No warranty, express or implied.
 
 " Maximum number of lines searched backwards for indenting special forms
 if !exists( 'g:slimv_indent_maxlines' )
-    let g:slimv_indent_maxlines = 20
+    let g:slimv_indent_maxlines = 50
+endif
+
+" Special indentation for keyword lists
+if !exists( 'g:slimv_indent_keylists' )
+    let g:slimv_indent_keylists = 1
 endif
 
 " Maximum length of the REPL buffer
                                                           " Skip matches inside string or comment 
 let s:frame_def = '^\s\{0,2}\d\{1,3}:'                    " Regular expression to match SLDB restart or frame identifier
 let s:spec_indent = 'flet\|labels\|macrolet'              " List of symbols need special indenting
+let s:binding_form = 'let\|let\*'                         " List of symbols with binding list
 
 " =====================================================================
 "  General utility functions
 " Position the cursor at the end of the REPL buffer
 " Optionally mark this position in Vim mark 's'
 function! SlimvEndOfReplBuffer()
-    if line( '.' ) >= b:repl_prompt_line
+    if line( '.' ) >= b:repl_prompt_line - 1
         " Go to the end of file only if the user did not move up from here
         normal! G$
     endif
 endfunction
 
 " Execute the given SWANK command, wait for and return the response
-function! SlimvCommandGetResponse( name, cmd )
+function! SlimvCommandGetResponse( name, cmd, timeout )
     let s:refresh_disabled = 1
     call SlimvCommand( a:cmd )
     let msg = ''
     let s:swank_action = ''
     let starttime = localtime()
-    let cmd_timeout = 3
+    let cmd_timeout = a:timeout
+    if cmd_timeout == 0
+        let cmd_timeout = 3
+    endif
     while s:swank_action == '' && localtime()-starttime < cmd_timeout
         python swank_output( 0 )
         redir => msg
     call SlimvOpenBuffer( g:slimv_inspect_name )
     let b:range_start = 0
     let b:range_end   = 0
+    let b:help = SlimvHelpInspect()
 
     " Add keybindings valid only for the Inspect buffer
+    noremap  <buffer> <silent>        <F1>   :call SlimvToggleHelp()<CR>
     noremap  <buffer> <silent>        <CR>   :call SlimvHandleEnterInspect()<CR>
     noremap  <buffer> <silent> <Backspace>   :call SlimvSendSilent(['[-1]'])<CR>
     execute 'noremap <buffer> <silent> ' . g:slimv_leader.'q      :call SlimvQuitInspect()<CR>'
 " Open a new Threads buffer
 function SlimvOpenThreadsBuffer()
     call SlimvOpenBuffer( g:slimv_threads_name )
+    let b:help = SlimvHelpThreads()
 
     " Add keybindings valid only for the Threads buffer
     "noremap  <buffer> <silent>        <CR>   :call SlimvHandleEnterThreads()<CR>
+    noremap  <buffer> <silent>        <F1>                        :call SlimvToggleHelp()<CR>
     noremap  <buffer> <silent> <Backspace>                        :call SlimvKillThread()<CR>
     execute 'noremap <buffer> <silent> ' . g:slimv_leader.'r      :call SlimvListThreads()<CR>'
     execute 'noremap <buffer> <silent> ' . g:slimv_leader.'d      :call SlimvDebugThread()<CR>'
     b #
 endfunction
 
+" Create help text for Inspect buffer
+function SlimvHelpInspect()
+    let help = []
+    call add( help, '<F1>        : toggle this help' )
+    call add( help, '<Enter>     : open object or select action under cursor' )
+    call add( help, '<Backspace> : go back to previous object' )
+    call add( help, g:slimv_leader . 'q          : quit' )
+    return help
+endfunction
+
+" Create help text for Threads buffer
+function SlimvHelpThreads()
+    let help = []
+    call add( help, '<F1>        : toggle this help' )
+    call add( help, '<Backspace> : kill thread' )
+    call add( help, g:slimv_leader . 'k          : kill thread' )
+    call add( help, g:slimv_leader . 'd          : debug thread' )
+    call add( help, g:slimv_leader . 'r          : refresh' )
+    call add( help, g:slimv_leader . 'q          : quit' )
+    return help
+endfunction
+
+" Write help text to current buffer at given line
+function SlimvHelp( line )
+    setlocal noreadonly
+    if exists( 'b:help_shown' )
+        let help = b:help
+    else
+        let help = ['Press <F1> for Help']
+    endif
+    let b:help_line = a:line
+    call append( b:help_line, help )
+    call SlimvEndUpdate()
+endfunction
+
+" Toggle help
+function SlimvToggleHelp()
+    if exists( 'b:help_shown' )
+        let lines = len( b:help )
+        unlet b:help_shown
+    else
+        let lines = 1
+        let b:help_shown = 1
+    endif
+    setlocal noreadonly
+    execute ":" . (b:help_line+1) . "," . (b:help_line+lines) . "d"
+    call SlimvHelp( b:help_line )
+endfunction
+
 " Open SLDB buffer and place cursor on the given frame
 function SlimvGotoFrame( frame )
     call SlimvOpenSldbBuffer()
 
 " Return the contents of register 's'
 function! SlimvGetSelection()
-    return getreg( '"s' )
+    return getreg( 's' )
 endfunction
 
-" Find the given string backwards and put it in front of the current selection
-" if it is a valid Lisp form (i.e. not inside comment or string)
-function! SlimvFindAddSel( string )
+" Find language specific package/namespace definition backwards
+" Set it as the current package for the next swank action
+function! SlimvFindPackage()
+    if !g:slimv_package || SlimvGetFiletype() == 'scheme'
+        return
+    endif
+    let oldpos = getpos( '.' )
+    if SlimvGetFiletype() == 'clojure'
+        let string = '\(in-ns\|ns\)'
+    else
+        let string = '\(cl:\|common-lisp:\|\)in-package'
+    endif
     let found = 0
-    let searching = search( '(\s*' . a:string . '\s', 'bcW' )
+    let searching = search( '(\s*' . string . '\s', 'bcW' )
     while searching
         " Search for the previos occurrence
         if synIDattr( synID( line('.'), col('.'), 0), 'name' ) !~ '[Ss]tring\|[Cc]omment'
             let found = 1
             break
         endif
-        let searching = search( '(\s*' . a:string . '\s', 'bW' )
+        let searching = search( '(\s*' . string . '\s', 'bW' )
     endwhile
     if found
         silent normal! ww
         let l:packagename_tokens = split(expand('<cWORD>'),')\|\s')
         if l:packagename_tokens != []
-            let s:swank_package = l:packagename_tokens[0]
+            " Remove quote character from package name
+            let s:swank_package = substitute( l:packagename_tokens[0], "'", '', '' )
         else
             let s:swank_package = ''
         endif
     endif
-endfunction
-
-" Find and add language specific package/namespace definition before the
-" cursor position and if exists then add it in front of the current selection
-function! SlimvFindPackage()
-    if !g:slimv_package || SlimvGetFiletype() == 'scheme'
-        return
-    endif
-    let oldpos = getpos( '.' )
-    if SlimvGetFiletype() == 'clojure'
-        call SlimvFindAddSel( 'in-ns' )
-    else
-        call SlimvFindAddSel( '\(cl:\|common-lisp:\|\)in-package' )
-    endif
     call setpos( '.', oldpos )
 endfunction
 
             call SlimvSwankResponse()
         endwhile
         if s:swank_version >= '2008-12-23'
-            call SlimvCommandGetResponse( ':create-repl', 'python swank_create_repl()' )
+            call SlimvCommandGetResponse( ':create-repl', 'python swank_create_repl()', g:slimv_timeout )
         endif
         let s:swank_connected = 1
         if g:slimv_simple_compl == 0
     " more than g:slimv_indent_maxlines lines.
     let backline = max([pnum-g:slimv_indent_maxlines, 1])
     let oldpos = getpos( '.' )
+    let indent_keylists = g:slimv_indent_keylists
     " Find beginning of the innermost containing form
+    normal! 0
     let [l, c] = searchpairpos( '(', '', ')', 'bW', s:skip_sc, backline )
     if l > 0
+        if SlimvGetFiletype() == 'clojure'
+            " Is this a clojure form with [] binding list?
+            call setpos( '.', oldpos )
+            let [lb, cb] = searchpairpos( '\[', '', '\]', 'bW', s:skip_sc, backline )
+            if lb >= l && (lb > l || cb > c)
+                call setpos( '.', oldpos )
+                return cb
+            endif
+        endif
         " Is this a form with special indentation?
-        if match( getline(l), '\c^(\s*\('.s:spec_indent.'\)\>', c-1 ) >= 0
+        let line = strpart( getline(l), c-1 )
+        if match( line, '\c^(\s*\('.s:spec_indent.'\)\>' ) >= 0
             " Search for the binding list and jump to its end
             if search( '(' ) > 0
                 exe 'normal! %'
             " second outer containing form (possible start of the binding list)
             let [l2, c2] = searchpairpos( '(', '', ')', 'bW', s:skip_sc, backline )
             if l2 > 0
+                let line2 = strpart( getline(l2), c2-1 )
+                if SlimvGetFiletype() != 'clojure'
+                    if l2 == l && match( line2, '\c^(\s*\('.s:binding_form.'\)\>' ) >= 0
+                        " Is this a lisp form with binding list?
+                        call setpos( '.', oldpos )
+                        return c
+                    endif
+                    if match( line2, '\c^(\s*cond\>' ) >= 0 && match( line, '\c^(\s*t\>' ) >= 0
+                        " Is this the 't' case for a 'cond' form?
+                        call setpos( '.', oldpos )
+                        return c
+                    endif
+                    if match( line2, '\c^(\s*defpackage\>' ) >= 0
+                        let indent_keylists = 0
+                    endif
+                endif
                 " Go one level higher and check if we reached a special form
                 let [l3, c3] = searchpairpos( '(', '', ')', 'bW', s:skip_sc, backline )
                 if l3 > 0
                     " Is this a form with special indentation?
-                    if match( getline(l3), '\c^(\s*\('.s:spec_indent.'\)\>', c3-1 ) >= 0
+                    let line3 = strpart( getline(l3), c3-1 )
+                    if match( line3, '\c^(\s*\('.s:spec_indent.'\)\>' ) >= 0
                         " This is the first body-line of a binding
                         call setpos( '.', oldpos )
                         return c + 1
                     endif
+                    if match( line3, '\c^(\s*defsystem\>' ) >= 0
+                        let indent_keylists = 0
+                    endif
+                    " Finally go to the topmost level to check for some forms with special keyword indenting
+                    let [l4, c4] = searchpairpos( '(', '', ')', 'brW', s:skip_sc, backline )
+                    if l4 > 0
+                        let line4 = strpart( getline(l4), c4-1 )
+                        if match( line4, '\c^(\s*defsystem\>' ) >= 0
+                            let indent_keylists = 0
+                        endif
+                    endif
                 endif
             endif
         endif
 
     " Check if the current form started in the previous nonblank line
     if l == pnum
-        " Found opening paren in the previous line, let's find out the function name
+        " Found opening paren in the previous line
         let line = getline(l)
-        let func = matchstr( line, '\<\k*\>', c )
+        let form = strpart( line, c )
+        " Contract strings, remove comments
+        let form = substitute( form, '".\{-}[^\\]"', '""', 'g' )
+        let form = substitute( form, ';.*$', '', 'g' )
+        " Contract subforms by replacing them with a single character
+        let f = ''
+        while form != f
+            let f = form
+            let form = substitute( form, '([^()]*)',     '0', 'g' )
+            let form = substitute( form, '\[[^\[\]]*\]', '0', 'g' )
+            let form = substitute( form, '{[^{}]*}',     '0', 'g' )
+        endwhile
+        " Find out the function name
+        let func = matchstr( form, '\<\k*\>' )
         " If it's a keyword, keep the indentation straight
-        if strpart(func, 0, 1) == ':'
+        if indent_keylists && strpart(func, 0, 1) == ':'
             return c
         endif
         if SlimvGetFiletype() == 'clojure'
         let func = substitute(func, '^.*:', '', '')
         if func != '' && s:swank_connected
             " Look how many arguments are on the same line
-            let args = strpart( line, c )
-            " Contract strings, remove comments
-            let args = substitute( args, '".\{-}[^\\]"', '""', 'g' )
-            let args = substitute( args, ';.*$', '', 'g' )
-            " Contract subforms by replacing them with a single character
-            let args0 = ''
-            while args != args0
-                let args0 = args
-                let args = substitute( args, '([^()]*)',     'x', 'g' )
-                let args = substitute( args, '\[[^\[\]]*\]', 'x', 'g' )
-                let args = substitute( args, '{[^{}]*}',     'x', 'g' )
-            endwhile
-            " Remove leftover parens and other special characters
-            let args = substitute( args, "[()\\[\\]{}#'`,]", '', 'g' )
-            let args_here = len( split( args ) ) - 1
+            let form = substitute( form, "[()\\[\\]{}#'`,]", '', 'g' )
+            let args_here = len( split( form ) ) - 1
             " Get swank indent info
             let s:indent = ''
             silent execute 'python get_indent_info("' . func . '")'
-            if s:indent == args_here
+            if s:indent != '' && s:indent == args_here
                 " The next one is an &body argument, so indent by 2 spaces from the opening '('
                 return c + 1
             endif
             let arg = matchstr( line, '\<\k*\>', c0 )
             if arg != ''
                 " Ask function argument list from SWANK
-                let msg = SlimvCommandGetResponse( ':operator-arglist', 'python swank_op_arglist("' . arg . '")' )
+                let msg = SlimvCommandGetResponse( ':operator-arglist', 'python swank_op_arglist("' . arg . '")', 0 )
                 if msg != ''
                     " Print argument list in status line with newlines removed.
                     " Disable showmode until the next ESC to prevent
 endfunction
 
 " Get the last region (visual block)
-function! SlimvGetRegion() range
+function! SlimvGetRegion(first, last)
     let oldpos = getpos( '.' ) 
-    if mode() == 'v' || mode() == 'V'
-        let lines = getline( a:firstline, a:lastline )
-        let firstcol = col( a:firstline ) - 1
-        let lastcol  = col( a:lastline  ) - 2
+    if a:first < a:last || ( a:first == line( "'<" ) && a:last == line( "'>" ) )
+        let lines = getline( a:first, a:last )
     else
         " No range was selected, select current paragraph
         normal! vap
             call SlimvError( "No range selected." )
             return []
         endif
-        let firstcol = col( "'<" ) - 1
-        let lastcol  = col( "'>" ) - 2
     endif
+    let firstcol = col( "'<" ) - 1
+    let lastcol  = col( "'>" ) - 2
     if lastcol >= 0
         let lines[len(lines)-1] = lines[len(lines)-1][ : lastcol]
     else
     endif
     let lines[0] = lines[0][firstcol : ]
 
-    " Find and add package/namespace definition in front of the region
-    if g:slimv_package
-        call setreg( '"s', '' )
-        call SlimvFindPackage()
-        let sel = SlimvGetSelection()
-        if sel != ''
-            let lines = [sel] + lines
-        endif
-    endif
+    " Find and set package/namespace definition preceding the region
+    call SlimvFindPackage()
     call setpos( '.', oldpos ) 
     return lines
 endfunction
 
 " Eval buffer lines in the given range
 function! SlimvEvalRegion() range
-    let lines = SlimvGetRegion()
+    if v:register == '"'
+        let lines = SlimvGetRegion(a:firstline, a:lastline)
+    else
+        " Register was passed, so eval register contents instead
+        let reg = getreg( v:register )
+        let ending = s:CloseForm( [reg] )
+        if ending == 'ERROR'
+            call SlimvError( 'Too many or invalid closing parens in register "' . v:register )
+            return
+        endif
+        let lines = [reg . ending]
+    endif
     if lines != []
         call SlimvEval( lines )
     endif
 endfunction
 
-" Eval contents of the 's' register
-function! SlimvEvalSelection()
-    let lines = [SlimvGetSelection()]
+" Eval contents of the 's' register, optionally store it in another register
+" Also optionally add a test form for quick testing (not stored in 'outreg')
+function! SlimvEvalSelection( outreg, testform )
+    let sel = SlimvGetSelection()
+    if a:outreg != '"'
+        " Register was passed, so store current selection in register
+        call setreg( a:outreg, sel )
+    endif
+    let lines = [sel]
+    if a:testform != ''
+        " Append optional test form at the tail
+        let lines = lines + [a:testform]
+    endif
+    if bufnr( "%" ) == bufnr( g:slimv_repl_name )
+        " If this is the REPL buffer then go to EOF
+        normal! G$
+    endif
     call SlimvEval( lines )
 endfunction
 
 "  Special functions
 " =====================================================================
 
-" Evaluate top level form at the cursor pos
-function! SlimvEvalDefun()
+" Evaluate and test top level form at the cursor pos
+function! SlimvEvalTestDefun( testform )
+    let outreg = v:register
     let oldpos = getpos( '.' ) 
     if !SlimvSelectDefun()
         return
     endif
     call SlimvFindPackage()
     call setpos( '.', oldpos ) 
-    call SlimvEvalSelection()
+    call SlimvEvalSelection( outreg, a:testform )
+endfunction
+
+" Evaluate top level form at the cursor pos
+function! SlimvEvalDefun()
+    call SlimvEvalTestDefun( '' )
 endfunction
 
 " Evaluate the whole buffer
     return ''
 endfunction
 
-" Evaluate current s-expression at the cursor pos
-function! SlimvEvalExp()
+" Evaluate and test current s-expression at the cursor pos
+function! SlimvEvalTestExp( testform )
+    let outreg = v:register
     let oldpos = getpos( '.' ) 
     if !SlimvSelectForm()
         return
     endif
     call SlimvFindPackage()
     call setpos( '.', oldpos ) 
-    call SlimvEvalSelection()
+    call SlimvEvalSelection( outreg, a:testform )
+endfunction
+
+" Evaluate current s-expression at the cursor pos
+function! SlimvEvalExp()
+    call SlimvEvalTestExp( '' )
 endfunction
 
 " Evaluate expression entered interactively
         " We are in the debugger, eval expression in the frame the cursor stands on
         let e = input( 'Eval in frame ' . frame . ': ' )
         if e != ''
-            let result = SlimvCommandGetResponse( ':eval-string-in-frame', 'python swank_eval_in_frame("' . e . '", ' . frame . ')' )
+            let result = SlimvCommandGetResponse( ':eval-string-in-frame', 'python swank_eval_in_frame("' . e . '", ' . frame . ')', 0 )
             if result != ''
                 redraw
                 echo result
 
 " ---------------------------------------------------------------------
 
-" General part of the various macroexpand functions
-function! SlimvMacroexpandGeneral( command )
-    call SlimvFindDefunStart()
-    let line = getline( "." )
-    if match( line, '(\s*defmacro\s' ) < 0
-        " The form does not contain 'defmacro', put it in a macroexpand block
-        if !SlimvSelectForm()
-            return
-        endif
-        let m = "(" . a:command . " '" . SlimvGetSelection() . ")"
-    else
-        " The form is a 'defmacro', so do a macroexpand from the macro name and parameters
-        if SlimvGetFiletype() == 'clojure'
-            " Some Vim configs (e.g. matchit.vim) include the trailing ']' after '%' in Visual mode
-            silent normal! vt[%ht]"sy
-        else
-            silent normal! vt(])"sy
-        endif
-        let m = SlimvGetSelection() . '))'
-        let m = substitute( m, "defmacro\\s*", a:command . " '(", 'g' )
-        if SlimvGetFiletype() == 'clojure'
-            " Remove opening bracket from the parameter list
-            " TODO: fix this for multi-line macro header
-            let m = substitute( m, "\\[\\(.*\\)", "\\1", 'g' )
-        else
-            " Remove opening brace from the parameter list
-            " The nice regular expression below says: remove the third '('
-            " ( + something + ( + something + ( + something -> ( + something + ( + something + something
-            " TODO: fix this for multi-line macro header
-            let m = substitute( m, "\\(([^()]*([^()]*\\)(\\(.*\\)", "\\1\\2", 'g' )
-        endif
-    endif
-    return m
-endfunction
-
 " Macroexpand-1 the current top level form
 function! SlimvMacroexpand()
+    call SlimvBeginUpdate()
     if SlimvConnectSwank()
         if !SlimvSelectForm()
             return
         endif
         let s:swank_form = SlimvGetSelection()
+        if bufnr( "%" ) == bufnr( g:slimv_repl_name )
+            " If this is the REPL buffer then go to EOF
+            normal! G$
+        endif
         call SlimvCommandUsePackage( 'python swank_macroexpand("s:swank_form")' )
     endif
 endfunction
 
 " Macroexpand the current top level form
 function! SlimvMacroexpandAll()
+    call SlimvBeginUpdate()
     if SlimvConnectSwank()
         if !SlimvSelectForm()
             return
         endif
         let s:swank_form = SlimvGetSelection()
+        if bufnr( "%" ) == bufnr( g:slimv_repl_name )
+            " If this is the REPL buffer then go to EOF
+            normal! G$
+        endif
         call SlimvCommandUsePackage( 'python swank_macroexpand_all("s:swank_form")' )
     endif
 endfunction
     endif
 endfunction
 
+" Compile buffer lines in the given range
 function! SlimvCompileRegion() range
-    let oldpos = getpos( '.' ) 
-    let lines = SlimvGetRegion()
+    if v:register == '"'
+        let lines = SlimvGetRegion(a:firstline, a:lastline)
+    else
+        " Register was passed, so compile register contents instead
+        let reg = getreg( v:register )
+        let ending = s:CloseForm( [reg] )
+        if ending == 'ERROR'
+            call SlimvError( 'Too many or invalid closing parens in register "' . v:register )
+            return
+        endif
+        let lines = [reg . ending]
+    endif
     if lines == []
         return
     endif
     if !s:swank_connected
         return ''
     endif
-    let arglist = SlimvCommandGetResponse( ':operator-arglist', 'python swank_op_arglist("' . arg . '")' )
+    let arglist = SlimvCommandGetResponse( ':operator-arglist', 'python swank_op_arglist("' . arg . '")', 0 )
     if arglist == ''
         " Not able to fetch arglist, assuming function is not defined
         " Skip calling describe, otherwise SWANK goes into the debugger
         return ''
     endif
-    let msg = SlimvCommandGetResponse( ':describe-function', 'python swank_describe_function("' . arg . '")' )
+    let msg = SlimvCommandGetResponse( ':describe-function', 'python swank_describe_function("' . arg . '")', 0 )
     if msg == ''
         " No describe info, display arglist
         if match( arglist, arg ) != 1
     endif
     if s:swank_connected
         if g:slimv_simple_compl
-            let msg = SlimvCommandGetResponse( ':simple-completions', 'python swank_completions("' . a:base . '")' )
+            let msg = SlimvCommandGetResponse( ':simple-completions', 'python swank_completions("' . a:base . '")', 0 )
         else
-            let msg = SlimvCommandGetResponse( ':fuzzy-completions', 'python swank_fuzzy_completions("' . a:base . '")' )
+            let msg = SlimvCommandGetResponse( ':fuzzy-completions', 'python swank_fuzzy_completions("' . a:base . '")', 0 )
         endif
         if msg != ''
             " We have a completion list from SWANK
     " No completion yet, try to fetch it from the Hyperspec database
     let res = []
     let symbol = b:SlimvHyperspecLookup( a:base, 0, 1 )
+    if symbol == []
+        return []
+    endif
     call sort( symbol )
     for m in symbol
         if m =~ '^' . a:base
         setlocal ballooneval
         setlocal balloonexpr=SlimvDescribe(v:beval_text)
     endif
+    " This is needed for safe switching of modified buffers
+    set hidden
 endfunction
 
 " Edit commands

ftplugin/swank.py

 #
 # SWANK client for Slimv
 # swank.py:     SWANK client code for slimv.vim plugin
-# Version:      0.9.3
-# Last Change:  21 Dec 2011
+# Version:      0.9.4
+# Last Change:  17 Jan 2012
 # Maintainer:   Tamas Kovacs <kovisoft at gmail dot com>
 # License:      This file is placed in the public domain.
 #               No warranty, express or implied.
 debug           = False
 log             = False         # Set this to True in order to enable logging
 logfile         = 'swank.log'   # Logfile name in case logging is on
+pid             = '0'           # Process id
 current_thread  = '0'
 debug_active    = False         # Swank debugger is active
 debug_activated = False         # Swank debugger was activated
                     sys.stdout.write( 'Socket error when receiving from SWANK server.\n' )
                     swank_disconnect()
                     return rec
+                if len(data) == 0:
+                    sys.stdout.write( 'Socket error when receiving from SWANK server.\n' )
+                    swank_disconnect()
+                    return rec
                 rec = rec + data
     rec = ''
 
 
     cur_line = vim.eval('line(".")')
     buf = vim.current.buffer
-    # First 3 lines are filled in swank_parse_inspect()
-    buf[3:] = []
+    # First 2 lines are filled in swank_parse_inspect()
+    buf[2:] = []
     if type(pcont[0]) == list:
         inspect_content = inspect_content + pcont[0]  # Append to the previous content
     istate = pcont[1]
         vim.command(vc)
         vc = ":let b:range_end=" + end
         vim.command(vc)
-        if lst[linestart][0] == '[':
-            lst.append("\n[--more--]")
-        else:
+        if linestart >= 0 and linestart < len(lst) and (len(lst[linestart]) == 0 or lst[linestart][0] != '['):
             lst[linestart:] = "[--more--]"
+        else:
+            lst.append("\n[--more--]")
     buf = vim.current.buffer
+    buf.append([''])
     buf.append("".join(lst).split("\n"))
     buf.append(['', '[<<]'])
     vim.command('normal! ' + cur_line + 'G')
-    vim.command('call SlimvEndUpdate()')
+    vim.command('normal! 3G0')
+    vim.command('call SlimvHelp(2)')
+    vim.command('normal! j')
 
 def swank_parse_inspect(struct):
     """
 
     vim.command('call SlimvOpenInspectBuffer()')
     buf = vim.current.buffer
-    buf[:] = ['Inspecting ' + parse_plist(struct, ':title'), '--------------------', '']
+    buf[:] = ['Inspecting ' + parse_plist(struct, ':title'), '--------------------']
     pcont = parse_plist(struct, ':content')
     inspect_content = []
     swank_parse_inspect_content(pcont)
     for i in range( len(restarts) ):
         r0 = unquote( restarts[i][0] )
         r1 = unquote( restarts[i][1] )
+        r1 = r1.replace("\n", " ")
         buf.append([str(i).rjust(3) + ': [' + r0 + '] ' + r1])
     buf.append(['', 'Backtrace:'])
     for f in frames:
 def swank_parse_list_threads(tl):
     vim.command('call SlimvOpenThreadsBuffer()')
     buf = vim.current.buffer
-    buf[:] = ['Idx  ID    Status                 Name                   Priority', \
-              '---- ----  --------------------   --------------------   ---------']
+    buf[:] = ['Threads in pid '+pid, '--------------------']
+    vim.command('call SlimvHelp(2)')
+    buf.append(['', 'Idx  ID    Status                 Name                   Priority', \
+                    '---- ----  --------------------   --------------------   ---------'])
+    vim.command('normal! G0')
     lst = tl[1]
     headers = lst.pop(0)
     logprint(str(lst))
             priority = unquote(t[3])
         buf.append(["%3d:  %3d  %-22s %-22s %s" % (idx, int(t[0]), unquote(t[2]), unquote(t[1]), priority)])
         idx = idx + 1
+    vim.command('normal! j')
     vim.command('call SlimvEndUpdate()')
 
 def swank_parse_frame_call(struct, action):
     global current_thread
     global prompt
     global package
+    global pid
 
     retval = ''
     msgcount = 0
     swank_rex(':connection-info', '(swank:connection-info)', 'nil', 't')
 
 def swank_create_repl():
-    swank_rex(':create-repl', '(swank:create-repl nil)', 'nil', 't')
+    swank_rex(':create-repl', '(swank:create-repl nil)', get_swank_package(), 't')
 
 def swank_eval(exp):
     cmd = '(swank:listener-eval ' + requote(exp) + ')'
 
 def swank_require(contrib):
     cmd = "(swank:swank-require '" + contrib + ')'
-    swank_rex(':swank-require', cmd, 'nil', ':repl-thread')
+    swank_rex(':swank-require', cmd, 'nil', 't')
 
 def swank_frame_call(frame):
     cmd = '(swank-backend:frame-call ' + frame + ')'

syntax/clojure/slimv-syntax-clojure.vim

 " slimv-syntax-clojure.vim:
 "               Clojure syntax plugin for Slimv
-" Version:      0.8.6
-" Last Change:  09 Aug 2011
+" Version:      0.9.4
+" Last Change:  26 Dec 2011
 " Maintainer:   Tamas Kovacs <kovisoft at gmail dot com>
 " License:      This file is placed in the public domain.
 "               No warranty, express or implied.
 " Add [] and {} to the lisp_rainbow handling
 syn match			 lispSymbol			  contained			   ![^()\[\]{}'`,"; \t]\+!
 syn match			 lispBarSymbol			  contained			   !|..\{-}|!
+syn match			 lispAtom			  "'[^ \t()\[\]{}]\+"		   contains=lispAtomMark
 if exists("g:lisp_rainbow") && g:lisp_rainbow != 0
     syn region lispParen0           matchgroup=hlLevel0 start="`\=\[" end="\]" skip="|.\{-}|" contains=@lispListCluster,lispParen1 
     syn region lispParen1 contained matchgroup=hlLevel1 start="`\=\[" end="\]" skip="|.\{-}|" contains=@lispListCluster,lispParen2