about summary refs log tree commit diff
path: root/src/etc/vim
diff options
context:
space:
mode:
Diffstat (limited to 'src/etc/vim')
-rw-r--r--src/etc/vim/autoload/rust.vim192
-rw-r--r--src/etc/vim/ftplugin/rust.vim110
2 files changed, 265 insertions, 37 deletions
diff --git a/src/etc/vim/autoload/rust.vim b/src/etc/vim/autoload/rust.vim
new file mode 100644
index 00000000000..688c1f690eb
--- /dev/null
+++ b/src/etc/vim/autoload/rust.vim
@@ -0,0 +1,192 @@
+" 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:
diff --git a/src/etc/vim/ftplugin/rust.vim b/src/etc/vim/ftplugin/rust.vim
index b70cda9b998..fee59b58687 100644
--- a/src/etc/vim/ftplugin/rust.vim
+++ b/src/etc/vim/ftplugin/rust.vim
@@ -1,13 +1,19 @@
-" 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
@@ -42,22 +48,74 @@ if exists("g:loaded_delimitMate")
 	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> [[
@@ -66,31 +124,9 @@ let b:undo_ftplugin = "
 		\|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: