]> git.lizzy.rs Git - rust.git/commitdiff
vim: Add :Run and :Expand commands
authorKevin Ballard <kevin@sb.org>
Tue, 27 May 2014 22:00:22 +0000 (15:00 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Thu, 19 Jun 2014 00:01:21 +0000 (17:01 -0700)
Define a command :Run to compile and run the current file. This supports
unnamed buffers (by writing to a temporary file). See the comment above
the command definition for notes on usage.

Define <D-r> and <D-R> mappings for :Run to make it easier to invoke in
MacVim.

Define a command :Expand to display the --pretty expanded output for the
current file. This can be configured to use different pretty types. See
the comment above the command definition for notes on usage.

Create an autoload file and put function definitions there to speed up
load time.

src/etc/vim/autoload/rust.vim [new file with mode: 0644]
src/etc/vim/ftplugin/rust.vim

diff --git a/src/etc/vim/autoload/rust.vim b/src/etc/vim/autoload/rust.vim
new file mode 100644 (file)
index 0000000..688c1f6
--- /dev/null
@@ -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:
index b70cda9b998c405ff372d89825f28f847e8b4384..fee59b586876687c5bcf94b0a64e09926bb90f05 100644 (file)
@@ -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: