--- /dev/null
+" Author: Kevin Ballard
+" Description: Helper functions for Rust commands/mappings
+" Last Modified: May 27, 2014
+
+" Jump {{{1
+
+function! rust#Jump(mode, function) range
+ let cnt = v:count1
+ normal! m'
+ if a:mode ==# 'v'
+ norm! gv
+ endif
+ let foldenable = &foldenable
+ set nofoldenable
+ while cnt > 0
+ execute "call <SID>Jump_" . a:function . "()"
+ let cnt = cnt - 1
+ endwhile
+ let &foldenable = foldenable
+endfunction
+
+function! s:Jump_Back()
+ call search('{', 'b')
+ keepjumps normal! w99[{
+endfunction
+
+function! s:Jump_Forward()
+ normal! j0
+ call search('{', 'b')
+ keepjumps normal! w99[{%
+ call search('{')
+endfunction
+
+" Run {{{1
+
+function! rust#Run(bang, args)
+ if a:bang
+ let idx = index(a:args, '--')
+ if idx != -1
+ let rustc_args = idx == 0 ? [] : a:args[:idx-1]
+ let args = a:args[idx+1:]
+ else
+ let rustc_args = a:args
+ let args = []
+ endif
+ else
+ let rustc_args = []
+ let args = a:args
+ endif
+
+ let b:rust_last_rustc_args = rustc_args
+ let b:rust_last_args = args
+
+ call s:WithPath(function("s:Run"), rustc_args, args)
+endfunction
+
+function! s:Run(path, rustc_args, args)
+ try
+ let exepath = tempname()
+ if has('win32')
+ let exepath .= '.exe'
+ endif
+
+ let rustc_args = [a:path, '-o', exepath] + a:rustc_args
+
+ let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc"
+
+ let output = system(shellescape(rustc) . " " . join(map(rustc_args, 'shellescape(v:val)')))
+ if output != ''
+ echohl WarningMsg
+ echo output
+ echohl None
+ endif
+ if !v:shell_error
+ exe '!' . shellescape(exepath) . " " . join(map(a:args, 'shellescape(v:val)'))
+ endif
+ finally
+ if exists("exepath")
+ silent! call delete(exepath)
+ endif
+ endtry
+endfunction
+
+" Expand {{{1
+
+function! rust#Expand(bang, args)
+ if a:bang && !empty(a:args)
+ let pretty = a:args[0]
+ let args = a:args[1:]
+ else
+ let pretty = "expanded"
+ let args = a:args
+ endif
+ call s:WithPath(function("s:Expand"), pretty, args)
+endfunction
+
+function! s:Expand(path, pretty, args)
+ try
+ let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc"
+
+ let args = [a:path, '--pretty', a:pretty] + a:args
+ let output = system(shellescape(rustc) . " " . join(map(args, "shellescape(v:val)")))
+ if v:shell_error
+ echohl WarningMsg
+ echo output
+ echohl None
+ else
+ new
+ silent put =output
+ 1
+ d
+ setl filetype=rust
+ setl buftype=nofile
+ setl bufhidden=hide
+ setl noswapfile
+ endif
+ endtry
+endfunction
+
+function! rust#CompleteExpand(lead, line, pos)
+ if a:line[: a:pos-1] =~ '^Expand!\s*\S*$'
+ " first argument and it has a !
+ let list = ["normal", "expanded", "typed", "expanded,identified", "flowgraph="]
+ if !empty(a:lead)
+ call filter(list, "v:val[:len(a:lead)-1] == a:lead")
+ endif
+ return list
+ endif
+
+ return glob(escape(a:lead, "*?[") . '*', 0, 1)
+endfunction
+
+" Utility functions {{{1
+
+function! s:WithPath(func, ...)
+ try
+ let save_write = &write
+ set write
+ let path = expand('%')
+ let pathisempty = empty(path)
+ if pathisempty || !save_write
+ " use a temporary file named 'unnamed.rs' inside a temporary
+ " directory. This produces better error messages
+ let tmpdir = tempname()
+ call mkdir(tmpdir)
+
+ let save_cwd = getcwd()
+ silent exe 'lcd' tmpdir
+
+ let path = 'unnamed.rs'
+
+ let save_mod = &mod
+ set nomod
+
+ silent exe 'keepalt write! ' . path
+ if pathisempty
+ silent keepalt 0file
+ endif
+ else
+ update
+ endif
+
+ call call(a:func, [path] + a:000)
+ finally
+ if exists("save_mod") | let &mod = save_mod | endif
+ if exists("save_write") | let &write = save_write | endif
+ if exists("save_cwd") | silent exe 'lcd' save_cwd | endif
+ if exists("tmpdir") | silent call s:RmDir(tmpdir) | endif
+ endtry
+endfunction
+
+function! rust#AppendCmdLine(text)
+ call setcmdpos(getcmdpos())
+ let cmd = getcmdline() . a:text
+ return cmd
+endfunction
+
+function! s:RmDir(path)
+ " sanity check; make sure it's not empty, /, or $HOME
+ if empty(a:path)
+ echoerr 'Attempted to delete empty path'
+ return 0
+ elseif a:path == '/' || a:path == $HOME
+ echoerr 'Attempted to delete protected path: ' . a:path
+ return 0
+ endif
+ silent exe "!rm -rf " . shellescape(a:path)
+endfunction
+
+" }}}1
+
+" vim: set noet sw=4 ts=4:
-" Vim syntax file
" Language: Rust
+" Description: Vim syntax file for Rust
" Maintainer: Chris Morgan <me@chrismorgan.info>
-" Last Change: 2014 Feb 27
+" Maintainer: Kevin Ballard <kevin@sb.org>
+" Last Change: May 27, 2014
if exists("b:did_ftplugin")
finish
endif
let b:did_ftplugin = 1
+let s:save_cpo = &cpo
+set cpo&vim
+
+" Variables {{{1
+
" The rust source code at present seems to typically omit a leader on /*!
" comments, so we'll use that as our default, but make it easy to switch.
" This does not affect indentation at all (I tested it with and without
let b:delimitMate_excluded_regions = delimitMate#Get("excluded_regions") . ',rustLifetimeCandidate,rustGenericLifetimeCandidate'
endif
+" Motion Commands {{{1
+
" Bind motion commands to support hanging indents
-nnoremap <silent> <buffer> [[ :call <SID>Rust_Jump('n', 'Back')<CR>
-nnoremap <silent> <buffer> ]] :call <SID>Rust_Jump('n', 'Forward')<CR>
-xnoremap <silent> <buffer> [[ :call <SID>Rust_Jump('v', 'Back')<CR>
-xnoremap <silent> <buffer> ]] :call <SID>Rust_Jump('v', 'Forward')<CR>
-onoremap <silent> <buffer> [[ :call <SID>Rust_Jump('o', 'Back')<CR>
-onoremap <silent> <buffer> ]] :call <SID>Rust_Jump('o', 'Forward')<CR>
+nnoremap <silent> <buffer> [[ :call rust#Jump('n', 'Back')<CR>
+nnoremap <silent> <buffer> ]] :call rust#Jump('n', 'Forward')<CR>
+xnoremap <silent> <buffer> [[ :call rust#Jump('v', 'Back')<CR>
+xnoremap <silent> <buffer> ]] :call rust#Jump('v', 'Forward')<CR>
+onoremap <silent> <buffer> [[ :call rust#Jump('o', 'Back')<CR>
+onoremap <silent> <buffer> ]] :call rust#Jump('o', 'Forward')<CR>
+
+" Commands {{{1
+
+" :Run will compile and run the current file. If it has unsaved changes, they
+" will be saved first. If it has no path, it will be written to a temporary
+" file first. The generated binary is always placed in a temporary directory,
+" but run from the current directory.
+"
+" The arguments passed to :Run will be passed to the generated binary.
+"
+" If ! is specified, the arguments are given to rustc as well. A -- argument
+" separates rustc args from the args passed to the binary.
+"
+" If g:rustc_path is defined, it is used as the path to rustc. Otherwise it is
+" assumed that rustc is in $PATH.
+command! -nargs=* -complete=file -bang -bar -buffer Run call rust#Run(<bang>0, [<f-args>])
+
+" :Expand will expand the current file using --pretty.
+"
+" Any arguments given to :Expand will be passed to rustc. This is largely so
+" you can pass various --cfg configurations.
+"
+" If ! is specified, the first argument will be interpreted as the --pretty
+" type. Otherwise it will default to 'expanded'.
+"
+" If the current file has unsaved changes, it will be saved first. If it's an
+" unnamed buffer, it will be written to a temporary file.
+"
+" If g:rustc_path is defined, it is used as the path to rustc. Otherwise it is
+" assumed that rustc is in $PATH.
+command! -nargs=* -complete=customlist,rust#CompleteExpand -bang -bar -buffer Expand call rust#Expand(<bang>0, [<f-args>])
+
+" Mappings {{{1
+
+" Bind ⌘R in MacVim to :Run
+nnoremap <silent> <buffer> <D-r> :Run<CR>
+" Bind ⌘⇧R in MacVim to :Run! pre-filled with the last args
+nnoremap <buffer> <D-R> :Run! <C-r>=join(b:rust_last_rustc_args)<CR><C-\>erust#AppendCmdLine(' -- ' . join(b:rust_last_args))<CR>
+
+if !exists("b:rust_last_rustc_args") || !exists("b:rust_last_args")
+ let b:rust_last_rustc_args = []
+ let b:rust_last_args = []
+endif
+
+" Cleanup {{{1
let b:undo_ftplugin = "
\setlocal formatoptions< comments< commentstring< includeexpr< suffixesadd<
\|if exists('b:rust_original_delimitMate_excluded_regions')
\|let b:delimitMate_excluded_regions = b:rust_original_delimitMate_excluded_regions
\|unlet b:rust_original_delimitMate_excluded_regions
- \|elseif exists('b:delimitMate_excluded_regions')
- \|unlet b:delimitMate_excluded_regions
+ \|else
+ \|unlet! b:delimitMate_excluded_regions
\|endif
+ \|unlet! b:rust_last_rustc_args b:rust_last_args
+ \|delcommand Run
+ \|delcommand Expand
+ \|nunmap <buffer> <D-r>
+ \|nunmap <buffer> <D-R>
\|nunmap <buffer> [[
\|nunmap <buffer> ]]
\|xunmap <buffer> [[
\|ounmap <buffer> ]]
\"
-if exists('*<SID>Rust_Jump') | finish | endif
+" }}}1
-function! <SID>Rust_Jump(mode, function) range
- let cnt = v:count1
- normal! m'
- if a:mode ==# 'v'
- norm! gv
- endif
- let foldenable = &foldenable
- set nofoldenable
- while cnt > 0
- execute "call <SID>Rust_Jump_" . a:function . "()"
- let cnt = cnt - 1
- endwhile
- let &foldenable = foldenable
-endfunction
-
-function! <SID>Rust_Jump_Back()
- call search('{', 'b')
- keepjumps normal! w99[{
-endfunction
-
-function! <SID>Rust_Jump_Forward()
- normal! j0
- call search('{', 'b')
- keepjumps normal! w99[{%
- call search('{')
-endfunction
+let &cpo = s:save_cpo
+unlet s:save_cpo
+
+" vim: set noet sw=4 ts=4: