Skip to content

Commit 303cadf

Browse files
lilyballalexcrichton
authored andcommitted
vim: Add :Run and :Expand commands
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.
1 parent 6ca454f commit 303cadf

File tree

2 files changed

+265
-37
lines changed

2 files changed

+265
-37
lines changed

src/etc/vim/autoload/rust.vim

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
" Author: Kevin Ballard
2+
" Description: Helper functions for Rust commands/mappings
3+
" Last Modified: May 27, 2014
4+
5+
" Jump {{{1
6+
7+
function! rust#Jump(mode, function) range
8+
let cnt = v:count1
9+
normal! m'
10+
if a:mode ==# 'v'
11+
norm! gv
12+
endif
13+
let foldenable = &foldenable
14+
set nofoldenable
15+
while cnt > 0
16+
execute "call <SID>Jump_" . a:function . "()"
17+
let cnt = cnt - 1
18+
endwhile
19+
let &foldenable = foldenable
20+
endfunction
21+
22+
function! s:Jump_Back()
23+
call search('{', 'b')
24+
keepjumps normal! w99[{
25+
endfunction
26+
27+
function! s:Jump_Forward()
28+
normal! j0
29+
call search('{', 'b')
30+
keepjumps normal! w99[{%
31+
call search('{')
32+
endfunction
33+
34+
" Run {{{1
35+
36+
function! rust#Run(bang, args)
37+
if a:bang
38+
let idx = index(a:args, '--')
39+
if idx != -1
40+
let rustc_args = idx == 0 ? [] : a:args[:idx-1]
41+
let args = a:args[idx+1:]
42+
else
43+
let rustc_args = a:args
44+
let args = []
45+
endif
46+
else
47+
let rustc_args = []
48+
let args = a:args
49+
endif
50+
51+
let b:rust_last_rustc_args = rustc_args
52+
let b:rust_last_args = args
53+
54+
call s:WithPath(function("s:Run"), rustc_args, args)
55+
endfunction
56+
57+
function! s:Run(path, rustc_args, args)
58+
try
59+
let exepath = tempname()
60+
if has('win32')
61+
let exepath .= '.exe'
62+
endif
63+
64+
let rustc_args = [a:path, '-o', exepath] + a:rustc_args
65+
66+
let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc"
67+
68+
let output = system(shellescape(rustc) . " " . join(map(rustc_args, 'shellescape(v:val)')))
69+
if output != ''
70+
echohl WarningMsg
71+
echo output
72+
echohl None
73+
endif
74+
if !v:shell_error
75+
exe '!' . shellescape(exepath) . " " . join(map(a:args, 'shellescape(v:val)'))
76+
endif
77+
finally
78+
if exists("exepath")
79+
silent! call delete(exepath)
80+
endif
81+
endtry
82+
endfunction
83+
84+
" Expand {{{1
85+
86+
function! rust#Expand(bang, args)
87+
if a:bang && !empty(a:args)
88+
let pretty = a:args[0]
89+
let args = a:args[1:]
90+
else
91+
let pretty = "expanded"
92+
let args = a:args
93+
endif
94+
call s:WithPath(function("s:Expand"), pretty, args)
95+
endfunction
96+
97+
function! s:Expand(path, pretty, args)
98+
try
99+
let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc"
100+
101+
let args = [a:path, '--pretty', a:pretty] + a:args
102+
let output = system(shellescape(rustc) . " " . join(map(args, "shellescape(v:val)")))
103+
if v:shell_error
104+
echohl WarningMsg
105+
echo output
106+
echohl None
107+
else
108+
new
109+
silent put =output
110+
1
111+
d
112+
setl filetype=rust
113+
setl buftype=nofile
114+
setl bufhidden=hide
115+
setl noswapfile
116+
endif
117+
endtry
118+
endfunction
119+
120+
function! rust#CompleteExpand(lead, line, pos)
121+
if a:line[: a:pos-1] =~ '^Expand!\s*\S*$'
122+
" first argument and it has a !
123+
let list = ["normal", "expanded", "typed", "expanded,identified", "flowgraph="]
124+
if !empty(a:lead)
125+
call filter(list, "v:val[:len(a:lead)-1] == a:lead")
126+
endif
127+
return list
128+
endif
129+
130+
return glob(escape(a:lead, "*?[") . '*', 0, 1)
131+
endfunction
132+
133+
" Utility functions {{{1
134+
135+
function! s:WithPath(func, ...)
136+
try
137+
let save_write = &write
138+
set write
139+
let path = expand('%')
140+
let pathisempty = empty(path)
141+
if pathisempty || !save_write
142+
" use a temporary file named 'unnamed.rs' inside a temporary
143+
" directory. This produces better error messages
144+
let tmpdir = tempname()
145+
call mkdir(tmpdir)
146+
147+
let save_cwd = getcwd()
148+
silent exe 'lcd' tmpdir
149+
150+
let path = 'unnamed.rs'
151+
152+
let save_mod = &mod
153+
set nomod
154+
155+
silent exe 'keepalt write! ' . path
156+
if pathisempty
157+
silent keepalt 0file
158+
endif
159+
else
160+
update
161+
endif
162+
163+
call call(a:func, [path] + a:000)
164+
finally
165+
if exists("save_mod") | let &mod = save_mod | endif
166+
if exists("save_write") | let &write = save_write | endif
167+
if exists("save_cwd") | silent exe 'lcd' save_cwd | endif
168+
if exists("tmpdir") | silent call s:RmDir(tmpdir) | endif
169+
endtry
170+
endfunction
171+
172+
function! rust#AppendCmdLine(text)
173+
call setcmdpos(getcmdpos())
174+
let cmd = getcmdline() . a:text
175+
return cmd
176+
endfunction
177+
178+
function! s:RmDir(path)
179+
" sanity check; make sure it's not empty, /, or $HOME
180+
if empty(a:path)
181+
echoerr 'Attempted to delete empty path'
182+
return 0
183+
elseif a:path == '/' || a:path == $HOME
184+
echoerr 'Attempted to delete protected path: ' . a:path
185+
return 0
186+
endif
187+
silent exe "!rm -rf " . shellescape(a:path)
188+
endfunction
189+
190+
" }}}1
191+
192+
" vim: set noet sw=4 ts=4:

src/etc/vim/ftplugin/rust.vim

Lines changed: 73 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
1-
" Vim syntax file
21
" Language: Rust
2+
" Description: Vim syntax file for Rust
33
" Maintainer: Chris Morgan <[email protected]>
4-
" Last Change: 2014 Feb 27
4+
" Maintainer: Kevin Ballard <[email protected]>
5+
" Last Change: May 27, 2014
56

67
if exists("b:did_ftplugin")
78
finish
89
endif
910
let b:did_ftplugin = 1
1011

12+
let s:save_cpo = &cpo
13+
set cpo&vim
14+
15+
" Variables {{{1
16+
1117
" The rust source code at present seems to typically omit a leader on /*!
1218
" comments, so we'll use that as our default, but make it easy to switch.
1319
" This does not affect indentation at all (I tested it with and without
@@ -42,22 +48,74 @@ if exists("g:loaded_delimitMate")
4248
let b:delimitMate_excluded_regions = delimitMate#Get("excluded_regions") . ',rustLifetimeCandidate,rustGenericLifetimeCandidate'
4349
endif
4450

51+
" Motion Commands {{{1
52+
4553
" Bind motion commands to support hanging indents
46-
nnoremap <silent> <buffer> [[ :call <SID>Rust_Jump('n', 'Back')<CR>
47-
nnoremap <silent> <buffer> ]] :call <SID>Rust_Jump('n', 'Forward')<CR>
48-
xnoremap <silent> <buffer> [[ :call <SID>Rust_Jump('v', 'Back')<CR>
49-
xnoremap <silent> <buffer> ]] :call <SID>Rust_Jump('v', 'Forward')<CR>
50-
onoremap <silent> <buffer> [[ :call <SID>Rust_Jump('o', 'Back')<CR>
51-
onoremap <silent> <buffer> ]] :call <SID>Rust_Jump('o', 'Forward')<CR>
54+
nnoremap <silent> <buffer> [[ :call rust#Jump('n', 'Back')<CR>
55+
nnoremap <silent> <buffer> ]] :call rust#Jump('n', 'Forward')<CR>
56+
xnoremap <silent> <buffer> [[ :call rust#Jump('v', 'Back')<CR>
57+
xnoremap <silent> <buffer> ]] :call rust#Jump('v', 'Forward')<CR>
58+
onoremap <silent> <buffer> [[ :call rust#Jump('o', 'Back')<CR>
59+
onoremap <silent> <buffer> ]] :call rust#Jump('o', 'Forward')<CR>
60+
61+
" Commands {{{1
62+
63+
" :Run will compile and run the current file. If it has unsaved changes, they
64+
" will be saved first. If it has no path, it will be written to a temporary
65+
" file first. The generated binary is always placed in a temporary directory,
66+
" but run from the current directory.
67+
"
68+
" The arguments passed to :Run will be passed to the generated binary.
69+
"
70+
" If ! is specified, the arguments are given to rustc as well. A -- argument
71+
" separates rustc args from the args passed to the binary.
72+
"
73+
" If g:rustc_path is defined, it is used as the path to rustc. Otherwise it is
74+
" assumed that rustc is in $PATH.
75+
command! -nargs=* -complete=file -bang -bar -buffer Run call rust#Run(<bang>0, [<f-args>])
76+
77+
" :Expand will expand the current file using --pretty.
78+
"
79+
" Any arguments given to :Expand will be passed to rustc. This is largely so
80+
" you can pass various --cfg configurations.
81+
"
82+
" If ! is specified, the first argument will be interpreted as the --pretty
83+
" type. Otherwise it will default to 'expanded'.
84+
"
85+
" If the current file has unsaved changes, it will be saved first. If it's an
86+
" unnamed buffer, it will be written to a temporary file.
87+
"
88+
" If g:rustc_path is defined, it is used as the path to rustc. Otherwise it is
89+
" assumed that rustc is in $PATH.
90+
command! -nargs=* -complete=customlist,rust#CompleteExpand -bang -bar -buffer Expand call rust#Expand(<bang>0, [<f-args>])
91+
92+
" Mappings {{{1
93+
94+
" Bind ⌘R in MacVim to :Run
95+
nnoremap <silent> <buffer> <D-r> :Run<CR>
96+
" Bind ⌘⇧R in MacVim to :Run! pre-filled with the last args
97+
nnoremap <buffer> <D-R> :Run! <C-r>=join(b:rust_last_rustc_args)<CR><C-\>erust#AppendCmdLine(' -- ' . join(b:rust_last_args))<CR>
98+
99+
if !exists("b:rust_last_rustc_args") || !exists("b:rust_last_args")
100+
let b:rust_last_rustc_args = []
101+
let b:rust_last_args = []
102+
endif
103+
104+
" Cleanup {{{1
52105

53106
let b:undo_ftplugin = "
54107
\setlocal formatoptions< comments< commentstring< includeexpr< suffixesadd<
55108
\|if exists('b:rust_original_delimitMate_excluded_regions')
56109
\|let b:delimitMate_excluded_regions = b:rust_original_delimitMate_excluded_regions
57110
\|unlet b:rust_original_delimitMate_excluded_regions
58-
\|elseif exists('b:delimitMate_excluded_regions')
59-
\|unlet b:delimitMate_excluded_regions
111+
\|else
112+
\|unlet! b:delimitMate_excluded_regions
60113
\|endif
114+
\|unlet! b:rust_last_rustc_args b:rust_last_args
115+
\|delcommand Run
116+
\|delcommand Expand
117+
\|nunmap <buffer> <D-r>
118+
\|nunmap <buffer> <D-R>
61119
\|nunmap <buffer> [[
62120
\|nunmap <buffer> ]]
63121
\|xunmap <buffer> [[
@@ -66,31 +124,9 @@ let b:undo_ftplugin = "
66124
\|ounmap <buffer> ]]
67125
\"
68126

69-
if exists('*<SID>Rust_Jump') | finish | endif
127+
" }}}1
70128

71-
function! <SID>Rust_Jump(mode, function) range
72-
let cnt = v:count1
73-
normal! m'
74-
if a:mode ==# 'v'
75-
norm! gv
76-
endif
77-
let foldenable = &foldenable
78-
set nofoldenable
79-
while cnt > 0
80-
execute "call <SID>Rust_Jump_" . a:function . "()"
81-
let cnt = cnt - 1
82-
endwhile
83-
let &foldenable = foldenable
84-
endfunction
85-
86-
function! <SID>Rust_Jump_Back()
87-
call search('{', 'b')
88-
keepjumps normal! w99[{
89-
endfunction
90-
91-
function! <SID>Rust_Jump_Forward()
92-
normal! j0
93-
call search('{', 'b')
94-
keepjumps normal! w99[{%
95-
call search('{')
96-
endfunction
129+
let &cpo = s:save_cpo
130+
unlet s:save_cpo
131+
132+
" vim: set noet sw=4 ts=4:

0 commit comments

Comments
 (0)