Tamas Kovacs avatar Tamas Kovacs committed 91354b5

Version 0.8.3

Added top/bottom/left/right directions to g:slimv_repl_split, added :Lisp (and an equivalent :Eval) command with completion, added g:slimv_leader and g:paredit_leader options, added g:slimv_echolines to echo only the first few lines of the form being evaluated, added fuzzy completion and option g:slimv_simple_compl (by Philipp Marek), indent macros with &body argument by two spaces when connected to swank (thanks to Philipp Marek and Andreas Fredriksson), special indentation for flet, labels and macrolet, default for Set-Package is current package (thanks to Philipp Marek), bugfixes: REPL output ordering problems, problem with inserting Space into visual block, blinking when g:slimv_repl_syntax is on, entering incomplete form in REPL command line, close form when inside comment, string, or with mixed ([.

Comments (0)

Files changed (7)

-*paredit.txt*                    Slimv               Last Change: 01 May 2011
+*paredit.txt*                    Slimv               Last Change: 09 May 2011
 
 Paredit mode for Slimv                                *paredit* *slimv-paredit*
-                               Version 0.8.2
+                               Version 0.8.3
 
 The paredit.vim plugin performs structured editing of s-expressions used in
 the Lisp or Clojure programming language.
     let g:paredit_mode = 0
 
 You can enable paredit mode for other file types as well. Here is how to set
-it for Scheme files (meant to be added to your .vimrc file):
+it for Arc files (meant to be added to your .vimrc file):
 
-    au BufNewFile,BufRead *.scm call PareditInitBuffer()
+    au BufNewFile,BufRead *.arc call PareditInitBuffer()
 
 It is also possible to use the paredit mode alone, without the other parts of
 Slimv. The easiest way to do it is to delete all Slimv related files from the 
 ===============================================================================
 PAREDIT OPTIONS                                               *paredit-options*
 
+|g:paredit_leader|           Custom <Leader> setting for Paredit.
 |g:paredit_matchlines|       Number of lines to look backward and forward
                              when checking if the current form is balanced.
 
                              Vim commands that are not frequently used.
 
 
+                                                             *g:paredit_leader*
+This option allows a custom <Leader> setting for the Paredit keybindings.
+By default it has the same value as |mapleader|. If neither g:paredit_leader
+nor mapleader are defined then the default <Leader> is "," in Paredit.
+Example:
+    let g:paredit_leader = '\'
+If this is set in the .vimrc then Wrap will be mapped to \W instead of ,W.
+
+There is a separate |g:slimv_leader| option for the general Slimv keybindings.
+
                                                          *g:paredit_matchlines*
 Number of lines to look backward and forward when checking if the current
 top level form is balanced in paredit mode. Default is 100.
                                                           *g:paredit_shortmaps*
 If nonzero, paredit is remapping some one-letter normal mode Vim commands that
 are not frequently used. These are <, >, J, O, W, S. The original function of
-these maps then can be reached via the <Leader> prefix (which is the ","
-character by default in Slimv).
-Otherwise these paredit functions can be reached via the <Leader> prefix.
+these maps then can be reached via <Leader> (which is the "," character
+by default in Paredit).
+Otherwise these paredit functions can be reached via <Leader> maintaining the
+original functions of these keys.
 
 
 ===============================================================================
-*slimv.txt*                    Slimv                 Last Change: 01 May 2011
+*slimv.txt*                    Slimv                 Last Change: 17 May 2011
 
 Slimv                                                                  *slimv*
-                               Version 0.8.2
+                               Version 0.8.3
 
 The Superior Lisp Interaction Mode for Vim.
 This plugin is aimed to help Lisp development by interfacing between Vim and
        ftplugin/lisp/slimv-lisp.vim
        ftplugin/scheme/slimv-scheme.vim
        indent/clojure.vim
+       indent/lisp.vim
        plugin/paredit.vim
        slime/*
        swank-clojure/*
 
 |g:slimv_ctags|              OS command to generate tags file.
 
+|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_javadoc_root|       Base URL for the JavaDoc.
 |g:slimv_keybindings|        Predefined Slimv keybindings. Possible values:
                              1 = set #1, 2 = set #2, other = no keybindings
 
+|g:slimv_leader|             Custom <Leader> setting for Slimv.
+
 |g:slimv_lisp|               Path for the Lisp interpreter.
 
 |g:slimv_menu|               If nonzero, Slimv menu is added to the Vim menu.
   "ctags.exe -a --language-force=lisp *.lisp *.clj"
 
                                                           *g:slimv_keybindings*
-Defines the keybinding set used by Slimv. Value 0 means no keybinding at all.
+Defines the keybinding set used by Slimv.
+Value 0 means no keybinding at all.
 Value 1 defines the short keybinding with one-key bindings (after <Leader>).
+        Example: Eval-Defun is mapped to ,d
 Value 2 defines the easy keybinding with two-key bindings (after <Leader>).
+        Example: Eval-Defun is mapped to ,ed
 Other values mean no predefined keybinding is wanted.
-The <Leader> is set to ',' by default. 
+<Leader> is set to "," by default in Slimv.
+
+                                                               *g:slimv_leader*
+This option allows a custom <Leader> setting for the Slimv keybindings.
+By default it has the same value as |mapleader|. If neither g:slimv_leader nor
+mapleader are defined then the default <Leader> is "," in Slimv.
+Example:
+    let g:slimv_leader = '\'
+If this is set in the .vimrc then Eval-Defun will be mapped to \d instead of ,d.
+
+There is a separate |g:paredit_leader| option for the Paredit keybindings.
 
                                                                  *g:slimv_menu*
 If nonzero then the Slimv menu is added to the end of the global menu.
 at the first evaluation, but any subsequent evaluation will be performed
 silently, with the REPL buffer kept hidden.
 
+It is also possible to define the desired split direction. The following
+values may be used for |g:slimv_repl_open|:
+
+    0: no split
+    1: horizontal split above (default)
+    2: horizontal split below
+    3: vertical split left
+    4: vertical split right
+
                                                            *g:slimv_updatetime*
 The REPL buffer is refreshed at every keystroke or when the user doesn't press
 a key for the time specified with 'updatetime'. Slimv alters the value for
 mode also enables keybindings for cursor movements, so that an <Up> keypress
 will move the cursor one line on the display and not one line in the document.
 
+                                                            *g:slimv_echolines*
+If a long form is evaluated then echo only this number of lines from the
+beginning of the form. This option prevents filling the REPL buffer with
+mostly unnecessary information. Closing parens are added to the end even if
+the end of the form is not echoed, so paren balance is kept.
+If this option is set to zero then all lines are always echoed.
 
                                                             *g:slimv_clhs_root*
                                                           *g:slimv_cljapi_root*
 The default keybindings (|g:slimv_keybindings|=1) and another easy to remember
 built-in keybinding set (|g:slimv_keybindings|=2) for Slimv are the following.
 Please note that the leading ',' key below refers to <Leader>, which is set
-by Slimv to ',' by default.
+by Slimv to ',' by default (see |g:slimv_leader|).
 In the graphical menu the currently active keyboard shortcuts are displayed
 beside the menu item names, so one can refer to the GUI menu as a quick
 reference for the keymappings.
 see |g:slimv_clhs_user_db| and |g:slimv_cljapi_user_db|.
 
 
-Slimv uses the Hyperspec symbol database for symbol name completion, via
-Vim's omni-completion feature (if it is enabled and 'omnifunc' is not
-defined already to something else).
+The SWANK client requests simple or fuzzy completion from the SWANK server,
+see |swank-completions| for details.
+
+Without the SWANK client Slimv uses the Hyperspec symbol database for symbol
+name completion, via Vim's omni-completion feature (if it is enabled and
+'omnifunc' is not defined already to something else).
 Start to enter the symbol in Insert mode, then at some point press the
 <C-X><C-O> (omni-complete) key combination or select the 'Complete Symbol'
 function. The first match in the symbol database is inserted at the cursor
 The indentation is also done via the default lisp.vim indent plugin, or an
 optionally installed Clojure indent plugin, just like for the syntax
 highlighting.
+When using the SWANK client and it is connected to the server, then indentation
+information is fetched from the SWANK server. This allows special indentation
+methods, e.g. when the given macro has an &body argument then it is indented
+by 2 spaces (instead of indenting the second argument below the first one).
+
 There are some built-in Vim reindentation commands that may come very handy
 when editing Lisp files. One can define a custom key mapping for any of them,
 such mappings are not defined by Slimv.
 
-    :set autoindent         Copy indent from current line when starting
-                            a new line.
-
     =                       Reindent selection, after a text has been selected.
 
     ==                      Reindent current line.
 
     99[(v%=                 Select top level form and reindent it.
 
+    gg=G                    Reindent whole file.
+
 
 3. Parenthesis handling
 
 ===============================================================================
 CHANGE LOG                                                    *slimv-changelog*
 
+0.8.3  - Added top/bottom/left/right directions to g:slimv_repl_split.
+       - Added :Lisp (and an equivalent :Eval) command with completion.
+       - Added g:slimv_leader and g:paredit_leader options.
+       - Added g:slimv_echolines to echo only the first few lines of the
+         form being evaluated.
+       - Added fuzzy completion and option g:slimv_simple_compl (by Philipp Marek).
+       - Indent macros with &body argument by two spaces when connected to swank
+         (thanks to Philipp Marek and Andreas Fredriksson).
+       - Special indentation for flet, labels, macrolet.
+       - Default for Set-Package is current package (thanks to Philipp Marek).
+       - Bugfix: REPL output ordering problems.
+       - Bugfix: problem with inserting Space into visual block.
+       - Bugfix: blinking when g:slimv_repl_syntax is on.
+       - Bugfix: entering incomplete form in REPL command line.
+       - Bugfix: close form when inside comment, string, or with mixed ([.
+
 0.8.2  - Added Paredit and g:lisp_rainbow support for Scheme files.
        - Added SWANK support for MIT Scheme on Linux.
        - Added frame call information to SLDB (thanks to Philipp Marek).
 
 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 for additional notes and
-contributions.
+Jon Thacker, Andrew Hills, Jerome Baum, John Obbele, Andreas Fredriksson
+for additional notes and contributions.
 
 Last but not least many thanks to my wife Andrea (for the Italians out there:
 hey, this is a female name in Hungary :) for her support and patience.
-*swank.txt*                    Slimv                 Last Change: 01 May 2011
+*swank.txt*                    Slimv                 Last Change: 17 May 2011
 
 SWANK client for Slimv                                    *swank* *slimv-swank*
-                               Version 0.8.2
+                               Version 0.8.3
 
 The Superior Lisp Interaction Mode for Vim.
 Slimv contains a SWANK client that can communicate with a running SWANK server
   The SWANK server is connected to port 4005 by default. This can be changed
   using the g:swank_port option.
 
+                                                              *g:slimv_balloon*
+  Specifies if tooltips are on (see |swank-describe|).
+
+                                                         *g:slimv_simple_compl*
+  If set to 1, swank:simple-completion is used. By default the fuzzy completion
+  is active, so that "m-v-b<TAB>" expands to "multiple-value-bind" (see
+  |swank-completions|).
+
                                                               *g:slimv_timeout*
   There is a 20 second timeout defined for starting up or connecting to the
   SWANK server. This timeout can be changed via the g:slimv_timeout option.
   timeout too low.
 
 
-                                                              *g:slimv_balloon*
-  Specifies if tooltips are on (see |swank-describe|).
-
-
 ===============================================================================
 FEATURES                                                       *swank-features*
 
   popup menu if there are multiple choices. In the popup menu subsequent <Tab>
   keypresses select the next possible completion.
 
+  Option |g:slimv_simple_compl| determines whether simple or fuzzy completion
+  is used. Default is fuzzy completion.
+
   Note: completions are not displayed when Slimv is not connected to the
-  SWANK server.
+  SWANK server. In this case the Hyperspec database is used for symbol lookup.
 
 
 -------------------------------------------------------------------------------
   :emacs-interrupt
   :emacs-pong
   :emacs-return-string
+  :indentation-update
   swank:compile-file-for-emacs
   swank:compile-string-for-emacs
   swank:connection-info
   swank:disassemble-form
   swank:frame-locals-and-catch-tags
   swank:frame-source-location
+  swank:fuzzy-completions
   swank:init-inspector
   swank:inspect-nth-part
   swank:inspector-call-nth-action
   swank:sldb-continue
   swank:swank-macroexpand-1
   swank:swank-macroexpand-all
+  swank:swank-require
   swank:swank-toggle-trace
   swank:throw-to-toplevel
   swank:toggle-profile-fdefinition

ftplugin/slimv.vim

 " slimv.vim:    The Superior Lisp Interaction Mode for VIM
-" Version:      0.8.2
-" Last Change:  30 Apr 2011
+" Version:      0.8.3
+" Last Change:  17 May 2011
 " Maintainer:   Tamas Kovacs <kovisoft at gmail dot com>
 " License:      This file is placed in the public domain.
 "               No warranty, express or implied.
     let g:slimv_repl_wrap = 1
 endif
 
+" Maximum number of lines echoed from the evaluated form
+if !exists( 'g:slimv_echolines' )
+    let g:slimv_echolines = 4
+endif
+
 " Syntax highlighting for the REPL buffer
 if !exists( 'g:slimv_repl_syntax' )
     let g:slimv_repl_syntax = 0
     let g:slimv_balloon = 1
 endif
 
+" Shall we use simple or fuzzy completion?
+if !exists( 'g:slimv_simple_compl' )
+    let g:slimv_simple_compl = 0
+endif
+
+" Custom <Leader> for the Slimv plugin
+if !exists( 'g:slimv_leader' )
+    if exists( 'mapleader' )
+        let g:slimv_leader = mapleader
+    else
+        let g:slimv_leader = ','
+    endif
+endif
+
 
 " =====================================================================
 "  Template definitions
     \ '(funcall (compile nil (read-from-string (format nil "(~S () ~A)" ' . "'" . 'lambda "%1"))))'
 endif
 
-if !exists( 'mapleader' )
-    let mapleader = ','
-endif
-
 
 " =====================================================================
 "  Other non-global script variables
 
 let s:repl_name = g:slimv_repl_dir . g:slimv_repl_file    " Name of the REPL buffer inside Vim
 let s:prompt = ''                                         " Lisp prompt in the last line
+let s:indent = ''                                         " Most recent indentation info
 let s:last_update = 0                                     " The last update time for the REPL buffer
 let s:last_size = 0                                       " The last size of the REPL buffer
-let s:leader = mapleader                                  " For some reason 'mapleader' is sometimes unreachable
 let s:save_updatetime = &updatetime                       " The original value for 'updatetime'
 let s:save_showmode = &showmode                           " The original value for 'showmode'
 let s:python_initialized = 0                              " Is the embedded Python initialized?
 
 " Handle response coming from the SWANK listener
 function! SlimvSwankResponse()
+    let s:refresh_disabled = 1
+    call SlimvCommand( 'python swank_output()' )
+    let s:refresh_disabled = 0
     let msg = ''
     redir => msg
     silent execute 'python swank_response("")'
     set nomodified
     let s:last_update = localtime()
 
-    syntax on
     if !g:slimv_repl_syntax
         set syntax=
     endif
     let this_win = winnr()
 
     if g:slimv_swank && s:swank_connected
-        "execute 'python swank_output(' . repl_buf . ')'
-        call SlimvCommand( 'python swank_output()' )
         call SlimvSwankResponse()
         return
     endif
     try
         " Check if REPL menu exists, then remove it
         aunmenu REPL
-        unmap <Leader>\
+        execute ':unmap ' . g:slimv_leader . '\'
     catch /.*/
         " REPL menu not found, we cannot remove it
     endtry
     endif
 endfunction
 
+" View the given file in a top/bottom/left/right split window
+function! s:SplitView( filename )
+    if g:slimv_repl_split == 1
+        execute "silent topleft sview! " . a:filename
+    elseif g:slimv_repl_split == 2
+        execute "silent botright sview! " . a:filename
+    elseif g:slimv_repl_split == 3
+        execute "silent topleft vertical sview! " . a:filename
+    elseif g:slimv_repl_split == 4
+        execute "silent botright vertical sview! " . a:filename
+    else
+        execute "silent view! " . a:filename
+    endif
+endfunction
+
 " Open a new REPL buffer or switch to the existing one
 function! SlimvOpenReplBuffer()
     let repl_buf = bufnr( g:slimv_repl_file )
     if repl_buf == -1
         " Create a new REPL buffer
-        if g:slimv_repl_split
-            execute "silent sview! " . s:repl_name
-        else
-            execute "silent view! " . s:repl_name
-        endif
+        call s:SplitView( s:repl_name )
     else
         if g:slimv_repl_split
             " REPL buffer is already created. Check if it is open in a window
             let repl_win = bufwinnr( repl_buf )
             if repl_win == -1
                 " Create windows
-                execute "silent sview! " . s:repl_name
+                call s:SplitView( s:repl_name )
             else
                 " Switch to the REPL window
                 if winnr() != repl_win
     endif
 
     if g:slimv_keybindings == 1
-        noremap <buffer> <silent> <Leader>.      :call SlimvSendCommand(0)<CR>
-        noremap <buffer> <silent> <Leader>/      :call SlimvSendCommand(1)<CR>
-        noremap <buffer> <silent> <Leader><Up>   :call SlimvPreviousCommand()<CR>
-        noremap <buffer> <silent> <Leader><Down> :call SlimvNextCommand()<CR>
-        noremap <buffer> <silent> <Leader>z      :call SlimvRefresh()<CR>
+        execute 'noremap <buffer> <silent> ' . g:slimv_leader.'.      :call SlimvSendCommand(0)<CR>'
+        execute 'noremap <buffer> <silent> ' . g:slimv_leader.'/      :call SlimvSendCommand(1)<CR>'
+        execute 'noremap <buffer> <silent> ' . g:slimv_leader.'<Up>   :call SlimvPreviousCommand()<CR>'
+        execute 'noremap <buffer> <silent> ' . g:slimv_leader.'<Down> :call SlimvNextCommand()<CR>'
+        execute 'noremap <buffer> <silent> ' . g:slimv_leader.'z      :call SlimvRefresh()<CR>'
     elseif g:slimv_keybindings == 2
-        noremap <buffer> <silent> <Leader>rs     :call SlimvSendCommand(0)<CR>
-        noremap <buffer> <silent> <Leader>ro     :call SlimvSendCommand(1)<CR>
-        noremap <buffer> <silent> <Leader>rp     :call SlimvPreviousCommand()<CR>
-        noremap <buffer> <silent> <Leader>rn     :call SlimvNextCommand()<CR>
-        noremap <buffer> <silent> <Leader>rr     :call SlimvRefresh()<CR>
+        execute 'noremap <buffer> <silent> ' . g:slimv_leader.'rs     :call SlimvSendCommand(0)<CR>'
+        execute 'noremap <buffer> <silent> ' . g:slimv_leader.'ro     :call SlimvSendCommand(1)<CR>'
+        execute 'noremap <buffer> <silent> ' . g:slimv_leader.'rp     :call SlimvPreviousCommand()<CR>'
+        execute 'noremap <buffer> <silent> ' . g:slimv_leader.'rn     :call SlimvNextCommand()<CR>'
+        execute 'noremap <buffer> <silent> ' . g:slimv_leader.'rr     :call SlimvRefresh()<CR>'
     endif
 
     if g:slimv_repl_wrap
             " SWANK server is not running, start server if possible
             let swank = SlimvSwankCommand()
             if swank != ''
+                redraw
                 echon "\rStarting SWANK server..."
                 silent execute swank
                 let starttime = localtime()
         endif
         if result == ''
             " Connected to SWANK server
+            redraw
             echon "\rGetting SWANK connection info..."
             let starttime = localtime()
             while s:swank_version == '' && localtime()-starttime < g:slimv_timeout
-                call SlimvCommand( 'python swank_output()' )
                 call SlimvSwankResponse()
             endwhile
             if s:swank_version >= '2008-12-23'
                 python swank_create_repl()
+                call SlimvSwankResponse()
             endif
             let s:swank_connected = 1
+            if g:slimv_simple_compl == 0
+                python swank_require('swank-fuzzy')
+                call SlimvSwankResponse()
+            endif
+            redraw
             echon "\rConnected to SWANK server on port " . g:swank_port . "."
         else
             " Display connection error message
         let s:refresh_disabled = 1
         let s:swank_form = text
         if a:echoing
+            if g:slimv_echolines > 0
+                let nlpos = match( s:swank_form, "\n", 0, g:slimv_echolines )
+                if nlpos > 0
+                    " Echo only the first g:slimv_echolines number of lines
+                    let s:swank_form = strpart( s:swank_form, 0, nlpos ) . " ..."
+                    let end = s:CloseForm( [s:swank_form] )
+                    if end != 'ERROR'
+                        let s:swank_form = s:swank_form . end
+                    endif
+                endif
+            endif
             call SlimvCommand( 'echo s:swank_form' )
+            let s:swank_form = text
         endif
         call SlimvCommand( 'python swank_input("s:swank_form")' )
         let s:swank_package = ''
     endif
 endfunction
 
-" Count the opening and closing parens or brackets to determine if they match
-function! s:GetParenCount( lines )
-    let paren = 0
-    let inside_string = 0
+" Return missing parens, double quotes, etc to properly close form
+function! s:CloseForm( lines )
+    let form = join( a:lines, "\n" )
+    let end = ''
     let i = 0
-    while i < len( a:lines )
-        let inside_comment = 0
-        let j = 0
-        while j < len( a:lines[i] )
-            if inside_string
-                " We are inside a string, skip parens, wait for closing '"'
-                if a:lines[i][j] == '"' && ( j < 1 || a:lines[i][j-1] != '\' )
-                    let inside_string = 0
-                endif
-            elseif inside_comment
-                " We are inside a comment, skip parens, wait for end of line
-            else
-                " We are outside of strings and comments, now we shall count parens
-                if a:lines[i][j] == '"'
-                    let inside_string = 1
-                endif
-                if a:lines[i][j] == ';'
-                    let inside_comment = 1
-                endif
-                if a:lines[i][j] == '(' || a:lines[i][j] == '['
-                    let paren = paren + 1
+    while i < len( form )
+        if form[i] == '"'
+            " Inside a string
+            let end = '"' . end
+            let i += 1
+            while i < len( form )
+                if form[i] == '\'
+                    " Ignore next character
+                    let i += 2
+                elseif form[i] == '"'
+                    let end = end[1:]
+                    break
+                else
+                    let i += 1
                 endif
-                if a:lines[i][j] == ')' || a:lines[i][j] == ']'
-                    let paren = paren - 1
-                    if paren < 0
-                        " Oops, too many closing parens in the middle
-                        return paren
-                    endif
+            endwhile
+        elseif form[i] == ';'
+            " Inside a comment
+            let end = "\n" . end
+            let cend = match(form, "\n", i)
+            if cend == -1
+                break
+            endif
+            let i = cend
+            let end = end[1:]
+        else
+            " We are outside of strings and comments, now we shall count parens
+            if form[i] == '('
+                let end = ')' . end
+            elseif form[i] == '['
+                let end = ']' . end
+            elseif form[i] == ')' || form[i] == ']'
+                if len( end ) == 0 || end[0] != form[i]
+                    " Oops, too many closing parens or invalid closing paren
+                    return 'ERROR'
                 endif
+                let end = end[1:]
             endif
-            let j = j + 1
-        endwhile
-        let i = i + 1
+        endif
+        let i += 1
     endwhile
-    return paren
+    return end
 endfunction
 
+" Return Lisp source code indentation at the given line
+function! SlimvIndent( lnum )
+    if a:lnum <= 1
+        " Start of the file
+        return 0
+    endif
+    let pnum = prevnonblank(a:lnum - 1)
+    if pnum == 0
+        " Hit the start of the file, use zero indent.
+        return 0
+    endif
+    " Use custom indentation only if default indenting is >2
+    let li = lispindent(a:lnum)
+    if li > 2
+        " Find start of current form
+        let [l, c] = searchpairpos( '(', '', ')', 'nbW', s:skip_sc, pnum )
+        " Use custom indentation only if default indenting is >2 from the opening paren in the previous line
+        if l == pnum && li > c + 1
+            let line = getline( l )
+            let parent = strpart( line, 0, c )
+            if match( parent, '\c(\s*\(flet\|labels\|macrolet\)\s*(\s*(\s*$' ) >= 0
+                " Handle special indentation style for flet, labels, etc.
+                return c + 1
+            endif
+            " Found opening paren in the previous line, let's find out the function name
+            let func = matchstr( line, '\<\k*\>', c )
+            if func != '' && g:slimv_swank && s:swank_connected
+                let s:indent = ''
+                silent execute 'python get_indent_info("' . func . '")'
+                if s:indent >= '0' && s:indent <= '9'
+                    " Function has &body argument, so indent by 2 spaces from the opening '('
+                    return c + 1
+                endif
+            endif
+        endif
+    endif
+
+    " Use default Lisp indening
+    return li
+endfunction 
+
 " Send command line to REPL buffer
 " Arguments: close = add missing closing parens
 function! SlimvSendCommand( close )
 
             " Build a possible multi-line command
             let l = lastline + 1
-            while l <= line("$") - 1
+            while l <= line("$")
                 call add( cmd, strpart( getline( l ), 0) )
                 let l = l + 1
             endwhile
 
             " Count the number of opening and closing braces
-            let paren = s:GetParenCount( cmd )
-            if paren > 0 && a:close
-                " Expression is not finished yet, add missing parens and evaluate it
-                while paren > 0
-                    let cmd[len(cmd)-1] = cmd[len(cmd)-1] . ')'
-                    let paren = paren - 1
-                endwhile
+            let end = s:CloseForm( cmd )
+            if end == 'ERROR'
+                " Too many closing parens
+                call SlimvErrorWait( "Too many or invalid closing parens found." )
+                return
+            endif
+            let echoing = 0
+            if a:close && end != ''
+                " Close form if necessary and evaluate it
+                let cmd[len(cmd)-1] = cmd[len(cmd)-1] . end
+                let end = ''
+                let echoing = 1
             endif
-            if paren == 0
+            if end == ''
                 " Expression finished, let's evaluate it
                 " but first add it to the history
                 call SlimvAddHistory( cmd )
-                " Evaluating without echoing
-                call SlimvSend( cmd, g:slimv_repl_open, 0 )
-            elseif paren < 0
-                " Too many closing braces
-                call SlimvErrorWait( "Too many closing parens found." )
+                " Evaluate, but echo only when form is actually closed here
+                call SlimvSend( cmd, g:slimv_repl_open, echoing )
             else
                 " Expression is not finished yet, indent properly and wait for completion
                 " Indentation works only if lisp indentation is switched on
-                let indent = ''
-                let i = lispindent( '.' )
-                while i > 0
-                    let indent = indent . ' '
-                    let i = i - 1
-                endwhile
-                call setline( ".", indent )
-                call SlimvEndOfReplBuffer()
+                let l = line('.') + 1
+                call append( '.', '' )
+                call setline( l, repeat( ' ', SlimvIndent(l) ) )
+                normal! j$
             endif
         endif
     else
         call add( form, getline( l ) )
         let l = l + 1
     endwhile
-    let paren = s:GetParenCount( form )
-    if paren < 0
-        " Too many closing braces
-        call SlimvErrorWait( "Too many closing parens found." )
-    elseif paren > 0
+    let end = s:CloseForm( form )
+    if end == 'ERROR'
+        " Too many closing parens
+        call SlimvErrorWait( "Too many or invalid closing parens found." )
+    elseif end != ''
         " Add missing parens
-        let lastline = getline( l2 )
-        while paren > 0
-            let lastline = lastline . ')'
-            let paren = paren - 1
-        endwhile
-        call setline( l2, lastline )
+        if end[0] == "\n"
+            call append( l2, end[1:] )
+        else
+            call setline( l2, getline( l2 ) . end )
+        endif
     endif
     normal! %
 endfunction
             endif
         endif
     endif
+
+    " Return empty string because this function is called from an insert mode mapping
+    return ''
 endfunction
 
 " Start and connect slimv server
             call SlimvCommandUsePackage( 'python swank_compile_file("' . filename . '")' )
             let starttime = localtime()
             while s:compiled_file == '' && localtime()-starttime < g:slimv_timeout
-                call SlimvCommand( 'python swank_output()' )
                 call SlimvSwankResponse()
             endwhile
             if s:compiled_file != ''
     call SlimvLookup( SlimvSelectSymbol() )
 endfunction
 
+" Complete symbol name starting with 'base'
+function! SlimvComplete( base )
+    " Find all symbols starting with "a:base"
+    if g:slimv_swank && s:swank_connected
+        if g:slimv_simple_compl
+            let msg = SlimvCommandGetResponse( ':simple-completions', 'python swank_completions("' . a:base . '")' )
+        else
+            let msg = SlimvCommandGetResponse( ':fuzzy-completions', 'python swank_fuzzy_completions("' . a:base . '")' )
+        endif
+        if msg != ''
+            " We have a completion list from SWANK
+            let res = split( msg, '\n' )
+            return res
+        endif
+    endif
+
+    " No completion yet, try to fetch it from the Hyperspec database
+    let res = []
+    let symbol = b:SlimvHyperspecLookup( a:base, 0, 1 )
+    call sort( symbol )
+    for m in symbol
+        if m =~ '^' . a:base
+            call add( res, m )
+        endif
+    endfor
+    return res
+endfunction
+
 " Complete function that uses the Hyperspec database
-function! SlimvComplete( findstart, base )
+function! SlimvOmniComplete( findstart, base )
     if a:findstart
         " Locate the start of the symbol name
         if SlimvGetFiletype() == 'clojure'
         let p = match(upto, '\k\+$')
         return p 
     else
-        " Find all symbols starting with "a:base"
-        if g:slimv_swank && s:swank_connected
-            let msg = SlimvCommandGetResponse( ':simple-completions', 'python swank_completions("' . a:base . '")' )
-            if msg != ''
-                " We have a completion list from SWANK
-                let res = split( msg, '\n' )
-                return res
-            endif
-        endif
-
-        " No completion yet, try to fetch it from the Hyperspec database
-        let res = []
-        let symbol = b:SlimvHyperspecLookup( a:base, 0, 1 )
-        call sort( symbol )
-        for m in symbol
-            if m =~ '^' . a:base
-                call add( res, m )
-            endif
-        endfor
-        return res
+        return SlimvComplete( a:base )
     endif
 endfunction
 
 " Define complete function only if none is defined yet
 if &omnifunc == ''
-    set omnifunc=SlimvComplete
+    set omnifunc=SlimvOmniComplete
 endif
 
+" Complete function for user-defined commands
+function! SlimvCommandComplete( arglead, cmdline, cursorpos )
+    " Locate the start of the symbol name
+    if SlimvGetFiletype() == 'clojure'
+        setlocal iskeyword+=~,#,&,\|,{,},!,?
+    else
+        setlocal iskeyword+=~,#,&,\|,{,},[,],!,?
+    endif
+    let upto = strpart( a:cmdline, 0, a:cursorpos )
+    let base = matchstr(upto, '\k\+$')
+    let ext  = matchstr(upto, '\S*\k\+$')
+    let compl = SlimvComplete( base )
+    if len(compl) > 0 && base != ext
+        " Command completion replaces whole word between spaces, so we
+        " need to add any prefix present in front of the keyword, like '('
+        let prefix = strpart( ext, 0, len(ext) - len(base) )
+        let i = 0
+        while i < len(compl)
+            let compl[i] = prefix . compl[i]
+            let i = i + 1
+        endwhile
+    endif
+    return compl
+endfunction
+
 " Set current package
 function! SlimvSetPackage()
     if s:swank_connected
-        let pkg = input( 'Package: ' )
+        let oldpos = getpos( '.' )
+        call SlimvFindPackage()
+        call setpos( '.', oldpos )
+        let pkg = input( 'Package: ', s:swank_package )
         if pkg != ''
             let s:refresh_disabled = 1
             call SlimvCommand( 'python swank_set_package("' . pkg . '")' )
 "  Slimv keybindings
 " =====================================================================
 
-" <Leader> can be set in .vimrc, it defaults here to ','
 " <Leader> timeouts in 1000 msec by default, if this is too short,
 " then increase 'timeoutlen'
 
     if shortcut != ''
         execute "noremap <silent> " . shortcut . " " . a:command
         if a:name != '' && g:slimv_menu == 1
-            let hint = substitute( shortcut, '\c<Leader>', s:leader, "g" )
-            silent execute "amenu " . a:name . "<Tab>" . hint . " " . a:command
+            silent execute "amenu " . a:name . "<Tab>" . shortcut . " " . a:command
         endif
     elseif a:name != '' && g:slimv_menu == 1
         silent execute "amenu " . a:name . " " . a:command
 
 if g:slimv_swank
     " Map space to display function argument list in status line
-    inoremap <silent> <Space>    <Space><C-O>:call SlimvArglist()<CR>
+    inoremap <silent> <Space>    <Space><C-R>=SlimvArglist()<CR>
     "noremap  <silent> <C-C>      :call SlimvInterrupt()<CR>
     au InsertLeave * :let &showmode=s:save_showmode
 endif
 " Edit commands
 inoremap <silent> <C-X>0     <C-O>:call SlimvCloseForm()<CR>
 inoremap <silent> <Tab>      <C-R>=pumvisible() ? "\<lt>C-N>" : "\<lt>C-X>\<lt>C-O>"<CR>
-call s:MenuMap( 'Slim&v.Edi&t.Close-&Form',                     '<Leader>)',  '<Leader>tc',  ':<C-U>call SlimvCloseForm()<CR>' )
-call s:MenuMap( 'Slim&v.Edi&t.&Complete-Symbol<Tab>Tab',        '',           '',            '<Ins><C-X><C-O>' )
-call s:MenuMap( 'Slim&v.Edi&t.&Paredit-Toggle',                 '<Leader>(',  '<Leader>(t',  ':<C-U>call PareditToggle()<CR>' )
+call s:MenuMap( 'Slim&v.Edi&t.Close-&Form',                     g:slimv_leader.')',  g:slimv_leader.'tc',  ':<C-U>call SlimvCloseForm()<CR>' )
+call s:MenuMap( 'Slim&v.Edi&t.&Complete-Symbol<Tab>Tab',        '',                  '',                   '<Ins><C-X><C-O>' )
+call s:MenuMap( 'Slim&v.Edi&t.&Paredit-Toggle',                 g:slimv_leader.'(',  g:slimv_leader.'(t',  ':<C-U>call PareditToggle()<CR>' )
 
 " Evaluation commands
-call s:MenuMap( 'Slim&v.&Evaluation.Eval-&Defun',               '<Leader>d',  '<Leader>ed',  ':<C-U>call SlimvEvalDefun()<CR>' )
-call s:MenuMap( 'Slim&v.&Evaluation.Eval-Current-&Exp',         '<Leader>e',  '<Leader>ee',  ':<C-U>call SlimvEvalExp()<CR>' )
+call s:MenuMap( 'Slim&v.&Evaluation.Eval-&Defun',               g:slimv_leader.'d',  g:slimv_leader.'ed',  ':<C-U>call SlimvEvalDefun()<CR>' )
+call s:MenuMap( 'Slim&v.&Evaluation.Eval-Current-&Exp',         g:slimv_leader.'e',  g:slimv_leader.'ee',  ':<C-U>call SlimvEvalExp()<CR>' )
 if !g:slimv_swank
-call s:MenuMap( 'Slim&v.&Evaluation.&Pprint-Eval-Exp',          '<Leader>E',  '<Leader>ep',  ':<C-U>call SlimvPprintEvalExp()<CR>' )
+call s:MenuMap( 'Slim&v.&Evaluation.&Pprint-Eval-Exp',          g:slimv_leader.'E',  g:slimv_leader.'ep',  ':<C-U>call SlimvPprintEvalExp()<CR>' )
 endif
-call s:MenuMap( 'Slim&v.&Evaluation.Eval-&Region',              '<Leader>r',  '<Leader>er',  ':call SlimvEvalRegion()<CR>' )
-call s:MenuMap( 'Slim&v.&Evaluation.Eval-&Buffer',              '<Leader>b',  '<Leader>eb',  ':<C-U>call SlimvEvalBuffer()<CR>' )
-call s:MenuMap( 'Slim&v.&Evaluation.Interacti&ve-Eval\.\.\.',   '<Leader>v',  '<Leader>ei',  ':call SlimvInteractiveEval()<CR>' )
-call s:MenuMap( 'Slim&v.&Evaluation.&Undefine-Function',        '<Leader>u',  '<Leader>eu',  ':call SlimvUndefineFunction()<CR>' )
+call s:MenuMap( 'Slim&v.&Evaluation.Eval-&Region',              g:slimv_leader.'r',  g:slimv_leader.'er',  ':call SlimvEvalRegion()<CR>' )
+call s:MenuMap( 'Slim&v.&Evaluation.Eval-&Buffer',              g:slimv_leader.'b',  g:slimv_leader.'eb',  ':<C-U>call SlimvEvalBuffer()<CR>' )
+call s:MenuMap( 'Slim&v.&Evaluation.Interacti&ve-Eval\.\.\.',   g:slimv_leader.'v',  g:slimv_leader.'ei',  ':call SlimvInteractiveEval()<CR>' )
+call s:MenuMap( 'Slim&v.&Evaluation.&Undefine-Function',        g:slimv_leader.'u',  g:slimv_leader.'eu',  ':call SlimvUndefineFunction()<CR>' )
 
 " Debug commands
-call s:MenuMap( 'Slim&v.De&bugging.Macroexpand-&1',             '<Leader>1',  '<Leader>m1',  ':<C-U>call SlimvMacroexpand()<CR>' )
-call s:MenuMap( 'Slim&v.De&bugging.&Macroexpand-All',           '<Leader>m',  '<Leader>ma',  ':<C-U>call SlimvMacroexpandAll()<CR>' )
+call s:MenuMap( 'Slim&v.De&bugging.Macroexpand-&1',             g:slimv_leader.'1',  g:slimv_leader.'m1',  ':<C-U>call SlimvMacroexpand()<CR>' )
+call s:MenuMap( 'Slim&v.De&bugging.&Macroexpand-All',           g:slimv_leader.'m',  g:slimv_leader.'ma',  ':<C-U>call SlimvMacroexpandAll()<CR>' )
 
 if g:slimv_swank
-call s:MenuMap( 'Slim&v.De&bugging.Toggle-&Trace\.\.\.',        '<Leader>t',  '<Leader>dt',  ':call SlimvTrace()<CR>' )
-call s:MenuMap( 'Slim&v.De&bugging.U&ntrace-All',               '<Leader>T',  '<Leader>du',  ':call SlimvUntrace()<CR>' )
+call s:MenuMap( 'Slim&v.De&bugging.Toggle-&Trace\.\.\.',        g:slimv_leader.'t',  g:slimv_leader.'dt',  ':call SlimvTrace()<CR>' )
+call s:MenuMap( 'Slim&v.De&bugging.U&ntrace-All',               g:slimv_leader.'T',  g:slimv_leader.'du',  ':call SlimvUntrace()<CR>' )
 else
-call s:MenuMap( 'Slim&v.De&bugging.&Trace\.\.\.',               '<Leader>t',  '<Leader>dt',  ':call SlimvTrace()<CR>' )
-call s:MenuMap( 'Slim&v.De&bugging.U&ntrace\.\.\.',             '<Leader>T',  '<Leader>du',  ':call SlimvUntrace()<CR>' )
+call s:MenuMap( 'Slim&v.De&bugging.&Trace\.\.\.',               g:slimv_leader.'t',  g:slimv_leader.'dt',  ':call SlimvTrace()<CR>' )
+call s:MenuMap( 'Slim&v.De&bugging.U&ntrace\.\.\.',             g:slimv_leader.'T',  g:slimv_leader.'du',  ':call SlimvUntrace()<CR>' )
 endif
 
-call s:MenuMap( 'Slim&v.De&bugging.Disassemb&le\.\.\.',         '<Leader>l',  '<Leader>dd',  ':call SlimvDisassemble()<CR>' )
-call s:MenuMap( 'Slim&v.De&bugging.&Inspect\.\.\.',             '<Leader>i',  '<Leader>di',  ':call SlimvInspect()<CR>' )
+call s:MenuMap( 'Slim&v.De&bugging.Disassemb&le\.\.\.',         g:slimv_leader.'l',  g:slimv_leader.'dd',  ':call SlimvDisassemble()<CR>' )
+call s:MenuMap( 'Slim&v.De&bugging.&Inspect\.\.\.',             g:slimv_leader.'i',  g:slimv_leader.'di',  ':call SlimvInspect()<CR>' )
 
 " Compile commands
-call s:MenuMap( 'Slim&v.&Compilation.Compile-&Defun',           '<Leader>D',  '<Leader>cd',  ':<C-U>call SlimvCompileDefun()<CR>' )
-call s:MenuMap( 'Slim&v.&Compilation.Compile-&Load-File',       '<Leader>L',  '<Leader>cl',  ':<C-U>call SlimvCompileLoadFile()<CR>' )
-call s:MenuMap( 'Slim&v.&Compilation.Compile-&File',            '<Leader>F',  '<Leader>cf',  ':<C-U>call SlimvCompileFile()<CR>' )
-call s:MenuMap( 'Slim&v.&Compilation.Compile-&Region',          '<Leader>R',  '<Leader>cr',  ':call SlimvCompileRegion()<CR>' )
+call s:MenuMap( 'Slim&v.&Compilation.Compile-&Defun',           g:slimv_leader.'D',  g:slimv_leader.'cd',  ':<C-U>call SlimvCompileDefun()<CR>' )
+call s:MenuMap( 'Slim&v.&Compilation.Compile-&Load-File',       g:slimv_leader.'L',  g:slimv_leader.'cl',  ':<C-U>call SlimvCompileLoadFile()<CR>' )
+call s:MenuMap( 'Slim&v.&Compilation.Compile-&File',            g:slimv_leader.'F',  g:slimv_leader.'cf',  ':<C-U>call SlimvCompileFile()<CR>' )
+call s:MenuMap( 'Slim&v.&Compilation.Compile-&Region',          g:slimv_leader.'R',  g:slimv_leader.'cr',  ':call SlimvCompileRegion()<CR>' )
 
 " Xref commands
-call s:MenuMap( 'Slim&v.&Xref.Who-&Calls',                      '<Leader>xc', '<Leader>xc',  ':call SlimvXrefCalls()<CR>' )
-call s:MenuMap( 'Slim&v.&Xref.Who-&References',                 '<Leader>xr', '<Leader>xr',  ':call SlimvXrefReferences()<CR>' )
-call s:MenuMap( 'Slim&v.&Xref.Who-&Sets',                       '<Leader>xs', '<Leader>xs',  ':call SlimvXrefSets()<CR>' )
-call s:MenuMap( 'Slim&v.&Xref.Who-&Binds',                      '<Leader>xb', '<Leader>xb',  ':call SlimvXrefBinds()<CR>' )
-call s:MenuMap( 'Slim&v.&Xref.Who-&Macroexpands',               '<Leader>xm', '<Leader>xm',  ':call SlimvXrefMacroexpands()<CR>' )
-call s:MenuMap( 'Slim&v.&Xref.Who-S&pecializes',                '<Leader>xp', '<Leader>xp',  ':call SlimvXrefSpecializes()<CR>' )
-call s:MenuMap( 'Slim&v.&Xref.&List-Callers',                   '<Leader>xl', '<Leader>xl',  ':call SlimvXrefCallers()<CR>' )
-call s:MenuMap( 'Slim&v.&Xref.List-Call&ees',                   '<Leader>xe', '<Leader>xe',  ':call SlimvXrefCallees()<CR>' )
+call s:MenuMap( 'Slim&v.&Xref.Who-&Calls',                      g:slimv_leader.'xc', g:slimv_leader.'xc',  ':call SlimvXrefCalls()<CR>' )
+call s:MenuMap( 'Slim&v.&Xref.Who-&References',                 g:slimv_leader.'xr', g:slimv_leader.'xr',  ':call SlimvXrefReferences()<CR>' )
+call s:MenuMap( 'Slim&v.&Xref.Who-&Sets',                       g:slimv_leader.'xs', g:slimv_leader.'xs',  ':call SlimvXrefSets()<CR>' )
+call s:MenuMap( 'Slim&v.&Xref.Who-&Binds',                      g:slimv_leader.'xb', g:slimv_leader.'xb',  ':call SlimvXrefBinds()<CR>' )
+call s:MenuMap( 'Slim&v.&Xref.Who-&Macroexpands',               g:slimv_leader.'xm', g:slimv_leader.'xm',  ':call SlimvXrefMacroexpands()<CR>' )
+call s:MenuMap( 'Slim&v.&Xref.Who-S&pecializes',                g:slimv_leader.'xp', g:slimv_leader.'xp',  ':call SlimvXrefSpecializes()<CR>' )
+call s:MenuMap( 'Slim&v.&Xref.&List-Callers',                   g:slimv_leader.'xl', g:slimv_leader.'xl',  ':call SlimvXrefCallers()<CR>' )
+call s:MenuMap( 'Slim&v.&Xref.List-Call&ees',                   g:slimv_leader.'xe', g:slimv_leader.'xe',  ':call SlimvXrefCallees()<CR>' )
 
 " Profile commands
 if g:slimv_swank
-call s:MenuMap( 'Slim&v.&Profiling.Toggle-&Profile\.\.\.',      '<Leader>p',  '<Leader>pp',  ':<C-U>call SlimvProfile()<CR>' )
-call s:MenuMap( 'Slim&v.&Profiling.Profile-&By-Substring\.\.\.','<Leader>B',  '<Leader>pb',  ':<C-U>call SlimvProfileSubstring()<CR>' )
+call s:MenuMap( 'Slim&v.&Profiling.Toggle-&Profile\.\.\.',      g:slimv_leader.'p',  g:slimv_leader.'pp',  ':<C-U>call SlimvProfile()<CR>' )
+call s:MenuMap( 'Slim&v.&Profiling.Profile-&By-Substring\.\.\.',g:slimv_leader.'B',  g:slimv_leader.'pb',  ':<C-U>call SlimvProfileSubstring()<CR>' )
 else
-call s:MenuMap( 'Slim&v.&Profiling.&Load-Profiler',             '<Leader>O',  '<Leader>pl',  ':<C-U>call SlimvLoadProfiler()<CR>' )
-call s:MenuMap( 'Slim&v.&Profiling.&Profile\.\.\.',             '<Leader>p',  '<Leader>pp',  ':<C-U>call SlimvProfile()<CR>' )
-call s:MenuMap( 'Slim&v.&Profiling.&Unprofile\.\.\.',           '<Leader>P',  '<Leader>pu',  ':<C-U>call SlimvUnprofile()<CR>' )
+call s:MenuMap( 'Slim&v.&Profiling.&Load-Profiler',             g:slimv_leader.'O',  g:slimv_leader.'pl',  ':<C-U>call SlimvLoadProfiler()<CR>' )
+call s:MenuMap( 'Slim&v.&Profiling.&Profile\.\.\.',             g:slimv_leader.'p',  g:slimv_leader.'pp',  ':<C-U>call SlimvProfile()<CR>' )
+call s:MenuMap( 'Slim&v.&Profiling.&Unprofile\.\.\.',           g:slimv_leader.'P',  g:slimv_leader.'pu',  ':<C-U>call SlimvUnprofile()<CR>' )
 endif
-call s:MenuMap( 'Slim&v.&Profiling.Unprofile-&All',             '<Leader>U',  '<Leader>pa',  ':<C-U>call SlimvUnprofileAll()<CR>' )
-call s:MenuMap( 'Slim&v.&Profiling.&Show-Profiled',             '<Leader>?',  '<Leader>ps',  ':<C-U>call SlimvShowProfiled()<CR>' )
-call s:MenuMap( 'Slim&v.&Profiling.-ProfilingSep-',             '',           '',            ':' )
-call s:MenuMap( 'Slim&v.&Profiling.Profile-Rep&ort',            '<Leader>o',  '<Leader>pr',  ':<C-U>call SlimvProfileReport()<CR>' )
-call s:MenuMap( 'Slim&v.&Profiling.Profile-&Reset',             '<Leader>X',  '<Leader>px',  ':<C-U>call SlimvProfileReset()<CR>' )
+call s:MenuMap( 'Slim&v.&Profiling.Unprofile-&All',             g:slimv_leader.'U',  g:slimv_leader.'pa',  ':<C-U>call SlimvUnprofileAll()<CR>' )
+call s:MenuMap( 'Slim&v.&Profiling.&Show-Profiled',             g:slimv_leader.'?',  g:slimv_leader.'ps',  ':<C-U>call SlimvShowProfiled()<CR>' )
+call s:MenuMap( 'Slim&v.&Profiling.-ProfilingSep-',             '',                  '',                   ':' )
+call s:MenuMap( 'Slim&v.&Profiling.Profile-Rep&ort',            g:slimv_leader.'o',  g:slimv_leader.'pr',  ':<C-U>call SlimvProfileReport()<CR>' )
+call s:MenuMap( 'Slim&v.&Profiling.Profile-&Reset',             g:slimv_leader.'X',  g:slimv_leader.'px',  ':<C-U>call SlimvProfileReset()<CR>' )
 
 " Documentation commands
-call s:MenuMap( 'Slim&v.&Documentation.Describe-&Symbol',       '<Leader>s',  '<Leader>ds',  ':call SlimvDescribeSymbol()<CR>' )
-call s:MenuMap( 'Slim&v.&Documentation.&Apropos',               '<Leader>a',  '<Leader>da',  ':call SlimvApropos()<CR>' )
-call s:MenuMap( 'Slim&v.&Documentation.&Hyperspec',             '<Leader>h',  '<Leader>dh',  ':call SlimvHyperspec()<CR>' )
-call s:MenuMap( 'Slim&v.&Documentation.Generate-&Tags',         '<Leader>]',  '<Leader>dg',  ':call SlimvGenerateTags()<CR>' )
+call s:MenuMap( 'Slim&v.&Documentation.Describe-&Symbol',       g:slimv_leader.'s',  g:slimv_leader.'ds',  ':call SlimvDescribeSymbol()<CR>' )
+call s:MenuMap( 'Slim&v.&Documentation.&Apropos',               g:slimv_leader.'a',  g:slimv_leader.'da',  ':call SlimvApropos()<CR>' )
+call s:MenuMap( 'Slim&v.&Documentation.&Hyperspec',             g:slimv_leader.'h',  g:slimv_leader.'dh',  ':call SlimvHyperspec()<CR>' )
+call s:MenuMap( 'Slim&v.&Documentation.Generate-&Tags',         g:slimv_leader.']',  g:slimv_leader.'dg',  ':call SlimvGenerateTags()<CR>' )
 
 " REPL commands
-call s:MenuMap( 'Slim&v.&Repl.&Connect-Server',                 '<Leader>c',  '<Leader>rc',  ':call SlimvConnectServer()<CR>' )
+call s:MenuMap( 'Slim&v.&Repl.&Connect-Server',                 g:slimv_leader.'c',  g:slimv_leader.'rc',  ':call SlimvConnectServer()<CR>' )
 if g:slimv_swank
-call s:MenuMap( '',                                             '<Leader>g',  '<Leader>rp',  ':call SlimvSetPackage()<CR>' )
+call s:MenuMap( '',                                             g:slimv_leader.'g',  g:slimv_leader.'rp',  ':call SlimvSetPackage()<CR>' )
 endif
-call s:MenuMap( 'Slim&v.&Repl.Interrup&t-Lisp-Process',         '<Leader>y',  '<Leader>ri',  ':call SlimvInterrupt()<CR>' )
+call s:MenuMap( 'Slim&v.&Repl.Interrup&t-Lisp-Process',         g:slimv_leader.'y',  g:slimv_leader.'ri',  ':call SlimvInterrupt()<CR>' )
 
 
 " =====================================================================
 
 if g:slimv_menu == 1
     " Works only if 'wildcharm' is <Tab>
-    ":map <Leader>, :emenu Slimv.<Tab>
     if &wildcharm == 0
         set wildcharm=<Tab>
     endif
     if &wildcharm != 0
-        execute ':map <Leader>, :emenu Slimv.' . nr2char( &wildcharm )
+        execute ':map ' . g:slimv_leader.', :emenu Slimv.' . nr2char( &wildcharm )
     endif
 endif
 
 " Add REPL menu. This menu exist only for the REPL buffer.
 function SlimvAddReplMenu()
     if &wildcharm != 0
-        execute ':map <Leader>\ :emenu REPL.' . nr2char( &wildcharm )
+        execute ':map ' . g:slimv_leader.'\ :emenu REPL.' . nr2char( &wildcharm )
     endif
 
     amenu &REPL.Send-&Input                            :call SlimvSendCommand(0)<CR>
     amenu &REPL.&Refresh                               :call SlimvRefresh()<CR>
 endfunction
 
+" =====================================================================
+"  Slimv commands
+" =====================================================================
+
+command! -complete=customlist,SlimvCommandComplete -nargs=* Lisp call SlimvEval([<q-args>])
+command! -complete=customlist,SlimvCommandComplete -nargs=* Eval call SlimvEval([<q-args>])
+
 " Switch on syntax highlighting
 syntax on
 

ftplugin/swank.py

 #
 # SWANK client for Slimv
 # swank.py:     SWANK client code for slimv.vim plugin
-# Version:      0.8.2
-# Last Change:  30 Apr 2011
+# Version:      0.8.3
+# Last Change:  17 May 2011
 # Maintainer:   Tamas Kovacs <kovisoft at gmail dot com>
 # License:      This file is placed in the public domain.
 #               No warranty, express or implied.
 prompt          = 'SLIMV'       # Command prompt
 package         = 'COMMON-LISP-USER' # Current package
 actions         = dict()        # Swank actions (like ':write-string'), by message id
+indent_info     = dict()        # Data of :indentation-update
 
 
 ###############################################################################
         f.write(text + '\n')
         f.close()
 
+def logtime(text):
+    logprint(text + ' ' + str(time.clock()))
+
 ###############################################################################
 # Simple Lisp s-expression parser
 ###############################################################################
 def swank_send(text):
     global sock
 
-    logprint('[---Sent---]\n' + text)
+    logtime('[---Sent---]')
+    logprint(text)
     l = hex(len(text))[2:]
     t = '0'*(lenbytes-len(l)) + l + text
     if debug:
         sock.send(t)
     except socket.error:
         sys.stdout.write( 'Socket error when sending to SWANK server.\n' )
-	swank_disconnect()
+        swank_disconnect()
 
 def swank_recv(msglen):
     global sock
     rec = ''
     if msglen > 0:
         sock.setblocking(0)
-        ready = select.select([sock], [], [], 0.1) # 0.1: timeout in seconds
+        ready = select.select([sock], [], [], 0.01) # 0.01: timeout in seconds
         if ready[0]:
             l = msglen
             sock.setblocking(1)
 
     retval = ''
     msgcount = 0
+    #logtime('[- Listen--]')
     while msgcount < maxmessages:
         rec = swank_recv(lenbytes)
         if rec == '':
             print 'Received length:', msglen
         if msglen > 0:
             rec = swank_recv(msglen)
-            logprint('[-Received-]\n' + rec)
+            logtime('[-Received-]')
+            logprint(rec)
             [s, r] = parse_sexpr( rec )
             if debug:
                 print 'Parsed:', r
                     # RERL requests entering a string
                     read_string = r[1:3]
 
+                elif message == ':indentation-update':
+                    for el in r[1]:
+                        indent_info[ unquote(el[0]) ] = el[2]
+
                 elif message == ':new-package':
                     package = unquote( r[1] )
                     prompt  = unquote( r[2] )
                     else:
                         action = None
                     if log:
-                        logprint('[Actionlist]')
+                        logtime('[Actionlist]')
                         for k,a in sorted(actions.items()):
                             if a.pending:
                                 pending = 'pending '
                                     if type(params) == list and type(params[0]) == str and params[0] != 'nil':
                                         compl = "\n".join(params)
                                         retval = retval + compl.replace('"', '')
+                                elif action.name == ':fuzzy-completions':
+                                    if type(params) == list and type(params[0]) == list:
+                                        compl = "\n".join(map(lambda x: x[0], params))
+                                        retval = retval + compl.replace('"', '')
                                 elif action.name == ':xref':
                                     retval = retval + swank_parse_xref(r[1][1])
                                     if len(retval) > 0 and retval[-1] != '\n':
     else:
         return requote(pkg)
 
+def get_indent_info(name):
+    indent = ''
+    if name in indent_info:
+        indent = indent_info[name]
+    vc = ":let s:indent='" + indent + "'"
+    vim.command(vc)
+
 ###############################################################################
 # Various SWANK messages
 ###############################################################################
 
 def swank_connection_info():
+    indent_info.clear()
     swank_rex(':connection-info', '(swank:connection-info)', 'nil', 't')
 
 def swank_create_repl():
 def swank_invoke_continue():
     swank_rex(':sldb-continue', '(swank:sldb-continue)', 'nil', current_thread)
 
+def swank_require(contrib):
+    cmd = "(swank:swank-require '" + contrib + ')'
+    swank_rex(':swank-require', cmd, 'nil', ':repl-thread')
+
 def swank_frame_call(frame):
     cmd = '(swank-backend:frame-call ' + frame + ')'
     swank_rex(':frame-call', cmd, 'nil', current_thread)
     cmd = '(swank:simple-completions "' + symbol + '" "' + package + '")'
     swank_rex(':simple-completions', cmd, 'nil', 't')
 
+def swank_fuzzy_completions(symbol):
+    cmd = '(swank:fuzzy-completions "' + symbol + '" "' + package + '" :limit 200 :time-limit-in-msec 2000)' 
+    swank_rex(':fuzzy-completions', cmd, 'nil', 't')
+
 def swank_undefine_function(fn):
     cmd = '(swank:undefine-function "' + fn + '")'
     swank_rex(':undefine-function', cmd, get_package(), 't')
     return result
 
 def swank_response(name):
+    #logtime('[-Response-]')
     for k,a in sorted(actions.items()):
         if not a.pending and (name == '' or name == a.name):
             vc = ":let s:swank_action='" + a.name + "'"
+" lisp.vim:
+"               Lisp indent plugin for Slimv
+" Version:      0.8.3
+" Last Change:  14 May 2011
+" Maintainer:   Tamas Kovacs <kovisoft at gmail dot com>
+" License:      This file is placed in the public domain.
+"               No warranty, express or implied.
+"               *** ***   Use At-Your-Own-Risk!   *** ***
+"
+" =====================================================================
+"
+"  Load Once:
+if exists("b:did_indent")
+   finish
+endif
+
+setlocal nolisp
+setlocal autoindent
+setlocal indentexpr=SlimvIndent(v:lnum)
+

plugin/paredit.vim

 " paredit.vim:
 "               Paredit mode for Slimv
-" Version:      0.8.2
-" Last Change:  27 Apr 2011
+" Version:      0.8.3
+" Last Change:  09 May 2011
 " Maintainer:   Tamas Kovacs <kovisoft at gmail dot com>
 " License:      This file is placed in the public domain.
 "               No warranty, express or implied.
     let g:paredit_shortmaps = 0
 endif
 
+" Custom <Leader> for the Paredit plugin
+if !exists( 'g:paredit_leader' )
+    if exists( 'mapleader' )
+        let g:paredit_leader = mapleader
+    else
+        let g:paredit_leader = ','
+    endif
+endif
+
 " =====================================================================
 "  Other variable definitions
 " =====================================================================
         nnoremap <buffer> <silent> cc           :<C-U>call PareditChangeLines()<CR>
         nnoremap <buffer> <silent> p            :<C-U>call PareditPut('p')<CR>
         nnoremap <buffer> <silent> P            :<C-U>call PareditPut('P')<CR>
-        nnoremap <buffer> <silent> <Leader>w(   :<C-U>call PareditWrap('(',')')<CR>
-        vnoremap <buffer> <silent> <Leader>w(   :<C-U>call PareditWrapSelection('(',')')<CR>
-        nnoremap <buffer> <silent> <Leader>w[   :<C-U>call PareditWrap('[',']')<CR>
-        vnoremap <buffer> <silent> <Leader>w[   :<C-U>call PareditWrapSelection('[',']')<CR>
-        nnoremap <buffer> <silent> <Leader>w"   :<C-U>call PareditWrap('"','"')<CR>
-        vnoremap <buffer> <silent> <Leader>w"   :<C-U>call PareditWrapSelection('"','"')<CR>
+        execute 'nnoremap <buffer> <silent> ' . g:paredit_leader.'w(  :<C-U>call PareditWrap("(",")")<CR>'
+        execute 'vnoremap <buffer> <silent> ' . g:paredit_leader.'w(  :<C-U>call PareditWrapSelection("(",")")<CR>'
+        execute 'nnoremap <buffer> <silent> ' . g:paredit_leader.'w[  :<C-U>call PareditWrap("[","]")<CR>'
+        execute 'vnoremap <buffer> <silent> ' . g:paredit_leader.'w[  :<C-U>call PareditWrapSelection("[","]")<CR>'
+        execute 'nnoremap <buffer> <silent> ' . g:paredit_leader.'w"  :<C-U>call PareditWrap('."'".'"'."','".'"'."')<CR>"
+        execute 'vnoremap <buffer> <silent> ' . g:paredit_leader.'w"  :<C-U>call PareditWrapSelection('."'".'"'."','".'"'."')<CR>"
 
         if g:paredit_shortmaps
             " Shorter keymaps: old functionality of KEY is remapped to <Leader>KEY
             nnoremap <buffer> <silent> W            :<C-U>call PareditWrap('(',')')<CR>
             vnoremap <buffer> <silent> W            :<C-U>call PareditWrapSelection('(',')')<CR>
             nnoremap <buffer> <silent> S            :<C-U>call PareditSplice()<CR>
-            nnoremap <buffer> <silent> <Leader><    :<C-U>normal! <<CR>
-            nnoremap <buffer> <silent> <Leader>>    :<C-U>normal! ><CR>
-            nnoremap <buffer> <silent> <Leader>O    :<C-U>normal! O<CR>
-            nnoremap <buffer> <silent> <Leader>J    :<C-U>normal! J<CR>
-            nnoremap <buffer> <silent> <Leader>W    :<C-U>normal! W<CR>
-            vnoremap <buffer> <silent> <Leader>W    :<C-U>normal! W<CR>
-            nnoremap <buffer> <silent> <Leader>S    :<C-U>normal! S<CR>
+            execute 'nnoremap <buffer> <silent> ' . g:paredit_leader.'<  :<C-U>normal! <<CR>'
+            execute 'nnoremap <buffer> <silent> ' . g:paredit_leader.'>  :<C-U>normal! ><CR>'
+            execute 'nnoremap <buffer> <silent> ' . g:paredit_leader.'O  :<C-U>normal! O<CR>'
+            execute 'nnoremap <buffer> <silent> ' . g:paredit_leader.'J  :<C-U>normal! J<CR>'
+            execute 'nnoremap <buffer> <silent> ' . g:paredit_leader.'W  :<C-U>normal! W<CR>'
+            execute 'vnoremap <buffer> <silent> ' . g:paredit_leader.'W  :<C-U>normal! W<CR>'
+            execute 'nnoremap <buffer> <silent> ' . g:paredit_leader.'S  :<C-U>normal! S<CR>'
         else
             " Longer keymaps with <Leader> prefix
             nnoremap <buffer> <silent> S            V:<C-U>call PareditChange(visualmode(),1)<CR>
-            nnoremap <buffer> <silent> <Leader><    :<C-U>call PareditMoveLeft()<CR>
-            nnoremap <buffer> <silent> <Leader>>    :<C-U>call PareditMoveRight()<CR>
-            nnoremap <buffer> <silent> <Leader>O    :<C-U>call PareditSplit()<CR>
-            nnoremap <buffer> <silent> <Leader>J    :<C-U>call PareditJoin()<CR>
-            nnoremap <buffer> <silent> <Leader>W    :<C-U>call PareditWrap('(',')')<CR>
-            vnoremap <buffer> <silent> <Leader>W    :<C-U>call PareditWrapSelection('(',')')<CR>
-            nnoremap <buffer> <silent> <Leader>S    :<C-U>call PareditSplice()<CR>
+            execute 'nnoremap <buffer> <silent> ' . g:paredit_leader.'<  :<C-U>call PareditMoveLeft()<CR>'
+            execute 'nnoremap <buffer> <silent> ' . g:paredit_leader.'>  :<C-U>call PareditMoveRight()<CR>'
+            execute 'nnoremap <buffer> <silent> ' . g:paredit_leader.'O  :<C-U>call PareditSplit()<CR>'
+            execute 'nnoremap <buffer> <silent> ' . g:paredit_leader.'J  :<C-U>call PareditJoin()<CR>'
+            execute 'nnoremap <buffer> <silent> ' . g:paredit_leader.'W  :<C-U>call PareditWrap("(",")")<CR>'
+            execute 'vnoremap <buffer> <silent> ' . g:paredit_leader.'W  :<C-U>call PareditWrapSelection("(",")")<CR>'
+            execute 'nnoremap <buffer> <silent> ' . g:paredit_leader.'S  :<C-U>call PareditSplice()<CR>'
         endif
     else
         " Paredit mode is off: remove keybindings
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.