summaryrefslogtreecommitdiff
path: root/vim/bundle/slimv/ftplugin/slimv.vim
diff options
context:
space:
mode:
Diffstat (limited to 'vim/bundle/slimv/ftplugin/slimv.vim')
-rw-r--r--vim/bundle/slimv/ftplugin/slimv.vim3676
1 files changed, 3676 insertions, 0 deletions
diff --git a/vim/bundle/slimv/ftplugin/slimv.vim b/vim/bundle/slimv/ftplugin/slimv.vim
new file mode 100644
index 0000000..bd94155
--- /dev/null
+++ b/vim/bundle/slimv/ftplugin/slimv.vim
@@ -0,0 +1,3676 @@
+" slimv.vim: The Superior Lisp Interaction Mode for VIM
+" Version: 0.9.13
+" Last Change: 18 Jan 2017
+" 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 &cp || exists( 'g:slimv_loaded' )
+ finish
+endif
+
+let g:slimv_loaded = 1
+
+let g:slimv_windows = 0
+let g:slimv_cygwin = 0
+let g:slimv_osx = 0
+
+if has( 'win32' ) || has( 'win95' ) || has( 'win64' ) || has( 'win16' )
+ let g:slimv_windows = 1
+elseif has( 'win32unix' )
+ let g:slimv_cygwin = 1
+elseif has( 'macunix' )
+ let g:slimv_osx = 1
+endif
+
+if ( !exists( 'g:slimv_python_version' ) && has( 'python3' ) ) ||
+\ ( exists( 'g:slimv_python_version' ) && g:slimv_python_version == 3 )
+ let s:py_cmd = 'python3 ' "note space
+ let s:pyfile_cmd = 'py3file '
+else
+ let s:py_cmd = 'python ' "note space
+ let s:pyfile_cmd = 'pyfile '
+endif
+
+
+" =====================================================================
+" Functions used by global variable definitions
+" =====================================================================
+
+" Convert Cygwin path to Windows path, if needed
+function! s:Cygpath( path )
+ let path = a:path
+ if g:slimv_cygwin
+ let path = system( 'cygpath -w ' . path )
+ let path = substitute( path, "\n", "", "g" )
+ let path = substitute( path, "\\", "/", "g" )
+ endif
+ return path
+endfunction
+
+" Find swank.py in the Vim ftplugin directory (if not given in vimrc)
+if !exists( 'g:swank_path' )
+ let plugins = split( globpath( &runtimepath, 'ftplugin/**/swank.py'), '\n' )
+ if len( plugins ) > 0
+ let g:swank_path = s:Cygpath( plugins[0] )
+ else
+ let g:swank_path = 'swank.py'
+ endif
+endif
+
+" Get the filetype (Lisp dialect) used by Slimv
+function! SlimvGetFiletype()
+ if &ft != ''
+ " Return Vim filetype if defined
+ return &ft
+ endif
+
+ if match( tolower( g:slimv_lisp ), 'clojure' ) >= 0 || match( tolower( g:slimv_lisp ), 'clj' ) >= 0
+ " Must be Clojure
+ return 'clojure'
+ endif
+
+ " We have no clue, guess its lisp
+ return 'lisp'
+endfunction
+
+" Try to autodetect SWANK and build the command to start the SWANK server
+function! SlimvSwankCommand()
+ if exists( 'g:slimv_swank_clojure' ) && SlimvGetFiletype() =~ '.*clojure.*'
+ return g:slimv_swank_clojure
+ endif
+ if exists( 'g:slimv_swank_scheme' ) && SlimvGetFiletype() == 'scheme'
+ return g:slimv_swank_scheme
+ endif
+ if exists( 'g:slimv_swank_cmd' )
+ return g:slimv_swank_cmd
+ endif
+
+ if g:slimv_lisp == ''
+ let g:slimv_lisp = input( 'Enter Lisp path (or fill g:slimv_lisp in your vimrc): ', '', 'file' )
+ endif
+
+ let cmd = SlimvSwankLoader()
+ if cmd != ''
+ if g:slimv_windows || g:slimv_cygwin
+ return '!start /MIN ' . cmd
+ elseif g:slimv_osx
+ let result = system('osascript -e "exists application \"iterm\""')
+ if result[:-2] == 'true'
+ let path2as = globpath( &runtimepath, 'ftplugin/**/iterm.applescript')
+ return '!' . path2as . ' ' . cmd
+ else
+ " doubles quotes within 'cmd' need to become '\\\"'
+ return '!osascript -e "tell application \"Terminal\" to do script \"' . escape(escape(cmd, '"'), '\"') . '\""'
+ endif
+ elseif $STY != ''
+ " GNU screen under Linux
+ return "! screen -X eval 'title swank' 'screen " . cmd . "' 'select swank'"
+ elseif $TMUX != ''
+ " tmux under Linux
+ return "! tmux new-window -d -n swank '" . cmd . "'"
+ elseif $DISPLAY == ''
+ " No X, no terminal multiplexer. Cannot run swank server.
+ call SlimvErrorWait( 'No X server. Run Vim from screen/tmux or start SWANK server manually.' )
+ return ''
+ else
+ " Must be Linux
+ return '! SWANK_PORT=' . g:swank_port . ' xterm -iconic -e ' . cmd . ' &'
+ endif
+ endif
+ return ''
+endfunction
+
+" =====================================================================
+" Global variable definitions
+" =====================================================================
+
+" Host name or IP address of the SWANK server
+if !exists( 'g:swank_host' )
+ let g:swank_host = 'localhost'
+endif
+
+" TCP port number to use for the SWANK server
+if !exists( 'g:swank_port' )
+ let g:swank_port = 4005
+endif
+
+" Find Lisp (if not given in vimrc)
+if !exists( 'g:slimv_lisp' )
+ let lisp = ['', '']
+ if exists( 'g:slimv_preferred' )
+ let lisp = SlimvAutodetect( tolower(g:slimv_preferred) )
+ endif
+ if lisp[0] == ''
+ let lisp = SlimvAutodetect( '' )
+ endif
+ let g:slimv_lisp = lisp[0]
+ if !exists( 'g:slimv_impl' )
+ let g:slimv_impl = lisp[1]
+ endif
+endif
+
+" Try to find out the Lisp implementation
+" if not autodetected and not given in vimrc
+if !exists( 'g:slimv_impl' )
+ let g:slimv_impl = SlimvImplementation()
+endif
+
+" REPL buffer name
+if !exists( 'g:slimv_repl_name' )
+ let g:slimv_repl_name = 'REPL'
+endif
+
+" SLDB buffer name
+if !exists( 'g:slimv_sldb_name' )
+ let g:slimv_sldb_name = 'SLDB'
+endif
+
+" INSPECT buffer name
+if !exists( 'g:slimv_inspect_name' )
+ let g:slimv_inspect_name = 'INSPECT'
+endif
+
+" THREADS buffer name
+if !exists( 'g:slimv_threads_name' )
+ let g:slimv_threads_name = 'THREADS'
+endif
+
+" Shall we open REPL buffer in split window?
+if !exists( 'g:slimv_repl_split' )
+ let g:slimv_repl_split = 1
+endif
+
+" Wrap long lines in REPL buffer
+if !exists( 'g:slimv_repl_wrap' )
+ let g:slimv_repl_wrap = 1
+endif
+
+" Wrap long lines in SLDB buffer
+if !exists( 'g:slimv_sldb_wrap' )
+ let g:slimv_sldb_wrap = 0
+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 = 1
+endif
+
+" Specifies the behaviour of insert mode <CR>, <Up>, <Down> in the REPL buffer:
+" 1: <CR> evaluates, <Up>/<Down> brings up command history
+" 0: <C-CR> evaluates, <C-Up>/<C-Down> brings up command history,
+" <CR> opens new line, <Up>/<Down> moves cursor up/down
+if !exists( 'g:slimv_repl_simple_eval' )
+ let g:slimv_repl_simple_eval = 1
+endif
+
+" Alternative value (in msec) for 'updatetime' while the REPL buffer is changing
+if !exists( 'g:slimv_updatetime' )
+ let g:slimv_updatetime = 500
+endif
+
+" Slimv keybinding set (0 = no keybindings)
+if !exists( 'g:slimv_keybindings' )
+ let g:slimv_keybindings = 1
+endif
+
+" Append Slimv menu to the global menu (0 = no menu)
+if !exists( 'g:slimv_menu' )
+ let g:slimv_menu = 1
+endif
+
+" Build the ctags command capable of generating lisp tags file
+" The command can be run with execute 'silent !' . g:slimv_ctags
+if !exists( 'g:slimv_ctags' )
+ let ctags = split( globpath( '$vim,$vimruntime', 'ctags.exe' ), '\n' )
+ if len( ctags ) > 0
+ " Remove -a option to regenerate every time
+ let g:slimv_ctags = '"' . ctags[0] . '" -a --language-force=lisp *.lisp *.clj'
+ endif
+endif
+
+" Name of tags file used by slimv for find-definitions
+" If this is the empty string then no tags file is used
+if !exists( 'g:slimv_tags_file' )
+ let g:slimv_tags_file = tempname()
+endif
+
+" Prepend tags file to the tags list
+if g:slimv_tags_file != ''
+ if &tags == ''
+ let &tags=g:slimv_tags_file
+ else
+ let &tags=g:slimv_tags_file . ',' . &tags
+ endif
+endif
+
+" Package/namespace handling
+if !exists( 'g:slimv_package' )
+ let g:slimv_package = 1
+endif
+
+" General timeout for various startup and connection events (seconds)
+if !exists( 'g:slimv_timeout' )
+ let g:slimv_timeout = 20
+endif
+
+" Use balloonexpr to display symbol description
+if !exists( 'g:slimv_balloon' )
+ 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' ) && mapleader != ' '
+ let g:slimv_leader = mapleader
+ else
+ let g:slimv_leader = ','
+ endif
+endif
+
+" Maximum number of lines searched backwards for indenting special forms
+if !exists( 'g:slimv_indent_maxlines' )
+ 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
+if !exists( 'g:slimv_repl_max_len' )
+ let g:slimv_repl_max_len = 0
+endif
+
+" =====================================================================
+" Template definitions
+" =====================================================================
+
+if !exists( 'g:slimv_template_apropos' )
+ if SlimvGetFiletype() =~ '.*clojure.*'
+ let g:slimv_template_apropos = '(find-doc "%1")'
+ else
+ let g:slimv_template_apropos = '(apropos "%1")'
+ endif
+endif
+
+
+" =====================================================================
+" Other non-global script variables
+" =====================================================================
+
+let s:indent = '' " Most recent indentation info
+let s:last_update = 0 " The last update time for the REPL buffer
+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?
+let s:swank_version = '' " SWANK server version string
+let s:swank_connected = 0 " Is the SWANK server connected?
+let s:swank_package = '' " Package to use at the next SWANK eval
+let s:swank_package_form = '' " The entire form that was used to set current package
+let s:swank_form = '' " Form to send to SWANK
+let s:refresh_disabled = 0 " Set this variable temporarily to avoid recursive REPL rehresh calls
+let s:sldb_level = -1 " Are we in the SWANK debugger? -1 == no, else SLDB level
+let s:break_on_exception = 0 " Enable debugger break on exceptions (for ritz-swank)
+let s:compiled_file = '' " Name of the compiled file
+let s:win_id = 0 " Counter for generating unique window id
+let s:repl_buf = -1 " Buffer number for the REPL buffer
+let s:current_buf = -1 " Swank action was requested from this buffer
+let s:current_win = 0 " Swank action was requested from this window
+let s:read_string_mode = 0 " Read string mode indicator
+let s:arglist_line = 0 " Arglist was requested in this line ...
+let s:arglist_col = 0 " ... and column
+let s:inspect_path = [] " Inspection path of the current object
+let s:skip_sc = 'synIDattr(synID(line("."), col("."), 0), "name") =~ "[Ss]tring\\|[Cc]omment"'
+ " Skip matches inside string or comment
+let s:skip_q = 'getline(".")[col(".")-2] == "\\"' " Skip escaped double quote characters in matches
+let s:frame_def = '^\s\{0,2}\d\{1,}:' " Regular expression to match SLDB restart or frame identifier
+let s:spec_indent = 'flet\|labels\|macrolet\|symbol-macrolet'
+ " List of symbols need special indenting
+let s:spec_param = 'defmacro' " List of symbols with special parameter list
+let s:binding_form = 'let\|let\*' " List of symbols with binding list
+
+" =====================================================================
+" General utility functions
+" =====================================================================
+
+" Check that current SWANK version is same or newer than the given parameter
+function! s:SinceVersion( ver )
+ " Before ver 2.18 SWANK version string was a date of form YYYY-MM-DD
+ if len( a:ver ) >= 8
+ " Checking for old style version string YYYY-MM-DD
+ if len( s:swank_version ) < 8
+ " Current version is new style -> must be newer than the one we are checking for
+ return 1
+ endif
+ else
+ " Checking for new style version string X.XX
+ if len( s:swank_version ) >= 8
+ " Current version is old style -> must be older than the one we are checking for
+ return 0
+ endif
+ endif
+ if s:swank_version >= a:ver
+ return 1
+ else
+ return 0
+ endif
+endfunction
+
+" Display an error message
+function! SlimvError( msg )
+ echohl ErrorMsg
+ echo a:msg
+ echohl None
+endfunction
+
+" Display an error message and a question, return user response
+function! SlimvErrorAsk( msg, question )
+ echohl ErrorMsg
+ let answer = input( a:msg . a:question )
+ echo ""
+ echohl None
+ return answer
+endfunction
+
+" Display an error message and wait for ENTER
+function! SlimvErrorWait( msg )
+ call SlimvErrorAsk( a:msg, " Press ENTER to continue." )
+endfunction
+
+" Shorten long messages to fit status line
+function! SlimvShortEcho( msg )
+ let saved=&shortmess
+ set shortmess+=T
+ exe "normal :echomsg a:msg\n"
+ let &shortmess=saved
+endfunction
+
+" Go to the end of buffer, make sure the cursor is positioned
+" after the last character of the buffer when in insert mode
+function s:EndOfBuffer()
+ normal! G$
+ if &virtualedit != 'all'
+ call cursor( line('$'), 99999 )
+ endif
+endfunction
+
+" Position the cursor at the end of the REPL buffer
+" Optionally mark this position in Vim mark 's'
+function! SlimvEndOfReplBuffer( force )
+ if line( '.' ) >= b:repl_prompt_line - 1 || a:force
+ " Go to the end of file only if the user did not move up from here
+ call s:EndOfBuffer()
+ endif
+endfunction
+
+" Remember the end of the REPL buffer: user may enter commands here
+" Also remember the prompt, because the user may overwrite it
+function! SlimvMarkBufferEnd( force )
+ if exists( 'b:slimv_repl_buffer' )
+ setlocal nomodified
+ call SlimvEndOfReplBuffer( a:force )
+ let b:repl_prompt_line = line( '$' )
+ let b:repl_prompt_col = len( getline('$') ) + 1
+ let b:repl_prompt = getline( b:repl_prompt_line )
+ endif
+endfunction
+
+" Get REPL prompt line. Fix stored prompt position when corrupted
+" (e.g. some lines were deleted from the REPL buffer)
+function! s:GetPromptLine()
+ if b:repl_prompt_line > line( '$' )
+ " Stored prompt line is corrupt
+ let b:repl_prompt_line = line( '$' )
+ let b:repl_prompt_col = len( getline('$') ) + 1
+ let b:repl_prompt = getline( b:repl_prompt_line )
+ endif
+ return b:repl_prompt_line
+endfunction
+
+" Generate unique window id for the current window
+function s:MakeWindowId()
+ if g:slimv_repl_split && !exists('w:id')
+ let s:win_id = s:win_id + 1
+ let w:id = s:win_id
+ endif
+endfunction
+
+" Find and switch to window with the specified window id
+function s:SwitchToWindow( id )
+ for winnr in range( 1, winnr('$') )
+ if getwinvar( winnr, 'id' ) is a:id
+ execute winnr . "wincmd w"
+ endif
+ endfor
+endfunction
+
+" Save caller buffer identification
+function! SlimvBeginUpdate()
+ call s:MakeWindowId()
+ let s:current_buf = bufnr( "%" )
+ let s:current_win = getwinvar( winnr(), 'id' )
+endfunction
+
+" Switch to the buffer/window that was active before a swank action
+function! SlimvRestoreFocus( hide_current_buf )
+ if exists("b:previous_buf")
+ let new_buf = b:previous_buf
+ let new_win = b:previous_win
+ else
+ let new_buf = s:current_buf
+ let new_win = s:current_win
+ endif
+ let buf = bufnr( "%" )
+ let win = getwinvar( winnr(), 'id' )
+ if a:hide_current_buf
+ set nobuflisted
+ b #
+ endif
+ if winnr('$') > 1 && new_win != '' && new_win != win
+ " Switch to the caller window
+ call s:SwitchToWindow( new_win )
+ endif
+ if new_buf >= 0 && buf != new_buf
+ " Switch to the caller buffer
+ execute "buf " . new_buf
+ endif
+endfunction
+
+" Handle response coming from the SWANK listener
+function! SlimvSwankResponse()
+ let s:swank_ok_result = ''
+ let s:refresh_disabled = 1
+ silent execute s:py_cmd . 'swank_output(1)'
+ let s:refresh_disabled = 0
+ let s:swank_action = ''
+ let s:swank_result = ''
+ silent execute s:py_cmd . 'swank_response("")'
+
+ if s:swank_action == ':describe-symbol' && s:swank_result != ''
+ echo substitute(s:swank_result,'^\n*','','')
+ elseif s:swank_ok_result != ''
+ " Display the :ok result also in status bar in case the REPL buffer is not shown
+ let s:swank_ok_result = substitute(s:swank_ok_result,"\<LF>",'','g')
+ if s:swank_ok_result == ''
+ call SlimvShortEcho( '=> OK' )
+ else
+ call SlimvShortEcho( '=> ' . s:swank_ok_result )
+ endif
+ endif
+ if s:swank_actions_pending
+ let s:last_update = -1
+ elseif s:last_update < 0
+ " Remember the time when all actions are processed
+ let s:last_update = localtime()
+ endif
+ if s:swank_actions_pending == 0 && s:last_update >= 0 && s:last_update < localtime() - 2
+ " All SWANK output handled long ago, restore original update frequency
+ let &updatetime = s:save_updatetime
+ else
+ " SWANK output still pending, keep higher update frequency
+ let &updatetime = g:slimv_updatetime
+ endif
+endfunction
+
+" Execute the given command and write its output at the end of the REPL buffer
+function! SlimvCommand( cmd )
+ silent execute a:cmd
+ if g:slimv_updatetime < &updatetime
+ " Update more frequently until all swank responses processed
+ let &updatetime = g:slimv_updatetime
+ let s:last_update = -1
+ endif
+endfunction
+
+" Execute the given SWANK command, wait for and return the response
+function! SlimvCommandGetResponse( name, cmd, timeout )
+ let s:refresh_disabled = 1
+ call SlimvCommand( a:cmd )
+ let s:swank_action = ''
+ let s:swank_result = ''
+ let starttime = localtime()
+ let cmd_timeout = a:timeout
+ if cmd_timeout == 0
+ let cmd_timeout = 3
+ endif
+ while s:swank_action == '' && localtime()-starttime < cmd_timeout
+ execute s:py_cmd . "swank_output( 0 )"
+ silent execute s:py_cmd . 'swank_response("' . a:name . '")'
+ endwhile
+ let s:refresh_disabled = 0
+ return s:swank_result
+endfunction
+
+" Reload the contents of the REPL buffer from the output file if changed
+function! SlimvRefreshReplBuffer()
+ if s:refresh_disabled
+ " Refresh is unwanted at the moment, probably another refresh is going on
+ return
+ endif
+
+ if s:repl_buf == -1
+ " REPL buffer not loaded
+ return
+ endif
+
+ if s:swank_connected
+ call SlimvSwankResponse()
+ endif
+
+ if exists("s:input_prompt") && s:input_prompt != ''
+ let answer = input( s:input_prompt )
+ unlet s:input_prompt
+ echo ""
+ call SlimvCommand( s:py_cmd . 'swank_return("' . answer . '")' )
+ endif
+endfunction
+
+" This function re-triggers the CursorHold event
+" after refreshing the REPL buffer
+function! SlimvTimer()
+ if v:count > 0
+ " Skip refreshing if the user started a command prefixed with a count
+ return
+ endif
+ " We don't want autocommands trigger during the quick switch to/from the REPL buffer
+ noautocmd call SlimvRefreshReplBuffer()
+ if mode() == 'i' || mode() == 'I' || mode() == 'r' || mode() == 'R'
+ if bufname('%') != g:slimv_sldb_name && bufname('%') != g:slimv_inspect_name && bufname('%') != g:slimv_threads_name
+ " Put '<Insert>' twice into the typeahead buffer, which should not do anything
+ " just switch to replace/insert mode then back to insert/replace mode
+ " But don't do this for readonly buffers
+ call feedkeys("\<insert>\<insert>")
+ endif
+ else
+ " Put an incomplete 'f' command and an Esc into the typeahead buffer
+ call feedkeys("f\e", 'n')
+ endif
+endfunction
+
+" Switch refresh mode on:
+" refresh REPL buffer on frequent Vim events
+function! SlimvRefreshModeOn()
+ augroup SlimvCursorHold
+ au!
+ execute "au CursorHold * :call SlimvTimer()"
+ execute "au CursorHoldI * :call SlimvTimer()"
+ augroup END
+endfunction
+
+" Switch refresh mode off
+function! SlimvRefreshModeOff()
+ augroup SlimvCursorHold
+ au!
+ augroup END
+endfunction
+
+" Called when entering REPL buffer
+function! SlimvReplEnter()
+ call SlimvAddReplMenu()
+ augroup SlimvReplChanged
+ au!
+ execute "au FileChangedRO " . g:slimv_repl_name . " :call SlimvRefreshModeOff()"
+ augroup END
+ call SlimvRefreshModeOn()
+endfunction
+
+" Called when leaving REPL buffer
+function! SlimvReplLeave()
+ try
+ " Check if REPL menu exists, then remove it
+ aunmenu REPL
+ execute ':unmap ' . g:slimv_leader . '\'
+ catch /.*/
+ " REPL menu not found, we cannot remove it
+ endtry
+ if g:slimv_repl_split
+ call SlimvRefreshModeOn()
+ else
+ call SlimvRefreshModeOff()
+ endif
+endfunction
+
+" Refresh cursor position in the REPL buffer after new lines appended
+function! SlimvReplSetCursorPos( force )
+ " We do not want these autocommands to fire, the buffer switch will be temporary
+ let savemark = getpos("'`'")
+ let save_ei = &eventignore
+ set eventignore=BufEnter,BufLeave,BufWinEnter
+ let win = winnr()
+ windo call SlimvMarkBufferEnd( a:force )
+ execute win . "wincmd w"
+ let &eventignore = save_ei
+ call setpos("'`", savemark)
+endfunction
+
+" View the given file in a top/bottom/left/right split window
+function! s:SplitView( filename )
+ " Check if we have at least two windows used by slimv (have a window id assigned)
+ let winnr1 = 0
+ let winnr2 = 0
+ for winnr in range( 1, winnr('$') )
+ if getwinvar( winnr, 'id' ) != ''
+ let winnr2 = winnr1
+ let winnr1 = winnr
+ endif
+ endfor
+ if winnr1 > 0 && winnr2 > 0
+ " We have already at least two windows used by slimv
+ let winid = getwinvar( winnr(), 'id' )
+ if bufnr("%") == s:current_buf && winid == s:current_win
+ " Keep the current window on screen, use the other window for the new buffer
+ if winnr1 != winnr()
+ execute winnr1 . "wincmd w"
+ else
+ execute winnr2 . "wincmd w"
+ endif
+ endif
+ execute "silent view! " . a:filename
+ else
+ " Generate unique window id for the old window if not yet done
+ call s:MakeWindowId()
+ " No windows yet, need to split
+ 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
+ " Generate unique window id for the new window as well
+ call s:MakeWindowId()
+ endif
+ stopinsert
+endfunction
+
+" Open a buffer with the given name if not yet open, and switch to it
+function! SlimvOpenBuffer( name )
+ let buf = bufnr( '^' . a:name . '$' )
+ if buf == -1
+ " Create a new buffer
+ call s:SplitView( a:name )
+ else
+ if g:slimv_repl_split
+ " Buffer is already created. Check if it is open in a window
+ let win = bufwinnr( buf )
+ if win == -1
+ " Create windows
+ call s:SplitView( a:name )
+ else
+ " Switch to the buffer's window
+ if winnr() != win
+ execute win . "wincmd w"
+ endif
+ endif
+ else
+ execute "buffer " . buf
+ stopinsert
+ endif
+ endif
+ if s:current_buf != bufnr( "%" )
+ " Keep track of the previous buffer and window
+ let b:previous_buf = s:current_buf
+ let b:previous_win = s:current_win
+ endif
+ setlocal buftype=nofile
+ setlocal noswapfile
+ setlocal modifiable
+endfunction
+
+" Go to the end of the screen line
+function s:EndOfScreenLine()
+ if len(getline('.')) < &columns
+ " g$ moves the cursor to the rightmost column if virtualedit=all
+ normal! $
+ else
+ normal! g$
+ endif
+endfunction
+
+" Set special syntax rules for the REPL buffer
+function! SlimvSetSyntaxRepl()
+ if SlimvGetFiletype() == 'scheme'
+ syn cluster replListCluster contains=@schemeListCluster,lispList
+ else
+ syn cluster replListCluster contains=@lispListCluster
+ endif
+
+if exists("g:lisp_rainbow") && g:lisp_rainbow != 0
+
+ if &bg == "dark"
+ hi def hlLevel0 ctermfg=red guifg=red1
+ hi def hlLevel1 ctermfg=yellow guifg=orange1
+ hi def hlLevel2 ctermfg=green guifg=yellow1
+ hi def hlLevel3 ctermfg=cyan guifg=greenyellow
+ hi def hlLevel4 ctermfg=magenta guifg=green1
+ hi def hlLevel5 ctermfg=red guifg=springgreen1
+ hi def hlLevel6 ctermfg=yellow guifg=cyan1
+ hi def hlLevel7 ctermfg=green guifg=slateblue1
+ hi def hlLevel8 ctermfg=cyan guifg=magenta1
+ hi def hlLevel9 ctermfg=magenta guifg=purple1
+ else
+ hi def hlLevel0 ctermfg=red guifg=red3
+ hi def hlLevel1 ctermfg=darkyellow guifg=orangered3
+ hi def hlLevel2 ctermfg=darkgreen guifg=orange2
+ hi def hlLevel3 ctermfg=blue guifg=yellow3
+ hi def hlLevel4 ctermfg=darkmagenta guifg=olivedrab4
+ hi def hlLevel5 ctermfg=red guifg=green4
+ hi def hlLevel6 ctermfg=darkyellow guifg=paleturquoise3
+ hi def hlLevel7 ctermfg=darkgreen guifg=deepskyblue4
+ hi def hlLevel8 ctermfg=blue guifg=darkslateblue
+ hi def hlLevel9 ctermfg=darkmagenta guifg=darkviolet
+ endif
+
+ if SlimvGetFiletype() =~ '.*\(clojure\|scheme\|racket\).*'
+
+ syn region lispParen9 matchgroup=hlLevel9 start="`\=(" matchgroup=hlLevel9 end=")" matchgroup=replPrompt end="^\S\+>" contains=TOP,@Spell
+ syn region lispParen0 matchgroup=hlLevel8 start="`\=(" end=")" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen0,lispParen1,lispParen2,lispParen3,lispParen4,lispParen5,lispParen6,lispParen7,lispParen8,NoInParens
+ syn region lispParen1 matchgroup=hlLevel7 start="`\=(" end=")" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen1,lispParen2,lispParen3,lispParen4,lispParen5,lispParen6,lispParen7,lispParen8,NoInParens
+ syn region lispParen2 matchgroup=hlLevel6 start="`\=(" end=")" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen2,lispParen3,lispParen4,lispParen5,lispParen6,lispParen7,lispParen8,NoInParens
+ syn region lispParen3 matchgroup=hlLevel5 start="`\=(" end=")" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen3,lispParen4,lispParen5,lispParen6,lispParen7,lispParen8,NoInParens
+ syn region lispParen4 matchgroup=hlLevel4 start="`\=(" end=")" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen4,lispParen5,lispParen6,lispParen7,lispParen8,NoInParens
+ syn region lispParen5 matchgroup=hlLevel3 start="`\=(" end=")" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen5,lispParen6,lispParen7,lispParen8,NoInParens
+ syn region lispParen6 matchgroup=hlLevel2 start="`\=(" end=")" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen6,lispParen7,lispParen8,NoInParens
+ syn region lispParen7 matchgroup=hlLevel1 start="`\=(" end=")" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen7,lispParen8,NoInParens
+ syn region lispParen8 matchgroup=hlLevel0 start="`\=(" end=")" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen8,NoInParens
+
+ syn region lispParen9 matchgroup=hlLevel9 start="`\=\[" matchgroup=hlLevel9 end="\]" matchgroup=replPrompt end="^\S\+>" contains=TOP,@Spell
+ syn region lispParen0 matchgroup=hlLevel8 start="`\=\[" end="\]" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen0,lispParen1,lispParen2,lispParen3,lispParen4,lispParen5,lispParen6,lispParen7,lispParen8,NoInParens
+ syn region lispParen1 matchgroup=hlLevel7 start="`\=\[" end="\]" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen1,lispParen2,lispParen3,lispParen4,lispParen5,lispParen6,lispParen7,lispParen8,NoInParens
+ syn region lispParen2 matchgroup=hlLevel6 start="`\=\[" end="\]" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen2,lispParen3,lispParen4,lispParen5,lispParen6,lispParen7,lispParen8,NoInParens
+ syn region lispParen3 matchgroup=hlLevel5 start="`\=\[" end="\]" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen3,lispParen4,lispParen5,lispParen6,lispParen7,lispParen8,NoInParens
+ syn region lispParen4 matchgroup=hlLevel4 start="`\=\[" end="\]" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen4,lispParen5,lispParen6,lispParen7,lispParen8,NoInParens
+ syn region lispParen5 matchgroup=hlLevel3 start="`\=\[" end="\]" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen5,lispParen6,lispParen7,lispParen8,NoInParens
+ syn region lispParen6 matchgroup=hlLevel2 start="`\=\[" end="\]" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen6,lispParen7,lispParen8,NoInParens
+ syn region lispParen7 matchgroup=hlLevel1 start="`\=\[" end="\]" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen7,lispParen8,NoInParens
+ syn region lispParen8 matchgroup=hlLevel0 start="`\=\[" end="\]" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen8,NoInParens
+
+ syn region lispParen9 matchgroup=hlLevel9 start="`\={" matchgroup=hlLevel9 end="}" matchgroup=replPrompt end="^\S\+>" contains=TOP,@Spell
+ syn region lispParen0 matchgroup=hlLevel8 start="`\={" end="}" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen0,lispParen1,lispParen2,lispParen3,lispParen4,lispParen5,lispParen6,lispParen7,lispParen8,NoInParens
+ syn region lispParen1 matchgroup=hlLevel7 start="`\={" end="}" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen1,lispParen2,lispParen3,lispParen4,lispParen5,lispParen6,lispParen7,lispParen8,NoInParens
+ syn region lispParen2 matchgroup=hlLevel6 start="`\={" end="}" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen2,lispParen3,lispParen4,lispParen5,lispParen6,lispParen7,lispParen8,NoInParens
+ syn region lispParen3 matchgroup=hlLevel5 start="`\={" end="}" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen3,lispParen4,lispParen5,lispParen6,lispParen7,lispParen8,NoInParens
+ syn region lispParen4 matchgroup=hlLevel4 start="`\={" end="}" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen4,lispParen5,lispParen6,lispParen7,lispParen8,NoInParens
+ syn region lispParen5 matchgroup=hlLevel3 start="`\={" end="}" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen5,lispParen6,lispParen7,lispParen8,NoInParens
+ syn region lispParen6 matchgroup=hlLevel2 start="`\={" end="}" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen6,lispParen7,lispParen8,NoInParens
+ syn region lispParen7 matchgroup=hlLevel1 start="`\={" end="}" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen7,lispParen8,NoInParens
+ syn region lispParen8 matchgroup=hlLevel0 start="`\={" end="}" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=TOP,lispParen8,NoInParens
+
+ else
+
+ syn region lispParen0 matchgroup=hlLevel0 start="`\=(" skip="|.\{-}|" end=")" matchgroup=replPrompt end="^\S\+>" contains=@replListCluster,lispParen1,replPrompt
+ syn region lispParen1 contained matchgroup=hlLevel1 start="`\=(" skip="|.\{-}|" end=")" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=@replListCluster,lispParen2
+ syn region lispParen2 contained matchgroup=hlLevel2 start="`\=(" skip="|.\{-}|" end=")" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=@replListCluster,lispParen3
+ syn region lispParen3 contained matchgroup=hlLevel3 start="`\=(" skip="|.\{-}|" end=")" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=@replListCluster,lispParen4
+ syn region lispParen4 contained matchgroup=hlLevel4 start="`\=(" skip="|.\{-}|" end=")" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=@replListCluster,lispParen5
+ syn region lispParen5 contained matchgroup=hlLevel5 start="`\=(" skip="|.\{-}|" end=")" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=@replListCluster,lispParen6
+ syn region lispParen6 contained matchgroup=hlLevel6 start="`\=(" skip="|.\{-}|" end=")" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=@replListCluster,lispParen7
+ syn region lispParen7 contained matchgroup=hlLevel7 start="`\=(" skip="|.\{-}|" end=")" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=@replListCluster,lispParen8
+ syn region lispParen8 contained matchgroup=hlLevel8 start="`\=(" skip="|.\{-}|" end=")" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=@replListCluster,lispParen9
+ syn region lispParen9 contained matchgroup=hlLevel9 start="`\=(" skip="|.\{-}|" end=")" matchgroup=replPrompt end="^\S\+>"me=s-1,re=s-1 contains=@replListCluster,lispParen0
+
+ endif
+
+else
+
+ if SlimvGetFiletype() !~ '.*clojure.*'
+ syn region lispList matchgroup=Delimiter start="(" skip="|.\{-}|" end=")" matchgroup=replPrompt end="^\S\+>" contains=@replListCluster
+ syn region lispBQList matchgroup=PreProc start="`(" skip="|.\{-}|" end=")" matchgroup=replPrompt end="^\S\+>" contains=@replListCluster
+ endif
+
+endif
+
+ syn match replPrompt /^[^(]\S\+>/
+ syn match replPrompt /^(\S\+)>/
+ hi def link replPrompt Type
+endfunction
+
+" Open a new REPL buffer
+function! SlimvOpenReplBuffer()
+ call SlimvOpenBuffer( g:slimv_repl_name )
+ setlocal noreadonly
+ let s:repl_buf = bufnr( "%" )
+ let b:slimv_repl_buffer = 1
+ call SlimvInitRepl()
+ if g:slimv_repl_syntax
+ call SlimvSetSyntaxRepl()
+ else
+ set syntax=
+ endif
+
+ " Prompt and its line and column number in the REPL buffer
+ if !exists( 'b:repl_prompt' )
+ let b:repl_prompt = ''
+ let b:repl_prompt_line = 1
+ let b:repl_prompt_col = 1
+ endif
+
+ " Add keybindings valid only for the REPL buffer
+ inoremap <buffer> <silent> <C-CR> <End><C-O>:call SlimvSendCommand(1)<CR><End>
+ inoremap <buffer> <silent> <C-C> <C-O>:call SlimvInterrupt()<CR>
+ inoremap <buffer> <silent> <expr> <C-W> SlimvHandleCW()
+
+ if g:slimv_repl_simple_eval
+ inoremap <buffer> <silent> <CR> <C-R>=pumvisible() ? "\<lt>C-Y>" : "\<lt>End>\<lt>C-O>:call SlimvSendCommand(0)\<lt>CR>\<lt>End>"<CR>
+ inoremap <buffer> <silent> <Up> <C-R>=pumvisible() ? "\<lt>Up>" : SlimvHandleUp()<CR>
+ inoremap <buffer> <silent> <Down> <C-R>=pumvisible() ? "\<lt>Down>" : SlimvHandleDown()<CR>
+ else
+ inoremap <buffer> <silent> <CR> <C-R>=pumvisible() ? "\<lt>C-Y>" : SlimvHandleEnterRepl()<CR><C-R>=SlimvArglistOnEnter()<CR>
+ inoremap <buffer> <silent> <C-Up> <C-R>=pumvisible() ? "\<lt>Up>" : SlimvHandleUp()<CR>
+ inoremap <buffer> <silent> <C-Down> <C-R>=pumvisible() ? "\<lt>Down>" : SlimvHandleDown()<CR>
+ endif
+
+ if exists( 'g:paredit_loaded' )
+ inoremap <buffer> <silent> <expr> <BS> PareditBackspace(1)
+ else
+ inoremap <buffer> <silent> <expr> <BS> SlimvHandleBS()
+ endif
+
+ if g:slimv_keybindings == 1
+ 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>'
+ elseif g:slimv_keybindings == 2
+ 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>'
+ endif
+
+ if g:slimv_repl_wrap
+ inoremap <buffer> <silent> <Home> <C-O>g<Home>
+ inoremap <buffer> <silent> <End> <C-O>:call <SID>EndOfScreenLine()<CR>
+ noremap <buffer> <silent> <Up> gk
+ noremap <buffer> <silent> <Down> gj
+ noremap <buffer> <silent> <Home> g<Home>
+ noremap <buffer> <silent> <End> :call <SID>EndOfScreenLine()<CR>
+ noremap <buffer> <silent> k gk
+ noremap <buffer> <silent> j gj
+ noremap <buffer> <silent> 0 g0
+ noremap <buffer> <silent> $ :call <SID>EndOfScreenLine()<CR>
+ setlocal wrap
+ endif
+
+ hi SlimvNormal term=none cterm=none gui=none
+ hi SlimvCursor term=reverse cterm=reverse gui=reverse
+
+ augroup SlimvReplAutoCmd
+ au!
+ " Add autocommands specific to the REPL buffer
+ execute "au FileChangedShell " . g:slimv_repl_name . " :call SlimvRefreshReplBuffer()"
+ execute "au FocusGained " . g:slimv_repl_name . " :call SlimvRefreshReplBuffer()"
+ execute "au BufEnter " . g:slimv_repl_name . " :call SlimvReplEnter()"
+ execute "au BufLeave " . g:slimv_repl_name . " :call SlimvReplLeave()"
+ execute "au BufWinEnter " . g:slimv_repl_name . " :call SlimvMarkBufferEnd(1)"
+ execute "au TabEnter *" . " :call SlimvReplSetCursorPos(1)"
+ augroup END
+
+ call SlimvRefreshReplBuffer()
+endfunction
+
+" Clear the contents of the REPL buffer, keeping the last prompt only
+function! SlimvClearReplBuffer()
+ let this_buf = bufnr( "%" )
+ if s:repl_buf == -1
+ call SlimvError( "There is no REPL buffer." )
+ return
+ endif
+ if this_buf != s:repl_buf
+ let oldpos = winsaveview()
+ execute "buf " . s:repl_buf
+ endif
+ if b:repl_prompt_line > 1
+ execute "normal! gg0d" . (b:repl_prompt_line-1) . "GG$"
+ let b:repl_prompt_line = 1
+ endif
+ if this_buf != s:repl_buf
+ execute "buf " . this_buf
+ call winrestview( oldpos )
+ endif
+endfunction
+
+" Open a new Inspect buffer
+function SlimvOpenInspectBuffer()
+ 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(1)<CR>'
+
+ if version < 703
+ " conceal mechanism is defined since Vim 7.3
+ syn region inspectItem matchgroup=Ignore start="{\[\d\+\]\s*" end="\[]}"
+ syn region inspectAction matchgroup=Ignore start="{<\d\+>\s*" end="<>}"
+ else
+ syn region inspectItem matchgroup=Ignore start="{\[\d\+\]\s*" end="\[]}" concealends
+ syn region inspectAction matchgroup=Ignore start="{<\d\+>\s*" end="<>}" concealends
+ setlocal conceallevel=3 concealcursor=nc
+ endif
+
+ hi def link inspectItem Special
+ hi def link inspectAction String
+
+ syn match Special /^\[<<\].*$/
+ syn match Special /^\[--....--\]$/
+endfunction
+
+" 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>'
+ execute 'noremap <buffer> <silent> ' . g:slimv_leader.'k :call SlimvKillThread()<CR>'
+ execute 'noremap <buffer> <silent> ' . g:slimv_leader.'q :call SlimvQuitThreads()<CR>'
+endfunction
+
+" Open a new SLDB buffer
+function SlimvOpenSldbBuffer()
+ call SlimvOpenBuffer( g:slimv_sldb_name )
+
+ " Add keybindings valid only for the SLDB buffer
+ noremap <buffer> <silent> <CR> :call SlimvHandleEnterSldb()<CR>
+ if g:slimv_keybindings == 1
+ execute 'noremap <buffer> <silent> ' . g:slimv_leader.'a :call SlimvDebugAbort()<CR>'
+ execute 'noremap <buffer> <silent> ' . g:slimv_leader.'q :call SlimvDebugQuit()<CR>'
+ execute 'noremap <buffer> <silent> ' . g:slimv_leader.'n :call SlimvDebugContinue()<CR>'
+ execute 'noremap <buffer> <silent> ' . g:slimv_leader.'N :call SlimvDebugRestartFrame()<CR>'
+ elseif g:slimv_keybindings == 2
+ execute 'noremap <buffer> <silent> ' . g:slimv_leader.'da :call SlimvDebugAbort()<CR>'
+ execute 'noremap <buffer> <silent> ' . g:slimv_leader.'dq :call SlimvDebugQuit()<CR>'
+ execute 'noremap <buffer> <silent> ' . g:slimv_leader.'dn :call SlimvDebugContinue()<CR>'
+ execute 'noremap <buffer> <silent> ' . g:slimv_leader.'dr :call SlimvDebugRestartFrame()<CR>'
+ endif
+
+ " Set folding parameters
+ setlocal foldmethod=marker
+ setlocal foldmarker={{{,}}}
+ setlocal foldtext=substitute(getline(v:foldstart),'{{{','','')
+ call s:SetKeyword()
+ if g:slimv_sldb_wrap
+ setlocal wrap
+ endif
+
+ if version < 703
+ " conceal mechanism is defined since Vim 7.3
+ syn match Ignore /{{{/
+ syn match Ignore /}}}/
+ else
+ setlocal conceallevel=3 concealcursor=nc
+ syn match Comment /{{{/ conceal
+ syn match Comment /}}}/ conceal
+ endif
+ syn match Type /^\s\{0,2}\d\{1,3}:/
+ syn match Type /^\s\+in "\(.*\)" \(line\|byte\) \(\d\+\)$/
+endfunction
+
+" End updating an otherwise readonly buffer
+function SlimvEndUpdate()
+ setlocal nomodifiable
+ setlocal nomodified
+endfunction
+
+" Quit Inspector
+function SlimvQuitInspect( force )
+ " Clear the contents of the Inspect buffer
+ if exists( 'b:inspect_pos' )
+ unlet b:inspect_pos
+ endif
+ setlocal modifiable
+ silent! %d _
+ call SlimvEndUpdate()
+ if a:force
+ call SlimvCommand( s:py_cmd . 'swank_quit_inspector()' )
+ endif
+ call SlimvRestoreFocus(1)
+endfunction
+
+" Quit Threads
+function SlimvQuitThreads()
+ " Clear the contents of the Threads buffer
+ setlocal modifiable
+ silent! %d _
+ call SlimvEndUpdate()
+ call SlimvRestoreFocus(1)
+endfunction
+
+" Quit Sldb
+function SlimvQuitSldb()
+ " Clear the contents of the Sldb buffer
+ setlocal modifiable
+ silent! %d _
+ call SlimvEndUpdate()
+ call SlimvRestoreFocus(1)
+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 modifiable
+ 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 )
+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 modifiable
+ execute ":" . (b:help_line+1) . "," . (b:help_line+lines) . "d"
+ call SlimvHelp( b:help_line )
+ call SlimvEndUpdate()
+endfunction
+
+" Open SLDB buffer and place cursor on the given frame
+function SlimvGotoFrame( frame )
+ call SlimvOpenSldbBuffer()
+ let bcktrpos = search( '^Backtrace:', 'bcnw' )
+ let line = getline( '.' )
+ let item = matchstr( line, '^\s*' . a:frame . ':' )
+ if item != '' && line('.') > bcktrpos
+ " Already standing on the frame
+ return
+ endif
+
+ " Must locate the frame starting from the 'Backtrace:' string
+ call search( '^Backtrace:', 'bcw' )
+ call search( '^\s*' . a:frame . ':', 'w' )
+endfunction
+
+" Set 'iskeyword' option depending on file type
+function! s:SetKeyword()
+ if SlimvGetFiletype() =~ '.*\(clojure\|scheme\|racket\).*'
+ setlocal iskeyword+=+,-,*,/,%,<,=,>,:,$,?,!,@-@,94,~,#,\|,&
+ else
+ setlocal iskeyword+=+,-,*,/,%,<,=,>,:,$,?,!,@-@,94,~,#,\|,&,.,{,},[,]
+ endif
+endfunction
+
+" Select symbol under cursor and return it
+function! SlimvSelectSymbol()
+ call s:SetKeyword()
+ let oldpos = winsaveview()
+ if col('.') > 1 && getline('.')[col('.')-1] =~ '\s'
+ normal! h
+ endif
+ let symbol = expand('<cword>')
+ call winrestview( oldpos )
+ return symbol
+endfunction
+
+" Select symbol with possible prefixes under cursor and return it
+function! SlimvSelectSymbolExt()
+ let save_iskeyword = &iskeyword
+ call s:SetKeyword()
+ setlocal iskeyword+='
+ let symbol = expand('<cword>')
+ let &iskeyword = save_iskeyword
+ return symbol
+endfunction
+
+" Select bottom level form the cursor is inside and copy it to register 's'
+function! SlimvSelectForm( extended )
+ if SlimvGetFiletype() == 'r'
+ silent! normal va(
+ silent! normal "sY
+ return 1
+ endif
+ " Search the opening '(' if we are standing on a special form prefix character
+ let c = col( '.' ) - 1
+ let firstchar = getline( '.' )[c]
+ while c < len( getline( '.' ) ) && match( "'`#", getline( '.' )[c] ) >= 0
+ normal! l
+ let c = c + 1
+ endwhile
+ normal! va(
+ let p1 = getpos('.')
+ normal! o
+ let p2 = getpos('.')
+ if firstchar != '(' && p1[1] == p2[1] && (p1[2] == p2[2] || p1[2] == p2[2]+1)
+ " Empty selection and no paren found, select current word instead
+ normal! aw
+ elseif a:extended || firstchar != '('
+ " Handle '() or #'() etc. type special syntax forms (but stop at prompt)
+ let c = col( '.' ) - 2
+ while c >= 0 && match( ' \t()>', getline( '.' )[c] ) < 0
+ normal! h
+ let c = c - 1
+ endwhile
+ endif
+ silent normal! "sy
+ let sel = SlimvGetSelection()
+ if sel == ''
+ call SlimvError( "Form is empty." )
+ return 0
+ elseif sel == '(' || sel == '[' || sel == '{'
+ call SlimvError( "Form is unbalanced." )
+ return 0
+ else
+ return 1
+ endif
+endfunction
+
+" Find starting '(' of a top level form
+function! SlimvFindDefunStart()
+ let l = line( '.' )
+ let matchb = max( [l-200, 1] )
+ if SlimvGetFiletype() == 'r'
+ while searchpair( '(', '', ')', 'bW', s:skip_sc, matchb ) || searchpair( '{', '', '}', 'bW', s:skip_sc, matchb ) || searchpair( '\[', '', '\]', 'bW', s:skip_sc, matchb )
+ endwhile
+ else
+ while searchpair( '(', '', ')', 'bW', s:skip_sc, matchb )
+ endwhile
+ endif
+endfunction
+
+" Select top level form the cursor is inside and copy it to register 's'
+function! SlimvSelectDefun()
+ call SlimvFindDefunStart()
+ if SlimvGetFiletype() == 'r'
+ " The cursor must be on the enclosing paren character
+ silent! normal v%"sY
+ return 1
+ else
+ return SlimvSelectForm( 1 )
+ endif
+endfunction
+
+" Return the contents of register 's'
+function! SlimvGetSelection()
+ return getreg( 's' )
+endfunction
+
+" 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 = winsaveview()
+ let save_ic = &ignorecase
+ set ignorecase
+ if SlimvGetFiletype() =~ '.*clojure.*'
+ let string = '\(in-ns\|ns\)'
+ else
+ let string = '\(cl:\|common-lisp:\|\)in-package'
+ endif
+ let found = 0
+ 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'
+ " It is not inside a comment or string
+ let found = 1
+ break
+ endif
+ let searching = search( '(\s*' . string . '\s', 'bW' )
+ endwhile
+ if found
+ " Find the package name with all folds open
+ normal! zn
+ silent normal! w
+ let l:package_command = expand('<cword>')
+ silent normal! w
+ let l:packagename_tokens = split(expand('<cWORD>'),')\|\s')
+ normal! zN
+ if l:packagename_tokens != []
+ " Remove quote character from package name
+ let s:swank_package = substitute( l:packagename_tokens[0], "'", '', '' )
+ let s:swank_package_form = "(" . l:package_command . " " . l:packagename_tokens[0] . ")\n"
+ else
+ let s:swank_package = ''
+ let s:swank_package_form = ''
+ endif
+ endif
+ let &ignorecase = save_ic
+ call winrestview( oldpos )
+endfunction
+
+" Execute the given SWANK command with current package defined
+function! SlimvCommandUsePackage( cmd )
+ call SlimvFindPackage()
+ let s:refresh_disabled = 1
+ call SlimvCommand( a:cmd )
+ let s:swank_package = ''
+ let s:swank_package_form = ''
+ let s:refresh_disabled = 0
+ call SlimvRefreshReplBuffer()
+endfunction
+
+" Initialize embedded Python and connect to SWANK server
+function! SlimvConnectSwank()
+ if !s:python_initialized
+ if ( s:py_cmd == 'python3 ' && ! has('python3') ) ||
+ \ ( s:py_cmd == 'python ' && ! has('python' ) )
+ call SlimvErrorWait( 'Vim is compiled without the Python feature or Python is not installed. Unable to run SWANK client.' )
+ return 0
+ endif
+ execute s:py_cmd . 'import vim'
+ execute s:pyfile_cmd . g:swank_path
+ let s:python_initialized = 1
+ endif
+
+
+ if !s:swank_connected
+ let s:swank_version = ''
+ let s:lisp_version = ''
+ if g:swank_host == ''
+ let g:swank_host = input( 'Swank server host name: ', 'localhost' )
+ endif
+ execute s:py_cmd . 'swank_connect("' . g:swank_host . '", ' . g:swank_port . ', "result" )'
+ if result != '' && ( g:swank_host == 'localhost' || g:swank_host == '127.0.0.1' )
+ " 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()
+ while result != '' && localtime()-starttime < g:slimv_timeout
+ sleep 500m
+ execute s:py_cmd . 'swank_connect("' . g:swank_host . '", ' . g:swank_port . ', "result" )'
+ endwhile
+ redraw!
+ endif
+ endif
+ if result != ''
+ " Display connection error message
+ call SlimvErrorWait( result )
+ return 0
+ endif
+
+ " Connected to SWANK server
+ redraw
+ echon "\rGetting SWANK connection info..."
+ let starttime = localtime()
+ while s:swank_version == '' && localtime()-starttime < g:slimv_timeout
+ call SlimvSwankResponse()
+ endwhile
+
+ " Require some contribs
+ let contribs = 'swank-presentations swank-fancy-inspector swank-c-p-c swank-arglists'
+ if SlimvGetFiletype() == 'lisp'
+ let contribs = 'swank-asdf swank-package-fu ' . contribs
+ endif
+ if g:slimv_simple_compl == 0
+ let contribs = contribs . ' swank-fuzzy'
+ endif
+ execute s:py_cmd . "swank_require('(" . contribs . ")')"
+ call SlimvSwankResponse()
+ if s:SinceVersion( '2011-12-04' )
+ execute s:py_cmd . "swank_require('swank-repl')"
+ call SlimvSwankResponse()
+ endif
+ if s:SinceVersion( '2008-12-23' )
+ call SlimvCommandGetResponse( ':create-repl', s:py_cmd . 'swank_create_repl()', g:slimv_timeout )
+ endif
+ let s:swank_connected = 1
+ redraw
+ echon "\rConnected to SWANK server on port " . g:swank_port . "."
+ if exists( "g:swank_block_size" ) && SlimvGetFiletype() == 'lisp'
+ " Override SWANK connection output buffer size
+ if s:SinceVersion( '2014-09-08' )
+ let cmd = "(progn (setf (slot-value (swank::connection.user-output swank::*emacs-connection*) 'swank/gray::buffer)"
+ else
+ let cmd = "(progn (setf (slot-value (swank::connection.user-output swank::*emacs-connection*) 'swank-backend::buffer)"
+ endif
+ let cmd = cmd . " (make-string " . g:swank_block_size . ")) nil)"
+ call SlimvSend( [cmd], 0, 1 )
+ endif
+ if exists( "*SlimvReplInit" )
+ " Perform implementation specific REPL initialization if supplied
+ call SlimvReplInit( s:lisp_version )
+ endif
+ endif
+
+ return s:swank_connected
+endfunction
+
+" Send argument to Lisp server for evaluation
+function! SlimvSend( args, echoing, output )
+ if ! SlimvConnectSwank()
+ return
+ endif
+
+ " Send the lines to the client for evaluation
+ let text = join( a:args, "\n" ) . "\n"
+
+ let s:refresh_disabled = 1
+ let s:swank_form = text
+ if a:echoing && g:slimv_echolines != 0
+ 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 trimmed = strpart( s:swank_form, nlpos )
+ let s:swank_form = strpart( s:swank_form, 0, nlpos )
+ let ending = s:CloseForm( s:swank_form )
+ if ending != 'ERROR'
+ if substitute( trimmed, '\s\|\n', '', 'g' ) == ''
+ " Only whitespaces are trimmed
+ let s:swank_form = s:swank_form . ending . "\n"
+ else
+ " Valuable characters trimmed, indicate it by printing "..."
+ let s:swank_form = s:swank_form . " ..." . ending . "\n"
+ endif
+ endif
+ endif
+ endif
+ if a:output
+ silent execute s:py_cmd . 'append_repl("s:swank_form", 1)'
+ endif
+ let s:swank_form = text
+ elseif a:output
+ " Open a new line for the output
+ silent execute s:py_cmd . " append_repl('\\n', 0)"
+ endif
+ call SlimvCommand( s:py_cmd . 'swank_input("s:swank_form")' )
+ let s:swank_package = ''
+ let s:swank_package_form = ''
+ let s:refresh_disabled = 0
+ call SlimvRefreshModeOn()
+ call SlimvRefreshReplBuffer()
+endfunction
+
+" Eval arguments in Lisp REPL
+function! SlimvEval( args )
+ call SlimvSend( a:args, 1, 1 )
+endfunction
+
+" Send argument silently to SWANK
+function! SlimvSendSilent( args )
+ call SlimvSend( a:args, 0, 0 )
+endfunction
+
+" Set command line after the prompt
+function! SlimvSetCommandLine( cmd )
+ let line = getline( "." )
+ if line( "." ) == s:GetPromptLine()
+ " The prompt is in the line marked by b:repl_prompt_line
+ let promptlen = len( b:repl_prompt )
+ else
+ let promptlen = 0
+ endif
+ if len( line ) > promptlen
+ let line = strpart( line, 0, promptlen )
+ endif
+
+ if s:GetPromptLine() < line( '$' )
+ " Delete extra lines after the prompt
+ let c = col( '.' )
+ execute (s:GetPromptLine()+1) . ',' . (line('$')) . 'd_'
+ call cursor( line('.'), c )
+ endif
+
+ let lines = split( a:cmd, '\n' )
+ if len(lines) > 0
+ let line = line . lines[0]
+ endif
+ call setline( ".", line )
+ if len(lines) > 1
+ call append( s:GetPromptLine(), lines[1:] )
+ endif
+ set nomodified
+endfunction
+
+" Add command list to the command history
+function! SlimvAddHistory( cmd )
+ if !exists( 'g:slimv_cmdhistory' )
+ let g:slimv_cmdhistory = []
+ endif
+ let i = 0
+ let form = join( a:cmd, "\n" )
+ " Trim leading and trailing whitespaces from the command
+ let form = substitute( form, '^\s*\(.*[^ ]\)\s*', '\1', 'g' )
+ if len( form ) > 1 || len( g:slimv_cmdhistory ) == 0 || form != g:slimv_cmdhistory[-1]
+ " Add command only if differs from the last one
+ call add( g:slimv_cmdhistory, form )
+ endif
+ let g:slimv_cmdhistorypos = len( g:slimv_cmdhistory )
+endfunction
+
+" Recall command from the command history at the marked position
+function! SlimvRecallHistory( direction )
+ let searchtext = ''
+ let l = line( '.' )
+ let c = col( '.' )
+ let set_cursor_pos = 0
+ if line( '.' ) == s:GetPromptLine() && c > b:repl_prompt_col
+ " Search for lines beginning with the text up to the cursor position
+ let searchtext = strpart( getline('.'), b:repl_prompt_col-1, c-b:repl_prompt_col )
+ let searchtext = substitute( searchtext, '^\s*$', '', 'g' )
+ let searchtext = substitute( searchtext, '^\s*\(.*[^ ]\)', '\1', 'g' )
+ endif
+ let historypos = g:slimv_cmdhistorypos
+ let g:slimv_cmdhistorypos = g:slimv_cmdhistorypos + a:direction
+ while g:slimv_cmdhistorypos >= 0 && g:slimv_cmdhistorypos < len( g:slimv_cmdhistory )
+ let cmd = g:slimv_cmdhistory[g:slimv_cmdhistorypos]
+ if len(cmd) >= len(searchtext) && strpart(cmd, 0, len(searchtext)) == searchtext
+ call SlimvSetCommandLine( g:slimv_cmdhistory[g:slimv_cmdhistorypos] )
+ return
+ endif
+ let g:slimv_cmdhistorypos = g:slimv_cmdhistorypos + a:direction
+ endwhile
+ if searchtext == ''
+ call SlimvSetCommandLine( "" )
+ else
+ let g:slimv_cmdhistorypos = historypos
+ endif
+endfunction
+
+" Return missing parens, double quotes, etc to properly close form
+function! s:CloseForm( form )
+ let end = ''
+ let i = 0
+ while i < len( a:form )
+ if a:form[i] == '"'
+ " Inside a string
+ let end = '"' . end
+ let i += 1
+ while i < len( a:form )
+ if a:form[i] == '\'
+ " Ignore next character
+ let i += 2
+ elseif a:form[i] == '"'
+ let end = end[1:]
+ break
+ else
+ let i += 1
+ endif
+ endwhile
+ elseif a:form[i] == ';'
+ " Inside a comment
+ let end = "\n" . end
+ let cend = match(a: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 a:form[i] == '('
+ let end = ')' . end
+ elseif a:form[i] == '[' && SlimvGetFiletype() =~ '.*\(clojure\|scheme\|racket\).*'
+ let end = ']' . end
+ elseif a:form[i] == '{' && SlimvGetFiletype() =~ '.*\(clojure\|scheme\|racket\).*'
+ let end = '}' . end
+ elseif a:form[i] == ')' || ((a:form[i] == ']' || a:form[i] == '}') && SlimvGetFiletype() =~ '.*\(clojure\|scheme\|racket\).*')
+ if len( end ) == 0 || end[0] != a:form[i]
+ " Oops, too many closing parens or invalid closing paren
+ return 'ERROR'
+ endif
+ let end = end[1:]
+ endif
+ endif
+ let i += 1
+ endwhile
+ return end
+endfunction
+
+" Some multi-byte characters screw up the built-in lispindent()
+" This function is a wrapper that tries to fix it
+" TODO: implement custom indent procedure and omit lispindent()
+function SlimvLispindent( lnum )
+ set lisp
+ let li = lispindent( a:lnum )
+ set nolisp
+ let backline = max([a:lnum-g:slimv_indent_maxlines, 1])
+ let oldpos = getpos( '.' )
+ call cursor( oldpos[1], 1 )
+ " Find containing form
+ let [lhead, chead] = searchpairpos( '(', '', ')', 'bW', s:skip_sc, backline )
+ if lhead == 0
+ " No containing form, lispindent() is OK
+ call cursor( oldpos[1], oldpos[2] )
+ return li
+ endif
+ " Find outer form
+ let [lparent, cparent] = searchpairpos( '(', '', ')', 'bW', s:skip_sc, backline )
+ call cursor( oldpos[1], oldpos[2] )
+ if lparent == 0 || lhead != lparent
+ " No outer form or starting above inner form, lispindent() is OK
+ return li
+ endif
+ " Count extra bytes before the function header
+ let header = strpart( getline( lparent ), 0 )
+ let total_extra = 0
+ let extra = 0
+ let c = 0
+ while a:lnum > 0 && c < chead-1
+ let bytes = byteidx( header, c+1 ) - byteidx( header, c )
+ if bytes > 1
+ let total_extra = total_extra + bytes - 1
+ if c >= cparent && extra < 10
+ " Extra bytes in the outer function header
+ let extra = extra + bytes - 1
+ endif
+ endif
+ let c = c + 1
+ endwhile
+ if total_extra == 0
+ " No multi-byte character, lispindent() is OK
+ return li
+ endif
+ " In some cases ending spaces add up to lispindent() if there are multi-byte characters
+ let ending_sp = len( matchstr( getline( lparent ), ' *$' ) )
+ " Determine how wrong lispindent() is based on the number of extra bytes
+ " These values were determined empirically
+ if lparent == a:lnum - 1
+ " Function header is in the previous line
+ if extra == 0 && total_extra > 1
+ let ending_sp = ending_sp + 1
+ endif
+ return li + [0, 1, 0, -3, -3, -3, -5, -5, -7, -7, -8][extra] - ending_sp
+ else
+ " Function header is in an upper line
+ if extra == 0 || total_extra == extra
+ let ending_sp = 0
+ endif
+ return li + [0, 1, 0, -2, -2, -3, -3, -3, -3, -3, -3][extra] - ending_sp
+ endif
+endfunction
+
+" Return Lisp source code indentation at the given line
+" Does not keep the cursor position
+function! SlimvIndentUnsafe( lnum )
+ if &autoindent == 0 || 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
+ let oldpos = getpos( '.' )
+ let linenum = a:lnum
+
+ " Handle multi-line string
+ let plen = len( getline( pnum ) )
+ if synIDattr( synID( pnum, plen, 0), 'name' ) =~ '[Ss]tring' && getline(pnum)[plen-1] != '"'
+ " Previous non-blank line ends with an unclosed string, so this is a multi-line string
+ let [l, c] = searchpairpos( '"', '', '"', 'bnW', s:skip_q )
+ if l == pnum && c > 0
+ " Indent to the opening double quote (if found)
+ return c
+ else
+ return SlimvLispindent( linenum )
+ endif
+ endif
+ if synIDattr( synID( pnum, 1, 0), 'name' ) =~ '[Ss]tring' && getline(pnum)[0] != '"'
+ " Previous non-blank line is the last line of a multi-line string
+ call cursor( pnum, 1 )
+ " First find the end of the multi-line string (omit \" characters)
+ let [lend, cend] = searchpos( '[^\\]"', 'nW' )
+ if lend > 0 && strpart(getline(lend), cend+1) =~ '(\|)\|\[\|\]\|{\|}'
+ " Structural change after the string, no special handling
+ else
+ " Find the start of the multi-line string (omit \" characters)
+ let [l, c] = searchpairpos( '"', '', '"', 'bnW', s:skip_q )
+ if l > 0 && strpart(getline(l), 0, c-1) =~ '^\s*$'
+ " Nothing else before the string: indent to the opening "
+ return c - 1
+ endif
+ if l > 0
+ " Pretend that we are really after the first line of the multi-line string
+ let pnum = l
+ let linenum = l + 1
+ endif
+ endif
+ call cursor( oldpos[1], oldpos[2] )
+ endif
+
+ " Handle special indentation style for flet, labels, etc.
+ " When searching for containing forms, don't go back
+ " more than g:slimv_indent_maxlines lines.
+ let backline = max([pnum-g:slimv_indent_maxlines, 1])
+ let indent_keylists = g:slimv_indent_keylists
+
+ " Check if the previous line actually ends with a multi-line subform
+ let parent = pnum
+ let [l, c] = searchpos( ')', 'bW' )
+ if l == pnum
+ let [l, c] = searchpairpos( '(', '', ')', 'bW', s:skip_sc, backline )
+ if l > 0
+ " Make sure it is not a top level form and the containing form starts in the same line
+ let [l2, c2] = searchpairpos( '(', '', ')', 'bW', s:skip_sc, backline )
+ if l2 == l
+ " Remember the first line of the multi-line form
+ let parent = l
+ endif
+ endif
+ endif
+
+ " Find beginning of the innermost containing form
+ call cursor( oldpos[1], 1 )
+ let [l, c] = searchpairpos( '(', '', ')', 'bW', s:skip_sc, backline )
+ if l > 0
+ if SlimvGetFiletype() =~ '.*\(clojure\|scheme\|racket\).*'
+ " Is this a clojure form with [] binding list?
+ call cursor( oldpos[1], oldpos[2] )
+ let [lb, cb] = searchpairpos( '\[', '', '\]', 'bW', s:skip_sc, backline )
+ if lb >= l && (lb > l || cb > c)
+ return cb
+ endif
+ endif
+ " Is this a form with special indentation?
+ 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
+ call searchpair( '(', '', ')', '', s:skip_sc )
+ if line('.') == pnum
+ " We are indenting the first line after the end of the binding list
+ return c + 1
+ endif
+ endif
+ elseif l == pnum
+ " If the containing form starts above this line then find the
+ " 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 match( line2, '\c^(\s*\('.s:spec_param.'\)\>' ) >= 0
+ if search( '(' ) > 0
+ if line('.') == l && col('.') == c
+ " This is the parameter list of a special form
+ return c
+ endif
+ endif
+ endif
+ if SlimvGetFiletype() !~ '.*clojure.*'
+ if l2 == l && match( line2, '\c^(\s*\('.s:binding_form.'\)\>' ) >= 0
+ " Is this a lisp form with binding list?
+ 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?
+ 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?
+ 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
+ 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
+ endif
+
+ " Restore all cursor movements
+ call cursor( oldpos[1], oldpos[2] )
+
+ " Check if the current form started in the previous nonblank line
+ if l == parent
+ " Found opening paren in the previous line
+ let line = getline(l)
+ let form = strpart( line, c )
+ " Determine the length of the function part up to the 1st argument
+ let funclen = matchend( form, '\s*\S*\s*' ) + 1
+ " 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' )
+ 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 indent_keylists && strpart(func, 0, 1) == ':'
+ if form =~ '^:\S*\s\+\S'
+ " This keyword has an associated value in the same line
+ return c
+ else
+ " The keyword stands alone in its line with no associated value
+ return c + 1
+ endif
+ endif
+ if SlimvGetFiletype() =~ '.*clojure.*'
+ " Fix clojure specific indentation issues not handled by the default lisp.vim
+ if match( func, 'defn$' ) >= 0
+ return c + 1
+ endif
+ else
+ if match( func, 'defgeneric$' ) >= 0 || match( func, 'defsystem$' ) >= 0 || match( func, 'aif$' ) >= 0
+ return c + 1
+ endif
+ endif
+ " Remove package specification
+ let func = substitute(func, '^.*:', '', '')
+ if func != '' && s:swank_connected
+ " Look how many arguments are on the same line
+ " If an argument is actually a multi-line subform, then replace it with a single character
+ let form = substitute( form, "([^()]*$", '0', 'g' )
+ let form = substitute( form, "[()\\[\\]{}#'`,]", '', 'g' )
+ let args_here = len( split( form ) ) - 1
+ " Get swank indent info
+ let s:indent = ''
+ silent execute s:py_cmd . 'get_indent_info("' . func . '")'
+ 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 llen = len( line )
+ if synIDattr( synID( l, llen, 0), 'name' ) =~ '[Ss]tring' && line[llen-1] != '"'
+ " Parent line ends with a multi-line string
+ " lispindent() fails to handle it correctly
+ if s:indent == '' && args_here > 0
+ " No &body argument, ignore lispindent() and indent to the 1st argument
+ return c + funclen - 1
+ endif
+ endif
+ endif
+ endif
+
+ " Use default Lisp indenting
+ let li = SlimvLispindent(linenum)
+ let line = strpart( getline(linenum-1), li-1 )
+ let gap = matchend( line, '^(\s\+\S' )
+ if gap >= 0
+ " Align to the gap between the opening paren and the first atom
+ return li + gap - 2
+ endif
+ return li
+endfunction
+
+" Indentation routine, keeps original cursor position
+function! SlimvIndent( lnum )
+ let oldpos = getpos( '.' )
+ let indent = SlimvIndentUnsafe( a:lnum )
+ call cursor( oldpos[1], oldpos[2] )
+ return indent
+endfunction
+
+" Convert indent value to spaces or a mix of tabs and spaces
+" depending on the value of 'expandtab'
+function! s:MakeIndent( indent )
+ if &expandtab
+ return repeat( ' ', a:indent )
+ else
+ return repeat( "\<Tab>", a:indent / &tabstop ) . repeat( ' ', a:indent % &tabstop )
+ endif
+endfunction
+
+" Send command line to REPL buffer
+" Arguments: close = add missing closing parens
+function! SlimvSendCommand( close )
+ call SlimvRefreshModeOn()
+ let lastline = s:GetPromptLine()
+ let lastcol = b:repl_prompt_col
+ if lastline > 0
+ if line( "." ) >= lastline
+ " Trim the prompt from the beginning of the command line
+ " The user might have overwritten some parts of the prompt
+ let cmdline = getline( lastline )
+ let c = 0
+ while c < lastcol - 1 && cmdline[c] == b:repl_prompt[c]
+ let c = c + 1
+ endwhile
+ let cmd = [ strpart( getline( lastline ), c ) ]
+
+ " Build a possible multi-line command
+ let l = lastline + 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 end = s:CloseForm( join( cmd, "\n" ) )
+ 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 end == ''
+ " Expression finished, let's evaluate it
+ " but first add it to the history
+ call SlimvAddHistory( cmd )
+ " Evaluate, but echo only when form is actually closed here
+ call SlimvSend( cmd, echoing, 1 )
+ else
+ " Expression is not finished yet, indent properly and wait for completion
+ " Indentation works only if lisp indentation is switched on
+ call SlimvArglist()
+ let l = line('.') + 1
+ call append( '.', '' )
+ call setline( l, s:MakeIndent( SlimvIndent(l) ) )
+ normal! j$
+ endif
+ endif
+ else
+ silent execute s:py_cmd . " append_repl('Slimv error: previous EOF mark not found, re-enter last form:\\n', 0)"
+ endif
+endfunction
+
+" Close current top level form by adding the missing parens
+function! SlimvCloseForm()
+ let l2 = line( '.' )
+ call SlimvFindDefunStart()
+ let l1 = line( '.' )
+ let form = []
+ let l = l1
+ while l <= l2
+ call add( form, getline( l ) )
+ let l = l + 1
+ endwhile
+ let end = s:CloseForm( join( form, "\n" ) )
+ if end == 'ERROR'
+ " Too many closing parens
+ call SlimvErrorWait( "Too many or invalid closing parens found." )
+ elseif end != ''
+ " Add missing parens
+ if end[0] == "\n"
+ call append( l2, end[1:] )
+ else
+ call setline( l2, getline( l2 ) . end )
+ endif
+ endif
+ normal! %
+endfunction
+
+" Handle insert mode 'Enter' keypress
+function! SlimvHandleEnter()
+ let s:arglist_line = line('.')
+ let s:arglist_col = col('.')
+ if pumvisible()
+ " Pressing <CR> in a pop up selects entry.
+ return "\<C-Y>"
+ else
+ if exists( 'g:paredit_mode' ) && g:paredit_mode && g:paredit_electric_return
+ " Apply electric return
+ return PareditEnter()
+ else
+ " No electric return handling, just enter a newline
+ return "\<CR>"
+ endif
+ endif
+endfunction
+
+" Display arglist after pressing Enter
+function! SlimvArglistOnEnter()
+ let retval = ""
+ if s:arglist_line > 0
+ if col('.') > len(getline('.'))
+ " Stay at the end of line
+ let retval = "\<End>"
+ endif
+ let l = line('.')
+ if getline(l) == ''
+ " Add spaces to make the correct indentation
+ call setline( l, s:MakeIndent( SlimvIndent(l) ) )
+ normal! $
+ endif
+ call SlimvArglist( s:arglist_line, s:arglist_col )
+ endif
+ let s:arglist_line = 0
+ let s:arglist_col = 0
+
+ " This function is called from <C-R>= mappings, return additional keypress
+ return retval
+endfunction
+
+" Handle insert mode 'Tab' keypress by doing completion or indentation
+function! SlimvHandleTab()
+ if pumvisible()
+ " Completions menu is active, go to next match
+ return "\<C-N>"
+ endif
+ let c = col('.')
+ if c > 1 && getline('.')[c-2] =~ '\k'
+ " At the end of a keyword, bring up completions
+ return "\<C-X>\<C-O>"
+ endif
+ let indent = SlimvIndent(line('.'))
+ if c-1 < indent && getline('.') !~ '\S\+'
+ " We are left from the autoindent position, do an autoindent
+ call setline( line('.'), s:MakeIndent( indent ) )
+ return "\<End>"
+ endif
+ " No keyword to complete, no need for autoindent, just enter a <Tab>
+ return "\<Tab>"
+endfunction
+
+" Handle insert mode 'Backspace' keypress in the REPL buffer
+function! SlimvHandleBS()
+ if line( "." ) == s:GetPromptLine() && col( "." ) <= b:repl_prompt_col
+ " No BS allowed before the previous EOF mark
+ return ""
+ else
+ return "\<BS>"
+ endif
+endfunction
+
+" Handle insert mode Ctrl-W keypress in the REPL buffer
+function! SlimvHandleCW()
+ if line( "." ) == s:GetPromptLine()
+ let trim_prompt = substitute( b:repl_prompt, '\s\+$', '', 'g' )
+ let promptlen = len( trim_prompt )
+ if col( "." ) > promptlen
+ let after_prompt = strpart( getline("."), promptlen-1, col(".")-promptlen )
+ else
+ let after_prompt = ''
+ endif
+ let word = matchstr( after_prompt, '^.*\s\S' )
+ if len( word ) == 0
+ " No word found after prompt, C-W not allowed
+ return ""
+ endif
+ endif
+ return "\<C-W>"
+endfunction
+
+" Recall previous command from command history
+function! s:PreviousCommand()
+ if exists( 'g:slimv_cmdhistory' ) && g:slimv_cmdhistorypos > 0
+ call SlimvRecallHistory( -1 )
+ endif
+endfunction
+
+" Recall next command from command history
+function! s:NextCommand()
+ if exists( 'g:slimv_cmdhistory' ) && g:slimv_cmdhistorypos < len( g:slimv_cmdhistory )
+ call SlimvRecallHistory( 1 )
+ else
+ call SlimvSetCommandLine( "" )
+ endif
+endfunction
+
+" Handle insert mode 'Up' keypress in the REPL buffer
+function! SlimvHandleUp()
+ let save_ve = &virtualedit
+ set virtualedit=onemore
+ if line( "." ) >= s:GetPromptLine()
+ call s:PreviousCommand()
+ else
+ normal! gk
+ endif
+ let &virtualedit=save_ve
+ return ''
+endfunction
+
+" Handle insert mode 'Down' keypress in the REPL buffer
+function! SlimvHandleDown()
+ let save_ve = &virtualedit
+ set virtualedit=onemore
+ if line( "." ) >= s:GetPromptLine()
+ call s:NextCommand()
+ else
+ normal! gj
+ endif
+ let &virtualedit=save_ve
+ return ''
+endfunction
+
+" Make a fold at the cursor point in the current buffer
+function SlimvMakeFold()
+ setlocal modifiable
+ normal! o }}}kA {{{0
+ setlocal nomodifiable
+endfunction
+
+" Handle insert mode 'Enter' keypress in the REPL buffer
+function! SlimvHandleEnterRepl()
+ " Trim the prompt from the beginning of the command line
+ " The user might have overwritten some parts of the prompt
+ let lastline = s:GetPromptLine()
+ let lastcol = b:repl_prompt_col
+ let cmdline = getline( lastline )
+ let c = 0
+ while c < lastcol - 1 && cmdline[c] == b:repl_prompt[c]
+ let c = c + 1
+ endwhile
+
+ " Copy command line up to the cursor position
+ if line(".") == lastline
+ let cmd = [ strpart( cmdline, c, col(".") - c - 1 ) ]
+ else
+ let cmd = [ strpart( cmdline, c ) ]
+ endif
+
+ " Build a possible multi-line command up to the cursor line/position
+ let l = lastline + 1
+ while l <= line(".")
+ if line(".") == l
+ call add( cmd, strpart( getline( l ), 0, col(".") - 1) )
+ else
+ call add( cmd, strpart( getline( l ), 0) )
+ endif
+ let l = l + 1
+ endwhile
+
+ " Count the number of opening and closing braces in the command before the cursor
+ let end = s:CloseForm( join( cmd, "\n" ) )
+ if end != 'ERROR' && end != ''
+ " Command part before cursor is unbalanced, insert newline
+ let s:arglist_line = line('.')
+ let s:arglist_col = col('.')
+ if pumvisible()
+ " Pressing <CR> in a pop up selects entry.
+ return "\<C-Y>"
+ else
+ if exists( 'g:paredit_mode' ) && g:paredit_mode && g:paredit_electric_return && lastline > 0 && line( "." ) >= lastline
+ " Apply electric return
+ return PareditEnter()
+ else
+ " No electric return handling, just enter a newline
+ return "\<CR>"
+ endif
+ endif
+ else
+ " Send current command line for evaluation
+ if &virtualedit != 'all'
+ call cursor( 0, 99999 )
+ endif
+ call SlimvSendCommand(0)
+ endif
+ return ''
+endfunction
+
+" Handle normal mode 'Enter' keypress in the SLDB buffer
+function! SlimvHandleEnterSldb()
+ let line = getline('.')
+ if s:sldb_level >= 0
+ " Check if Enter was pressed in a section printed by the SWANK debugger
+ " The source specification is within a fold, so it has to be tested first
+ let mlist = matchlist( line, '^\s\+in "\=\(.*\)"\= \(line\|byte\) \(\d\+\)$' )
+ if len(mlist)
+ if g:slimv_repl_split
+ " Switch back to other window
+ execute "wincmd p"
+ endif
+ " Jump to the file at the specified position
+ if mlist[2] == 'line'
+ exec ":edit +" . mlist[3] . " " . mlist[1]
+ else
+ exec ":edit +" . mlist[3] . "go " . mlist[1]
+ endif
+ return
+ endif
+ if foldlevel('.')
+ " With a fold just toggle visibility
+ normal za
+ return
+ endif
+ let item = matchstr( line, s:frame_def )
+ if item != ''
+ let item = substitute( item, '\s\|:', '', 'g' )
+ if search( '^Backtrace:', 'bnW' ) > 0
+ " Display item-th frame
+ call SlimvMakeFold()
+ silent execute s:py_cmd . 'swank_frame_locals("' . item . '")'
+ if SlimvGetFiletype() != 'scheme' && g:slimv_impl != 'clisp'
+ " Not implemented for CLISP or scheme
+ silent execute s:py_cmd . 'swank_frame_source_loc("' . item . '")'
+ endif
+ if SlimvGetFiletype() == 'lisp' && g:slimv_impl != 'clisp' && g:slimv_impl != 'allegro'
+ " Not implemented for CLISP or other lisp dialects
+ silent execute s:py_cmd . 'swank_frame_call("' . item . '")'
+ endif
+ call SlimvRefreshReplBuffer()
+ return
+ endif
+ if search( '^Restarts:', 'bnW' ) > 0
+ " Apply item-th restart
+ call SlimvQuitSldb()
+ silent execute s:py_cmd . 'swank_invoke_restart("' . s:sldb_level . '", "' . item . '")'
+ call SlimvRefreshReplBuffer()
+ return
+ endif
+ endif
+ endif
+
+ " No special treatment, perform the original function
+ execute "normal! \<CR>"
+endfunction
+
+" Restore Inspector cursor position if the referenced title has already been visited
+function SlimvSetInspectPos( title )
+ if exists( 'b:inspect_pos' ) && has_key( b:inspect_pos, a:title )
+ call winrestview( b:inspect_pos[a:title] )
+ else
+ normal! gg0
+ endif
+endfunction
+
+" Handle normal mode 'Enter' keypress in the Inspector buffer
+function! SlimvHandleEnterInspect()
+ let line = getline('.')
+ if line[0:9] == 'Inspecting'
+ " Reload inspected item
+ call SlimvSendSilent( ['[0]'] )
+ return
+ endif
+
+ " Find the closest [dd] or <dd> token to the left of the cursor
+ let [l, c] = searchpos( '{\[\d\+\]', 'bncW' )
+ let [l2, c2] = searchpos( '{<\d\+>', 'bncW' )
+ if l < line('.') || (l2 == line('.') && c2 > c)
+ let l = l2
+ let c = c2
+ endif
+
+ if l < line('.')
+ " No preceding token found, find the closest [dd] or <dd> to the right
+ let [l, c] = searchpos( '{\[\d\+\]', 'ncW' )
+ let [l2, c2] = searchpos( '{<\d\+>', 'ncW' )
+ if l == 0 || l > line('.') || (l2 == line('.') && c2 < c)
+ let l = l2
+ let c = c2
+ endif
+ endif
+
+ if l == line( '.' )
+ " Keep the relevant part of the line
+ let line = strpart( line, c )
+ endif
+
+ if exists( 'b:inspect_title' ) && b:inspect_title != ''
+ " Save cursor position in case we'll return to this page later on
+ if !exists( 'b:inspect_pos' )
+ let b:inspect_pos = {}
+ endif
+ let b:inspect_pos[b:inspect_title] = winsaveview()
+ endif
+
+ if line[0] == '['
+ if line =~ '^\[--more--\]$'
+ " More data follows, fetch next part
+ call SlimvCommand( s:py_cmd . 'swank_inspector_range()' )
+ call SlimvRefreshReplBuffer()
+ return
+ elseif line =~ '^\[--all---\]$'
+ " More data follows, fetch all parts
+ echon "\rFetching all entries, please wait..."
+ let b:inspect_more = -1
+ call SlimvCommand( s:py_cmd . 'swank_inspector_range()' )
+ call SlimvRefreshReplBuffer()
+ let starttime = localtime()
+ while b:inspect_more < 0 && localtime()-starttime < g:slimv_timeout
+ " Wait for the first swank_inspector_range() call to finish
+ call SlimvRefreshReplBuffer()
+ endwhile
+ let starttime = localtime()
+ while b:inspect_more > 0 && localtime()-starttime < g:slimv_timeout
+ " There are more parts to fetch (1 entry is usually 4 parts)
+ echon "\rFetching all entries, please wait [" . (b:inspect_more / 4) . "]"
+ call SlimvCommand( s:py_cmd . 'swank_inspector_range()' )
+ call SlimvRefreshReplBuffer()
+ if getchar(1)
+ " User is impatient, stop fetching
+ break
+ endif
+ endwhile
+ if b:inspect_more > 0
+ echon "\rFetch exhausted. Select [--all---] to resume."
+ else
+ echon "\rSuccessfully fetched all entries."
+ endif
+ return
+ elseif line[0:3] == '[<<]'
+ " Pop back up in the inspector
+ let item = '-1'
+ else
+ " Inspect n-th part
+ let item = matchstr( line, '\d\+' )
+ if item != ''
+ " Add item name to the object path
+ let entry = matchstr(line, '\[\d\+\]\s*\zs.\{-}\ze\s*\[\]}')
+ if entry == ''
+ let entry = matchstr(line, '\[\d\+\]\s*\zs.*')
+ endif
+ if entry == ''
+ let entry = 'Unknown object'
+ endif
+ if len( entry ) > 40
+ " Crop if too long
+ let entry = strpart( entry, 0, 37 ) . '...'
+ endif
+ let s:inspect_path = s:inspect_path + [entry]
+ endif
+ endif
+ if item != ''
+ call SlimvSendSilent( ['[' . item . ']'] )
+ return
+ endif
+ endif
+
+ if line[0] == '<'
+ " Inspector n-th action
+ let item = matchstr( line, '\d\+' )
+ if item != ''
+ call SlimvSendSilent( ['<' . item . '>'] )
+ return
+ endif
+ endif
+
+ " No special treatment, perform the original function
+ execute "normal! \<CR>"
+endfunction
+
+" Go to command line and recall previous command from command history
+function! SlimvPreviousCommand()
+ let save_ve = &virtualedit
+ set virtualedit=onemore
+ call SlimvEndOfReplBuffer(0)
+ if line( "." ) >= s:GetPromptLine()
+ call s:PreviousCommand()
+ endif
+ let &virtualedit=save_ve
+endfunction
+
+" Go to command line and recall next command from command history
+function! SlimvNextCommand()
+ let save_ve = &virtualedit
+ set virtualedit=onemore
+ call SlimvEndOfReplBuffer(0)
+ if line( "." ) >= s:GetPromptLine()
+ call s:NextCommand()
+ endif
+ let &virtualedit=save_ve
+endfunction
+
+" Handle interrupt (Ctrl-C) keypress in the REPL buffer
+function! SlimvInterrupt()
+ call SlimvCommand( s:py_cmd . 'swank_interrupt()' )
+ call SlimvRefreshReplBuffer()
+endfunction
+
+" Select a specific restart in debugger
+function! SlimvDebugCommand( name, cmd )
+ if SlimvConnectSwank()
+ if s:sldb_level >= 0
+ if bufname('%') != g:slimv_sldb_name
+ call SlimvOpenSldbBuffer()
+ endif
+ call SlimvCommand( s:py_cmd . '' . a:cmd . '()' )
+ call SlimvRefreshReplBuffer()
+ if s:sldb_level < 0
+ " Swank exited the debugger
+ if bufname('%') != g:slimv_sldb_name
+ call SlimvOpenSldbBuffer()
+ endif
+ call SlimvQuitSldb()
+ else
+ echomsg 'Debugger re-activated by the SWANK server.'
+ endif
+ else
+ call SlimvError( "Debugger is not activated." )
+ endif
+ endif
+endfunction
+
+" Various debugger restarts
+function! SlimvDebugAbort()
+ call SlimvDebugCommand( ":sldb-abort", "swank_invoke_abort" )
+endfunction
+
+function! SlimvDebugQuit()
+ call SlimvDebugCommand( ":throw-to-toplevel", "swank_throw_toplevel" )
+endfunction
+
+function! SlimvDebugContinue()
+ call SlimvDebugCommand( ":sldb-continue", "swank_invoke_continue" )
+endfunction
+
+" Restart execution of the frame with the same arguments
+function! SlimvDebugRestartFrame()
+ let frame = s:DebugFrame()
+ if frame != ''
+ call SlimvCommand( s:py_cmd . 'swank_restart_frame("' . frame . '")' )
+ call SlimvRefreshReplBuffer()
+ endif
+endfunction
+
+" List current Lisp threads
+function! SlimvListThreads()
+ if SlimvConnectSwank()
+ call SlimvCommand( s:py_cmd . 'swank_list_threads()' )
+ call SlimvRefreshReplBuffer()
+ endif
+endfunction
+
+" Kill thread(s) selected from the Thread List
+function! SlimvKillThread() range
+ if SlimvConnectSwank()
+ if a:firstline == a:lastline
+ let line = getline('.')
+ let item = matchstr( line, '\d\+' )
+ if bufname('%') != g:slimv_threads_name
+ " We are not in the Threads buffer, not sure which thread to kill
+ let item = input( 'Thread to kill: ', item )
+ endif
+ if item != ''
+ call SlimvCommand( s:py_cmd . 'swank_kill_thread(' . item . ')' )
+ call SlimvRefreshReplBuffer()
+ endif
+ echomsg 'Thread ' . item . ' is killed.'
+ else
+ for line in getline(a:firstline, a:lastline)
+ let item = matchstr( line, '\d\+' )
+ if item != ''
+ call SlimvCommand( s:py_cmd . 'swank_kill_thread(' . item . ')' )
+ endif
+ endfor
+ call SlimvRefreshReplBuffer()
+ endif
+ call SlimvListThreads()
+ endif
+endfunction
+
+" Debug thread selected from the Thread List
+function! SlimvDebugThread()
+ if SlimvConnectSwank()
+ let line = getline('.')
+ let item = matchstr( line, '\d\+' )
+ let item = input( 'Thread to debug: ', item )
+ if item != ''
+ call SlimvCommand( s:py_cmd . 'swank_debug_thread(' . item . ')' )
+ call SlimvRefreshReplBuffer()
+ endif
+ endif
+endfunction
+
+function! SlimvRFunction()
+ " search backwards for the alphanums before a '('
+ let l = line('.')
+ let c = col('.') - 1
+ let line = (getline('.'))[0:c]
+ let list = matchlist(line, '\([a-zA-Z0-9_.]\+\)\s*(')
+ if !len(list)
+ return ""
+ endif
+ let valid = filter(reverse(list), 'v:val != ""')
+ return valid[0]
+endfunction
+
+" Display function argument list
+" Optional argument is the number of characters typed after the keyword
+function! SlimvArglist( ... )
+ let retval = ''
+ let save_ve = &virtualedit
+ set virtualedit=all
+ if a:0
+ " Symbol position supplied
+ let l = a:1
+ let c = a:2 - 1
+ let line = getline(l)
+ else
+ " Check symbol at cursor position
+ let l = line('.')
+ let line = getline(l)
+ let c = col('.') - 1
+ if c >= len(line)
+ " Stay at the end of line
+ let c = len(line) - 1
+ let retval = "\<End>"
+ endif
+ if line[c-1] == ' '
+ " Is this the space we have just inserted in a mapping?
+ let c = c - 1
+ endif
+ endif
+ call s:SetKeyword()
+ if s:swank_connected && !s:read_string_mode && c > 0 && line[c-1] =~ '\k\|)\|\]\|}\|"'
+ " Display only if entering the first space after a keyword
+ let arg = ''
+ if SlimvGetFiletype() == 'r'
+ let arg = SlimvRFunction()
+ else
+ let matchb = max( [l-200, 1] )
+ let [l0, c0] = searchpairpos( '(', '', ')', 'nbW', s:skip_sc, matchb )
+ if l0 > 0
+ " Found opening paren, let's find out the function name
+ while arg == '' && l0 <= l
+ let funcline = substitute( getline(l0), ';.*$', '', 'g' )
+ let arg = matchstr( funcline, '\<\k*\>', c0 )
+ let l0 = l0 + 1
+ let c0 = 0
+ endwhile
+ endif
+ endif
+
+ if arg != ''
+ " Ask function argument list from SWANK
+ call SlimvFindPackage()
+ let msg = SlimvCommandGetResponse( ':operator-arglist', s:py_cmd . 'swank_op_arglist("' . arg . '")', 0 )
+ if msg != ''
+ " Print argument list in status line with newlines removed.
+ " Disable showmode until the next ESC to prevent
+ " immeditate overwriting by the "-- INSERT --" text.
+ set noshowmode
+ let msg = substitute( msg, "\n", "", "g" )
+ redraw
+ if SlimvGetFiletype() == 'r'
+ call SlimvShortEcho( arg . '(' . msg . ')' )
+ elseif match( msg, "\\V" . arg ) != 1 " Use \V ('very nomagic') for exact string match instead of regex
+ " Function name is not received from REPL
+ call SlimvShortEcho( "(" . arg . ' ' . msg[1:] )
+ else
+ call SlimvShortEcho( msg )
+ endif
+ endif
+ endif
+ endif
+
+ " This function is also called from <C-R>= mappings, return additional keypress
+ let &virtualedit=save_ve
+ return retval
+endfunction
+
+" Start and connect swank server
+function! SlimvConnectServer()
+ if s:swank_connected
+ execute s:py_cmd . "swank_disconnect()"
+ let s:swank_connected = 0
+ " Give swank server some time for disconnecting
+ sleep 500m
+ endif
+ if SlimvConnectSwank()
+ let repl_win = bufwinnr( s:repl_buf )
+ if s:repl_buf == -1 || ( g:slimv_repl_split && repl_win == -1 )
+ call SlimvOpenReplBuffer()
+ endif
+ endif
+endfunction
+
+" Get the last region (visual block)
+function! SlimvGetRegion(first, last)
+ let oldpos = winsaveview()
+ 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
+ execute "normal! \<Esc>"
+ call winrestview( oldpos )
+ let lines = getline( "'<", "'>" )
+ if lines == [] || lines == ['']
+ call SlimvError( "No range selected." )
+ return []
+ endif
+ endif
+ let firstcol = col( "'<" ) - 1
+ let lastcol = col( "'>" ) - 2
+ if lastcol >= 0
+ let lines[len(lines)-1] = lines[len(lines)-1][ : lastcol]
+ else
+ let lines[len(lines)-1] = ''
+ endif
+ let lines[0] = lines[0][firstcol : ]
+
+ " Find and set package/namespace definition preceding the region
+ call SlimvFindPackage()
+ call winrestview( oldpos )
+ return lines
+endfunction
+
+" Eval buffer lines in the given range
+function! SlimvEvalRegion() range
+ if v:register == '"' || 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 = ""
+ if SlimvGetFiletype() != 'r'
+ let ending = s:CloseForm( reg )
+ if ending == 'ERROR'
+ call SlimvError( 'Too many or invalid closing parens in register "' . v:register )
+ return
+ endif
+ endif
+ let lines = [reg . ending]
+ endif
+ if lines != []
+ if SlimvGetFiletype() == 'scheme'
+ " Swank-scheme requires us to pass a single s-expression
+ " so embed buffer lines in a (begin ...) block
+ let lines = ['(begin'] + lines + [')']
+ endif
+ call SlimvEval( lines )
+ endif
+endfunction
+
+" Eval contents of the 's' register, optionally store it in another register
+" Also optionally append a test form for quick testing (not stored in 'outreg')
+" If the test form contains '%1' then it 'wraps' the selection around the '%1'
+function! SlimvEvalSelection( outreg, testform )
+ let sel = SlimvGetSelection()
+ if a:outreg != '"' && a:outreg != '+'
+ " Register was passed, so store current selection in register
+ call setreg( a:outreg, s:swank_package_form . sel)
+ endif
+ let lines = [sel]
+ if a:testform != ''
+ if match( a:testform, '%1' ) >= 0
+ " We need to wrap the selection in the testform
+ if match( sel, "\n" ) < 0
+ " The selection is a single line, keep the wrapped form in one line
+ let sel = substitute( a:testform, '%1', sel, 'g' )
+ let lines = [sel]
+ else
+ " The selection is multiple lines, wrap it by adding new lines
+ let lines = [strpart( a:testform, 0, match( a:testform, '%1' ) ),
+ \ sel,
+ \ strpart( a:testform, matchend( a:testform, '%1' ) )]
+ endif
+ else
+ " Append optional test form at the tail
+ let lines = lines + [a:testform]
+ endif
+ endif
+ if exists( 'b:slimv_repl_buffer' )
+ " If this is the REPL buffer then go to EOF
+ call s:EndOfBuffer()
+ endif
+ call SlimvEval( lines )
+endfunction
+
+" Eval Lisp form.
+" Form given in the template is passed to Lisp without modification.
+function! SlimvEvalForm( template )
+ let lines = [a:template]
+ call SlimvEval( lines )
+endfunction
+
+" Eval Lisp form, with the given parameter substituted in the template.
+" %1 string is substituted with par1
+function! SlimvEvalForm1( template, par1 )
+ let p1 = escape( a:par1, '&' )
+ let temp1 = substitute( a:template, '%1', p1, 'g' )
+ let lines = [temp1]
+ call SlimvEval( lines )
+endfunction
+
+" Eval Lisp form, with the given parameters substituted in the template.
+" %1 string is substituted with par1
+" %2 string is substituted with par2
+function! SlimvEvalForm2( template, par1, par2 )
+ let p1 = escape( a:par1, '&' )
+ let p2 = escape( a:par2, '&' )
+ let temp1 = substitute( a:template, '%1', p1, 'g' )
+ let temp2 = substitute( temp1, '%2', p2, 'g' )
+ let lines = [temp2]
+ call SlimvEval( lines )
+endfunction
+
+
+" =====================================================================
+" Special functions
+" =====================================================================
+
+" Evaluate and test top level form at the cursor pos
+function! SlimvEvalTestDefun( testform )
+ let outreg = v:register
+ let oldpos = winsaveview()
+ if !SlimvSelectDefun()
+ return
+ endif
+ call SlimvFindPackage()
+ call winrestview( oldpos )
+ call SlimvEvalSelection( outreg, a:testform )
+endfunction
+
+" Evaluate top level form at the cursor pos
+function! SlimvEvalDefun()
+ call SlimvEvalTestDefun( '' )
+endfunction
+
+" Evaluate the whole buffer
+function! SlimvEvalBuffer()
+ if exists( 'b:slimv_repl_buffer' )
+ call SlimvError( "Cannot evaluate the REPL buffer." )
+ return
+ endif
+ let lines = getline( 1, '$' )
+ if SlimvGetFiletype() == 'scheme'
+ " Swank-scheme requires us to pass a single s-expression
+ " so embed buffer lines in a (begin ...) block
+ let lines = ['(begin'] + lines + [')']
+ endif
+ call SlimvEval( lines )
+endfunction
+
+" Return frame number if we are in the Backtrace section of the debugger
+function! s:DebugFrame()
+ if s:swank_connected && s:sldb_level >= 0
+ " Check if we are in SLDB
+ let sldb_buf = bufnr( '^' . g:slimv_sldb_name . '$' )
+ if sldb_buf != -1 && sldb_buf == bufnr( "%" )
+ let bcktrpos = search( '^Backtrace:', 'bcnw' )
+ let framepos = line( '.' )
+ if matchstr( getline('.'), s:frame_def ) == ''
+ let framepos = search( s:frame_def, 'bcnw' )
+ endif
+ if framepos > 0 && bcktrpos > 0 && framepos > bcktrpos
+ let line = getline( framepos )
+ let item = matchstr( line, s:frame_def )
+ if item != ''
+ return substitute( item, '\s\|:', '', 'g' )
+ endif
+ endif
+ endif
+ endif
+ return ''
+endfunction
+
+" Evaluate and test current s-expression at the cursor pos
+function! SlimvEvalTestExp( testform )
+ let outreg = v:register
+ let oldpos = winsaveview()
+ if !SlimvSelectForm( 1 )
+ return
+ endif
+ call SlimvFindPackage()
+ call winrestview( oldpos )
+ call SlimvEvalSelection( outreg, a:testform )
+endfunction
+
+" Evaluate current s-expression at the cursor pos
+function! SlimvEvalExp()
+ call SlimvEvalTestExp( '' )
+endfunction
+
+" Evaluate expression entered interactively
+function! SlimvInteractiveEval()
+ let frame = s:DebugFrame()
+ if frame != ''
+ " 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', s:py_cmd . 'swank_eval_in_frame("' . e . '", ' . frame . ')', 0 )
+ if result != ''
+ redraw
+ echo result
+ endif
+ endif
+ else
+ let e = input( 'Eval: ' )
+ if e != ''
+ call SlimvEval([e])
+ endif
+ endif
+endfunction
+
+" Undefine function
+function! SlimvUndefineFunction()
+ if s:swank_connected
+ call SlimvCommand( s:py_cmd . 'swank_undefine_function("' . SlimvSelectSymbol() . '")' )
+ call SlimvRefreshReplBuffer()
+ endif
+endfunction
+
+" ---------------------------------------------------------------------
+
+" Macroexpand-1 the current top level form
+function! SlimvMacroexpand()
+ if SlimvConnectSwank()
+ if !SlimvSelectForm( 0 )
+ return
+ endif
+ let s:swank_form = SlimvGetSelection()
+ if exists( 'b:slimv_repl_buffer' )
+ " If this is the REPL buffer then go to EOF
+ call s:EndOfBuffer()
+ endif
+ call SlimvCommandUsePackage( s:py_cmd . 'swank_macroexpand("s:swank_form")' )
+ endif
+endfunction
+
+" Macroexpand the current top level form
+function! SlimvMacroexpandAll()
+ if SlimvConnectSwank()
+ if !SlimvSelectForm( 0 )
+ return
+ endif
+ let s:swank_form = SlimvGetSelection()
+ if exists( 'b:slimv_repl_buffer' )
+ " If this is the REPL buffer then go to EOF
+ call s:EndOfBuffer()
+ endif
+ call SlimvCommandUsePackage( s:py_cmd . 'swank_macroexpand_all("s:swank_form")' )
+ endif
+endfunction
+
+" Toggle debugger break on exceptions
+" Only for ritz-swank 0.4.0 and above
+function! SlimvBreakOnException()
+ if SlimvGetFiletype() =~ '.*clojure.*' && s:SinceVersion( '2010-11-13' )
+ " swank-clojure is abandoned at protocol version 20100404, so it must be ritz-swank
+ if SlimvConnectSwank()
+ let s:break_on_exception = ! s:break_on_exception
+ call SlimvCommand( s:py_cmd . 'swank_break_on_exception(' . s:break_on_exception . ')' )
+ call SlimvRefreshReplBuffer()
+ echomsg 'Break On Exception ' . (s:break_on_exception ? 'enabled.' : 'disabled.')
+ endif
+ else
+ call SlimvError( "This function is implemented only for ritz-swank." )
+ endif
+endfunction
+
+" Set a breakpoint on the beginning of a function
+function! SlimvBreak()
+ if SlimvConnectSwank()
+ let s = input( 'Set breakpoint: ', SlimvSelectSymbol() )
+ if s != ''
+ call SlimvCommandUsePackage( s:py_cmd . 'swank_set_break("' . s . '")' )
+ redraw!
+ endif
+ endif
+endfunction
+
+" Switch trace on for the selected function (toggle for swank)
+function! SlimvTrace()
+ if SlimvGetFiletype() == 'scheme'
+ call SlimvError( "Tracing is not supported by swank-scheme." )
+ return
+ endif
+ if SlimvConnectSwank()
+ let s = input( '(Un)trace: ', SlimvSelectSymbol() )
+ if s != ''
+ call SlimvCommandUsePackage( s:py_cmd . 'swank_toggle_trace("' . s . '")' )
+ redraw!
+ endif
+ endif
+endfunction
+
+" Switch trace off for the selected function (or all functions for swank)
+function! SlimvUntrace()
+ if SlimvGetFiletype() == 'scheme'
+ call SlimvError( "Tracing is not supported by swank-scheme." )
+ return
+ endif
+ if SlimvConnectSwank()
+ let s:refresh_disabled = 1
+ call SlimvCommand( s:py_cmd . 'swank_untrace_all()' )
+ let s:refresh_disabled = 0
+ call SlimvRefreshReplBuffer()
+ endif
+endfunction
+
+" Disassemble the selected function
+function! SlimvDisassemble()
+ let symbol = SlimvSelectSymbol()
+ if SlimvConnectSwank()
+ let s = input( 'Disassemble: ', symbol )
+ if s != ''
+ call SlimvCommandUsePackage( s:py_cmd . 'swank_disassemble("' . s . '")' )
+ endif
+ endif
+endfunction
+
+" Inspect symbol under cursor
+function! SlimvInspect()
+ if !SlimvConnectSwank()
+ return
+ endif
+ let s:inspect_path = []
+ let frame = s:DebugFrame()
+ if frame != ''
+ " Inspect selected for a frame in the debugger's Backtrace section
+ let line = getline( '.' )
+ if matchstr( line, s:frame_def ) != ''
+ " This is the base frame line in form ' 1: xxxxx'
+ let sym = ''
+ elseif matchstr( line, '^\s\+in "\(.*\)" \(line\|byte\)' ) != ''
+ " This is the source location line
+ let sym = ''
+ elseif matchstr( line, '^\s\+No source line information' ) != ''
+ " This is the no source location line
+ let sym = ''
+ elseif matchstr( line, '^\s\+Locals:' ) != ''
+ " This is the 'Locals' line
+ let sym = ''
+ else
+ let sym = SlimvSelectSymbolExt()
+ endif
+ let s = input( 'Inspect in frame ' . frame . ' (evaluated): ', sym )
+ if s != ''
+ let s:inspect_path = [s]
+ call SlimvCommand( s:py_cmd . 'swank_inspect_in_frame("' . s . '", ' . frame . ')' )
+ call SlimvRefreshReplBuffer()
+ endif
+ else
+ let s = input( 'Inspect: ', SlimvSelectSymbolExt() )
+ if s != ''
+ let s:inspect_path = [s]
+ call SlimvCommandUsePackage( s:py_cmd . 'swank_inspect("' . s . '")' )
+ endif
+ endif
+endfunction
+
+" Cross reference: who calls
+function! SlimvXrefBase( text, cmd )
+ if SlimvConnectSwank()
+ let s = input( a:text, SlimvSelectSymbol() )
+ if s != ''
+ call SlimvCommandUsePackage( s:py_cmd . 'swank_xref("' . s . '", "' . a:cmd . '")' )
+ endif
+ endif
+endfunction
+
+" Cross reference: who calls
+function! SlimvXrefCalls()
+ call SlimvXrefBase( 'Who calls: ', ':calls' )
+endfunction
+
+" Cross reference: who references
+function! SlimvXrefReferences()
+ call SlimvXrefBase( 'Who references: ', ':references' )
+endfunction
+
+" Cross reference: who sets
+function! SlimvXrefSets()
+ call SlimvXrefBase( 'Who sets: ', ':sets' )
+endfunction
+
+" Cross reference: who binds
+function! SlimvXrefBinds()
+ call SlimvXrefBase( 'Who binds: ', ':binds' )
+endfunction
+
+" Cross reference: who macroexpands
+function! SlimvXrefMacroexpands()
+ call SlimvXrefBase( 'Who macroexpands: ', ':macroexpands' )
+endfunction
+
+" Cross reference: who specializes
+function! SlimvXrefSpecializes()
+ call SlimvXrefBase( 'Who specializes: ', ':specializes' )
+endfunction
+
+" Cross reference: list callers
+function! SlimvXrefCallers()
+ call SlimvXrefBase( 'List callers: ', ':callers' )
+endfunction
+
+" Cross reference: list callees
+function! SlimvXrefCallees()
+ call SlimvXrefBase( 'List callees: ', ':callees' )
+endfunction
+
+" ---------------------------------------------------------------------
+
+" Switch or toggle profiling on for the selected function
+function! SlimvProfile()
+ if SlimvConnectSwank()
+ let s = input( '(Un)profile: ', SlimvSelectSymbol() )
+ if s != ''
+ call SlimvCommandUsePackage( s:py_cmd . 'swank_toggle_profile("' . s . '")' )
+ redraw!
+ endif
+ endif
+endfunction
+
+" Switch profiling on based on substring
+function! SlimvProfileSubstring()
+ if SlimvConnectSwank()
+ let s = input( 'Profile by matching substring: ', SlimvSelectSymbol() )
+ if s != ''
+ let p = input( 'Package (RET for all packages): ' )
+ call SlimvCommandUsePackage( s:py_cmd . 'swank_profile_substring("' . s . '","' . p . '")' )
+ redraw!
+ endif
+ endif
+endfunction
+
+" Switch profiling completely off
+function! SlimvUnprofileAll()
+ if SlimvConnectSwank()
+ call SlimvCommandUsePackage( s:py_cmd . 'swank_unprofile_all()' )
+ endif
+endfunction
+
+" Display list of profiled functions
+function! SlimvShowProfiled()
+ if SlimvConnectSwank()
+ call SlimvCommandUsePackage( s:py_cmd . 'swank_profiled_functions()' )
+ endif
+endfunction
+
+" Report profiling results
+function! SlimvProfileReport()
+ if SlimvConnectSwank()
+ call SlimvCommandUsePackage( s:py_cmd . 'swank_profile_report()' )
+ endif
+endfunction
+
+" Reset profiling counters
+function! SlimvProfileReset()
+ if SlimvConnectSwank()
+ call SlimvCommandUsePackage( s:py_cmd . 'swank_profile_reset()' )
+ endif
+endfunction
+
+" ---------------------------------------------------------------------
+
+" Compile the current top-level form
+function! SlimvCompileDefun()
+ let oldpos = winsaveview()
+ if !SlimvSelectDefun()
+ call winrestview( oldpos )
+ return
+ endif
+ if SlimvConnectSwank()
+ let s:swank_form = SlimvGetSelection()
+ call SlimvCommandUsePackage( s:py_cmd . 'swank_compile_string("s:swank_form")' )
+ endif
+ call winrestview( oldpos )
+endfunction
+
+" Compile and load whole file
+function! SlimvCompileLoadFile()
+ if exists( 'b:slimv_repl_buffer' )
+ call SlimvError( "Cannot compile the REPL buffer." )
+ return
+ endif
+ let filename = fnamemodify( bufname(''), ':p' )
+ let filename = substitute( filename, '\\', '/', 'g' )
+ if &modified
+ let answer = SlimvErrorAsk( '', "Save file before compiling [Y/n]?" )
+ if answer[0] != 'n' && answer[0] != 'N'
+ write
+ endif
+ endif
+ if SlimvConnectSwank()
+ let s:compiled_file = ''
+ call SlimvCommandUsePackage( s:py_cmd . 'swank_compile_file("' . filename . '")' )
+ let starttime = localtime()
+ while s:compiled_file == '' && localtime()-starttime < g:slimv_timeout
+ call SlimvSwankResponse()
+ endwhile
+ if s:compiled_file != ''
+ let s:compiled_file = substitute( s:compiled_file, '\\', '/', 'g' )
+ call SlimvCommandUsePackage( s:py_cmd . 'swank_load_file("' . s:compiled_file . '")' )
+ let s:compiled_file = ''
+ endif
+ endif
+endfunction
+
+" Compile whole file
+function! SlimvCompileFile()
+ if exists( 'b:slimv_repl_buffer' )
+ call SlimvError( "Cannot compile the REPL buffer." )
+ return
+ endif
+ let filename = fnamemodify( bufname(''), ':p' )
+ let filename = substitute( filename, '\\', '/', 'g' )
+ if &modified
+ let answer = SlimvErrorAsk( '', "Save file before compiling [Y/n]?" )
+ if answer[0] != 'n' && answer[0] != 'N'
+ write
+ endif
+ endif
+ if SlimvConnectSwank()
+ call SlimvCommandUsePackage( s:py_cmd . 'swank_compile_file("' . filename . '")' )
+ endif
+endfunction
+
+" Compile buffer lines in the given range
+function! SlimvCompileRegion() range
+ if v:register == '"' || 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
+ let region = join( lines, "\n" )
+ if SlimvConnectSwank()
+ let s:swank_form = region
+ call SlimvCommandUsePackage( s:py_cmd . 'swank_compile_string("s:swank_form")' )
+ endif
+endfunction
+
+" ---------------------------------------------------------------------
+
+" Describe the selected symbol
+function! SlimvDescribeSymbol()
+ if SlimvConnectSwank()
+ let symbol = SlimvSelectSymbol()
+ if symbol == ''
+ call SlimvError( "No symbol under cursor." )
+ return
+ endif
+ call SlimvCommandUsePackage( s:py_cmd . 'swank_describe_symbol("' . symbol . '")' )
+ endif
+endfunction
+
+" Display symbol description in balloonexpr
+function! SlimvDescribe(arg)
+ let arg=a:arg
+ if a:arg == ''
+ let arg = expand('<cword>')
+ endif
+ " We don't want to try connecting here ... the error message would just
+ " confuse the balloon logic
+ if !s:swank_connected || s:read_string_mode
+ return ''
+ endif
+ call SlimvFindPackage()
+ let arglist = SlimvCommandGetResponse( ':operator-arglist', s:py_cmd . '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', s:py_cmd . 'swank_describe_function("' . arg . '")', 0 )
+ if msg == ''
+ " No describe info, display arglist
+ if match( arglist, arg ) != 1
+ " Function name is not received from REPL
+ return "(" . arg . ' ' . arglist[1:]
+ else
+ return arglist
+ endif
+ else
+ return substitute(msg,'^\n*','','')
+ endif
+endfunction
+
+" Apropos of the selected symbol
+function! SlimvApropos()
+ call SlimvEvalForm1( g:slimv_template_apropos, SlimvSelectSymbol() )
+endfunction
+
+" Generate tags file using ctags
+function! SlimvGenerateTags()
+ if exists( 'g:slimv_ctags' ) && g:slimv_ctags != ''
+ execute 'silent !' . g:slimv_ctags
+ else
+ call SlimvError( "Copy ctags to the Vim path or define g:slimv_ctags." )
+ endif
+endfunction
+
+" ---------------------------------------------------------------------
+
+" Find word in the CLHS symbol database, with exact or partial match.
+" Return either the first symbol found with the associated URL,
+" or the list of all symbols found without the associated URL.
+function! SlimvFindSymbol( word, exact, all, db, root, init )
+ if a:word == ''
+ return []
+ endif
+ if !a:all && a:init != []
+ " Found something already at a previous db lookup, no need to search this db
+ return a:init
+ endif
+ let lst = a:init
+ let i = 0
+ let w = tolower( a:word )
+ if a:exact
+ while i < len( a:db )
+ " Try to find an exact match
+ if a:db[i][0] == w
+ " No reason to check a:all here
+ return [a:db[i][0], a:root . a:db[i][1]]
+ endif
+ let i = i + 1
+ endwhile
+ else
+ while i < len( a:db )
+ " Try to find the symbol starting with the given word
+ let w2 = escape( w, '~' )
+ if match( a:db[i][0], w2 ) == 0
+ if a:all
+ call add( lst, a:db[i][0] )
+ else
+ return [a:db[i][0], a:root . a:db[i][1]]
+ endif
+ endif
+ let i = i + 1
+ endwhile
+ endif
+
+ " Return whatever found so far
+ return lst
+endfunction
+
+" Lookup word in Common Lisp Hyperspec
+function! SlimvLookup( word )
+ " First try an exact match
+ let w = a:word
+ let symbol = []
+ while symbol == []
+ let symbol = SlimvHyperspecLookup( w, 1, 0 )
+ if symbol == []
+ " Symbol not found, try a match on beginning of symbol name
+ let symbol = SlimvHyperspecLookup( w, 0, 0 )
+ if symbol == []
+ " We are out of luck, can't find anything
+ let msg = 'Symbol ' . w . ' not found. Hyperspec lookup word: '
+ let val = ''
+ else
+ let msg = 'Hyperspec lookup word: '
+ let val = symbol[0]
+ endif
+ " Ask user if this is that he/she meant
+ let w = input( msg, val )
+ if w == ''
+ " OK, user does not want to continue
+ return
+ endif
+ let symbol = []
+ endif
+ endwhile
+ if symbol != [] && len(symbol) > 1
+ " Symbol found, open HS page in browser
+ if match( symbol[1], ':' ) < 0 && exists( 'g:slimv_hs_root' )
+ let page = g:slimv_hs_root . symbol[1]
+ else
+ " URL is already a fully qualified address
+ let page = symbol[1]
+ endif
+ if exists( "g:slimv_browser_cmd" )
+ " We have an given command to start the browser
+ if !exists( "g:slimv_browser_cmd_suffix" )
+ " Fork the browser by default
+ let g:slimv_browser_cmd_suffix = '&'
+ endif
+ silent execute '! ' . g:slimv_browser_cmd . ' ' . page . ' ' . g:slimv_browser_cmd_suffix
+ else
+ if g:slimv_windows
+ " Run the program associated with the .html extension
+ silent execute '! start ' . page
+ else
+ " On Linux it's not easy to determine the default browser
+ if executable( 'xdg-open' )
+ silent execute '! xdg-open ' . page . ' &'
+ else
+ " xdg-open not installed, ask help from Python webbrowser package
+ let pycmd = "import webbrowser; webbrowser.open('" . page . "')"
+ silent execute '! python -c "' . pycmd . '"'
+ endif
+ endif
+ endif
+ " This is needed especially when using text browsers
+ redraw!
+ endif
+endfunction
+
+" Lookup current symbol in the Common Lisp Hyperspec
+function! SlimvHyperspec()
+ call SlimvLookup( SlimvSelectSymbol() )
+endfunction
+
+" Complete symbol name starting with 'base'
+function! SlimvComplete( base )
+ " Find all symbols starting with "a:base"
+ if a:base == ''
+ return []
+ endif
+ if s:swank_connected && !s:read_string_mode
+ " Save current buffer and window in case a swank command causes a buffer change
+ let buf = bufnr( "%" )
+ if winnr('$') < 2
+ let win = 0
+ else
+ let win = winnr()
+ endif
+
+ call SlimvFindPackage()
+ if g:slimv_simple_compl
+ let msg = SlimvCommandGetResponse( ':simple-completions', s:py_cmd . 'swank_completions("' . a:base . '")', 0 )
+ else
+ let msg = SlimvCommandGetResponse( ':fuzzy-completions', s:py_cmd . 'swank_fuzzy_completions("' . a:base . '")', 0 )
+ endif
+
+ " Restore window and buffer, because it is not allowed to change buffer here
+ if win > 0 && winnr() != win
+ execute win . "wincmd w"
+ let msg = ''
+ endif
+ if bufnr( "%" ) != buf
+ execute "buf " . buf
+ let msg = ''
+ 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 = SlimvHyperspecLookup( a:base, 0, 1 )
+ if symbol == []
+ return []
+ endif
+ 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! SlimvOmniComplete( findstart, base )
+ if a:findstart
+ " Locate the start of the symbol name
+ call s:SetKeyword()
+ let upto = strpart( getline( '.' ), 0, col( '.' ) - 1)
+ return match(upto, '\k\+$')
+ else
+ return SlimvComplete( a:base )
+ endif
+endfunction
+
+" Define complete function only if none is defined yet
+if &omnifunc == ''
+ set omnifunc=SlimvOmniComplete
+endif
+
+" Complete function for user-defined commands
+function! SlimvCommandComplete( arglead, cmdline, cursorpos )
+ " Locate the start of the symbol name
+ call s:SetKeyword()
+ 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
+
+" Create a tags file containing the definitions
+" of the given symbol, then perform a tag lookup
+function! SlimvFindDefinitionsForEmacs( symbol )
+ if g:slimv_tags_file == ''
+ let msg = ''
+ else
+ let msg = SlimvCommandGetResponse( ':find-definitions-for-emacs', s:py_cmd . 'swank_find_definitions_for_emacs("' . a:symbol . '")', 0 )
+ endif
+ try
+ if msg != ''
+ exec ":tjump " . msg
+ else
+ exec ":tjump " . a:symbol
+ endif
+ catch /^Vim\%((\a\+)\)\=:E426/
+ call SlimvError( "\r" . v:exception )
+ endtry
+endfunction
+
+" Lookup definition(s) of the symbol under cursor
+function! SlimvFindDefinitions()
+ if SlimvConnectSwank()
+ let symbol = SlimvSelectSymbol()
+ if symbol == ''
+ call SlimvError( "No symbol under cursor." )
+ return
+ endif
+ call SlimvFindPackage()
+ call SlimvFindDefinitionsForEmacs( symbol )
+ endif
+endfunction
+
+" Lookup definition(s) of symbol entered in prompt
+function! SlimvFindDefinitionsPrompt()
+ if SlimvConnectSwank()
+ let symbol = input( 'Find Definitions For: ', SlimvSelectSymbol() )
+ call SlimvFindDefinitionsForEmacs( symbol )
+ endif
+endfunction
+
+" Set current package
+function! SlimvSetPackage()
+ if SlimvConnectSwank()
+ call SlimvFindPackage()
+ let pkg = input( 'Package: ', s:swank_package )
+ if pkg != ''
+ let s:refresh_disabled = 1
+ call SlimvCommand( s:py_cmd . 'swank_set_package("' . pkg . '")' )
+ let s:refresh_disabled = 0
+ call SlimvRefreshReplBuffer()
+ endif
+ endif
+endfunction
+
+" Close lisp process running the swank server
+" and quit REPL buffer
+function! SlimvQuitRepl()
+ if s:swank_connected
+ call SlimvCommand( s:py_cmd . 'swank_quit_lisp()' )
+ let s:swank_connected = 0
+ let buf = bufnr( '^' . g:slimv_repl_name . '$' )
+ if buf != -1
+ if g:slimv_repl_split
+ " REPL buffer exists, check if it is open in a window
+ let win = bufwinnr( buf )
+ if win != -1
+ " Switch to the REPL window and close it
+ if winnr() != win
+ execute win . "wincmd w"
+ endif
+ execute "wincmd c"
+ endif
+ endif
+ execute "bd " . buf
+ endif
+ endif
+endfunction
+
+" =====================================================================
+" Slimv keybindings
+" =====================================================================
+
+" <Leader> timeouts in 1000 msec by default, if this is too short,
+" then increase 'timeoutlen'
+
+" Map keyboard keyset dependant shortcut to command and also add it to menu
+function! s:MenuMap( name, shortcut1, shortcut2, command )
+ if g:slimv_keybindings == 1
+ " Short (one-key) keybinding set
+ let shortcut = a:shortcut1
+ elseif g:slimv_keybindings == 2
+ " Easy to remember (two-key) keybinding set
+ let shortcut = a:shortcut2
+ else
+ " No bindings
+ let shortcut = ''
+ endif
+
+ if shortcut != ''
+ execute "noremap <silent> " . shortcut . " " . a:command
+ if a:name != '' && g:slimv_menu == 1
+ silent execute "amenu " . a:name . "<Tab>" . shortcut . " " . a:command
+ endif
+ elseif a:name != '' && g:slimv_menu == 1
+ silent execute "amenu " . a:name . " " . a:command
+ endif
+endfunction
+
+" Initialize buffer by adding buffer specific mappings
+function! SlimvInitBuffer()
+ " Map space to display function argument list in status line
+ if SlimvGetFiletype() == 'r'
+ inoremap <silent> <buffer> ( (<C-R>=SlimvArglist()<CR>
+ else
+ if !exists("g:slimv_unmap_space") || g:slimv_unmap_space == 0
+ inoremap <silent> <buffer> <Space> <Space><C-R>=SlimvArglist()<CR>
+ endif
+ if !exists("g:slimv_unmap_cr") || g:slimv_unmap_cr == 0
+ inoremap <silent> <buffer> <CR> <C-R>=pumvisible() ? "\<lt>C-Y>" : SlimvHandleEnter()<CR><C-R>=SlimvArglistOnEnter()<CR>
+ endif
+ endif
+ "noremap <silent> <buffer> <C-C> :call SlimvInterrupt()<CR>
+ augroup SlimvInsertLeave
+ au!
+ au InsertEnter * :let s:save_showmode=&showmode
+ au InsertLeave * :let &showmode=s:save_showmode
+ augroup END
+ inoremap <silent> <buffer> <C-X>0 <C-O>:call SlimvCloseForm()<CR>
+ if !exists("g:slimv_unmap_tab") || g:slimv_unmap_tab == 0
+ inoremap <silent> <buffer> <Tab> <C-R>=SlimvHandleTab()<CR>
+ endif
+ inoremap <silent> <buffer> <S-Tab> <C-R>=pumvisible() ? "\<lt>C-P>" : "\<lt>S-Tab>"<CR>
+ if g:slimv_tags_file != ''
+ nnoremap <silent> <buffer> <C-]> :call SlimvFindDefinitions()<CR>
+ endif
+
+ " Setup balloonexp to display symbol description
+ if g:slimv_balloon && has( 'balloon_eval' )
+ "setlocal balloondelay=100
+ setlocal ballooneval
+ setlocal balloonexpr=SlimvDescribe(v:beval_text)
+ endif
+ " This is needed for safe switching of modified buffers
+ set hidden
+ call s:MakeWindowId()
+endfunction
+
+" Edit commands
+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.Find-&Definitions\.\.\.', g:slimv_leader.'j', g:slimv_leader.'fd', ':call SlimvFindDefinitionsPrompt()<CR>' )
+
+if exists( 'g:paredit_loaded' )
+call s:MenuMap( 'Slim&v.Edi&t.&Paredit-Toggle', g:slimv_leader.'(', g:slimv_leader.'(t', ':<C-U>call PareditToggle()<CR>' )
+call s:MenuMap( 'Slim&v.Edi&t.-PareditSep-', '', '', ':' )
+
+if g:paredit_shortmaps
+call s:MenuMap( 'Slim&v.Edi&t.Paredit-&Wrap<Tab>' .'W', '', '', ':<C-U>call PareditWrap("(",")")<CR>' )
+call s:MenuMap( 'Slim&v.Edi&t.Paredit-Spli&ce<Tab>' .'S', '', '', ':<C-U>call PareditSplice()<CR>' )
+call s:MenuMap( 'Slim&v.Edi&t.Paredit-&Split<Tab>' .'O', '', '', ':<C-U>call PareditSplit()<CR>' )
+call s:MenuMap( 'Slim&v.Edi&t.Paredit-&Join<Tab>' .'J', '', '', ':<C-U>call PareditJoin()<CR>' )
+call s:MenuMap( 'Slim&v.Edi&t.Paredit-Ra&ise<Tab>' .g:slimv_leader.'I', '', '', ':<C-U>call PareditRaise()<CR>' )
+call s:MenuMap( 'Slim&v.Edi&t.Paredit-Move&Left<Tab>' .'<', '', '', ':<C-U>call PareditMoveLeft()<CR>' )
+call s:MenuMap( 'Slim&v.Edi&t.Paredit-Move&Right<Tab>' .'>', '', '', ':<C-U>call PareditMoveRight()<CR>' )
+else
+call s:MenuMap( 'Slim&v.Edi&t.Paredit-&Wrap<Tab>' .g:slimv_leader.'W', '', '', ':<C-U>call PareditWrap("(",")")<CR>' )
+call s:MenuMap( 'Slim&v.Edi&t.Paredit-Spli&ce<Tab>' .g:slimv_leader.'S', '', '', ':<C-U>call PareditSplice()<CR>' )
+call s:MenuMap( 'Slim&v.Edi&t.Paredit-&Split<Tab>' .g:slimv_leader.'O', '', '', ':<C-U>call PareditSplit()<CR>' )
+call s:MenuMap( 'Slim&v.Edi&t.Paredit-&Join<Tab>' .g:slimv_leader.'J', '', '', ':<C-U>call PareditJoin()<CR>' )
+call s:MenuMap( 'Slim&v.Edi&t.Paredit-Ra&ise<Tab>' .g:slimv_leader.'I', '', '', ':<C-U>call PareditRaise()<CR>' )
+call s:MenuMap( 'Slim&v.Edi&t.Paredit-Move&Left<Tab>' .g:slimv_leader.'<', '', '', ':<C-U>call PareditMoveLeft()<CR>' )
+call s:MenuMap( 'Slim&v.Edi&t.Paredit-Move&Right<Tab>' .g:slimv_leader.'>', '', '', ':<C-U>call PareditMoveRight()<CR>' )
+endif "g:paredit_shortmaps
+endif "g:paredit_loaded
+
+" Evaluation commands
+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>' )
+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', 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>' )
+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>' )
+call s:MenuMap( 'Slim&v.De&bugging.Set-&Breakpoint', g:slimv_leader.'B', g:slimv_leader.'db', ':call SlimvBreak()<CR>' )
+call s:MenuMap( 'Slim&v.De&bugging.Break-on-&Exception', g:slimv_leader.'E', g:slimv_leader.'de', ':call SlimvBreakOnException()<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>' )
+call s:MenuMap( 'Slim&v.De&bugging.-SldbSep-', '', '', ':' )
+call s:MenuMap( 'Slim&v.De&bugging.&Abort', g:slimv_leader.'a', g:slimv_leader.'da', ':call SlimvDebugAbort()<CR>' )
+call s:MenuMap( 'Slim&v.De&bugging.&Quit-to-Toplevel', g:slimv_leader.'q', g:slimv_leader.'dq', ':call SlimvDebugQuit()<CR>' )
+call s:MenuMap( 'Slim&v.De&bugging.&Continue', g:slimv_leader.'n', g:slimv_leader.'dc', ':call SlimvDebugContinue()<CR>' )
+call s:MenuMap( 'Slim&v.De&bugging.&Restart-Frame', g:slimv_leader.'N', g:slimv_leader.'dr', ':call SlimvDebugRestartFrame()<CR>' )
+call s:MenuMap( 'Slim&v.De&bugging.-ThreadSep-', '', '', ':' )
+call s:MenuMap( 'Slim&v.De&bugging.List-T&hreads', g:slimv_leader.'H', g:slimv_leader.'dl', ':call SlimvListThreads()<CR>' )
+call s:MenuMap( 'Slim&v.De&bugging.&Kill-Thread\.\.\.', g:slimv_leader.'K', g:slimv_leader.'dk', ':call SlimvKillThread()<CR>' )
+call s:MenuMap( 'Slim&v.De&bugging.&Debug-Thread\.\.\.', g:slimv_leader.'G', g:slimv_leader.'dT', ':call SlimvDebugThread()<CR>' )
+
+" Compile commands
+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', 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
+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.'P', g:slimv_leader.'pb', ':<C-U>call SlimvProfileSubstring()<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', 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.'dp', ':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', g:slimv_leader.'c', g:slimv_leader.'rc', ':call SlimvConnectServer()<CR>' )
+call s:MenuMap( '', g:slimv_leader.'g', g:slimv_leader.'rp', ':call SlimvSetPackage()<CR>' )
+call s:MenuMap( 'Slim&v.&Repl.Interrup&t-Lisp-Process', g:slimv_leader.'y', g:slimv_leader.'ri', ':call SlimvInterrupt()<CR>' )
+call s:MenuMap( 'Slim&v.&Repl.Clear-&REPL', g:slimv_leader.'-', g:slimv_leader.'-', ':call SlimvClearReplBuffer()<CR>' )
+call s:MenuMap( 'Slim&v.&Repl.&Quit-REPL', g:slimv_leader.'Q', g:slimv_leader.'rq', ':call SlimvQuitRepl()<CR>' )
+
+
+" =====================================================================
+" Slimv menu
+" =====================================================================
+
+if g:slimv_menu == 1
+ " Works only if 'wildcharm' is <Tab>
+ if &wildcharm == 0
+ set wildcharm=<Tab>
+ endif
+ if &wildcharm != 0
+ 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 ' . g:slimv_leader.'\ :emenu REPL.' . nr2char( &wildcharm )
+ endif
+
+ amenu &REPL.Send-&Input :call SlimvSendCommand(0)<CR>
+ amenu &REPL.Cl&ose-Send-Input :call SlimvSendCommand(1)<CR>
+ amenu &REPL.Set-Packa&ge :call SlimvSetPackage()<CR>
+ amenu &REPL.Interrup&t-Lisp-Process <Esc>:<C-U>call SlimvInterrupt()<CR>
+ amenu &REPL.-REPLSep- :
+ amenu &REPL.&Previous-Input :call SlimvPreviousCommand()<CR>
+ amenu &REPL.&Next-Input :call SlimvNextCommand()<CR>
+ amenu &REPL.Clear-&REPL :call SlimvClearReplBuffer()<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
+if !exists("g:syntax_on")
+ syntax on
+endif
+