Skip to content

Commit dae6dd8

Browse files
lhchavezdbarnett
authored andcommitted
Add support for rustfmt (#129)
Fixes: #126
1 parent 18f47c3 commit dae6dd8

File tree

5 files changed

+183
-0
lines changed

5 files changed

+183
-0
lines changed

Diff for: README.md

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ helpfiles in the `doc/` directory. The helpfiles are also available via
2323
* JSON (js-beautify)
2424
* Proto (clang-format)
2525
* Python (Autopep8 or YAPF)
26+
* Rust ([rustfmt](https://github.com/rust-lang/rustfmt))
2627
* TypeScript (clang-format)
2728
* Shell (shfmt)
2829
* [Vue](http://vuejs.org) (prettier)
@@ -87,6 +88,7 @@ augroup autoformat_settings
8788
autocmd FileType java AutoFormatBuffer google-java-format
8889
autocmd FileType python AutoFormatBuffer yapf
8990
" Alternative: autocmd FileType python AutoFormatBuffer autopep8
91+
autocmd FileType rust AutoFormatBuffer rustfmt
9092
autocmd FileType vue AutoFormatBuffer prettier
9193
augroup END
9294
```

Diff for: autoload/codefmt/rustfmt.vim

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
" Copyright 2018 Google Inc. All rights reserved.
2+
"
3+
" Licensed under the Apache License, Version 2.0 (the "License");
4+
" you may not use this file except in compliance with the License.
5+
" You may obtain a copy of the License at
6+
"
7+
" http://www.apache.org/licenses/LICENSE-2.0
8+
"
9+
" Unless required by applicable law or agreed to in writing, software
10+
" distributed under the License is distributed on an "AS IS" BASIS,
11+
" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
" See the License for the specific language governing permissions and
13+
" limitations under the License.
14+
15+
16+
let s:plugin = maktaba#plugin#Get('codefmt')
17+
18+
19+
""
20+
" @private
21+
" Formatter: rustfmt
22+
function! codefmt#rustfmt#GetFormatter() abort
23+
let l:formatter = {
24+
\ 'name': 'rustfmt',
25+
\ 'setup_instructions': 'Install ' .
26+
\ 'rustfmt (https://github.com/rust-lang/rustfmt) ' .
27+
\ 'and configure the rustfmt_executable flag'}
28+
29+
function l:formatter.IsAvailable() abort
30+
return executable(s:plugin.Flag('rustfmt_executable'))
31+
endfunction
32+
33+
function l:formatter.AppliesToBuffer() abort
34+
return &filetype is# 'rust'
35+
endfunction
36+
37+
""
38+
" Reformat the current buffer with rustfmt or the binary named in
39+
" @flag(rustfmt_executable).
40+
function l:formatter.FormatRange(startline, endline) abort
41+
let l:Rustfmt_options = s:plugin.Flag('rustfmt_options')
42+
if type(l:Rustfmt_options) is# type([])
43+
let l:rustfmt_options = l:Rustfmt_options
44+
elseif maktaba#value#IsCallable(l:Rustfmt_options)
45+
let l:rustfmt_options = maktaba#function#Call(l:Rustfmt_options)
46+
else
47+
throw maktaba#error#WrongType(
48+
\ 'rustfmt_options flag must be list or callable. Found %s',
49+
\ string(l:Rustfmt_options))
50+
endif
51+
let l:cmd = [s:plugin.Flag('rustfmt_executable'), '--emit=stdout', '--color=never']
52+
53+
call extend(l:cmd, l:rustfmt_options)
54+
try
55+
let l:lines = getline(1, line('$'))
56+
let l:input = join(l:lines, "\n")
57+
let l:result = maktaba#syscall#Create(l:cmd).WithStdin(l:input).Call()
58+
let l:formatted = split(l:result.stdout, "\n")
59+
" Even though rustfmt supports formatting ranges through the --file-lines
60+
" flag, it is not still enabled in the stable binaries.
61+
call maktaba#buffer#Overwrite(1, line('$'), l:formatted)
62+
catch /ERROR(ShellError):/
63+
" Parse all the errors and stick them in the quickfix list.
64+
let l:errors = []
65+
let l:last_error_text = ''
66+
for l:line in split(v:exception, "\n")
67+
let l:error_text_tokens = matchlist(l:line,
68+
\ '\C\v^error: (.*)')
69+
if !empty(l:error_text_tokens)
70+
let l:last_error_text = l:error_text_tokens[1]
71+
endif
72+
73+
let l:tokens = matchlist(l:line,
74+
\ '\C\v^.*\<stdin\>:(\d+):(\d+).*')
75+
if !empty(l:tokens)
76+
call add(l:errors, {
77+
\ 'filename': @%,
78+
\ 'lnum': l:tokens[1],
79+
\ 'col': l:tokens[2],
80+
\ 'text': l:last_error_text})
81+
endif
82+
endfor
83+
84+
if empty(l:errors)
85+
" Couldn't parse rustfmt error format; display it all.
86+
call maktaba#error#Shout('Error formatting file: %s', v:exception)
87+
else
88+
call setqflist(l:errors, 'r')
89+
cc 1
90+
endif
91+
endtry
92+
endfunction
93+
94+
return l:formatter
95+
endfunction

Diff for: instant/flags.vim

+9
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,12 @@ call s:plugin.Flag('prettier_options', [
115115
""
116116
" The path to the prettier executable.
117117
call s:plugin.Flag('prettier_executable', 'prettier')
118+
119+
""
120+
" Command line arguments to feed rustfmt. Either a list or callable that
121+
" takes no args and returns a list with command line arguments.
122+
call s:plugin.Flag('rustfmt_options', [])
123+
124+
""
125+
" The path to the rustfmt executable.
126+
call s:plugin.Flag('rustfmt_executable', 'rustfmt')

Diff for: plugin/register.vim

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ call s:registry.SetValidator('codefmt#EnsureFormatter')
2424
" Formatters that are registered later are given more priority when deciding
2525
" what the default formatter will be for a particular file type.
2626
call s:registry.AddExtension(codefmt#prettier#GetFormatter())
27+
call s:registry.AddExtension(codefmt#rustfmt#GetFormatter())
2728
call s:registry.AddExtension(codefmt#jsbeautify#GetFormatter())
2829
call s:registry.AddExtension(codefmt#clangformat#GetFormatter())
2930
call s:registry.AddExtension(codefmt#gofmt#GetFormatter())

Diff for: vroom/rustfmt.vroom

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
The rustfmt formatter knows how to format Rust code.
2+
If you aren't familiar with basic codefmt usage yet, see main.vroom first.
3+
4+
We'll set up codefmt and configure the vroom environment, then jump into some
5+
examples.
6+
7+
:source $VROOMDIR/setupvroom.vim
8+
9+
:let g:repeat_calls = []
10+
:function FakeRepeat(...)<CR>
11+
| call add(g:repeat_calls, a:000)<CR>
12+
:endfunction
13+
:call maktaba#test#Override('repeat#set', 'FakeRepeat')
14+
15+
:call codefmt#SetWhetherToPerformIsAvailableChecksForTesting(0)
16+
17+
18+
The rustfmt formatter expects the rustfmt executable to be installed on your system.
19+
20+
% fn main(){println!("Hello World!");}
21+
:FormatCode rustfmt
22+
! rustfmt .*
23+
$ fn main() {
24+
$ println!("Hello World!");
25+
$ }
26+
27+
The name or path of the rustfmt executable can be configured via the
28+
rustfmt_executable flag if the default of "rustfmt" doesn't work.
29+
30+
:Glaive codefmt rustfmt_executable='myrustfmt'
31+
:FormatCode rustfmt
32+
! myrustfmt .*
33+
$ fn main() {
34+
$ println!("Hello World!");
35+
$ }
36+
:Glaive codefmt rustfmt_executable='rustfmt'
37+
38+
39+
You can format any buffer with rustfmt specifying the formatter explicitly.
40+
41+
@clear
42+
% fn main(){println!("Hello World!");}
43+
44+
:FormatCode rustfmt
45+
! rustfmt .*2>.*
46+
$ fn main() {
47+
$ println!("Hello World!");
48+
$ }
49+
fn main() {
50+
println!("Hello World!");
51+
}
52+
@end
53+
54+
Errors are reported using the quickfix list.
55+
56+
@clear
57+
% fn main() {
58+
59+
:FormatCode rustfmt
60+
! rustfmt .*2> (.*)
61+
$ 2 (status)
62+
$ echo >\1 ' (command)
63+
|error: this file contains an un-closed delimiter\n
64+
| --> <stdin>:1:13\n
65+
| |\n
66+
|1 | fn main() {\n
67+
| | - ^\n
68+
| | |\n
69+
| | un-closed delimiter'
70+
fn main() {
71+
@end
72+
:echomsg line('.') . ',' . col('.')
73+
~ 1,11
74+
:echomsg string(map(getqflist(),
75+
|'v:val.lnum . "," . v:val.col . "," . v:val.text'))
76+
~ ['1,13,this file contains an un-closed delimiter']

0 commit comments

Comments
 (0)