"SuperCollider/Vim interaction scripts
"Copyright 2007 Alex Norman
"
"This file is part of SCVIM.
"
"SCVIM is free software: you can redistribute it and/or modify
"it under the terms of the GNU General Public License as published by
"the Free Software Foundation, either version 3 of the License, or
"(at your option) any later version.
"
"SCVIM is distributed in the hope that it will be useful,
"but WITHOUT ANY WARRANTY; without even the implied warranty of
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
"GNU General Public License for more details.
"
"You should have received a copy of the GNU General Public License
"along with SCVIM. If not, see .
"au VimLeave
"if exists("$SCVIM_DIR") == 0
" echo "$SCVIM_DIR must be defined for SCVIM to work"
" finish
"endif
"source the syntax file as it can change
"so $SCVIM_DIR/syntax/supercollider.vim
runtime! syntax/supercollider.vim
if exists("loaded_scvim") || &cp
finish
endif
let loaded_scvim = 1
"first if SCVIM_CACHE_DIR is defined, use that,
"otherwise use ~/.scvim
if exists("$SCVIM_CACHE_DIR")
let s:scvim_cache_dir = $SCVIM_CACHE_DIR
else
let s:scvim_cache_dir = $HOME . "/.scvim"
let $SCVIM_CACHE_DIR = s:scvim_cache_dir
endif
"source the scvimrc file if it exists
if filereadable($HOME . "/.scvimrc")
source $HOME/.scvimrc
end
"add the cache dir to
set runtimepath+=$SCVIM_CACHE_DIR
if exists("g:sclangKillOnExit")
let s:sclangKillOnExit = g:sclangKillOnExit
else
let s:sclangKillOnExit = 1
endif
if exists("g:sclangPipeLoc")
let s:sclangPipeLoc = g:sclangPipeLoc
else
let s:sclangPipeLoc = "/tmp/sclang-pipe"
endif
let $SCVIM_PIPE_LOC = s:sclangPipeLoc
if exists("g:sclangPipeAppPidLoc")
let s:sclangPipeAppPidLoc = g:sclangPipeAppPidLoc
else
let s:sclangPipeAppPidLoc = "/tmp/sclangpipe_app-pid"
endif
let $SCVIM_PIPE_PID_LOC = s:sclangPipeAppPidLoc
if exists("g:sclangTerm")
let s:sclangTerm = g:sclangTerm
else
let s:sclangTerm = "xterm -e"
endif
if exists("g:sclangPipeApp")
let s:sclangPipeApp = g:sclangPipeApp
else
let s:sclangPipeApp = "sclangpipe_app"
endif
"function SClangRunning()
" if s:sclang_pid != 0 && `pidof "#{$sclangsclangPipeApp_no_quotes}"`.chomp != ""
" return true
" else
" $sclang_pid = 0
" return false
" end
"end
function! FindOuterMostBlock()
"search backwards for parens dont wrap
let l:search_expression_up = "call searchpair('(', '', ')', 'bW'," .
\"'synIDattr(synID(line(\".\"), col(\".\"), 0), \"name\") =~? \"scComment\" || " .
\"synIDattr(synID(line(\".\"), col(\".\"), 0), \"name\") =~? \"scString\" || " .
\"synIDattr(synID(line(\".\"), col(\".\"), 0), \"name\") =~? \"scSymbol\"')"
"search forward for parens, don't wrap
let l:search_expression_down = "call searchpair('(', '', ')', 'W'," .
\"'synIDattr(synID(line(\".\"), col(\".\"), 0), \"name\") =~? \"scComment\" || " .
\"synIDattr(synID(line(\".\"), col(\".\"), 0), \"name\") =~? \"scString\" || " .
\"synIDattr(synID(line(\".\"), col(\".\"), 0), \"name\") =~? \"scSymbol\"')"
"save our current cursor position
let l:returnline = line(".")
let l:returncol = col(".")
"if we're on an opening paren then we should actually go to the closing one to start the search
"if buf[l:returnline][l:returncol-1,1] == "("
if strpart(getline(line(".")),col(".") - 1,1) == "("
exe l:search_expression_down
endif
let l:origline = line(".")
let l:origcol = col(".")
"these numbers will define our range, first init them to illegal values
let l:range_e = [-1, -1]
let l:range_s = [-1, -1]
"this is the last line in our search
let l:lastline = line(".")
let l:lastcol = col(".")
exe l:search_expression_up
while line(".") != l:lastline || (line(".") == l:lastline && col(".") != l:lastcol)
"keep track of the last line/col we were on
let l:lastline = line(".")
let l:lastcol = col(".")
"go to the matching paren
exe l:search_expression_down
"if there isn't a match print an error
if l:lastline == line(".") && l:lastcol == col(".")
call cursor(l:returnline,l:returncol)
throw "UnmachedParen at line:" . l:lastline . ", col: " . l:lastcol
endif
"if this is equal to or later than our original cursor position
if line(".") > l:origline || (line(".") == l:origline && col(".") >= l:origcol)
let l:range_e = [line("."), col(".")]
"go back to opening paren
exe l:search_expression_up
let l:range_s = [line("."), col(".")]
else
"go back to opening paren
exe l:search_expression_up
endif
"find next paren (if there is one)
exe l:search_expression_up
endwhile
"restore the settings
call cursor(l:returnline,l:returncol)
if l:range_s[0] == -1 || l:range_s[1] == -1
throw "OutsideOfParens"
endif
"return the ranges
return [l:range_s, l:range_e]
endfunction
"this causes the sclang pipe / terminal app to be killed when you exit vim, if you don't
"want that to happen then just comment this out
if !exists("loaded_kill_sclang")
if s:sclangKillOnExit
au VimLeave * call SClangKill()
endif
let loaded_kill_sclang = 1
endif
"the vim version of SendToSC
function SendToSC(text)
let l:text = substitute(a:text, '\', '\\\\', 'g')
let l:text = substitute(l:text, '"', '\\"', 'g')
let l:cmd = system('echo "' . l:text . '" >> ' . s:sclangPipeLoc)
"let l:cmd = system('echo "' . l:text . '" >> /tmp/test')
endfunction
function SendLineToSC(linenum)
let cmd = a:linenum . "w! >> " . s:sclangPipeLoc
silent exe cmd
"let cmd = a:linenum . "w! >> /tmp/test"
"silent exe cmd
endfunction
function! SClang_send()
let cmd = ".w! >> " . s:sclangPipeLoc
exe cmd
if line(".") == a:lastline
call SendToSC('')
"redraw!
endif
endfunction
function SClangStart()
if !filewritable(s:sclangPipeAppPidLoc)
call system("tmux splitw -h -p 25; tmux send-keys " . s:sclangPipeApp . " C-m; tmux selectp -L; sleep 1; tmux renamew scvim")
else
throw s:sclangPipeAppPidLoc . " exists, is " . s:sclangPipeApp . " running? If not try deleting " . s:sclangPipeAppPidLoc
endif
endfunction
function SClangKill()
if filewritable(s:sclangPipeAppPidLoc)
call system("tmux selectp -R; tmux send-keys C-c; tmux killp -t scvim.1")
call SendToSC("Server.quitAll;")
:sleep 10m
call system("kill `cat " . s:sclangPipeAppPidLoc . "` && rm " . s:sclangPipeAppPidLoc . " && rm " . s:sclangPipeLoc)
end
endfunction
function SClangRestart()
if filewritable(s:sclangPipeAppPidLoc)
call system("kill -HUP `cat " . s:sclangPipeAppPidLoc . "`")
else
call SClangStart()
end
endfunction
function SClang_free(server)
call SendToSC('s.freeAll;')
redraw!
endfunction
function SClang_thisProcess_stop()
call SendToSC('thisProcess.stop;')
redraw!
endfunction
function SClang_TempoClock_clear()
call SendToSC('TempoClock.default.clear;')
redraw!
endfunction
function! SClang_block()
let [blkstart,blkend] = FindOuterMostBlock()
"blkstart[0],blkend[0] call SClang_send()
"these next lines are just a hack, how can i do the above??
let cmd = blkstart[0] . "," . blkend[0] . " call SClang_send()"
let l:origline = line(".")
let l:origcol = col(".")
exe cmd
call cursor(l:origline,l:origcol)
""if the range is just one line
"if blkstart[0] == blkend[0]
" "XXX call SendToSC(strpart(getline(blkstart[0]),blkstart[1] - 1, (blkend[1] - blkstart[1] + 1)))
" call SendLineToSC(blkstart[0])
"else
" let linen = blkstart[0] - 1
" "send the first line as it might not be a full line
" "XXX let line = getline(linen)
" "XXX call SendToSC(strpart(line, blkstart[1] - 1))
" call SendLineToSC(linen)
" let linen += 1
" let endlinen = blkend[0]
" while linen < endlinen
" "XXX call SendToSC(getline(linen))
" call SendLineToSC(linen)
" let linen += 1
" endwhile
" "send the last line as it might not be a full line
" "XXX let line = getline(endlinen)
" "XXX call SendToSC(strpart(line,0,blkend[1]))
" call SendLineToSC(endlinen)
"endif
"call SendToSC('')
endfunction
function SCdef(subject)
let l:tagfile = s:scvim_cache_dir . "/TAGS_SCDEF"
let l:tagdest = s:scvim_cache_dir . "/doc/tags"
if !filereadable(l:tagfile)
echo "definition tag cache does not exist, you must run SCVim.updateCaches in supercollider"
let l:dontcare = system("echo 'SC:SCVim SCVim.scd /^' > " . l:tagdest)
exe "help SC:SCVim"
else
let l:dontcare = system("grep SCdef:" . a:subject . " " . l:tagfile . " > " . l:tagdest)
exe "help SCdef:" . a:subject
end
endfun
function SChelp(subject)
let l:tagfile = s:scvim_cache_dir . "/doc/TAGS_HELP"
let l:tagdest = s:scvim_cache_dir . "/doc/tags"
if !filereadable(l:tagfile)
echo "help tag cache does not exist, you must run SCVim.updateHelpCache in supercollider in order have help docs"
let l:dontcare = system("echo 'SC:SCVim SCVim.scd /^' > $SCVIM_CACHE_DIR/doc/tags")
exe "help SC:SCVim"
return
end
"the keybindings won't find * but will find ** for some reason
if a:subject == ""
let l:dontcare = system("grep \"SC:Help\" " . l:tagfile . " > " . l:tagdest)
exe "help SC:Help"
elseif a:subject == "*"
let l:dontcare = system("grep \"SC:\\*\" " . l:tagfile . " > " . l:tagdest)
exe "help SC:\*" . a:subject
elseif a:subject == "**"
let l:dontcare = system("grep \"SC:\\*\\*\" " . l:tagfile . " > " . l:tagdest)
exe "help SC:\*\*" . a:subject
else
let l:dontcare = system("grep SC:\"" . a:subject . "\" " . l:tagfile . " > " . l:tagdest)
exe "help SC:" . a:subject
endif
endfun
" search help files for word under the cursor
" or open the HelpBrowser front page
function! HelpBrowser(subject)
if strlen(a:subject) > 0 && a:subject!~" " && a:subject!~"\t"
let string= "HelpBrowser.openHelpFor"
let format= "(\"" . a:subject . "\");"
let string= string . format
call SendToSC(string)
else
call SendToSC('Help.gui;')
endif
endfunction
function ListSCObjects(A,L,P)
return system("cat $SCVIM_CACHE_DIR/sc_object_completion")
endfun
function ListSCHelpItems(A,L,P)
return system("cat $SCVIM_CACHE_DIR/doc/sc_help_completion")
endfun
"custom commands (SChelp,SCdef,SClangfree)
com -complete=custom,ListSCHelpItems -nargs=? SChelp call SChelp("")
com -complete=custom,ListSCObjects -nargs=1 SCdef call SCdef("")
com -nargs=1 SClangfree call SClang_free("")
com -nargs=0 SClangStart call SClangStart()
com -nargs=0 SClangKill call SClangKill()
com -nargs=0 SClangRestart call SClangRestart()
" end supercollider.vim