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