Skip to content

Commit

Permalink
Merge pull request #52 from IanConnolly/feature/rustfmt
Browse files Browse the repository at this point in the history
Integrate with rustfmt
  • Loading branch information
steveklabnik committed Nov 14, 2015
2 parents 95f2b2a + 15081c8 commit f8b6893
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 3 deletions.
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Description

This is a vim plugin that provides [Rust][r] file detection and syntax highlighting.
This is a vim plugin that provides [Rust][r] file detection, syntax highlighting, and (optional) autoformatting.

## Installation

Expand Down Expand Up @@ -31,3 +31,12 @@ git clone --depth=1 https://github.com/rust-lang/rust.vim.git ~/.vim/bundle/rust

1. Add `NeoBundle 'rust-lang/rust.vim'` to `~/.vimrc`
2. Re-open vim or execute `:source ~/.vimrc`

## Enabling autoformat

This plugin can optionally format your code using [rustfmt][rfmt] every time a
buffer is written. Simple put `let g:rustfmt_autosave = 1` in your `.vimrc`.

## Help

Further help can be found in the documentation with `:help rust`.
79 changes: 79 additions & 0 deletions autoload/rustfmt.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
" Author: Stephen Sugden <stephen@stephensugden.com>
"
" Adapted from https://github.com/fatih/vim-go

if !exists("g:rustfmt_autosave")
let g:rustfmt_autosave = 0
endif

if !exists("g:rustfmt_command")
let g:rustfmt_command = "rustfmt"
endif

if !exists("g:rustfmt_options")
let g:rustfmt_options = ""
endif

if !exists("g:rustfmt_fail_silently")
let g:rustfmt_fail_silently = 0
endif

let s:got_fmt_error = 0

function! rustfmt#Format()
let l:curw = winsaveview()
let l:tmpname = expand("%:p:h") . "/." . expand("%:p:t") . ".rustfmt"
call writefile(getline(1, '$'), l:tmpname)

let command = g:rustfmt_command . " --write-mode=overwrite "

let out = systemlist(command . g:rustfmt_options . " " . shellescape(l:tmpname))

if v:shell_error == 0
" remove undo point caused via BufWritePre
try | silent undojoin | catch | endtry

" Replace current file with temp file, then reload buffer
call rename(l:tmpname, expand('%'))
silent edit!
let &syntax = &syntax

" only clear location list if it was previously filled to prevent
" clobbering other additions
if s:got_fmt_error
let s:got_fmt_error = 0
call setloclist(0, [])
lwindow
endif
elseif g:rustfmt_fail_silently == 0
" otherwise get the errors and put them in the location list
let errors = []

for line in out
" src/lib.rs:13:5: 13:10 error: expected `,`, or `}`, found `value`
let tokens = matchlist(line, '^\(.\{-}\):\(\d\+\):\(\d\+\):\s*\(\d\+:\d\+\s*\)\?\s*error: \(.*\)')
if !empty(tokens)
call add(errors, {"filename": @%,
\"lnum": tokens[2],
\"col": tokens[3],
\"text": tokens[5]})
endif
endfor

if empty(errors)
% | " Couldn't detect rustfmt error format, output errors
endif

if !empty(errors)
call setloclist(0, errors, 'r')
echohl Error | echomsg "rustfmt returned error" | echohl None
endif

let s:got_fmt_error = 1
lwindow
" We didn't use the temp file, so clean up
call delete(l:tmpname)
endif

call winrestview(l:curw)
endfunction
39 changes: 37 additions & 2 deletions doc/rust.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,37 @@ g:ftplugin_rust_source_path~
let g:ftplugin_rust_source_path = $HOME.'/dev/rust'
<

*g:cargo_manifest_name*
*g:cargo_manifest_name*
g:cargo_manifest_name~
Set this option to the name of the manifest file for your projects. If
not specified it defaults to 'Cargo.toml' : >
let g:cargo_manifest_name = 'Cargo.toml'
let g:cargo_manifest_name = 'Cargo.toml'
<

*g:rustfmt_command*
g:rustfmt_command~
Set this option to the name of the 'rustfmt' executable in your $PATH. If
not specified it defaults to 'rustfmt' : >
let g:rustfmt_command = 'rustfmt'
<
*g:rustfmt_autosave*
g:rustfmt_autosave~
Set this option to 1 to run |:RustFmt| automatically when saving a
buffer. If not specified it defaults to 0 : >
let g:rustfmt_autosave = 0
<
*g:rustfmt_fail_silently*
g:rustfmt_fail_silently~
Set this option to 1 to prevent 'rustfmt' from populating the
|location-list| with errors. If not specified it defaults to 0: >
let g:rustfmt_fail_silently = 0
<
*g:rustfmt_options*
g:rustfmt_options~
Set this option to a string of options to pass to 'rustfmt'. The
write-mode is already set to 'overwrite'. If not specified it
defaults to '' : >
let g:rustmft_options = ''
<

*g:rust_playpen_url*
Expand Down Expand Up @@ -183,6 +209,15 @@ COMMANDS *rust-commands*
|g:rust_shortener_url| is the base url for the shorterner, by
default "https://is.gd/"

:RustFmt *:RustFmt*
Runs |g:rustfmt_command| on the current buffer. If
|g:rustfmt_options| is set then those will be passed to the
executable.

If |g:rustfmt_fail_silently| is 0 (the default) then it
will populate the |location-list| with the errors from
|g:rustfmt_command|. If |g:rustfmt_fail_silently| is set to 1
then it will not populate the |location-list|.

==============================================================================
MAPPINGS *rust-mappings*
Expand Down
3 changes: 3 additions & 0 deletions ftplugin/rust.vim
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ command! -nargs=* -buffer RustEmitAsm call rust#Emit("asm", <q-args>)
" See |:RustPlay| for docs
command! -range=% RustPlay :call rust#Play(<count>, <line1>, <line2>, <f-args>)

" See |:RustFmt| for docs
command! -buffer RustFmt call rustfmt#Format()

" Mappings {{{1

" Bind ⌘R in MacVim to :RustRun
Expand Down
8 changes: 8 additions & 0 deletions plugin/rustfmt.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
augroup rustfmt
autocmd!

" code formatting on save
if get(g:, "rustfmt_autosave", 0)
autocmd BufWritePre *.rs call rustfmt#Format()
endif
augroup END

0 comments on commit f8b6893

Please sign in to comment.