mirror of
1
0
Fork 0
ultimate-vim/sources_non_forked/slimv/ftplugin/slimv.vim

3806 lines
144 KiB
VimL
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

" slimv.vim: The Superior Lisp Interaction Mode for VIM
" Version: 0.9.14
" Last Change: 24 Aug 2021
" 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 $STY != ''
" GNU screen under Linux or macOS
return "! screen -X eval 'title swank' 'screen " . cmd . "' 'select swank'"
elseif $TMUX != ''
" tmux under Linux or macOS
return "! tmux new-window -d -n swank '" . 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 $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
" Size of the split window
if !exists( 'g:slimv_repl_split_size' )
let g:slimv_repl_split_size = ''
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
" Shall we strip ANSI escape sequences from the REPL output?
if !exists( 'g:slimv_strip_ansi' )
let g:slimv_strip_ansi = 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
if &updatetime == g:slimv_updatetime
let &updatetime = s:save_updatetime
endif
else
" SWANK output still pending, keep higher update frequency
if &updatetime != g:slimv_updatetime
let s:save_updatetime = &updatetime
endif
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 &updatetime != g:slimv_updatetime
let s:save_updatetime = &updatetime
endif
" Update more frequently until all swank responses processed
let &updatetime = g:slimv_updatetime
let s:last_update = -1
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
" create a unique buffer name that does not collide with any file or directory name
let bname = a:filename
let i = 0
while filereadable(bname) || isdirectory(bname)
let i = i+1
let bname = a:filename . i
endwhile
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! " . bname
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 " . g:slimv_repl_split_size . "sview! " . bname
elseif g:slimv_repl_split == 2
execute "silent botright " . g:slimv_repl_split_size . "sview! " . bname
elseif g:slimv_repl_split == 3
execute "silent topleft vertical " . g:slimv_repl_split_size . "sview! " . bname
elseif g:slimv_repl_split == 4
execute "silent botright vertical " . g:slimv_repl_split_size . "sview! " . bname
else
execute "silent view! " . bname
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>'
execute 'noremap <buffer> <silent> ' . g:slimv_leader.'si :call SlimvDebugStepInto()<CR>'
execute 'noremap <buffer> <silent> ' . g:slimv_leader.'sn :call SlimvDebugStepNext()<CR>'
execute 'noremap <buffer> <silent> ' . g:slimv_leader.'so :call SlimvDebugStepOut()<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>'
execute 'noremap <buffer> <silent> ' . g:slimv_leader.'si :call SlimvDebugStepInto()<CR>'
execute 'noremap <buffer> <silent> ' . g:slimv_leader.'sn :call SlimvDebugStepNext()<CR>'
execute 'noremap <buffer> <silent> ' . g:slimv_leader.'so :call SlimvDebugStepOut()<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()
let old_value = &iskeyword
if match(old_value, '\^$') >= 0
" remove trailing ^ because it will be added as chr 94
setlocal iskeyword-=^
endif
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
" Find the matching pair
function! SlimvFindMatchingPair()
let c = col( '.' ) - 1
let firstchar = getline( '.' )[c]
while c < len( getline( '.' ) ) && getline( '.' )[c] !~ '(\|)\|\[\|\]\|{\|}'
normal! l
let c = c + 1
endwhile
if getline( '.' )[c] =~ '(\|\[\|{'
call searchpair( '(', '', ')', 'W', s:skip_sc )
else
call searchpair( '(', '', ')', 'bW', s:skip_sc )
endif
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
" select the whole form
" if firstchar != '('
if getline( '.' )[c] != '('
call searchpair( '(', '', ')', 'bW', s:skip_sc )
endif
silent! normal v
call searchpair( '(', '', ')', 'W', s:skip_sc )
if &selection == 'exclusive'
silent! normal l
endif
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! vvaw
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
if SlimvGetFiletype() =~ '.*clojure.*' && exists( '*GetClojureIndent' ) && line('.') == a:lnum
let li = GetClojureIndent()
else
let li = lispindent( a:lnum )
endif
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
" Is this a multi-arity function definition?
let line = strpart( getline(l), c-1 )
if match( line, '(\s*\[' ) >= 0
return c + 1
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
" Fix indentation issues not handled by the default lisp.vim
if SlimvGetFiletype() =~ '.*clojure.*'
if match( func, 'defn$' ) >= 0
return c + 1
endif
elseif SlimvGetFiletype() =~ '.*\(scheme\|racket\).*'
if match( func, 'syntax-rules$' ) >= 0
return c + 1
endif
else
if match( func, 'defgeneric$' ) >= 0 || match( func, 'defsystem$' ) >= 0 || match( func, 'aif$' ) >= 0
return c + 1
endif
endif
if match( func, 'if$' ) >= 0 || match( func, 'do$' ) >= 0
return c + funclen - 1
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 )
if exists("g:slimv_indent_disable") && g:slimv_indent_disable
let indent = lispindent( a:lnum )
else
let oldpos = getpos( '.' )
let indent = SlimvIndentUnsafe( a:lnum )
call cursor( oldpos[1], oldpos[2] )
endif
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
if col( "." ) == b:repl_prompt_col
return "\<BS> "
else
" No BS allowed before the previous EOF mark
return ""
endif
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
" Added in frame argument to support stepper
function! SlimvDebugCommand( name, cmd, frame )
if SlimvConnectSwank()
if s:sldb_level >= 0
if bufname('%') != g:slimv_sldb_name
call SlimvOpenSldbBuffer()
endif
if a:frame == ''
call SlimvCommand( s:py_cmd . '' . a:cmd . '()' )
else
call SlimvCommand( s:py_cmd . '' . a:cmd . '(' . string(a:frame) . ')' )
endif
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()
let in_stepper = search ('STEP-CONTINUE', 'bcnw')
if in_stepper == 0
call SlimvDebugCommand( ":sldb-continue", "swank_invoke_continue", '' )
else
call SlimvQuitSldb()
silent execute s:py_cmd . 'swank_invoke_restart("' . s:sldb_level . '", "' . string(0) . '")'
call SlimvRefreshReplBuffer()
endif
endfunction
" Debugger stepper functions
function! SlimvDebugStepInto()
let frame = s:DebugFrame()
if frame != ''
call SlimvDebugCommand( ":sldb-step", "swank_step_into", frame )
endif
endfunction
function! SlimvDebugStepNext()
let frame = s:DebugFrame()
if frame != ''
call SlimvDebugCommand( ":sldb-next", "swank_step_next", frame )
endif
endfunction
function! SlimvDebugStepOut()
let frame = s:DebugFrame()
if frame != ''
call SlimvDebugCommand( ":sldb-out", "swank_step_out", frame )
endif
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 first_line = 1
if getline( first_line )[0] == '#'
" skip shebang line
let first_line += 1
endif
let lines = getline( first_line, '$' )
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 a given shell 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
elseif exists( "g:slimv_browser_cmd_ex" )
" We have a given Ex command to start the browser
silent execute g:slimv_browser_cmd_ex . ' ' . page
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 =~ '^' . escape( 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
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() )
echon "\r"
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
nnoremap <silent> <buffer> % :call SlimvFindMatchingPair()<CR>
"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.&Step-Into', g:slimv_leader.'si', g:slimv_leader.'si', ':call SlimvDebugStepInto()<CR>' )
call s:MenuMap( 'Slim&v.De&bugging.&Step-Next', g:slimv_leader.'sn', g:slimv_leader.'sn', ':call SlimvDebugStepNext()<CR>' )
call s:MenuMap( 'Slim&v.De&bugging.&Step-Out', g:slimv_leader.'so', g:slimv_leader.'so', ':call SlimvDebugStepOut()<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