Update rust.vim to 53f40ec6c628099e353f25cabd54e5047c28d81d

This commit is contained in:
Anthony Rose 2019-06-03 15:56:49 +01:00
parent bfa2dc4040
commit b815d29703
30 changed files with 2123 additions and 778 deletions

View file

@ -0,0 +1,7 @@
---
sudo: required
services:
- docker
language: generic
script: |
cd test && ./run-tests

View file

@ -0,0 +1,10 @@
cmdargs:
# Checking more strictly
severity: style_problem
policies:
# Disable a violation
ProhibitUnnecessaryDoubleQuote:
enabled: false
ProhibitImplicitScopeVariable:
enabled: false

View file

@ -0,0 +1,27 @@
<!--
Hi, and thanks for reporting an issue with rust.vim.
Details about your environment will help us assist you.
Please edit this template!
-->
* rust.vim version: <!-- Describe if you use a Vim plugin manager, and you
can use it to tell which version of rust.vim you are running. -->
Steps to reproduce:
<!-- It's best to try to reproduce the issue with the master version of
rust.vim. The issue may already be fixed! -->
_?_
Expected vs. actual behavior:
_?_
Paste debugging info from the Rust Vim plugin via _one_ of the following
commands: `:RustInfo`, `:RustInfoToClipboard`, or `:RustInfoToFile <filename>`.
_?_

View file

@ -3,42 +3,46 @@
## Description ## Description
This is a Vim plugin that provides [Rust][r] file detection, syntax highlighting, formatting, This is a Vim plugin that provides [Rust][r] file detection, syntax highlighting, formatting,
[Syntastic][syn] integration, and more. [Syntastic][syn] integration, and more. It requires Vim 8 or higher for full functionality.
Some things may not work on earlier versions.
## Installation ## Installation
### Using [Vundle][v] Use one of the following package managers:
1. Add `Plugin 'rust-lang/rust.vim'` to `~/.vimrc` * [Vim8 packages][vim8pack]:
2. `:PluginInstall` or `$ vim +PluginInstall +qall` * `git clone https://github.com/rust-lang/rust.vim ~/.vim/pack/plugins/start/rust.vim`
* [Vundle][v]:
*Note:* Vundle will not automatically detect Rust files properly if `filetype * Add `Plugin 'rust-lang/rust.vim'` to `~/.vimrc`
* `:PluginInstall` or `$ vim +PluginInstall +qall`
* *Note:* Vundle will not automatically detect Rust files properly if `filetype
on` is executed before Vundle. Please check the [quickstart][vqs] for more on` is executed before Vundle. Please check the [quickstart][vqs] for more
details. details. Errors such as `Not an editor command: RustFmt` may occur if Vundle
is misconfigured with this plugin.
### Using [Pathogen][p] * [Pathogen][p]:
* `git clone --depth=1 https://github.com/rust-lang/rust.vim.git ~/.vim/bundle/rust.vim`
```shell * [vim-plug][vp]:
git clone --depth=1 https://github.com/rust-lang/rust.vim.git ~/.vim/bundle/rust.vim * Add `Plug 'rust-lang/rust.vim'` to `~/.vimrc`
``` * `:PlugInstall` or `$ vim +PlugInstall +qall`
* [dein.vim][d]:
### Using [NeoBundle][nb] * Add `call dein#add('rust-lang/rust.vim')` to `~/.vimrc`
* `:call dein#install()`
1. Add `NeoBundle 'rust-lang/rust.vim'` to `~/.vimrc` * [NeoBundle][nb]:
2. Re-open vim or execute `:source ~/.vimrc` * Add `NeoBundle 'rust-lang/rust.vim'` to `~/.vimrc`
* Re-open vim or execute `:source ~/.vimrc`
### Using [vim-plug][vp]
1. Add `Plug 'rust-lang/rust.vim'` to `~/.vimrc`
2. `:PlugInstall` or `$ vim +PlugInstall +qall`
## Features ## Features
### Error checking with [Syntastic][syn] ### Error checking with [Syntastic][syn]
`rust.vim` automatically registers `rustc` as a syntax checker `rust.vim` automatically registers `cargo` as a syntax checker with
with [Syntastic][syn]. Check Syntastic's documentation for [Syntastic][syn], if nothing else is specified. See `:help rust-syntastic`
information on how to customize its behaviour. for more details.
### Source browsing with [Tagbar][tgbr]
`rust.vim` has builtin `ctags/` definitions for [Tagbar][tgbr] which
are loaded if Tagbar is installed.
### Formatting with [rustfmt][rfmt] ### Formatting with [rustfmt][rfmt]
@ -58,7 +62,20 @@ options.
The `:RustPlay` command will send the current selection, or if The `:RustPlay` command will send the current selection, or if
nothing is selected the current buffer, to the [Rust playpen][pp]. nothing is selected the current buffer, to the [Rust playpen][pp].
[rfmt]: https://crates.io/crates/rustfmt/ If you set g:rust_clip_command RustPlay will copy the url to the clipboard.
- Mac:
let g:rust_clip_command = 'pbcopy'
- Linux:
let g:rust_clip_command = 'xclip -selection clipboard'
### Running a test under cursor
In cargo project, the `:RustTest` command will run a test under the cursor.
This is useful when your project is bigger and running all tests take longer time.
## Help ## Help
@ -81,7 +98,10 @@ LICENSE-MIT for details.
[p]: https://github.com/tpope/vim-pathogen [p]: https://github.com/tpope/vim-pathogen
[nb]: https://github.com/Shougo/neobundle.vim [nb]: https://github.com/Shougo/neobundle.vim
[vp]: https://github.com/junegunn/vim-plug [vp]: https://github.com/junegunn/vim-plug
[d]: https://github.com/Shougo/dein.vim
[rfmt]: https://github.com/rust-lang-nursery/rustfmt [rfmt]: https://github.com/rust-lang-nursery/rustfmt
[syn]: https://github.com/scrooloose/syntastic [syn]: https://github.com/scrooloose/syntastic
[tgbr]: https://github.com/majutsushi/tagbar
[wav]: https://github.com/mattn/webapi-vim [wav]: https://github.com/mattn/webapi-vim
[pp]: https://play.rust-lang.org/ [pp]: https://play.rust-lang.org/
[vim8pack]: http://vimhelp.appspot.com/repeat.txt.html#packages

View file

@ -1,10 +1,12 @@
if !exists('g:rust_conceal') || g:rust_conceal == 0 || !has('conceal') || &enc != 'utf-8' scriptencoding utf-8
finish
if !get(g:, 'rust_conceal', 0) || !has('conceal') || &encoding !=# 'utf-8'
finish
endif endif
" For those who don't want to see `::`... " For those who don't want to see `::`...
if exists('g:rust_conceal_mod_path') && g:rust_conceal_mod_path != 0 if get(g:, 'rust_conceal_mod_path', 0)
syn match rustNiceOperator "::" conceal cchar= syn match rustNiceOperator "::" conceal cchar=
endif endif
syn match rustRightArrowHead contained ">" conceal cchar=  syn match rustRightArrowHead contained ">" conceal cchar= 
@ -18,7 +20,7 @@ syn match rustNiceOperator "=>" contains=rustFatRightArrowHead,rustFatRightArrow
syn match rustNiceOperator /\<\@!_\(_*\>\)\@=/ conceal cchar= syn match rustNiceOperator /\<\@!_\(_*\>\)\@=/ conceal cchar=
" For those who don't want to see `pub`... " For those who don't want to see `pub`...
if exists('g:rust_conceal_pub') && g:rust_conceal_pub != 0 if get(g:, 'rust_conceal_pub', 0)
syn match rustPublicSigil contained "pu" conceal cchar= syn match rustPublicSigil contained "pu" conceal cchar=
syn match rustPublicRest contained "b" conceal cchar=  syn match rustPublicRest contained "b" conceal cchar= 
syn match rustNiceOperator "pub " contains=rustPublicSigil,rustPublicRest syn match rustNiceOperator "pub " contains=rustPublicSigil,rustPublicRest
@ -26,9 +28,14 @@ endif
hi link rustNiceOperator Operator hi link rustNiceOperator Operator
if !(exists('g:rust_conceal_mod_path') && g:rust_conceal_mod_path != 0) if !get(g:, 'rust_conceal_mod_path', 0)
hi! link Conceal Operator hi! link Conceal Operator
" And keep it after a colorscheme change augroup rust.vim.after
au ColorScheme <buffer> hi! link Conceal Operator autocmd!
" And keep it after a colorscheme change
autocmd ColorScheme <buffer> hi! link Conceal Operator
augroup END
endif endif
" vim: set et sw=4 sts=4 ts=8:

View file

@ -0,0 +1,115 @@
function! cargo#Load()
" Utility call to get this script loaded, for debugging
endfunction
function! cargo#cmd(args)
execute "! cargo" a:args
endfunction
function! s:nearest_cargo(...) abort
" If the second argument is not specified, the first argument determines
" whether we will start from the current directory or the directory of the
" current buffer, otherwise, we start with the provided path on the
" second argument.
let l:is_getcwd = get(a:, 1, 0)
if l:is_getcwd
let l:starting_path = get(a:, 2, getcwd())
else
let l:starting_path = get(a:, 2, expand('%:p:h'))
endif
return findfile('Cargo.toml', l:starting_path . ';')
endfunction
function! cargo#nearestCargo(is_getcwd) abort
return s:nearest_cargo(a:is_getcwd)
endfunction
function! cargo#nearestWorkspaceCargo(is_getcwd) abort
let l:nearest = s:nearest_cargo(a:is_getcwd)
while l:nearest !=# ''
for l:line in readfile(l:nearest, '', 0x100)
if l:line =~# '\V[workspace]'
return l:nearest
endif
endfor
let l:next = fnamemodify(l:nearest, ':p:h:h')
let l:nearest = s:nearest_cargo(0, l:next)
endwhile
return ''
endfunction
function! cargo#nearestRootCargo(is_getcwd) abort
" Try to find a workspace Cargo.toml, and if not found, take the nearest
" regular Cargo.toml
let l:workspace_cargo = cargo#nearestWorkspaceCargo(a:is_getcwd)
if l:workspace_cargo !=# ''
return l:workspace_cargo
endif
return s:nearest_cargo(a:is_getcwd)
endfunction
function! cargo#build(args)
call cargo#cmd("build " . a:args)
endfunction
function! cargo#clean(args)
call cargo#cmd("clean " . a:args)
endfunction
function! cargo#doc(args)
call cargo#cmd("doc " . a:args)
endfunction
function! cargo#new(args)
call cargo#cmd("new " . a:args)
cd `=a:args`
endfunction
function! cargo#init(args)
call cargo#cmd("init " . a:args)
endfunction
function! cargo#run(args)
call cargo#cmd("run " . a:args)
endfunction
function! cargo#test(args)
call cargo#cmd("test " . a:args)
endfunction
function! cargo#bench(args)
call cargo#cmd("bench " . a:args)
endfunction
function! cargo#runtarget(args)
let l:filename = expand('%:p')
let l:read_manifest = system('cargo read-manifest')
let l:metadata = json_decode(l:read_manifest)
let l:targets = get(l:metadata, 'targets', [])
let l:did_run = 0
for l:target in l:targets
let l:src_path = get(l:target, 'src_path', '')
let l:kinds = get(l:target, 'kind', [])
let l:name = get(l:target, 'name', '')
if l:src_path == l:filename
if index(l:kinds, 'example') != -1
let l:did_run = 1
call cargo#run("--example " . shellescape(l:name) . " " . a:args)
return
elseif index(l:kinds, 'bin') != -1
let l:did_run = 1
call cargo#run("--bin " . shellescape(l:name) . " " . a:args)
return
endif
endif
endfor
if l:did_run != 1
call cargo#run(a:args)
return
endif
endfunction
" vim: set et sw=4 sts=4 ts=8:

View file

@ -0,0 +1,26 @@
function! cargo#quickfix#CmdPre() abort
if &filetype ==# 'rust' && get(b:, 'current_compiler', '') ==# 'cargo'
" Preserve the current directory, and 'lcd' to the nearest Cargo file.
let b:rust_compiler_cargo_qf_has_lcd = haslocaldir()
let b:rust_compiler_cargo_qf_prev_cd = getcwd()
let b:rust_compiler_cargo_qf_prev_cd_saved = 1
let l:nearest = fnamemodify(cargo#nearestRootCargo(0), ':h')
execute 'lchdir! '.l:nearest
else
let b:rust_compiler_cargo_qf_prev_cd_saved = 0
endif
endfunction
function! cargo#quickfix#CmdPost() abort
if exists("b:rust_compiler_cargo_qf_prev_cd_saved") && b:rust_compiler_cargo_qf_prev_cd_saved
" Restore the current directory.
if b:rust_compiler_cargo_qf_has_lcd
execute 'lchdir! '.b:rust_compiler_cargo_qf_prev_cd
else
execute 'chdir! '.b:rust_compiler_cargo_qf_prev_cd
endif
let b:rust_compiler_cargo_qf_prev_cd_saved = 0
endif
endfunction
" vim: set et sw=4 sts=4 ts=8:

View file

@ -1,206 +1,259 @@
" Author: Kevin Ballard " Author: Kevin Ballard
" Description: Helper functions for Rust commands/mappings " Description: Helper functions for Rust commands/mappings
" Last Modified: May 27, 2014 " Last Modified: May 27, 2014
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim
function! rust#Load()
" Utility call to get this script loaded, for debugging
endfunction
function! rust#GetConfigVar(name, default)
" Local buffer variable with same name takes predeence over global
if has_key(b:, a:name)
return get(b:, a:name)
endif
if has_key(g:, a:name)
return get(g:, a:name)
endif
return a:default
endfunction
" Include expression {{{1
function! rust#IncludeExpr(fname) abort
" Remove leading 'crate::' to deal with 2018 edition style 'use'
" statements
let l:fname = substitute(a:fname, '^crate::', '', '')
" Remove trailing colons arising from lines like
"
" use foo::{Bar, Baz};
let l:fname = substitute(l:fname, ':\+$', '', '')
" Replace '::' with '/'
let l:fname = substitute(l:fname, '::', '/', 'g')
" When we have
"
" use foo::bar::baz;
"
" we can't tell whether baz is a module or a function; and we can't tell
" which modules correspond to files.
"
" So we work our way up, trying
"
" foo/bar/baz.rs
" foo/bar.rs
" foo.rs
while l:fname !=# '.'
let l:path = findfile(l:fname)
if !empty(l:path)
return l:fname
endif
let l:fname = fnamemodify(l:fname, ':h')
endwhile
return l:fname
endfunction
" Jump {{{1 " Jump {{{1
function! rust#Jump(mode, function) range function! rust#Jump(mode, function) range
let cnt = v:count1 let cnt = v:count1
normal! m' normal! m'
if a:mode ==# 'v' if a:mode ==# 'v'
norm! gv norm! gv
endif endif
let foldenable = &foldenable let foldenable = &foldenable
set nofoldenable set nofoldenable
while cnt > 0 while cnt > 0
execute "call <SID>Jump_" . a:function . "()" execute "call <SID>Jump_" . a:function . "()"
let cnt = cnt - 1 let cnt = cnt - 1
endwhile endwhile
let &foldenable = foldenable let &foldenable = foldenable
endfunction endfunction
function! s:Jump_Back() function! s:Jump_Back()
call search('{', 'b') call search('{', 'b')
keepjumps normal! w99[{ keepjumps normal! w99[{
endfunction endfunction
function! s:Jump_Forward() function! s:Jump_Forward()
normal! j0 normal! j0
call search('{', 'b') call search('{', 'b')
keepjumps normal! w99[{% keepjumps normal! w99[{%
call search('{') call search('{')
endfunction endfunction
" Run {{{1 " Run {{{1
function! rust#Run(bang, args) function! rust#Run(bang, args)
let args = s:ShellTokenize(a:args) let args = s:ShellTokenize(a:args)
if a:bang if a:bang
let idx = index(l:args, '--') let idx = index(l:args, '--')
if idx != -1 if idx != -1
let rustc_args = idx == 0 ? [] : l:args[:idx-1] let rustc_args = idx == 0 ? [] : l:args[:idx-1]
let args = l:args[idx+1:] let args = l:args[idx+1:]
else else
let rustc_args = l:args let rustc_args = l:args
let args = [] let args = []
endif endif
else else
let rustc_args = [] let rustc_args = []
endif endif
let b:rust_last_rustc_args = l:rustc_args let b:rust_last_rustc_args = l:rustc_args
let b:rust_last_args = l:args let b:rust_last_args = l:args
call s:WithPath(function("s:Run"), rustc_args, args) call s:WithPath(function("s:Run"), rustc_args, args)
endfunction endfunction
function! s:Run(dict, rustc_args, args) function! s:Run(dict, rustc_args, args)
let exepath = a:dict.tmpdir.'/'.fnamemodify(a:dict.path, ':t:r') let exepath = a:dict.tmpdir.'/'.fnamemodify(a:dict.path, ':t:r')
if has('win32') if has('win32')
let exepath .= '.exe' let exepath .= '.exe'
endif endif
let relpath = get(a:dict, 'tmpdir_relpath', a:dict.path) let relpath = get(a:dict, 'tmpdir_relpath', a:dict.path)
let rustc_args = [relpath, '-o', exepath] + a:rustc_args let rustc_args = [relpath, '-o', exepath] + a:rustc_args
let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc" let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc"
let pwd = a:dict.istemp ? a:dict.tmpdir : '' let pwd = a:dict.istemp ? a:dict.tmpdir : ''
let output = s:system(pwd, shellescape(rustc) . " " . join(map(rustc_args, 'shellescape(v:val)'))) let output = s:system(pwd, shellescape(rustc) . " " . join(map(rustc_args, 'shellescape(v:val)')))
if output != '' if output !=# ''
echohl WarningMsg echohl WarningMsg
echo output echo output
echohl None echohl None
endif endif
if !v:shell_error if !v:shell_error
exe '!' . shellescape(exepath) . " " . join(map(a:args, 'shellescape(v:val)')) exe '!' . shellescape(exepath) . " " . join(map(a:args, 'shellescape(v:val)'))
endif endif
endfunction endfunction
" Expand {{{1 " Expand {{{1
function! rust#Expand(bang, args) function! rust#Expand(bang, args)
let args = s:ShellTokenize(a:args) let args = s:ShellTokenize(a:args)
if a:bang && !empty(l:args) if a:bang && !empty(l:args)
let pretty = remove(l:args, 0) let pretty = remove(l:args, 0)
else else
let pretty = "expanded" let pretty = "expanded"
endif endif
call s:WithPath(function("s:Expand"), pretty, args) call s:WithPath(function("s:Expand"), pretty, args)
endfunction endfunction
function! s:Expand(dict, pretty, args) function! s:Expand(dict, pretty, args)
try try
let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc" let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc"
if a:pretty =~? '^\%(everybody_loops$\|flowgraph=\)' if a:pretty =~? '^\%(everybody_loops$\|flowgraph=\)'
let flag = '--xpretty' let flag = '--xpretty'
else else
let flag = '--pretty' let flag = '--pretty'
endif endif
let relpath = get(a:dict, 'tmpdir_relpath', a:dict.path) let relpath = get(a:dict, 'tmpdir_relpath', a:dict.path)
let args = [relpath, '-Z', 'unstable-options', l:flag, a:pretty] + a:args let args = [relpath, '-Z', 'unstable-options', l:flag, a:pretty] + a:args
let pwd = a:dict.istemp ? a:dict.tmpdir : '' let pwd = a:dict.istemp ? a:dict.tmpdir : ''
let output = s:system(pwd, shellescape(rustc) . " " . join(map(args, 'shellescape(v:val)'))) let output = s:system(pwd, shellescape(rustc) . " " . join(map(args, 'shellescape(v:val)')))
if v:shell_error if v:shell_error
echohl WarningMsg echohl WarningMsg
echo output echo output
echohl None echohl None
else else
new new
silent put =output silent put =output
1 1
d d
setl filetype=rust setl filetype=rust
setl buftype=nofile setl buftype=nofile
setl bufhidden=hide setl bufhidden=hide
setl noswapfile setl noswapfile
" give the buffer a nice name " give the buffer a nice name
let suffix = 1 let suffix = 1
let basename = fnamemodify(a:dict.path, ':t:r') let basename = fnamemodify(a:dict.path, ':t:r')
while 1 while 1
let bufname = basename let bufname = basename
if suffix > 1 | let bufname .= ' ('.suffix.')' | endif if suffix > 1 | let bufname .= ' ('.suffix.')' | endif
let bufname .= '.pretty.rs' let bufname .= '.pretty.rs'
if bufexists(bufname) if bufexists(bufname)
let suffix += 1 let suffix += 1
continue continue
endif endif
exe 'silent noautocmd keepalt file' fnameescape(bufname) exe 'silent noautocmd keepalt file' fnameescape(bufname)
break break
endwhile endwhile
endif endif
endtry endtry
endfunction endfunction
function! rust#CompleteExpand(lead, line, pos) function! rust#CompleteExpand(lead, line, pos)
if a:line[: a:pos-1] =~ '^RustExpand!\s*\S*$' if a:line[: a:pos-1] =~# '^RustExpand!\s*\S*$'
" first argument and it has a ! " first argument and it has a !
let list = ["normal", "expanded", "typed", "expanded,identified", "flowgraph=", "everybody_loops"] let list = ["normal", "expanded", "typed", "expanded,identified", "flowgraph=", "everybody_loops"]
if !empty(a:lead) if !empty(a:lead)
call filter(list, "v:val[:len(a:lead)-1] == a:lead") call filter(list, "v:val[:len(a:lead)-1] == a:lead")
endif endif
return list return list
endif endif
return glob(escape(a:lead, "*?[") . '*', 0, 1) return glob(escape(a:lead, "*?[") . '*', 0, 1)
endfunction endfunction
" Emit {{{1 " Emit {{{1
function! rust#Emit(type, args) function! rust#Emit(type, args)
let args = s:ShellTokenize(a:args) let args = s:ShellTokenize(a:args)
call s:WithPath(function("s:Emit"), a:type, args) call s:WithPath(function("s:Emit"), a:type, args)
endfunction endfunction
function! s:Emit(dict, type, args) function! s:Emit(dict, type, args)
try try
let output_path = a:dict.tmpdir.'/output' let output_path = a:dict.tmpdir.'/output'
let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc" let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc"
let relpath = get(a:dict, 'tmpdir_relpath', a:dict.path) let relpath = get(a:dict, 'tmpdir_relpath', a:dict.path)
let args = [relpath, '--emit', a:type, '-o', output_path] + a:args let args = [relpath, '--emit', a:type, '-o', output_path] + a:args
let pwd = a:dict.istemp ? a:dict.tmpdir : '' let pwd = a:dict.istemp ? a:dict.tmpdir : ''
let output = s:system(pwd, shellescape(rustc) . " " . join(map(args, 'shellescape(v:val)'))) let output = s:system(pwd, shellescape(rustc) . " " . join(map(args, 'shellescape(v:val)')))
if output != '' if output !=# ''
echohl WarningMsg echohl WarningMsg
echo output echo output
echohl None echohl None
endif endif
if !v:shell_error if !v:shell_error
new new
exe 'silent keepalt read' fnameescape(output_path) exe 'silent keepalt read' fnameescape(output_path)
1 1
d d
if a:type == "llvm-ir" if a:type ==# "llvm-ir"
setl filetype=llvm setl filetype=llvm
let extension = 'll' let extension = 'll'
elseif a:type == "asm" elseif a:type ==# "asm"
setl filetype=asm setl filetype=asm
let extension = 's' let extension = 's'
endif endif
setl buftype=nofile setl buftype=nofile
setl bufhidden=hide setl bufhidden=hide
setl noswapfile setl noswapfile
if exists('l:extension') if exists('l:extension')
" give the buffer a nice name " give the buffer a nice name
let suffix = 1 let suffix = 1
let basename = fnamemodify(a:dict.path, ':t:r') let basename = fnamemodify(a:dict.path, ':t:r')
while 1 while 1
let bufname = basename let bufname = basename
if suffix > 1 | let bufname .= ' ('.suffix.')' | endif if suffix > 1 | let bufname .= ' ('.suffix.')' | endif
let bufname .= '.'.extension let bufname .= '.'.extension
if bufexists(bufname) if bufexists(bufname)
let suffix += 1 let suffix += 1
continue continue
endif endif
exe 'silent noautocmd keepalt file' fnameescape(bufname) exe 'silent noautocmd keepalt file' fnameescape(bufname)
break break
endwhile endwhile
endif endif
endif endif
endtry endtry
endfunction endfunction
" Utility functions {{{1 " Utility functions {{{1
@ -218,145 +271,145 @@ endfunction
" existing path of the current buffer. If the path is inside of {dict.tmpdir} " existing path of the current buffer. If the path is inside of {dict.tmpdir}
" then it is guaranteed to have a '.rs' extension. " then it is guaranteed to have a '.rs' extension.
function! s:WithPath(func, ...) function! s:WithPath(func, ...)
let buf = bufnr('') let buf = bufnr('')
let saved = {} let saved = {}
let dict = {} let dict = {}
try try
let saved.write = &write let saved.write = &write
set write set write
let dict.path = expand('%') let dict.path = expand('%')
let pathisempty = empty(dict.path) let pathisempty = empty(dict.path)
" Always create a tmpdir in case the wrapped command wants it " Always create a tmpdir in case the wrapped command wants it
let dict.tmpdir = tempname() let dict.tmpdir = tempname()
call mkdir(dict.tmpdir) call mkdir(dict.tmpdir)
if pathisempty || !saved.write if pathisempty || !saved.write
let dict.istemp = 1 let dict.istemp = 1
" if we're doing this because of nowrite, preserve the filename " if we're doing this because of nowrite, preserve the filename
if !pathisempty if !pathisempty
let filename = expand('%:t:r').".rs" let filename = expand('%:t:r').".rs"
else else
let filename = 'unnamed.rs' let filename = 'unnamed.rs'
endif endif
let dict.tmpdir_relpath = filename let dict.tmpdir_relpath = filename
let dict.path = dict.tmpdir.'/'.filename let dict.path = dict.tmpdir.'/'.filename
let saved.mod = &mod let saved.mod = &modified
set nomod set nomodified
silent exe 'keepalt write! ' . fnameescape(dict.path) silent exe 'keepalt write! ' . fnameescape(dict.path)
if pathisempty if pathisempty
silent keepalt 0file silent keepalt 0file
endif endif
else else
let dict.istemp = 0 let dict.istemp = 0
update update
endif endif
call call(a:func, [dict] + a:000) call call(a:func, [dict] + a:000)
finally finally
if bufexists(buf) if bufexists(buf)
for [opt, value] in items(saved) for [opt, value] in items(saved)
silent call setbufvar(buf, '&'.opt, value) silent call setbufvar(buf, '&'.opt, value)
unlet value " avoid variable type mismatches unlet value " avoid variable type mismatches
endfor endfor
endif endif
if has_key(dict, 'tmpdir') | silent call s:RmDir(dict.tmpdir) | endif if has_key(dict, 'tmpdir') | silent call s:RmDir(dict.tmpdir) | endif
endtry endtry
endfunction endfunction
function! rust#AppendCmdLine(text) function! rust#AppendCmdLine(text)
call setcmdpos(getcmdpos()) call setcmdpos(getcmdpos())
let cmd = getcmdline() . a:text let cmd = getcmdline() . a:text
return cmd return cmd
endfunction endfunction
" Tokenize the string according to sh parsing rules " Tokenize the string according to sh parsing rules
function! s:ShellTokenize(text) function! s:ShellTokenize(text)
" states: " states:
" 0: start of word " 0: start of word
" 1: unquoted " 1: unquoted
" 2: unquoted backslash " 2: unquoted backslash
" 3: double-quote " 3: double-quote
" 4: double-quoted backslash " 4: double-quoted backslash
" 5: single-quote " 5: single-quote
let l:state = 0 let l:state = 0
let l:current = '' let l:current = ''
let l:args = [] let l:args = []
for c in split(a:text, '\zs') for c in split(a:text, '\zs')
if l:state == 0 || l:state == 1 " unquoted if l:state == 0 || l:state == 1 " unquoted
if l:c ==# ' ' if l:c ==# ' '
if l:state == 0 | continue | endif if l:state == 0 | continue | endif
call add(l:args, l:current) call add(l:args, l:current)
let l:current = '' let l:current = ''
let l:state = 0 let l:state = 0
elseif l:c ==# '\' elseif l:c ==# '\'
let l:state = 2 let l:state = 2
elseif l:c ==# '"' elseif l:c ==# '"'
let l:state = 3 let l:state = 3
elseif l:c ==# "'" elseif l:c ==# "'"
let l:state = 5 let l:state = 5
else else
let l:current .= l:c let l:current .= l:c
let l:state = 1 let l:state = 1
endif endif
elseif l:state == 2 " unquoted backslash elseif l:state == 2 " unquoted backslash
if l:c !=# "\n" " can it even be \n? if l:c !=# "\n" " can it even be \n?
let l:current .= l:c let l:current .= l:c
endif endif
let l:state = 1 let l:state = 1
elseif l:state == 3 " double-quote elseif l:state == 3 " double-quote
if l:c ==# '\' if l:c ==# '\'
let l:state = 4 let l:state = 4
elseif l:c ==# '"' elseif l:c ==# '"'
let l:state = 1 let l:state = 1
else else
let l:current .= l:c let l:current .= l:c
endif endif
elseif l:state == 4 " double-quoted backslash elseif l:state == 4 " double-quoted backslash
if stridx('$`"\', l:c) >= 0 if stridx('$`"\', l:c) >= 0
let l:current .= l:c let l:current .= l:c
elseif l:c ==# "\n" " is this even possible? elseif l:c ==# "\n" " is this even possible?
" skip it " skip it
else else
let l:current .= '\'.l:c let l:current .= '\'.l:c
endif endif
let l:state = 3 let l:state = 3
elseif l:state == 5 " single-quoted elseif l:state == 5 " single-quoted
if l:c == "'" if l:c ==# "'"
let l:state = 1 let l:state = 1
else else
let l:current .= l:c let l:current .= l:c
endif endif
endif endif
endfor endfor
if l:state != 0 if l:state != 0
call add(l:args, l:current) call add(l:args, l:current)
endif endif
return l:args return l:args
endfunction endfunction
function! s:RmDir(path) function! s:RmDir(path)
" sanity check; make sure it's not empty, /, or $HOME " sanity check; make sure it's not empty, /, or $HOME
if empty(a:path) if empty(a:path)
echoerr 'Attempted to delete empty path' echoerr 'Attempted to delete empty path'
return 0 return 0
elseif a:path == '/' || a:path == $HOME elseif a:path ==# '/' || a:path ==# $HOME
echoerr 'Attempted to delete protected path: ' . a:path echoerr 'Attempted to delete protected path: ' . a:path
return 0 return 0
endif endif
return system("rm -rf " . shellescape(a:path)) return system("rm -rf " . shellescape(a:path))
endfunction endfunction
" Executes {cmd} with the cwd set to {pwd}, without changing Vim's cwd. " Executes {cmd} with the cwd set to {pwd}, without changing Vim's cwd.
" If {pwd} is the empty string then it doesn't change the cwd. " If {pwd} is the empty string then it doesn't change the cwd.
function! s:system(pwd, cmd) function! s:system(pwd, cmd)
let cmd = a:cmd let cmd = a:cmd
if !empty(a:pwd) if !empty(a:pwd)
let cmd = 'cd ' . shellescape(a:pwd) . ' && ' . cmd let cmd = 'cd ' . shellescape(a:pwd) . ' && ' . cmd
endif endif
return system(cmd) return system(cmd)
endfunction endfunction
" Playpen Support {{{1 " Playpen Support {{{1
@ -364,51 +417,130 @@ endfunction
" gist.vim available under the BSD license, available at " gist.vim available under the BSD license, available at
" http://github.com/mattn/gist-vim " http://github.com/mattn/gist-vim
function! s:has_webapi() function! s:has_webapi()
if !exists("*webapi#http#post") if !exists("*webapi#http#post")
try try
call webapi#http#post() call webapi#http#post()
catch catch
endtry endtry
endif endif
return exists("*webapi#http#post") return exists("*webapi#http#post")
endfunction endfunction
function! rust#Play(count, line1, line2, ...) abort function! rust#Play(count, line1, line2, ...) abort
redraw redraw
let l:rust_playpen_url = get(g:, 'rust_playpen_url', 'https://play.rust-lang.org/') let l:rust_playpen_url = get(g:, 'rust_playpen_url', 'https://play.rust-lang.org/')
let l:rust_shortener_url = get(g:, 'rust_shortener_url', 'https://is.gd/') let l:rust_shortener_url = get(g:, 'rust_shortener_url', 'https://is.gd/')
if !s:has_webapi() if !s:has_webapi()
echohl ErrorMsg | echomsg ':RustPlay depends on webapi.vim (https://github.com/mattn/webapi-vim)' | echohl None echohl ErrorMsg | echomsg ':RustPlay depends on webapi.vim (https://github.com/mattn/webapi-vim)' | echohl None
return return
endif endif
let bufname = bufname('%') let bufname = bufname('%')
if a:count < 1 if a:count < 1
let content = join(getline(a:line1, a:line2), "\n") let content = join(getline(a:line1, a:line2), "\n")
else else
let save_regcont = @" let save_regcont = @"
let save_regtype = getregtype('"') let save_regtype = getregtype('"')
silent! normal! gvy silent! normal! gvy
let content = @" let content = @"
call setreg('"', save_regcont, save_regtype) call setreg('"', save_regcont, save_regtype)
endif endif
let body = l:rust_playpen_url."?code=".webapi#http#encodeURI(content) let url = l:rust_playpen_url."?code=".webapi#http#encodeURI(content)
if strlen(body) > 5000 if strlen(url) > 5000
echohl ErrorMsg | echomsg 'Buffer too large, max 5000 encoded characters ('.strlen(body).')' | echohl None echohl ErrorMsg | echomsg 'Buffer too large, max 5000 encoded characters ('.strlen(url).')' | echohl None
return return
endif endif
let payload = "format=simple&url=".webapi#http#encodeURI(body) let payload = "format=simple&url=".webapi#http#encodeURI(url)
let res = webapi#http#post(l:rust_shortener_url.'create.php', payload, {}) let res = webapi#http#post(l:rust_shortener_url.'create.php', payload, {})
let url = res.content if res.status[0] ==# '2'
let url = res.content
endif
redraw | echomsg 'Done: '.url let footer = ''
if exists('g:rust_clip_command')
call system(g:rust_clip_command, url)
if !v:shell_error
let footer = ' (copied to clipboard)'
endif
endif
redraw | echomsg 'Done: '.url.footer
endfunction
" Run a test under the cursor or all tests {{{1
" Finds a test function name under the cursor. Returns empty string when a
" test function is not found.
function! s:SearchTestFunctionNameUnderCursor() abort
let cursor_line = line('.')
" Find #[test] attribute
if search('\m\C#\[test\]', 'bcW') is 0
return ''
endif
" Move to an opening brace of the test function
let test_func_line = search('\m\C^\s*fn\s\+\h\w*\s*(.\+{$', 'eW')
if test_func_line is 0
return ''
endif
" Search the end of test function (closing brace) to ensure that the
" cursor position is within function definition
normal! %
if line('.') < cursor_line
return ''
endif
return matchstr(getline(test_func_line), '\m\C^\s*fn\s\+\zs\h\w*')
endfunction
function! rust#Test(all, options) abort
let manifest = findfile('Cargo.toml', expand('%:p:h') . ';')
if manifest ==# ''
return rust#Run(1, '--test ' . a:options)
endif
if exists(':terminal')
let cmd = 'terminal '
else
let cmd = '!'
let manifest = shellescape(manifest)
endif
if a:all
if a:options ==# ''
execute cmd . 'cargo test --manifest-path' manifest
else
execute cmd . 'cargo test --manifest-path' manifest a:options
endif
return
endif
let saved = getpos('.')
try
let func_name = s:SearchTestFunctionNameUnderCursor()
if func_name ==# ''
echohl ErrorMsg
echo 'No test function was found under the cursor. Please add ! to command if you want to run all tests'
echohl None
return
endif
if a:options ==# ''
execute cmd . 'cargo test --manifest-path' manifest func_name
else
execute cmd . 'cargo test --manifest-path' manifest func_name a:options
endif
return
finally
call setpos('.', saved)
endtry
endfunction endfunction
" }}}1 " }}}1
" vim: set noet sw=4 ts=4: " vim: set et sw=4 sts=4 ts=8:

View file

@ -0,0 +1,101 @@
" For debugging, inspired by https://github.com/w0rp/rust/blob/master/autoload/rust/debugging.vim
let s:global_variable_list = [
\ 'ftplugin_rust_source_path',
\ 'loaded_syntastic_rust_cargo_checker',
\ 'loaded_syntastic_rust_filetype',
\ 'loaded_syntastic_rust_rustc_checker',
\ 'rust_bang_comment_leader',
\ 'rust_cargo_avoid_whole_workspace',
\ 'rust_clip_command',
\ 'rust_conceal',
\ 'rust_conceal_mod_path',
\ 'rust_conceal_pub',
\ 'rust_fold',
\ 'rust_last_args',
\ 'rust_last_rustc_args',
\ 'rust_original_delimitMate_excluded_regions',
\ 'rust_playpen_url',
\ 'rust_prev_delimitMate_quotes',
\ 'rust_recent_nearest_cargo_tol',
\ 'rust_recent_root_cargo_toml',
\ 'rust_recommended_style',
\ 'rust_set_conceallevel',
\ 'rust_set_conceallevel=1',
\ 'rust_set_foldmethod',
\ 'rust_set_foldmethod=1',
\ 'rust_shortener_url',
\ 'rustc_makeprg_no_percent',
\ 'rustc_path',
\ 'rustfmt_autosave',
\ 'rustfmt_autosave_because_of_config',
\ 'rustfmt_autosave_if_config_present',
\ 'rustfmt_command',
\ 'rustfmt_emit_files',
\ 'rustfmt_fail_silently',
\ 'rustfmt_options',
\ 'syntastic_extra_filetypes',
\ 'syntastic_rust_cargo_fname',
\]
function! s:Echo(message) abort
execute 'echo a:message'
endfunction
function! s:EchoGlobalVariables() abort
for l:key in s:global_variable_list
call s:Echo('let g:' . l:key . ' = ' . string(get(g:, l:key, v:null)))
if has_key(b:, l:key)
call s:Echo('let b:' . l:key . ' = ' . string(b:[l:key]))
endif
endfor
endfunction
function! rust#debugging#Info() abort
call cargo#Load()
call rust#Load()
call rustfmt#Load()
call s:Echo('rust.vim Global Variables:')
call s:Echo('')
call s:EchoGlobalVariables()
silent let l:output = system(g:rustfmt_command . ' --version')
echo l:output
let l:rustc = exists("g:rustc_path") ? g:rustc_path : "rustc"
silent let l:output = system(l:rustc . ' --version')
echo l:output
silent let l:output = system('cargo --version')
echo l:output
version
if exists(":SyntasticInfo")
echo "----"
echo "Info from Syntastic:"
execute "SyntasticInfo"
endif
endfunction
function! rust#debugging#InfoToClipboard() abort
redir @"
silent call rust#debugging#Info()
redir END
call s:Echo('RustInfo copied to your clipboard')
endfunction
function! rust#debugging#InfoToFile(filename) abort
let l:expanded_filename = expand(a:filename)
redir => l:output
silent call rust#debugging#Info()
redir END
call writefile(split(l:output, "\n"), l:expanded_filename)
call s:Echo('RustInfo written to ' . l:expanded_filename)
endfunction
" vim: set et sw=4 sts=4 ts=8:

View file

@ -0,0 +1,44 @@
let s:delimitMate_extra_excluded_regions = ',rustLifetimeCandidate,rustGenericLifetimeCandidate'
" For this buffer, when delimitMate issues the `User delimitMate_map`
" event in the autocommand system, add the above-defined extra excluded
" regions to delimitMate's state, if they have not already been added.
function! rust#delimitmate#onMap() abort
if &filetype !=# 'rust'
return
endif
if get(b:, "delimitMate_quotes")
let b:rust_prev_delimitMate_quotes = b:delimitMate_quotes
endif
let b:delimitMate_quotes = "\" `"
if match(delimitMate#Get("excluded_regions"),
\ s:delimitMate_extra_excluded_regions) == -1
call delimitMate#Set("excluded_regions",
\delimitMate#Get("excluded_regions").s:delimitMate_extra_excluded_regions)
endif
endfunction
" For this buffer, when delimitMate issues the `User delimitMate_unmap`
" event in the autocommand system, delete the above-defined extra excluded
" regions from delimitMate's state (the deletion being idempotent and
" having no effect if the extra excluded regions are not present in the
" targeted part of delimitMate's state).
function! rust#delimitmate#onUnmap() abort
if &filetype !=# 'rust'
return
endif
if get(b:, "rust_prev_delimitMate_quotes")
let b:delimitMate_quotes = b:rust_prev_delimitMate_quotes
endif
call delimitMate#Set("excluded_regions", substitute(
\ delimitMate#Get("excluded_regions"),
\ '\C\V' . s:delimitMate_extra_excluded_regions,
\ '', 'g'))
endfunction
" vim: set et sw=4 sts=4 ts=8:

View file

@ -1,9 +1,10 @@
" Author: Stephen Sugden <stephen@stephensugden.com> " Author: Stephen Sugden <stephen@stephensugden.com>
" "
" Adapted from https://github.com/fatih/vim-go " Adapted from https://github.com/fatih/vim-go
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim
if !exists("g:rustfmt_autosave") if !exists("g:rustfmt_autosave")
let g:rustfmt_autosave = 0 let g:rustfmt_autosave = 0
endif endif
if !exists("g:rustfmt_command") if !exists("g:rustfmt_command")
@ -11,96 +12,246 @@ if !exists("g:rustfmt_command")
endif endif
if !exists("g:rustfmt_options") if !exists("g:rustfmt_options")
let g:rustfmt_options = "" let g:rustfmt_options = ""
endif endif
if !exists("g:rustfmt_fail_silently") if !exists("g:rustfmt_fail_silently")
let g:rustfmt_fail_silently = 0 let g:rustfmt_fail_silently = 0
endif
function! rustfmt#DetectVersion()
" Save rustfmt '--help' for feature inspection
silent let s:rustfmt_help = system(g:rustfmt_command . " --help")
let s:rustfmt_unstable_features = s:rustfmt_help =~# "--unstable-features"
" Build a comparable rustfmt version varible out of its `--version` output:
silent let l:rustfmt_version_full = system(g:rustfmt_command . " --version")
let l:rustfmt_version_list = matchlist(l:rustfmt_version_full,
\ '\vrustfmt ([0-9]+[.][0-9]+[.][0-9]+)')
if len(l:rustfmt_version_list) < 3
let s:rustfmt_version = "0"
else
let s:rustfmt_version = l:rustfmt_version_list[1]
endif
return s:rustfmt_version
endfunction
call rustfmt#DetectVersion()
if !exists("g:rustfmt_emit_files")
let g:rustfmt_emit_files = s:rustfmt_version >= "0.8.2"
endif
if !exists("g:rustfmt_file_lines")
let g:rustfmt_file_lines = s:rustfmt_help =~# "--file-lines JSON"
endif endif
let s:got_fmt_error = 0 let s:got_fmt_error = 0
function! rustfmt#Load()
" Utility call to get this script loaded, for debugging
endfunction
function! s:RustfmtWriteMode()
if g:rustfmt_emit_files
return "--emit=files"
else
return "--write-mode=overwrite"
endif
endfunction
function! s:RustfmtConfig()
let l:rustfmt_toml = findfile('rustfmt.toml', expand('%:p:h') . ';')
if l:rustfmt_toml !=# ''
return '--config-path '.l:rustfmt_toml
endif
let l:_rustfmt_toml = findfile('.rustfmt.toml', expand('%:p:h') . ';')
if l:_rustfmt_toml !=# ''
return '--config-path '.l:_rustfmt_toml
endif
return ''
endfunction
function! s:RustfmtCommandRange(filename, line1, line2) function! s:RustfmtCommandRange(filename, line1, line2)
let l:arg = {"file": shellescape(a:filename), "range": [a:line1, a:line2]} if g:rustfmt_file_lines == 0
return printf("%s %s --write-mode=overwrite --file-lines '[%s]'", g:rustfmt_command, g:rustfmt_options, json_encode(l:arg)) echo "--file-lines is not supported in the installed `rustfmt` executable"
return
endif
let l:arg = {"file": shellescape(a:filename), "range": [a:line1, a:line2]}
let l:write_mode = s:RustfmtWriteMode()
let l:rustfmt_config = s:RustfmtConfig()
" FIXME: When --file-lines gets to be stable, add version range checking
" accordingly.
let l:unstable_features = s:rustfmt_unstable_features ? '--unstable-features' : ''
let l:cmd = printf("%s %s %s %s %s --file-lines '[%s]' %s", g:rustfmt_command,
\ l:write_mode, g:rustfmt_options,
\ l:unstable_features, l:rustfmt_config,
\ json_encode(l:arg), shellescape(a:filename))
return l:cmd
endfunction endfunction
function! s:RustfmtCommand(filename) function! s:RustfmtCommand()
return g:rustfmt_command . " --write-mode=overwrite " . g:rustfmt_options . " " . shellescape(a:filename) if g:rustfmt_emit_files
let l:write_mode = "--emit=stdout"
else
let l:write_mode = "--write-mode=display"
endif
" rustfmt will pick on the right config on its own due to the
" current directory change.
return g:rustfmt_command . " ". l:write_mode . " " . g:rustfmt_options
endfunction endfunction
function! s:RunRustfmt(command, curw, tmpname) function! s:DeleteLines(start, end) abort
if exists("*systemlist") silent! execute a:start . ',' . a:end . 'delete _'
let out = systemlist(a:command) endfunction
else
let out = split(system(a:command), '\r\?\n')
endif
if v:shell_error == 0 || v:shell_error == 3 function! s:RunRustfmt(command, tmpname, fail_silently)
" remove undo point caused via BufWritePre mkview!
try | silent undojoin | catch | endtry
" Replace current file with temp file, then reload buffer let l:stderr_tmpname = tempname()
call rename(a:tmpname, expand('%')) call writefile([], l:stderr_tmpname)
silent edit!
let &syntax = &syntax
" only clear location list if it was previously filled to prevent let l:command = a:command . ' 2> ' . l:stderr_tmpname
" 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 if a:tmpname ==# ''
" src/lib.rs:13:5: 13:10 error: expected `,`, or `}`, found `value` " Rustfmt in stdin/stdout mode
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) " chdir to the directory of the file
% | " Couldn't detect rustfmt error format, output errors let l:has_lcd = haslocaldir()
let l:prev_cd = getcwd()
execute 'lchdir! '.expand('%:h')
let l:buffer = getline(1, '$')
if exists("*systemlist")
silent let out = systemlist(l:command, l:buffer)
else
silent let out = split(system(l:command,
\ join(l:buffer, "\n")), '\r\?\n')
endif
else
if exists("*systemlist")
silent let out = systemlist(l:command)
else
silent let out = split(system(l:command), '\r\?\n')
endif
endif endif
if !empty(errors) let l:stderr = readfile(l:stderr_tmpname)
call setloclist(0, errors, 'r')
echohl Error | echomsg "rustfmt returned error" | echohl None call delete(l:stderr_tmpname)
let l:open_lwindow = 0
if v:shell_error == 0
" remove undo point caused via BufWritePre
try | silent undojoin | catch | endtry
if a:tmpname ==# ''
let l:content = l:out
else
" take the tmpfile's content, this is better than rename
" because it preserves file modes.
let l:content = readfile(a:tmpname)
endif
call s:DeleteLines(len(l:content), line('$'))
call setline(1, l:content)
" 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, [])
let l:open_lwindow = 1
endif
elseif g:rustfmt_fail_silently == 0 && a:fail_silently == 0
" otherwise get the errors and put them in the location list
let l:errors = []
let l:prev_line = ""
for l:line in l:stderr
" error: expected one of `;` or `as`, found `extern`
" --> src/main.rs:2:1
let tokens = matchlist(l:line, '^\s\+-->\s\(.\{-}\):\(\d\+\):\(\d\+\)$')
if !empty(tokens)
call add(l:errors, {"filename": @%,
\"lnum": tokens[2],
\"col": tokens[3],
\"text": l:prev_line})
endif
let l:prev_line = l:line
endfor
if !empty(l:errors)
call setloclist(0, l:errors, 'r')
echohl Error | echomsg "rustfmt returned error" | echohl None
else
echo "rust.vim: was not able to parse rustfmt messages. Here is the raw output:"
echo "\n"
for l:line in l:stderr
echo l:line
endfor
endif
let s:got_fmt_error = 1
let l:open_lwindow = 1
endif endif
let s:got_fmt_error = 1 " Restore the current directory if needed
lwindow if a:tmpname ==# ''
" We didn't use the temp file, so clean up if l:has_lcd
call delete(a:tmpname) execute 'lchdir! '.l:prev_cd
endif else
execute 'chdir! '.l:prev_cd
endif
endif
call winrestview(a:curw) " Open lwindow after we have changed back to the previous directory
if l:open_lwindow == 1
lwindow
endif
silent! loadview
endfunction endfunction
function! rustfmt#FormatRange(line1, line2) function! rustfmt#FormatRange(line1, line2)
let l:curw = winsaveview() let l:tmpname = tempname()
let l:tmpname = expand("%:p:h") . "/." . expand("%:p:t") . ".rustfmt" call writefile(getline(1, '$'), l:tmpname)
call writefile(getline(1, '$'), l:tmpname) let command = s:RustfmtCommandRange(l:tmpname, a:line1, a:line2)
call s:RunRustfmt(command, l:tmpname, 0)
let command = s:RustfmtCommandRange(l:tmpname, a:line1, a:line2) call delete(l:tmpname)
call s:RunRustfmt(command, l:curw, l:tmpname)
endfunction endfunction
function! rustfmt#Format() function! rustfmt#Format()
let l:curw = winsaveview() call s:RunRustfmt(s:RustfmtCommand(), '', 0)
let l:tmpname = expand("%:p:h") . "/." . expand("%:p:t") . ".rustfmt"
call writefile(getline(1, '$'), l:tmpname)
let command = s:RustfmtCommand(l:tmpname)
call s:RunRustfmt(command, l:curw, l:tmpname)
endfunction endfunction
function! rustfmt#Cmd()
" Mainly for debugging
return s:RustfmtCommand()
endfunction
function! rustfmt#PreWrite()
if !filereadable(expand("%@"))
return
endif
if rust#GetConfigVar('rustfmt_autosave_if_config_present', 0)
if findfile('rustfmt.toml', '.;') !=# '' || findfile('.rustfmt.toml', '.;') !=# ''
let b:rustfmt_autosave = 1
let b:rustfmt_autosave_because_of_config = 1
endif
endif
if !rust#GetConfigVar("rustfmt_autosave", 0)
return
endif
call s:RunRustfmt(s:RustfmtCommand(), '', 1)
endfunction
" vim: set et sw=4 sts=4 ts=8:

View file

@ -2,13 +2,19 @@
" Compiler: Cargo Compiler " Compiler: Cargo Compiler
" Maintainer: Damien Radtke <damienradtke@gmail.com> " Maintainer: Damien Radtke <damienradtke@gmail.com>
" Latest Revision: 2014 Sep 24 " Latest Revision: 2014 Sep 24
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim
if exists('current_compiler') if exists('current_compiler')
finish finish
endif endif
runtime compiler/rustc.vim runtime compiler/rustc.vim
let current_compiler = "cargo" let current_compiler = "cargo"
" vint: -ProhibitAbbreviationOption
let s:save_cpo = &cpo
set cpo&vim
" vint: +ProhibitAbbreviationOption
if exists(':CompilerSet') != 2 if exists(':CompilerSet') != 2
command -nargs=* CompilerSet setlocal <args> command -nargs=* CompilerSet setlocal <args>
endif endif
@ -19,10 +25,25 @@ else
CompilerSet makeprg=cargo\ $* CompilerSet makeprg=cargo\ $*
endif endif
augroup RustCargoQuickFixHooks
autocmd!
autocmd QuickFixCmdPre make call cargo#quickfix#CmdPre()
autocmd QuickFixCmdPost make call cargo#quickfix#CmdPost()
augroup END
" Ignore general cargo progress messages " Ignore general cargo progress messages
CompilerSet errorformat+= CompilerSet errorformat+=
\%-G%\\s%#Downloading%.%#, \%-G%\\s%#Downloading%.%#,
\%-G%\\s%#Compiling%.%#, \%-G%\\s%#Compiling%.%#,
\%-G%\\s%#Finished%.%#, \%-G%\\s%#Finished%.%#,
\%-G%\\s%#error:\ Could\ not\ compile\ %.%#, \%-G%\\s%#error:\ Could\ not\ compile\ %.%#,
\%-G%\\s%#To\ learn\ more\\,%.%# \%-G%\\s%#To\ learn\ more\\,%.%#,
\%-Gnote:\ Run\ with\ \`RUST_BACKTRACE=%.%#,
\%.%#panicked\ at\ \\'%m\\'\\,\ %f:%l:%c
" vint: -ProhibitAbbreviationOption
let &cpo = s:save_cpo
unlet s:save_cpo
" vint: +ProhibitAbbreviationOption
" vim: set et sw=4 sts=4 ts=8:

View file

@ -2,44 +2,52 @@
" Compiler: Rust Compiler " Compiler: Rust Compiler
" Maintainer: Chris Morgan <me@chrismorgan.info> " Maintainer: Chris Morgan <me@chrismorgan.info>
" Latest Revision: 2013 Jul 12 " Latest Revision: 2013 Jul 12
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim
if exists("current_compiler") if exists("current_compiler")
finish finish
endif endif
let current_compiler = "rustc" let current_compiler = "rustc"
let s:cpo_save = &cpo " vint: -ProhibitAbbreviationOption
let s:save_cpo = &cpo
set cpo&vim set cpo&vim
" vint: +ProhibitAbbreviationOption
if exists(":CompilerSet") != 2 if exists(":CompilerSet") != 2
command -nargs=* CompilerSet setlocal <args> command -nargs=* CompilerSet setlocal <args>
endif endif
if exists("g:rustc_makeprg_no_percent") && g:rustc_makeprg_no_percent != 0 if get(g:, 'rustc_makeprg_no_percent', 0)
CompilerSet makeprg=rustc CompilerSet makeprg=rustc
else else
CompilerSet makeprg=rustc\ \% CompilerSet makeprg=rustc\ \%
endif endif
" Old errorformat (before nightly 2016/08/10)
CompilerSet errorformat=
\%f:%l:%c:\ %t%*[^:]:\ %m,
\%f:%l:%c:\ %*\\d:%*\\d\ %t%*[^:]:\ %m,
\%-G%f:%l\ %s,
\%-G%*[\ ]^,
\%-G%*[\ ]^%*[~],
\%-G%*[\ ]...
" New errorformat (after nightly 2016/08/10) " New errorformat (after nightly 2016/08/10)
CompilerSet errorformat+= CompilerSet errorformat=
\%-G, \%-G,
\%-Gerror:\ aborting\ %.%#, \%-Gerror:\ aborting\ %.%#,
\%-Gerror:\ Could\ not\ compile\ %.%#, \%-Gerror:\ Could\ not\ compile\ %.%#,
\%Eerror:\ %m, \%Eerror:\ %m,
\%Eerror[E%n]:\ %m, \%Eerror[E%n]:\ %m,
\%Wwarning:\ %m, \%Wwarning:\ %m,
\%Inote:\ %m, \%Inote:\ %m,
\%C\ %#-->\ %f:%l:%c \%C\ %#-->\ %f:%l:%c,
\%E\ \ left:%m,%C\ right:%m\ %f:%l:%c,%Z
let &cpo = s:cpo_save " Old errorformat (before nightly 2016/08/10)
unlet s:cpo_save CompilerSet errorformat+=
\%f:%l:%c:\ %t%*[^:]:\ %m,
\%f:%l:%c:\ %*\\d:%*\\d\ %t%*[^:]:\ %m,
\%-G%f:%l\ %s,
\%-G%*[\ ]^,
\%-G%*[\ ]^%*[~],
\%-G%*[\ ]...
" vint: -ProhibitAbbreviationOption
let &cpo = s:save_cpo
unlet s:save_cpo
" vint: +ProhibitAbbreviationOption
" vim: set et sw=4 sts=4 ts=8:

View file

@ -0,0 +1,11 @@
--langdef=Rust
--langmap=Rust:.rs
--regex-Rust=/^[ \t]*(#\[[^\]]\][ \t]*)*(pub[ \t]+)?(extern[ \t]+)?("[^"]+"[ \t]+)?(unsafe[ \t]+)?fn[ \t]+([a-zA-Z0-9_]+)/\6/f,functions,function definitions/
--regex-Rust=/^[ \t]*(pub[ \t]+)?type[ \t]+([a-zA-Z0-9_]+)/\2/T,types,type definitions/
--regex-Rust=/^[ \t]*(pub[ \t]+)?enum[ \t]+([a-zA-Z0-9_]+)/\2/g,enum,enumeration names/
--regex-Rust=/^[ \t]*(pub[ \t]+)?struct[ \t]+([a-zA-Z0-9_]+)/\2/s,structure names/
--regex-Rust=/^[ \t]*(pub[ \t]+)?mod[ \t]+([a-zA-Z0-9_]+)/\2/m,modules,module names/
--regex-Rust=/^[ \t]*(pub[ \t]+)?(static|const)[ \t]+([a-zA-Z0-9_]+)/\3/c,consts,static constants/
--regex-Rust=/^[ \t]*(pub[ \t]+)?trait[ \t]+([a-zA-Z0-9_]+)/\2/t,traits,traits/
--regex-Rust=/^[ \t]*(pub[ \t]+)?impl([ \t\n]*<[^>]*>)?[ \t]+(([a-zA-Z0-9_:]+)[ \t]*(<[^>]*>)?[ \t]+(for)[ \t]+)?([a-zA-Z0-9_]+)/\4 \6 \7/i,impls,trait implementations/
--regex-Rust=/^[ \t]*macro_rules![ \t]+([a-zA-Z0-9_]+)/\1/d,macros,macro definitions/

View file

@ -1,7 +1,7 @@
*rust.txt* Filetype plugin for Rust *ft_rust.txt* Filetype plugin for Rust
============================================================================== ==============================================================================
CONTENTS *rust* *ft-rust* CONTENTS *rust*
1. Introduction |rust-intro| 1. Introduction |rust-intro|
2. Settings |rust-settings| 2. Settings |rust-settings|
@ -12,7 +12,8 @@ CONTENTS *rust* *ft-rust*
INTRODUCTION *rust-intro* INTRODUCTION *rust-intro*
This plugin provides syntax and supporting functionality for the Rust This plugin provides syntax and supporting functionality for the Rust
filetype. filetype. It requires Vim 8 or higher for full functionality. Some commands
will not work on earlier versions.
============================================================================== ==============================================================================
SETTINGS *rust-settings* SETTINGS *rust-settings*
@ -20,6 +21,9 @@ SETTINGS *rust-settings*
This plugin has a few variables you can define in your vimrc that change the This plugin has a few variables you can define in your vimrc that change the
behavior of the plugin. behavior of the plugin.
Some variables can be set buffer local (`:b` prefix), and the buffer local
will take precedence over the global `g:` counterpart.
*g:rustc_path* *g:rustc_path*
g:rustc_path~ g:rustc_path~
Set this option to the path to rustc for use in the |:RustRun| and Set this option to the path to rustc for use in the |:RustRun| and
@ -81,6 +85,20 @@ g:rust_bang_comment_leader~
let g:rust_bang_comment_leader = 1 let g:rust_bang_comment_leader = 1
< <
*g:rust_use_custom_ctags_defs*
g:rust_use_custom_ctags_defs~
Set this option to 1 if you have customized ctags definitions for Rust
and do not wish for those included with rust.vim to be used: >
let g:rust_use_custom_ctags_defs = 1
<
Note that rust.vim's built-in definitions are only used for the Tagbar
Vim plugin, if you have it installed--it is not automatically used
when generating |tags| files that Vim can use to navigate to
definitions across different source files. Feel free to copy
`rust.vim/ctags/rust.ctags` into your own `~/.ctags` if you wish to
generate |tags| files.
*g:ftplugin_rust_source_path* *g:ftplugin_rust_source_path*
g:ftplugin_rust_source_path~ g:ftplugin_rust_source_path~
Set this option to a path that should be prepended to 'path' for Rust Set this option to a path that should be prepended to 'path' for Rust
@ -100,6 +118,23 @@ g:rustfmt_autosave~
buffer. If not specified it defaults to 0 : > buffer. If not specified it defaults to 0 : >
let g:rustfmt_autosave = 0 let g:rustfmt_autosave = 0
< <
There is also a buffer-local b:rustfmt_autosave that can be set for
the same purpose, and can override the global setting.
*g:rustfmt_autosave_if_config_present*
g:rustfmt_autosave_if_config_present~
Set this option to 1 to to have *b:rustfmt_autosave* be set automatically
if a `rustfmt.toml` file is present in any parent directly leading to
the file being edited. If not set, default to 0: >
let g:rustfmt_autosave_if_config_present = 0
<
This is useful to have `rustfmt` only execute on save, on projects
that have `rustfmt.toml` configuration.
There is also a buffer-local b:rustfmt_autosave_if_config_present
that can be set for the same purpose, which can overrides the global
setting.
*g:rustfmt_fail_silently* *g:rustfmt_fail_silently*
g:rustfmt_fail_silently~ g:rustfmt_fail_silently~
Set this option to 1 to prevent 'rustfmt' from populating the Set this option to 1 to prevent 'rustfmt' from populating the
@ -113,6 +148,13 @@ g:rustfmt_options~
defaults to '' : > defaults to '' : >
let g:rustfmt_options = '' let g:rustfmt_options = ''
< <
*g:rustfmt_emit_files*
g:rustfmt_emit_files~
If not specified rust.vim tries to detect the right parameter to
pass to rustfmt based on its reported version. Otherwise, it
determines whether to run rustfmt with '--emit=files' (when 1 is
provided) instead of '--write-mode=overwrite'. >
let g:rustfmt_emit_files = 0
*g:rust_playpen_url* *g:rust_playpen_url*
g:rust_playpen_url~ g:rust_playpen_url~
@ -126,10 +168,196 @@ g:rust_shortener_url~
let g:rust_shortener_url = 'https://is.gd/' let g:rust_shortener_url = 'https://is.gd/'
< <
*g:rust_clip_command*
g:rust_clip_command~
Set this option to the command used in your OS to copy the Rust Play
url to the clipboard: >
let g:rust_clip_command = 'xclip -selection clipboard'
<
*g:cargo_makeprg_params*
g:cargo_makeprg_params~
Set this option to the string of parameters to pass to cargo. If not
specified it defaults to '$*' : >
let g:cargo_makeprg_params = 'build'
<
Integration with Syntastic *rust-syntastic*
--------------------------
This plugin automatically integrates with the Syntastic checker. There are two
checkers provided: 'rustc', and 'cargo'. The later invokes 'Cargo' in order to
build code, and the former delivers a single edited '.rs' file as a compilation
target directly to the Rust compiler, `rustc`.
Because Cargo is almost exclusively being used for building Rust code these
days, 'cargo' is the default checker. >
let g:syntastic_rust_checkers = ['cargo']
<
If you would like to change it, you can set `g:syntastic_rust_checkers` to a
different value.
*g:rust_cargo_avoid_whole_workspace*
*b:rust_cargo_avoid_whole_workspace*
g:rust_cargo_avoid_whole_workspace~
When editing a crate that is part of a Cargo workspace, and this
option is set to 1 (the default), then 'cargo' will be executed
directly in that crate directory instead of in the workspace
directory. Setting 0 prevents this behavior - however be aware that if
you are working in large workspace, Cargo commands may take more time,
plus the Syntastic error list may include all the crates in the
workspace. >
let g:rust_cargo_avoid_whole_workspace = 0
<
*g:rust_cargo_check_all_targets*
*b:rust_cargo_check_all_targets*
g:rust_cargo_check_all_targets~
When set to 1, the `--all-targets` option will be passed to cargo when
Syntastic executes it, allowing the linting of all targets under the
package.
The default is 0.
*g:rust_cargo_check_all_features*
*b:rust_cargo_check_all_features*
g:rust_cargo_check_all_features~
When set to 1, the `--all-features` option will be passed to cargo when
Syntastic executes it, allowing the linting of all features of the
package.
The default is 0.
*g:rust_cargo_check_examples*
*b:rust_cargo_check_examples*
g:rust_cargo_check_examples~
When set to 1, the `--examples` option will be passed to cargo when
Syntastic executes it, to prevent the exclusion of examples from
linting. The examples are normally under the `examples/` directory of
the crate.
The default is 0.
*g:rust_cargo_check_tests*
*b:rust_cargo_check_tests*
g:rust_cargo_check_tests~
When set to 1, the `--tests` option will be passed to cargo when
Syntastic executes it, to prevent the exclusion of tests from linting.
The tests are normally under the `tests/` directory of the crate.
The default is 0.
*g:rust_cargo_check_benches*
*b:rust_cargo_check_benches*
g:rust_cargo_check_benches~
When set to 1, the `--benches` option will be passed to cargo when
Syntastic executes it. The benches are normally under the `benches/`
directory of the crate.
The default is 0.
Integration with auto-pairs *rust-auto-pairs*
---------------------------
This plugin automatically configures the auto-pairs plugin not to duplicate
single quotes, which are used more often for lifetime annotations than for
single character literals.
*g:rust_keep_autopairs_default*
g:rust_keep_autopairs_default~
Don't override auto-pairs default for the Rust filetype. The default
is 0.
============================================================================== ==============================================================================
COMMANDS *rust-commands* COMMANDS *rust-commands*
Invoking Cargo
--------------
This plug defines very simple shortcuts for invoking Cargo from with Vim.
:Cargo <args> *:Cargo*
Runs 'cargo' with the provided arguments.
:Cbuild <args> *:Cbuild*
Shortcut for 'cargo build`.
:Cclean <args> *:Cclean*
Shortcut for 'cargo clean`.
:Cdoc <args> *:Cdoc*
Shortcut for 'cargo doc`.
:Cinit <args> *:Cinit*
Shortcut for 'cargo init`.
:Crun <args> *:Crun*
Shortcut for 'cargo run`.
:Ctest <args> *:Ctest*
Shortcut for 'cargo test`.
:Cupdate <args> *:Cupdate*
Shortcut for 'cargo update`.
:Cbench <args> *:Cbench*
Shortcut for 'cargo bench`.
:Csearch <args> *:Csearch*
Shortcut for 'cargo search`.
:Cpublish <args> *:Cpublish*
Shortcut for 'cargo publish`.
:Cinstall <args> *:Cinstall*
Shortcut for 'cargo install`.
:Cruntarget <args> *:Cruntarget*
Shortcut for 'cargo run --bin' or 'cargo run --example',
depending on the currently open buffer.
Formatting
----------
: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|.
:RustFmtRange *:RustFmtRange*
Runs |g:rustfmt_command| with selected range. See
|:RustFmt| for any other information.
Playpen integration
-------------------
:RustPlay *:RustPlay*
This command will only work if you have web-api.vim installed
(available at https://github.com/mattn/webapi-vim). It sends the
current selection, or if nothing is selected, the entirety of the
current buffer to the Rust playpen, and emits a message with the
shortened URL to the playpen.
|g:rust_playpen_url| is the base URL to the playpen, by default
"https://play.rust-lang.org/".
|g:rust_shortener_url| is the base url for the shorterner, by
default "https://is.gd/"
|g:rust_clip_command| is the command to run to copy the
playpen url to the clipboard of your system.
Evaulation of a single Rust file
--------------------------------
NOTE: These commands are useful only when working with standalone Rust files,
which is usually not the case for common Rust development. If you wish to
building Rust crates from with Vim can should use Vim's make, Syntastic, or
functionality from other plugins.
:RustRun [args] *:RustRun* :RustRun [args] *:RustRun*
:RustRun! [rustc-args] [--] [args] :RustRun! [rustc-args] [--] [args]
Compiles and runs the current file. If it has unsaved changes, Compiles and runs the current file. If it has unsaved changes,
@ -189,49 +417,47 @@ COMMANDS *rust-commands*
If |g:rustc_path| is defined, it is used as the path to rustc. If |g:rustc_path| is defined, it is used as the path to rustc.
Otherwise it is assumed rustc can be found in $PATH. Otherwise it is assumed rustc can be found in $PATH.
:RustPlay *:RustPlay*
This command will only work if you have web-api.vim installed
(available at https://github.com/mattn/webapi-vim). It sends the
current selection, or if nothing is selected, the entirety of the
current buffer to the Rust playpen, and emits a message with the
shortened URL to the playpen.
|g:rust_playpen_url| is the base URL to the playpen, by default Running test(s)
"https://play.rust-lang.org/". ---------------
|g:rust_shortener_url| is the base url for the shorterner, by :RustTest[!] [options] *:RustTest*
default "https://is.gd/" Runs a test under the cursor when the current buffer is in a
cargo project with "cargo test" command. If the command did
not find any test function under the cursor, it stops with an
error message.
:RustFmt *:RustFmt* When ! is given, runs all tests regardless of current cursor
Runs |g:rustfmt_command| on the current buffer. If position.
|g:rustfmt_options| is set then those will be passed to the
executable.
If |g:rustfmt_fail_silently| is 0 (the default) then it When [options] is given, it is passed to "cargo" command
will populate the |location-list| with the errors from arguments.
|g:rustfmt_command|. If |g:rustfmt_fail_silently| is set to 1
then it will not populate the |location-list|.
:RustFmtRange *:RustFmtRange* When the current buffer is outside cargo project, the command
Runs |g:rustfmt_command| with selected range. See runs "rustc --test" command instead of "cargo test" as
|:RustFmt| for any other information. fallback. All tests are run regardless of adding ! since there
is no way to run specific test function with rustc. [options]
is passed to "rustc" command arguments in the case.
rust.vim Debugging
------------------
:RustInfo *:RustInfo*
Emits debugging info of the Vim Rust plugin.
:RustInfoToClipboard *:RustInfoClipboard*
Saves debugging info of the Vim Rust plugin to the default
register.
:RustInfoToFile [filename] *:RustInfoToFile*
Saves debugging info of the Vim Rust plugin to the the given
file, overwritting it.
============================================================================== ==============================================================================
MAPPINGS *rust-mappings* MAPPINGS *rust-mappings*
This plugin defines mappings for |[[| and |]]| to support hanging indents. This plugin defines mappings for |[[| and |]]| to support hanging indents.
It also has a few other mappings:
*rust_<D-r>*
<D-r> Executes |:RustRun| with no arguments.
Note: This binding is only available in MacVim.
*rust_<D-R>*
<D-R> Populates the command line with |:RustRun|! using the
arguments given to the last invocation, but does not
execute it.
Note: This binding is only available in MacVim.
============================================================================== ==============================================================================
vim:tw=78:sw=4:noet:ts=8:ft=help:norl: vim:tw=78:sw=4:noet:ts=8:ft=help:norl:

View file

@ -1 +1,12 @@
au BufRead,BufNewFile *.rs set filetype=rust " vint: -ProhibitAutocmdWithNoGroup
autocmd BufRead,BufNewFile *.rs call s:set_rust_filetype()
autocmd BufRead,BufNewFile Cargo.toml setf FALLBACK cfg
function! s:set_rust_filetype() abort
if &filetype !=# 'rust'
set filetype=rust
endif
endfunction
" vim: set et sw=4 sts=4 ts=8:

View file

@ -1,19 +1,27 @@
" Language: Rust " Language: Rust
" Description: Vim syntax file for Rust " Description: Vim ftplugin for Rust
" Maintainer: Chris Morgan <me@chrismorgan.info> " Maintainer: Chris Morgan <me@chrismorgan.info>
" Maintainer: Kevin Ballard <kevin@sb.org> " Maintainer: Kevin Ballard <kevin@sb.org>
" Last Change: June 08, 2016 " Last Change: June 08, 2016
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim
if exists("b:did_ftplugin") if exists("b:did_ftplugin")
finish finish
endif endif
let b:did_ftplugin = 1 let b:did_ftplugin = 1
" vint: -ProhibitAbbreviationOption
let s:save_cpo = &cpo let s:save_cpo = &cpo
set cpo&vim set cpo&vim
" vint: +ProhibitAbbreviationOption
augroup rust.vim if get(b:, 'current_compiler', '') ==# ''
autocmd! if strlen(findfile('Cargo.toml', '.;')) > 0
compiler cargo
else
compiler rustc
endif
endif
" Variables {{{1 " Variables {{{1
@ -21,13 +29,13 @@ autocmd!
" comments, so we'll use that as our default, but make it easy to switch. " 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 " This does not affect indentation at all (I tested it with and without
" leader), merely whether a leader is inserted by default or not. " leader), merely whether a leader is inserted by default or not.
if exists("g:rust_bang_comment_leader") && g:rust_bang_comment_leader != 0 if get(g:, 'rust_bang_comment_leader', 0)
" Why is the `,s0:/*,mb:\ ,ex:*/` there, you ask? I don't understand why, " Why is the `,s0:/*,mb:\ ,ex:*/` there, you ask? I don't understand why,
" but without it, */ gets indented one space even if there were no " but without it, */ gets indented one space even if there were no
" leaders. I'm fairly sure that's a Vim bug. " leaders. I'm fairly sure that's a Vim bug.
setlocal comments=s1:/*,mb:*,ex:*/,s0:/*,mb:\ ,ex:*/,:///,://!,:// setlocal comments=s1:/*,mb:*,ex:*/,s0:/*,mb:\ ,ex:*/,:///,://!,://
else else
setlocal comments=s0:/*!,m:\ ,ex:*/,s1:/*,mb:*,ex:*/,:///,://!,:// setlocal comments=s0:/*!,m:\ ,ex:*/,s1:/*,mb:*,ex:*/,:///,://!,://
endif endif
setlocal commentstring=//%s setlocal commentstring=//%s
setlocal formatoptions-=t formatoptions+=croqnl setlocal formatoptions-=t formatoptions+=croqnl
@ -38,13 +46,14 @@ silent! setlocal formatoptions+=j
" otherwise it's better than nothing. " otherwise it's better than nothing.
setlocal smartindent nocindent setlocal smartindent nocindent
if !exists("g:rust_recommended_style") || g:rust_recommended_style != 0 if get(g:, 'rust_recommended_style', 1)
setlocal tabstop=4 shiftwidth=4 softtabstop=4 expandtab let b:rust_set_style = 1
setlocal textwidth=99 setlocal tabstop=8 shiftwidth=4 softtabstop=4 expandtab
setlocal textwidth=99
endif endif
" This includeexpr isn't perfect, but it's a good start setlocal include=\\v^\\s*(pub\\s+)?use\\s+\\zs(\\f\|:)+
setlocal includeexpr=substitute(v:fname,'::','/','g') setlocal includeexpr=rust#IncludeExpr(v:fname)
setlocal suffixesadd=.rs setlocal suffixesadd=.rs
@ -53,51 +62,36 @@ if exists("g:ftplugin_rust_source_path")
endif endif
if exists("g:loaded_delimitMate") if exists("g:loaded_delimitMate")
if exists("b:delimitMate_excluded_regions") if exists("b:delimitMate_excluded_regions")
let b:rust_original_delimitMate_excluded_regions = b:delimitMate_excluded_regions let b:rust_original_delimitMate_excluded_regions = b:delimitMate_excluded_regions
endif endif
let s:delimitMate_extra_excluded_regions = ',rustLifetimeCandidate,rustGenericLifetimeCandidate' augroup rust.vim.DelimitMate
autocmd!
" For this buffer, when delimitMate issues the `User delimitMate_map` autocmd User delimitMate_map :call rust#delimitmate#onMap()
" event in the autocommand system, add the above-defined extra excluded autocmd User delimitMate_unmap :call rust#delimitmate#onUnmap()
" regions to delimitMate's state, if they have not already been added. augroup END
autocmd User <buffer>
\ if expand('<afile>') ==# 'delimitMate_map' && match(
\ delimitMate#Get("excluded_regions"),
\ s:delimitMate_extra_excluded_regions) == -1
\| let b:delimitMate_excluded_regions =
\ delimitMate#Get("excluded_regions")
\ . s:delimitMate_extra_excluded_regions
\|endif
" For this buffer, when delimitMate issues the `User delimitMate_unmap`
" event in the autocommand system, delete the above-defined extra excluded
" regions from delimitMate's state (the deletion being idempotent and
" having no effect if the extra excluded regions are not present in the
" targeted part of delimitMate's state).
autocmd User <buffer>
\ if expand('<afile>') ==# 'delimitMate_unmap'
\| let b:delimitMate_excluded_regions = substitute(
\ delimitMate#Get("excluded_regions"),
\ '\C\V' . s:delimitMate_extra_excluded_regions,
\ '', 'g')
\|endif
endif endif
if has("folding") && exists('g:rust_fold') && g:rust_fold != 0 " Integration with auto-pairs (https://github.com/jiangmiao/auto-pairs)
let b:rust_set_foldmethod=1 if exists("g:AutoPairsLoaded") && !get(g:, 'rust_keep_autopairs_default', 0)
setlocal foldmethod=syntax let b:AutoPairs = {'(':')', '[':']', '{':'}','"':'"', '`':'`'}
if g:rust_fold == 2
setlocal foldlevel<
else
setlocal foldlevel=99
endif
endif endif
if has('conceal') && exists('g:rust_conceal') && g:rust_conceal != 0 if has("folding") && get(g:, 'rust_fold', 0)
let b:rust_set_conceallevel=1 let b:rust_set_foldmethod=1
setlocal conceallevel=2 setlocal foldmethod=syntax
if g:rust_fold == 2
setlocal foldlevel<
else
setlocal foldlevel=99
endif
endif
if has('conceal') && get(g:, 'rust_conceal', 0)
let b:rust_set_conceallevel=1
setlocal conceallevel=2
endif endif
" Motion Commands {{{1 " Motion Commands {{{1
@ -133,75 +127,75 @@ command! -buffer RustFmt call rustfmt#Format()
" See |:RustFmtRange| for docs " See |:RustFmtRange| for docs
command! -range -buffer RustFmtRange call rustfmt#FormatRange(<line1>, <line2>) command! -range -buffer RustFmtRange call rustfmt#FormatRange(<line1>, <line2>)
" Mappings {{{1 " See |:RustInfo| for docs
command! -bar RustInfo call rust#debugging#Info()
" Bind ⌘R in MacVim to :RustRun " See |:RustInfoToClipboard| for docs
nnoremap <silent> <buffer> <D-r> :RustRun<CR> command! -bar RustInfoToClipboard call rust#debugging#InfoToClipboard()
" Bind ⌘⇧R in MacVim to :RustRun! pre-filled with the last args
nnoremap <buffer> <D-R> :RustRun! <C-r>=join(b:rust_last_rustc_args)<CR><C-\>erust#AppendCmdLine(' -- ' . join(b:rust_last_args))<CR> " See |:RustInfoToFile| for docs
command! -bar -nargs=1 RustInfoToFile call rust#debugging#InfoToFile(<f-args>)
" See |:RustTest| for docs
command! -buffer -nargs=* -bang RustTest call rust#Test(<bang>0, <q-args>)
if !exists("b:rust_last_rustc_args") || !exists("b:rust_last_args") if !exists("b:rust_last_rustc_args") || !exists("b:rust_last_args")
let b:rust_last_rustc_args = [] let b:rust_last_rustc_args = []
let b:rust_last_args = [] let b:rust_last_args = []
endif endif
" Cleanup {{{1 " Cleanup {{{1
let b:undo_ftplugin = " let b:undo_ftplugin = "
\ setlocal formatoptions< comments< commentstring< includeexpr< suffixesadd< \ setlocal formatoptions< comments< commentstring< include< includeexpr< suffixesadd<
\|setlocal tabstop< shiftwidth< softtabstop< expandtab< textwidth< \|if exists('b:rust_set_style')
\|if exists('b:rust_original_delimitMate_excluded_regions') \|setlocal tabstop< shiftwidth< softtabstop< expandtab< textwidth<
\|let b:delimitMate_excluded_regions = b:rust_original_delimitMate_excluded_regions \|endif
\|unlet b:rust_original_delimitMate_excluded_regions \|if exists('b:rust_original_delimitMate_excluded_regions')
\|else \|let b:delimitMate_excluded_regions = b:rust_original_delimitMate_excluded_regions
\|unlet! b:delimitMate_excluded_regions \|unlet b:rust_original_delimitMate_excluded_regions
\|endif \|else
\|if exists('b:rust_set_foldmethod') \|unlet! b:delimitMate_excluded_regions
\|setlocal foldmethod< foldlevel< \|endif
\|unlet b:rust_set_foldmethod \|if exists('b:rust_set_foldmethod')
\|endif \|setlocal foldmethod< foldlevel<
\|if exists('b:rust_set_conceallevel') \|unlet b:rust_set_foldmethod
\|setlocal conceallevel< \|endif
\|unlet b:rust_set_conceallevel \|if exists('b:rust_set_conceallevel')
\|endif \|setlocal conceallevel<
\|unlet! b:rust_last_rustc_args b:rust_last_args \|unlet b:rust_set_conceallevel
\|delcommand RustRun \|endif
\|delcommand RustExpand \|unlet! b:rust_last_rustc_args b:rust_last_args
\|delcommand RustEmitIr \|delcommand RustRun
\|delcommand RustEmitAsm \|delcommand RustExpand
\|delcommand RustPlay \|delcommand RustEmitIr
\|nunmap <buffer> <D-r> \|delcommand RustEmitAsm
\|nunmap <buffer> <D-R> \|delcommand RustPlay
\|nunmap <buffer> [[ \|nunmap <buffer> [[
\|nunmap <buffer> ]] \|nunmap <buffer> ]]
\|xunmap <buffer> [[ \|xunmap <buffer> [[
\|xunmap <buffer> ]] \|xunmap <buffer> ]]
\|ounmap <buffer> [[ \|ounmap <buffer> [[
\|ounmap <buffer> ]] \|ounmap <buffer> ]]
\|set matchpairs-=<:> \|setlocal matchpairs-=<:>
\|unlet b:match_skip \|unlet b:match_skip
\" \"
" }}}1 " }}}1
" Code formatting on save " Code formatting on save
if get(g:, "rustfmt_autosave", 0) augroup rust.vim.PreWrite
autocmd BufWritePre *.rs silent! call rustfmt#Format() autocmd!
endif autocmd BufWritePre *.rs silent! call rustfmt#PreWrite()
augroup END augroup END
" %-matching. <:> is handy for generics. setlocal matchpairs+=<:>
set matchpairs+=<:> " For matchit.vim (rustArrow stops `Fn() -> X` messing things up)
" There are two minor issues with it; (a) comparison operators in expressions,
" where a less-than may match a greater-than later on—this is deemed a trivial
" issue—and (b) `Fn() -> X` syntax. This latter issue is irremediable from the
" highlighting perspective (built into Vim), but the actual % functionality
" can be fixed by this use of matchit.vim.
let b:match_skip = 's:comment\|string\|rustArrow' let b:match_skip = 's:comment\|string\|rustArrow'
source $VIMRUNTIME/macros/matchit.vim
" vint: -ProhibitAbbreviationOption
let &cpo = s:save_cpo let &cpo = s:save_cpo
unlet s:save_cpo unlet s:save_cpo
" vint: +ProhibitAbbreviationOption
" vim: set noet sw=4 ts=4: " vim: set et sw=4 sts=4 ts=8:

View file

@ -0,0 +1,40 @@
"
" Support for Tagbar -- https://github.com/majutsushi/tagbar
"
if !exists(':Tagbar')
finish
endif
" vint: -ProhibitAbbreviationOption
let s:save_cpo = &cpo
set cpo&vim
" vint: +ProhibitAbbreviationOption
if !exists('g:tagbar_type_rust')
let g:tagbar_type_rust = {
\ 'ctagstype' : 'rust',
\ 'kinds' : [
\'T:types',
\'f:functions',
\'g:enumerations',
\'s:structures',
\'m:modules',
\'c:constants',
\'t:traits',
\'i:trait implementations',
\ ]
\ }
endif
" In case you've updated/customized your ~/.ctags and prefer to use it.
if !get(g:, 'rust_use_custom_ctags_defs', 0)
let g:tagbar_type_rust.deffile = expand('<sfile>:p:h:h:h') . '/ctags/rust.ctags'
endif
" vint: -ProhibitAbbreviationOption
let &cpo = s:save_cpo
unlet s:save_cpo
" vint: +ProhibitAbbreviationOption
" vim: set et sw=4 sts=4 ts=8:

View file

@ -1,19 +1,20 @@
" Vim indent file " Vim indent file
" Language: Rust " Language: Rust
" Author: Chris Morgan <me@chrismorgan.info> " Author: Chris Morgan <me@chrismorgan.info>
" Last Change: 2016 Jul 15 " Last Change: 2018 Jan 10
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim
" Only load this indent file when no other was loaded. " Only load this indent file when no other was loaded.
if exists("b:did_indent") if exists("b:did_indent")
finish finish
endif endif
let b:did_indent = 1 let b:did_indent = 1
setlocal cindent setlocal cindent
setlocal cinoptions=L0,(0,Ws,J1,j1 setlocal cinoptions=L0,(0,Ws,J1,j1,m1
setlocal cinkeys=0{,0},!^F,o,O,0[,0] setlocal cinkeys=0{,0},!^F,o,O,0[,0]
" Don't think cinwords will actually do anything at all... never mind " Don't think cinwords will actually do anything at all... never mind
setlocal cinwords=for,if,else,while,loop,impl,mod,unsafe,trait,struct,enum,fn,extern setlocal cinwords=for,if,else,while,loop,impl,mod,unsafe,trait,struct,enum,fn,extern,macro
" Some preliminary settings " Some preliminary settings
setlocal nolisp " Make sure lisp indenting doesn't supersede us setlocal nolisp " Make sure lisp indenting doesn't supersede us
@ -25,182 +26,194 @@ setlocal indentexpr=GetRustIndent(v:lnum)
" Only define the function once. " Only define the function once.
if exists("*GetRustIndent") if exists("*GetRustIndent")
finish finish
endif endif
" vint: -ProhibitAbbreviationOption
let s:save_cpo = &cpo
set cpo&vim
" vint: +ProhibitAbbreviationOption
" Come here when loading the script the first time. " Come here when loading the script the first time.
function! s:get_line_trimmed(lnum) function! s:get_line_trimmed(lnum)
" Get the line and remove a trailing comment. " Get the line and remove a trailing comment.
" Use syntax highlighting attributes when possible. " Use syntax highlighting attributes when possible.
" NOTE: this is not accurate; /* */ or a line continuation could trick it " NOTE: this is not accurate; /* */ or a line continuation could trick it
let line = getline(a:lnum) let line = getline(a:lnum)
let line_len = strlen(line) let line_len = strlen(line)
if has('syntax_items') if has('syntax_items')
" If the last character in the line is a comment, do a binary search for " If the last character in the line is a comment, do a binary search for
" the start of the comment. synID() is slow, a linear search would take " the start of the comment. synID() is slow, a linear search would take
" too long on a long line. " too long on a long line.
if synIDattr(synID(a:lnum, line_len, 1), "name") =~ 'Comment\|Todo' if synIDattr(synID(a:lnum, line_len, 1), "name") =~? 'Comment\|Todo'
let min = 1 let min = 1
let max = line_len let max = line_len
while min < max while min < max
let col = (min + max) / 2 let col = (min + max) / 2
if synIDattr(synID(a:lnum, col, 1), "name") =~ 'Comment\|Todo' if synIDattr(synID(a:lnum, col, 1), "name") =~? 'Comment\|Todo'
let max = col let max = col
else else
let min = col + 1 let min = col + 1
endif endif
endwhile endwhile
let line = strpart(line, 0, min - 1) let line = strpart(line, 0, min - 1)
endif endif
return substitute(line, "\s*$", "", "") return substitute(line, "\s*$", "", "")
else else
" Sorry, this is not complete, nor fully correct (e.g. string "//"). " Sorry, this is not complete, nor fully correct (e.g. string "//").
" Such is life. " Such is life.
return substitute(line, "\s*//.*$", "", "") return substitute(line, "\s*//.*$", "", "")
endif endif
endfunction endfunction
function! s:is_string_comment(lnum, col) function! s:is_string_comment(lnum, col)
if has('syntax_items') if has('syntax_items')
for id in synstack(a:lnum, a:col) for id in synstack(a:lnum, a:col)
let synname = synIDattr(id, "name") let synname = synIDattr(id, "name")
if synname == "rustString" || synname =~ "^rustComment" if synname ==# "rustString" || synname =~# "^rustComment"
return 1 return 1
endif endif
endfor endfor
else else
" without syntax, let's not even try " without syntax, let's not even try
return 0 return 0
endif endif
endfunction endfunction
function GetRustIndent(lnum) function GetRustIndent(lnum)
" Starting assumption: cindent (called at the end) will do it right " Starting assumption: cindent (called at the end) will do it right
" normally. We just want to fix up a few cases. " normally. We just want to fix up a few cases.
let line = getline(a:lnum) let line = getline(a:lnum)
if has('syntax_items') if has('syntax_items')
let synname = synIDattr(synID(a:lnum, 1, 1), "name") let synname = synIDattr(synID(a:lnum, 1, 1), "name")
if synname == "rustString" if synname ==# "rustString"
" If the start of the line is in a string, don't change the indent " If the start of the line is in a string, don't change the indent
return -1 return -1
elseif synname =~ '\(Comment\|Todo\)' elseif synname =~? '\(Comment\|Todo\)'
\ && line !~ '^\s*/\*' " not /* opening line \ && line !~# '^\s*/\*' " not /* opening line
if synname =~ "CommentML" " multi-line if synname =~? "CommentML" " multi-line
if line !~ '^\s*\*' && getline(a:lnum - 1) =~ '^\s*/\*' if line !~# '^\s*\*' && getline(a:lnum - 1) =~# '^\s*/\*'
" This is (hopefully) the line after a /*, and it has no " This is (hopefully) the line after a /*, and it has no
" leader, so the correct indentation is that of the " leader, so the correct indentation is that of the
" previous line. " previous line.
return GetRustIndent(a:lnum - 1) return GetRustIndent(a:lnum - 1)
endif endif
endif endif
" If it's in a comment, let cindent take care of it now. This is " If it's in a comment, let cindent take care of it now. This is
" for cases like "/*" where the next line should start " * ", not " for cases like "/*" where the next line should start " * ", not
" "* " as the code below would otherwise cause for module scope " "* " as the code below would otherwise cause for module scope
" Fun fact: " /*\n*\n*/" takes two calls to get right! " Fun fact: " /*\n*\n*/" takes two calls to get right!
return cindent(a:lnum) return cindent(a:lnum)
endif endif
endif endif
" cindent gets second and subsequent match patterns/struct members wrong, " cindent gets second and subsequent match patterns/struct members wrong,
" as it treats the comma as indicating an unfinished statement:: " as it treats the comma as indicating an unfinished statement::
" "
" match a { " match a {
" b => c, " b => c,
" d => e, " d => e,
" f => g, " f => g,
" }; " };
" Search backwards for the previous non-empty line. " Search backwards for the previous non-empty line.
let prevlinenum = prevnonblank(a:lnum - 1) let prevlinenum = prevnonblank(a:lnum - 1)
let prevline = s:get_line_trimmed(prevlinenum) let prevline = s:get_line_trimmed(prevlinenum)
while prevlinenum > 1 && prevline !~ '[^[:blank:]]' while prevlinenum > 1 && prevline !~# '[^[:blank:]]'
let prevlinenum = prevnonblank(prevlinenum - 1) let prevlinenum = prevnonblank(prevlinenum - 1)
let prevline = s:get_line_trimmed(prevlinenum) let prevline = s:get_line_trimmed(prevlinenum)
endwhile endwhile
" Handle where clauses nicely: subsequent values should line up nicely. " Handle where clauses nicely: subsequent values should line up nicely.
if prevline[len(prevline) - 1] == "," if prevline[len(prevline) - 1] ==# ","
\ && prevline =~# '^\s*where\s' \ && prevline =~# '^\s*where\s'
return indent(prevlinenum) + 6 return indent(prevlinenum) + 6
endif endif
if prevline[len(prevline) - 1] == "," if prevline[len(prevline) - 1] ==# ","
\ && s:get_line_trimmed(a:lnum) !~ '^\s*[\[\]{}]' \ && s:get_line_trimmed(a:lnum) !~# '^\s*[\[\]{}]'
\ && prevline !~ '^\s*fn\s' \ && prevline !~# '^\s*fn\s'
\ && prevline !~ '([^()]\+,$' \ && prevline !~# '([^()]\+,$'
\ && s:get_line_trimmed(a:lnum) !~ '^\s*\S\+\s*=>' \ && s:get_line_trimmed(a:lnum) !~# '^\s*\S\+\s*=>'
" Oh ho! The previous line ended in a comma! I bet cindent will try to " Oh ho! The previous line ended in a comma! I bet cindent will try to
" take this too far... For now, let's normally use the previous line's " take this too far... For now, let's normally use the previous line's
" indent. " indent.
" One case where this doesn't work out is where *this* line contains " One case where this doesn't work out is where *this* line contains
" square or curly brackets; then we normally *do* want to be indenting " square or curly brackets; then we normally *do* want to be indenting
" further. " further.
" "
" Another case where we don't want to is one like a function " Another case where we don't want to is one like a function
" definition with arguments spread over multiple lines: " definition with arguments spread over multiple lines:
" "
" fn foo(baz: Baz, " fn foo(baz: Baz,
" baz: Baz) // <-- cindent gets this right by itself " baz: Baz) // <-- cindent gets this right by itself
" "
" Another case is similar to the previous, except calling a function " Another case is similar to the previous, except calling a function
" instead of defining it, or any conditional expression that leaves " instead of defining it, or any conditional expression that leaves
" an open paren: " an open paren:
" "
" foo(baz, " foo(baz,
" baz); " baz);
" "
" if baz && (foo || " if baz && (foo ||
" bar) { " bar) {
" "
" Another case is when the current line is a new match arm. " Another case is when the current line is a new match arm.
" "
" There are probably other cases where we don't want to do this as " There are probably other cases where we don't want to do this as
" well. Add them as needed. " well. Add them as needed.
return indent(prevlinenum) return indent(prevlinenum)
endif endif
if !has("patch-7.4.355") if !has("patch-7.4.355")
" cindent before 7.4.355 doesn't do the module scope well at all; e.g.:: " cindent before 7.4.355 doesn't do the module scope well at all; e.g.::
" "
" static FOO : &'static [bool] = [ " static FOO : &'static [bool] = [
" true, " true,
" false, " false,
" false, " false,
" true, " true,
" ]; " ];
" "
" uh oh, next statement is indented further! " uh oh, next statement is indented further!
" Note that this does *not* apply the line continuation pattern properly; " Note that this does *not* apply the line continuation pattern properly;
" that's too hard to do correctly for my liking at present, so I'll just " that's too hard to do correctly for my liking at present, so I'll just
" start with these two main cases (square brackets and not returning to " start with these two main cases (square brackets and not returning to
" column zero) " column zero)
call cursor(a:lnum, 1) call cursor(a:lnum, 1)
if searchpair('{\|(', '', '}\|)', 'nbW', if searchpair('{\|(', '', '}\|)', 'nbW',
\ 's:is_string_comment(line("."), col("."))') == 0 \ 's:is_string_comment(line("."), col("."))') == 0
if searchpair('\[', '', '\]', 'nbW', if searchpair('\[', '', '\]', 'nbW',
\ 's:is_string_comment(line("."), col("."))') == 0 \ 's:is_string_comment(line("."), col("."))') == 0
" Global scope, should be zero " Global scope, should be zero
return 0 return 0
else else
" At the module scope, inside square brackets only " At the module scope, inside square brackets only
"if getline(a:lnum)[0] == ']' || search('\[', '', '\]', 'nW') == a:lnum "if getline(a:lnum)[0] == ']' || search('\[', '', '\]', 'nW') == a:lnum
if line =~ "^\\s*]" if line =~# "^\\s*]"
" It's the closing line, dedent it " It's the closing line, dedent it
return 0 return 0
else else
return &shiftwidth return &shiftwidth
endif endif
endif endif
endif endif
endif endif
" Fall back on cindent, which does it mostly right " Fall back on cindent, which does it mostly right
return cindent(a:lnum) return cindent(a:lnum)
endfunction endfunction
" vint: -ProhibitAbbreviationOption
let &cpo = s:save_cpo
unlet s:save_cpo
" vint: +ProhibitAbbreviationOption
" vim: set et sw=4 sts=4 ts=8:

View file

@ -0,0 +1,26 @@
if exists('g:loaded_rust_vim_plugin_cargo')
finish
endif
let g:loaded_rust_vim_plugin_cargo = 1
let s:save_cpo = &cpoptions
set cpoptions&vim
command! -nargs=+ Cargo call cargo#cmd(<q-args>)
command! -nargs=* Cbuild call cargo#build(<q-args>)
command! -nargs=* Cclean call cargo#clean(<q-args>)
command! -nargs=* Cdoc call cargo#doc(<q-args>)
command! -nargs=+ Cnew call cargo#new(<q-args>)
command! -nargs=* Cinit call cargo#init(<q-args>)
command! -nargs=* Crun call cargo#run(<q-args>)
command! -nargs=* Ctest call cargo#test(<q-args>)
command! -nargs=* Cbench call cargo#bench(<q-args>)
command! -nargs=* Cupdate call cargo#update(<q-args>)
command! -nargs=* Csearch call cargo#search(<q-args>)
command! -nargs=* Cpublish call cargo#publish(<q-args>)
command! -nargs=* Cinstall call cargo#install(<q-args>)
command! -nargs=* Cruntarget call cargo#runtarget(<q-args>)
let &cpoptions = s:save_cpo
unlet s:save_cpo
" vim: set et sw=4 sts=4 ts=8:

View file

@ -2,12 +2,12 @@
" Language: Rust " Language: Rust
" Maintainer: Andrew Gallant <jamslam@gmail.com> " Maintainer: Andrew Gallant <jamslam@gmail.com>
if exists("g:loaded_syntastic_rust_filetype") if exists('g:loaded_rust_vim')
finish finish
endif endif
let g:loaded_syntastic_rust_filetype = 1 let g:loaded_rust_vim = 1
let s:save_cpo = &cpo let s:save_cpo = &cpoptions
set cpo&vim set cpoptions&vim
" This is to let Syntastic know about the Rust filetype. " This is to let Syntastic know about the Rust filetype.
" It enables tab completion for the 'SyntasticInfo' command. " It enables tab completion for the 'SyntasticInfo' command.
@ -18,5 +18,11 @@ else
let g:syntastic_extra_filetypes = ['rust'] let g:syntastic_extra_filetypes = ['rust']
endif endif
let &cpo = s:save_cpo if !exists('g:syntastic_rust_checkers')
let g:syntastic_rust_checkers = ['cargo']
endif
let &cpoptions = s:save_cpo
unlet s:save_cpo unlet s:save_cpo
" vim: set et sw=4 sts=4 ts=8:

View file

@ -4,11 +4,12 @@
" Maintainer: Ben Blum <bblum@cs.cmu.edu> " Maintainer: Ben Blum <bblum@cs.cmu.edu>
" Maintainer: Chris Morgan <me@chrismorgan.info> " Maintainer: Chris Morgan <me@chrismorgan.info>
" Last Change: Feb 24, 2016 " Last Change: Feb 24, 2016
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim
if version < 600 if version < 600
syntax clear syntax clear
elseif exists("b:current_syntax") elseif exists("b:current_syntax")
finish finish
endif endif
" Syntax definitions {{{1 " Syntax definitions {{{1
@ -20,27 +21,32 @@ syn keyword rustStructure struct enum nextgroup=rustIdentifier skipwhite skipe
syn keyword rustUnion union nextgroup=rustIdentifier skipwhite skipempty contained syn keyword rustUnion union nextgroup=rustIdentifier skipwhite skipempty contained
syn match rustUnionContextual /\<union\_s\+\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*/ transparent contains=rustUnion syn match rustUnionContextual /\<union\_s\+\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*/ transparent contains=rustUnion
syn keyword rustOperator as syn keyword rustOperator as
syn keyword rustExistential existential nextgroup=rustTypedef skipwhite skipempty contained
syn match rustExistentialContextual /\<existential\_s\+type/ transparent contains=rustExistential,rustTypedef
syn match rustAssert "\<assert\(\w\)*!" contained syn match rustAssert "\<assert\(\w\)*!" contained
syn match rustPanic "\<panic\(\w\)*!" contained syn match rustPanic "\<panic\(\w\)*!" contained
syn match rustKeyword "\<async\%(\s\|\n\)\@="
syn keyword rustKeyword break syn keyword rustKeyword break
syn keyword rustKeyword box nextgroup=rustBoxPlacement skipwhite skipempty syn keyword rustKeyword box nextgroup=rustBoxPlacement skipwhite skipempty
syn keyword rustKeyword continue syn keyword rustKeyword continue
syn keyword rustKeyword crate
syn keyword rustKeyword extern nextgroup=rustExternCrate,rustObsoleteExternMod skipwhite skipempty syn keyword rustKeyword extern nextgroup=rustExternCrate,rustObsoleteExternMod skipwhite skipempty
syn keyword rustKeyword fn nextgroup=rustFuncName skipwhite skipempty syn keyword rustKeyword fn nextgroup=rustFuncName skipwhite skipempty
syn keyword rustKeyword in impl let syn keyword rustKeyword in impl let
syn keyword rustKeyword macro
syn keyword rustKeyword pub nextgroup=rustPubScope skipwhite skipempty syn keyword rustKeyword pub nextgroup=rustPubScope skipwhite skipempty
syn keyword rustKeyword return syn keyword rustKeyword return
syn keyword rustKeyword yield
syn keyword rustSuper super syn keyword rustSuper super
syn keyword rustKeyword unsafe where syn keyword rustKeyword where
syn keyword rustUnsafeKeyword unsafe
syn keyword rustKeyword use nextgroup=rustModPath skipwhite skipempty syn keyword rustKeyword use nextgroup=rustModPath skipwhite skipempty
" FIXME: Scoped impl's name is also fallen in this category " FIXME: Scoped impl's name is also fallen in this category
syn keyword rustKeyword mod trait nextgroup=rustIdentifier skipwhite skipempty syn keyword rustKeyword mod trait nextgroup=rustIdentifier skipwhite skipempty
syn keyword rustStorage move mut ref static const syn keyword rustStorage move mut ref static const
syn match rustDefault /\<default\ze\_s\+\(impl\|fn\|type\|const\)\>/ syn match rustDefault /\<default\ze\_s\+\(impl\|fn\|type\|const\)\>/
syn keyword rustInvalidBareKeyword crate
syn keyword rustPubScopeCrate crate contained syn keyword rustPubScopeCrate crate contained
syn match rustPubScopeDelim /[()]/ contained syn match rustPubScopeDelim /[()]/ contained
syn match rustPubScope /([^()]*)/ contained contains=rustPubScopeDelim,rustPubScopeCrate,rustSuper,rustModPath,rustModPathSep,rustSelf transparent syn match rustPubScope /([^()]*)/ contained contains=rustPubScopeDelim,rustPubScopeCrate,rustSuper,rustModPath,rustModPathSep,rustSelf transparent
@ -66,7 +72,7 @@ syn match rustMacroRepeatCount ".\?[*+]" contained
syn match rustMacroVariable "$\w\+" syn match rustMacroVariable "$\w\+"
" Reserved (but not yet used) keywords {{{2 " Reserved (but not yet used) keywords {{{2
syn keyword rustReservedKeyword alignof become do offsetof priv pure sizeof typeof unsized yield abstract virtual final override macro syn keyword rustReservedKeyword alignof become do offsetof priv pure sizeof typeof unsized abstract virtual final override
" Built-in types {{{2 " Built-in types {{{2
syn keyword rustType isize usize char bool u8 u16 u32 u64 u128 f32 syn keyword rustType isize usize char bool u8 u16 u32 u64 u128 f32
@ -137,7 +143,7 @@ syn match rustMacro '#\w\(\w\)*' contains=rustAssert,rustPanic
syn match rustEscapeError display contained /\\./ syn match rustEscapeError display contained /\\./
syn match rustEscape display contained /\\\([nrt0\\'"]\|x\x\{2}\)/ syn match rustEscape display contained /\\\([nrt0\\'"]\|x\x\{2}\)/
syn match rustEscapeUnicode display contained /\\u{\x\{1,6}}/ syn match rustEscapeUnicode display contained /\\u{\%(\x_*\)\{1,6}}/
syn match rustStringContinuation display contained /\\\n\s*/ syn match rustStringContinuation display contained /\\\n\s*/
syn region rustString start=+b"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeError,rustStringContinuation syn region rustString start=+b"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeError,rustStringContinuation
syn region rustString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeUnicode,rustEscapeError,rustStringContinuation,@Spell syn region rustString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeUnicode,rustEscapeError,rustStringContinuation,@Spell
@ -149,6 +155,16 @@ syn region rustDerive start="derive(" end=")" contained contains=rustDer
" Some are deprecated (Encodable, Decodable) or to be removed after a new snapshot (Show). " Some are deprecated (Encodable, Decodable) or to be removed after a new snapshot (Show).
syn keyword rustDeriveTrait contained Clone Hash RustcEncodable RustcDecodable Encodable Decodable PartialEq Eq PartialOrd Ord Rand Show Debug Default FromPrimitive Send Sync Copy syn keyword rustDeriveTrait contained Clone Hash RustcEncodable RustcDecodable Encodable Decodable PartialEq Eq PartialOrd Ord Rand Show Debug Default FromPrimitive Send Sync Copy
" dyn keyword: It's only a keyword when used inside a type expression, so
" we make effort here to highlight it only when Rust identifiers follow it
" (not minding the case of pre-2018 Rust where a path starting with :: can
" follow).
"
" This is so that uses of dyn variable names such as in 'let &dyn = &2'
" and 'let dyn = 2' will not get highlighted as a keyword.
syn match rustKeyword "\<dyn\ze\_s\+\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)" contains=rustDynKeyword
syn keyword rustDynKeyword dyn contained
" Number literals " Number literals
syn match rustDecNumber display "\<[0-9][0-9_]*\%([iu]\%(size\|8\|16\|32\|64\|128\)\)\=" syn match rustDecNumber display "\<[0-9][0-9_]*\%([iu]\%(size\|8\|16\|32\|64\|128\)\)\="
syn match rustHexNumber display "\<0x[a-fA-F0-9_]\+\%([iu]\%(size\|8\|16\|32\|64\|128\)\)\=" syn match rustHexNumber display "\<0x[a-fA-F0-9_]\+\%([iu]\%(size\|8\|16\|32\|64\|128\)\)\="
@ -167,8 +183,8 @@ syn match rustFloat display "\<[0-9][0-9_]*\%(\.[0-9][0-9_]*\)\=\%([eE
syn match rustFloat display "\<[0-9][0-9_]*\%(\.[0-9][0-9_]*\)\=\%([eE][+-]\=[0-9_]\+\)\=\(f32\|f64\)" syn match rustFloat display "\<[0-9][0-9_]*\%(\.[0-9][0-9_]*\)\=\%([eE][+-]\=[0-9_]\+\)\=\(f32\|f64\)"
" For the benefit of delimitMate " For the benefit of delimitMate
syn region rustLifetimeCandidate display start=/&'\%(\([^'\\]\|\\\(['nrt0\\\"]\|x\x\{2}\|u{\x\{1,6}}\)\)'\)\@!/ end=/[[:cntrl:][:space:][:punct:]]\@=\|$/ contains=rustSigil,rustLifetime syn region rustLifetimeCandidate display start=/&'\%(\([^'\\]\|\\\(['nrt0\\\"]\|x\x\{2}\|u{\%(\x_*\)\{1,6}}\)\)'\)\@!/ end=/[[:cntrl:][:space:][:punct:]]\@=\|$/ contains=rustSigil,rustLifetime
syn region rustGenericRegion display start=/<\%('\|[^[cntrl:][:space:][:punct:]]\)\@=')\S\@=/ end=/>/ contains=rustGenericLifetimeCandidate syn region rustGenericRegion display start=/<\%('\|[^[:cntrl:][:space:][:punct:]]\)\@=')\S\@=/ end=/>/ contains=rustGenericLifetimeCandidate
syn region rustGenericLifetimeCandidate display start=/\%(<\|,\s*\)\@<='/ end=/[[:cntrl:][:space:][:punct:]]\@=\|$/ contains=rustSigil,rustLifetime syn region rustGenericLifetimeCandidate display start=/\%(<\|,\s*\)\@<='/ end=/[[:cntrl:][:space:][:punct:]]\@=\|$/ contains=rustSigil,rustLifetime
"rustLifetime must appear before rustCharacter, or chars will get the lifetime highlighting "rustLifetime must appear before rustCharacter, or chars will get the lifetime highlighting
@ -178,18 +194,19 @@ syn match rustCharacterInvalid display contained /b\?'\zs[\n\r\t']\ze'/
" The groups negated here add up to 0-255 but nothing else (they do not seem to go beyond ASCII). " The groups negated here add up to 0-255 but nothing else (they do not seem to go beyond ASCII).
syn match rustCharacterInvalidUnicode display contained /b'\zs[^[:cntrl:][:graph:][:alnum:][:space:]]\ze'/ syn match rustCharacterInvalidUnicode display contained /b'\zs[^[:cntrl:][:graph:][:alnum:][:space:]]\ze'/
syn match rustCharacter /b'\([^\\]\|\\\(.\|x\x\{2}\)\)'/ contains=rustEscape,rustEscapeError,rustCharacterInvalid,rustCharacterInvalidUnicode syn match rustCharacter /b'\([^\\]\|\\\(.\|x\x\{2}\)\)'/ contains=rustEscape,rustEscapeError,rustCharacterInvalid,rustCharacterInvalidUnicode
syn match rustCharacter /'\([^\\]\|\\\(.\|x\x\{2}\|u{\x\{1,6}}\)\)'/ contains=rustEscape,rustEscapeUnicode,rustEscapeError,rustCharacterInvalid syn match rustCharacter /'\([^\\]\|\\\(.\|x\x\{2}\|u{\%(\x_*\)\{1,6}}\)\)'/ contains=rustEscape,rustEscapeUnicode,rustEscapeError,rustCharacterInvalid
syn match rustShebang /\%^#![^[].*/ syn match rustShebang /\%^#![^[].*/
syn region rustCommentLine start="//" end="$" contains=rustTodo,@Spell syn region rustCommentLine start="//" end="$" contains=rustTodo,@Spell
syn region rustCommentLineDoc start="//\%(//\@!\|!\)" end="$" contains=rustTodo,@Spell syn region rustCommentLineDoc start="//\%(//\@!\|!\)" end="$" contains=rustTodo,@Spell
syn region rustCommentLineDocError start="//\%(//\@!\|!\)" end="$" contains=rustTodo,@Spell contained syn region rustCommentLineDocError start="//\%(//\@!\|!\)" end="$" contains=rustTodo,@Spell contained
syn region rustCommentBlock matchgroup=rustCommentBlock start="/\*\%(!\|\*[*/]\@!\)\@!" end="\*/" contains=rustTodo,rustCommentBlockNest,@Spell syn region rustCommentBlock matchgroup=rustCommentBlock start="/\*\%(!\|\*[*/]\@!\)\@!" end="\*/" contains=rustTodo,rustCommentBlockNest,@Spell
syn region rustCommentBlockDoc matchgroup=rustCommentBlockDoc start="/\*\%(!\|\*[*/]\@!\)" end="\*/" contains=rustTodo,rustCommentBlockDocNest,@Spell syn region rustCommentBlockDoc matchgroup=rustCommentBlockDoc start="/\*\%(!\|\*[*/]\@!\)" end="\*/" contains=rustTodo,rustCommentBlockDocNest,rustCommentBlockDocRustCode,@Spell
syn region rustCommentBlockDocError matchgroup=rustCommentBlockDocError start="/\*\%(!\|\*[*/]\@!\)" end="\*/" contains=rustTodo,rustCommentBlockDocNestError,@Spell contained syn region rustCommentBlockDocError matchgroup=rustCommentBlockDocError start="/\*\%(!\|\*[*/]\@!\)" end="\*/" contains=rustTodo,rustCommentBlockDocNestError,@Spell contained
syn region rustCommentBlockNest matchgroup=rustCommentBlock start="/\*" end="\*/" contains=rustTodo,rustCommentBlockNest,@Spell contained transparent syn region rustCommentBlockNest matchgroup=rustCommentBlock start="/\*" end="\*/" contains=rustTodo,rustCommentBlockNest,@Spell contained transparent
syn region rustCommentBlockDocNest matchgroup=rustCommentBlockDoc start="/\*" end="\*/" contains=rustTodo,rustCommentBlockDocNest,@Spell contained transparent syn region rustCommentBlockDocNest matchgroup=rustCommentBlockDoc start="/\*" end="\*/" contains=rustTodo,rustCommentBlockDocNest,@Spell contained transparent
syn region rustCommentBlockDocNestError matchgroup=rustCommentBlockDocError start="/\*" end="\*/" contains=rustTodo,rustCommentBlockDocNestError,@Spell contained transparent syn region rustCommentBlockDocNestError matchgroup=rustCommentBlockDocError start="/\*" end="\*/" contains=rustTodo,rustCommentBlockDocNestError,@Spell contained transparent
" FIXME: this is a really ugly and not fully correct implementation. Most " FIXME: this is a really ugly and not fully correct implementation. Most
" importantly, a case like ``/* */*`` should have the final ``*`` not being in " importantly, a case like ``/* */*`` should have the final ``*`` not being in
" a comment, but in practice at present it leaves comments open two levels " a comment, but in practice at present it leaves comments open two levels
@ -209,6 +226,39 @@ syn keyword rustTodo contained TODO FIXME XXX NB NOTE
" FIXME: use the AST to make really good folding " FIXME: use the AST to make really good folding
syn region rustFoldBraces start="{" end="}" transparent fold syn region rustFoldBraces start="{" end="}" transparent fold
if !exists("b:current_syntax_embed")
let b:current_syntax_embed = 1
syntax include @RustCodeInComment <sfile>:p:h/rust.vim
unlet b:current_syntax_embed
" Currently regions marked as ```<some-other-syntax> will not get
" highlighted at all. In the future, we can do as vim-markdown does and
" highlight with the other syntax. But for now, let's make sure we find
" the closing block marker, because the rules below won't catch it.
syn region rustCommentLinesDocNonRustCode matchgroup=rustCommentDocCodeFence start='^\z(\s*//[!/]\s*```\).\+$' end='^\z1$' keepend contains=rustCommentLineDoc
" We borrow the rules from rusts src/librustdoc/html/markdown.rs, so that
" we only highlight as Rust what it would perceive as Rust (almost; its
" possible to trick it if you try hard, and indented code blocks arent
" supported because Markdown is a menace to parse and only mad dogs and
" Englishmen would try to handle that case correctly in this syntax file).
syn region rustCommentLinesDocRustCode matchgroup=rustCommentDocCodeFence start='^\z(\s*//[!/]\s*```\)[^A-Za-z0-9_-]*\%(\%(should_panic\|no_run\|ignore\|allow_fail\|rust\|test_harness\|compile_fail\|E\d\{4}\|edition201[58]\)\%([^A-Za-z0-9_-]\+\|$\)\)*$' end='^\z1$' keepend contains=@RustCodeInComment,rustCommentLineDocLeader
syn region rustCommentBlockDocRustCode matchgroup=rustCommentDocCodeFence start='^\z(\%(\s*\*\)\?\s*```\)[^A-Za-z0-9_-]*\%(\%(should_panic\|no_run\|ignore\|allow_fail\|rust\|test_harness\|compile_fail\|E\d\{4}\|edition201[58]\)\%([^A-Za-z0-9_-]\+\|$\)\)*$' end='^\z1$' keepend contains=@RustCodeInComment,rustCommentBlockDocStar
" Strictly, this may or may not be correct; this code, for example, would
" mishighlight:
"
" /**
" ```rust
" println!("{}", 1
" * 1);
" ```
" */
"
" … but I dont care. Balance of probability, and all that.
syn match rustCommentBlockDocStar /^\s*\*\s\?/ contained
syn match rustCommentLineDocLeader "^\s*//\%(//\@!\|!\)" contained
endif
" Default highlighting {{{1 " Default highlighting {{{1
hi def link rustDecNumber rustNumber hi def link rustDecNumber rustNumber
hi def link rustHexNumber rustNumber hi def link rustHexNumber rustNumber
@ -240,12 +290,15 @@ hi def link rustFloat Float
hi def link rustArrowCharacter rustOperator hi def link rustArrowCharacter rustOperator
hi def link rustOperator Operator hi def link rustOperator Operator
hi def link rustKeyword Keyword hi def link rustKeyword Keyword
hi def link rustDynKeyword rustKeyword
hi def link rustTypedef Keyword " More precise is Typedef, but it doesn't feel right for Rust hi def link rustTypedef Keyword " More precise is Typedef, but it doesn't feel right for Rust
hi def link rustStructure Keyword " More precise is Structure hi def link rustStructure Keyword " More precise is Structure
hi def link rustUnion rustStructure hi def link rustUnion rustStructure
hi def link rustExistential rustKeyword
hi def link rustPubScopeDelim Delimiter hi def link rustPubScopeDelim Delimiter
hi def link rustPubScopeCrate rustKeyword hi def link rustPubScopeCrate rustKeyword
hi def link rustSuper rustKeyword hi def link rustSuper rustKeyword
hi def link rustUnsafeKeyword Exception
hi def link rustReservedKeyword Error hi def link rustReservedKeyword Error
hi def link rustRepeat Conditional hi def link rustRepeat Conditional
hi def link rustConditional Conditional hi def link rustConditional Conditional
@ -259,10 +312,13 @@ hi def link rustFuncCall Function
hi def link rustShebang Comment hi def link rustShebang Comment
hi def link rustCommentLine Comment hi def link rustCommentLine Comment
hi def link rustCommentLineDoc SpecialComment hi def link rustCommentLineDoc SpecialComment
hi def link rustCommentLineDocLeader rustCommentLineDoc
hi def link rustCommentLineDocError Error hi def link rustCommentLineDocError Error
hi def link rustCommentBlock rustCommentLine hi def link rustCommentBlock rustCommentLine
hi def link rustCommentBlockDoc rustCommentLineDoc hi def link rustCommentBlockDoc rustCommentLineDoc
hi def link rustCommentBlockDocStar rustCommentBlockDoc
hi def link rustCommentBlockDocError Error hi def link rustCommentBlockDocError Error
hi def link rustCommentDocCodeFence rustCommentLineDoc
hi def link rustAssert PreCondit hi def link rustAssert PreCondit
hi def link rustPanic PreCondit hi def link rustPanic PreCondit
hi def link rustMacro Macro hi def link rustMacro Macro
@ -275,7 +331,6 @@ hi def link rustStorage StorageClass
hi def link rustObsoleteStorage Error hi def link rustObsoleteStorage Error
hi def link rustLifetime Special hi def link rustLifetime Special
hi def link rustLabel Label hi def link rustLabel Label
hi def link rustInvalidBareKeyword Error
hi def link rustExternCrate rustKeyword hi def link rustExternCrate rustKeyword
hi def link rustObsoleteExternMod Error hi def link rustObsoleteExternMod Error
hi def link rustBoxPlacementParens Delimiter hi def link rustBoxPlacementParens Delimiter
@ -292,3 +347,5 @@ syn sync minlines=200
syn sync maxlines=500 syn sync maxlines=500
let b:current_syntax = "rust" let b:current_syntax = "rust"
" vim: set et sw=4 sts=4 ts=8:

View file

@ -0,0 +1,93 @@
" Vim syntastic plugin
" Language: Rust
" Maintainer: Julien Levesy <jlevesy@gmail.com>
"
" See for details on how to add an external Syntastic checker:
" https://github.com/scrooloose/syntastic/wiki/Syntax-Checker-Guide#external
if exists("g:loaded_syntastic_rust_cargo_checker")
finish
endif
let g:loaded_syntastic_rust_cargo_checker = 1
" Force syntastic to call cargo without a specific file name
let g:syntastic_rust_cargo_fname = ""
let s:save_cpo = &cpo
set cpo&vim
function! SyntaxCheckers_rust_cargo_IsAvailable() dict
if exists("*syntastic#util#getVersion")
echom "rust.vim: version of Syntastic is too old. Needs to be at least 3.7.0."
return v:false
endif
return executable(self.getExec()) &&
\ syntastic#util#versionIsAtLeast(self.getVersion(), [0, 16, 0])
endfunction
function! SyntaxCheckers_rust_cargo_GetLocList() dict
let makeprg = self.makeprgBuild({ "args": "check" })
let l:root_cargo_toml = cargo#nearestRootCargo(0)
let l:nearest_cargo_toml = cargo#nearestCargo(0)
let b:rust_recent_root_cargo_toml = l:root_cargo_toml
let b:rust_recent_nearest_cargo_toml = l:nearest_cargo_toml
" All pathname prints are relative to the Cargo.toml of the workspace, if
" there is a workspace, otherwise they are relative to the Cargo.toml of
" the single crate. Where to actually execute under these varying
" circumtances 'cargo' is determined here, and controlled by
" configuration.
if rust#GetConfigVar('rust_cargo_avoid_whole_workspace', 1)
if l:root_cargo_toml !=# l:nearest_cargo_toml
let makeprg = "cd " . fnamemodify(l:nearest_cargo_toml, ":p:h")
\ . " && " . makeprg
endif
else
let makeprg = "cd " . fnamemodify(l:root_cargo_toml, ":p:h")
\ . " && " . makeprg
endif
let l:check_all_targets = rust#GetConfigVar('rust_cargo_check_all_targets', 0)
let l:check_all_features = rust#GetConfigVar('rust_cargo_check_all_features', 0)
let l:check_examples = rust#GetConfigVar('rust_cargo_check_examples', 0)
let l:check_tests = rust#GetConfigVar('rust_cargo_check_tests', 0)
let l:check_benches = rust#GetConfigVar('rust_cargo_check_benches', 0)
let makeprg = makeprg. ' '
\ . (l:check_all_targets ? ' --all-targets' : '')
\ . (l:check_all_features ? ' --all-features' : '')
\ . (l:check_benches ? ' --benches' : '')
\ . (l:check_examples ? ' --examples' : '')
\ . (l:check_tests ? ' --tests' : '')
" Ignored patterns, and blank lines
let errorformat =
\ '%-G,' .
\ '%-Gerror: aborting %.%#,' .
\ '%-Gerror: Could not compile %.%#,'
" Meaningful lines (errors, notes, warnings, contextual information)
let errorformat .=
\ '%Eerror: %m,' .
\ '%Eerror[E%n]: %m,' .
\ '%Wwarning: %m,' .
\ '%Inote: %m,' .
\ '%C %#--> %f:%l:%c'
return SyntasticMake({
\ 'makeprg': makeprg,
\ 'cwd': fnamemodify(l:root_cargo_toml, ":p:h:."),
\ 'errorformat': errorformat })
endfunction
call g:SyntasticRegistry.CreateAndRegisterChecker({
\ 'filetype': 'rust',
\ 'name': 'cargo'})
let &cpo = s:save_cpo
unlet s:save_cpo
" vim: set et sw=4 sts=4 ts=8:

View file

@ -10,39 +10,45 @@ if exists("g:loaded_syntastic_rust_rustc_checker")
endif endif
let g:loaded_syntastic_rust_rustc_checker = 1 let g:loaded_syntastic_rust_rustc_checker = 1
" vint: -ProhibitAbbreviationOption
let s:save_cpo = &cpo let s:save_cpo = &cpo
set cpo&vim set cpo&vim
" vint: +ProhibitAbbreviationOption
function! SyntaxCheckers_rust_rustc_GetLocList() dict function! SyntaxCheckers_rust_rustc_GetLocList() dict
let makeprg = self.makeprgBuild({}) let makeprg = self.makeprgBuild({})
" Old errorformat (before nightly 2016/08/10) " Old errorformat (before nightly 2016/08/10)
let errorformat = let errorformat =
\ '%E%f:%l:%c: %\d%#:%\d%# %.%\{-}error:%.%\{-} %m,' . \ '%E%f:%l:%c: %\d%#:%\d%# %.%\{-}error:%.%\{-} %m,' .
\ '%W%f:%l:%c: %\d%#:%\d%# %.%\{-}warning:%.%\{-} %m,' . \ '%W%f:%l:%c: %\d%#:%\d%# %.%\{-}warning:%.%\{-} %m,' .
\ '%C%f:%l %m' \ '%C%f:%l %m'
" New errorformat (after nightly 2016/08/10) " New errorformat (after nightly 2016/08/10)
let errorformat .= let errorformat .=
\ ',' . \ ',' .
\ '%-G,' . \ '%-G,' .
\ '%-Gerror: aborting %.%#,' . \ '%-Gerror: aborting %.%#,' .
\ '%-Gerror: Could not compile %.%#,' . \ '%-Gerror: Could not compile %.%#,' .
\ '%Eerror: %m,' . \ '%Eerror: %m,' .
\ '%Eerror[E%n]: %m,' . \ '%Eerror[E%n]: %m,' .
\ '%-Gwarning: the option `Z` is unstable %.%#,' . \ '%-Gwarning: the option `Z` is unstable %.%#,' .
\ '%Wwarning: %m,' . \ '%Wwarning: %m,' .
\ '%Inote: %m,' . \ '%Inote: %m,' .
\ '%C %#--> %f:%l:%c' \ '%C %#--> %f:%l:%c'
return SyntasticMake({ return SyntasticMake({
\ 'makeprg': makeprg, \ 'makeprg': makeprg,
\ 'errorformat': errorformat }) \ 'errorformat': errorformat })
endfunction endfunction
call g:SyntasticRegistry.CreateAndRegisterChecker({ call g:SyntasticRegistry.CreateAndRegisterChecker({
\ 'filetype': 'rust', \ 'filetype': 'rust',
\ 'name': 'rustc'}) \ 'name': 'rustc'})
" vint: -ProhibitAbbreviationOption
let &cpo = s:save_cpo let &cpo = s:save_cpo
unlet s:save_cpo unlet s:save_cpo
" vint: +ProhibitAbbreviationOption
" vim: set et sw=4 sts=4 ts=8:

View file

View file

@ -0,0 +1,34 @@
# This is brought as reference, to be able to reproduce a new image
FROM alonid/vim-testbed:10
RUN install_vim -tag v7.4.052 -name vim74-trusty -build \
-tag v8.0.1850 -name vim80 -build \
-tag v8.1.0105 -name vim81 -build \
-tag neovim:v0.1.7 -build \
-tag neovim:v0.2.2 -build
ENV PACKAGES="\
bash \
git \
python \
python2-pip \
curl \
"
RUN dnf install -y $PACKAGES
RUN pip install vim-vint==0.3.19
RUN export HOME=/rust ; mkdir $HOME ; curl https://sh.rustup.rs -sSf | sh -s -- -y
RUN chown vimtest.vimtest -R /rust
RUN (dnf remove -y gcc \*-devel ; \
dnf install -y gpm msgpack libvterm libtermkey unibilium ) || true
RUN dnf clean all
RUN echo "export PATH=~/.cargo/bin:$PATH" >> ~/.bashrc
RUN git clone https://github.com/da-x/vader.vim vader && \
cd vader && git checkout v2017-12-26

View file

@ -0,0 +1,24 @@
Given rust (Some Rust code):
fn main() {
println!("Hello World\n")
}
Execute (RustInfo - call it to see that it works):
redir => m
silent RustInfo
redir END
Log m
Execute (RustEmitAsm - see that we actually get assembly output):
silent! w test.rs
silent! e! test.rs
redir => m
silent! RustEmitAsm
redir END
AssertEqual 'asm', &filetype
normal! ggVGy:q<CR>
AssertEqual 1,(@" =~# '\V.section')
bd
call delete('test.rs')
# TODO: a lot more tests

View file

@ -0,0 +1,105 @@
#!/usr/bin/env python
import os
import sys
REPO = "alonid/vim-testbed"
TAG = "10-rust.vim"
IMAGE = "%s:%s" % (REPO, TAG)
class Error(Exception):
pass
def system(cmd, capture=False, ok_fail=False):
if capture:
f = os.popen(cmd)
d = f.read()
return d
res = os.system(cmd)
if res != 0:
if ok_fail:
return res
raise Error("Error executing: %s" % (cmd, ))
return 0
def root():
return os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
def prep():
d = os.path.join(root(), "test")
for i in [".cargo", ".rustup", ".multirust"]:
l = os.path.join(d, i)
if not os.path.lexists(l):
os.symlink("/rust/" + i, l)
l = os.path.join(root(), "test/.vimrc")
if not os.path.lexists(l):
os.symlink("vimrc", l)
if not os.path.exists(os.path.join(d, ".profile")):
f = open(os.path.join(d, ".profile"), "w")
f.write('export PATH="$HOME/.cargo/bin:$PATH"\n')
f.close()
def docker_run(cmd, interactive=False, ok_fail=False):
prep()
d = root()
params = "-v %s:/testplugin -v %s/test:/home/vimtest" % (d, d)
params += " -e HOME=/home/vimtest"
if not interactive:
params += " -a stderr"
params += " -e VADER_OUTPUT_FILE=/dev/stderr"
params += " -u %s" % (os.getuid(), )
params += " -w /testplugin"
if interactive:
interactive_str = "-it"
else:
interactive_str = ""
return system("docker run %s --rm %s %s %s" % (interactive_str, params, IMAGE, cmd),
ok_fail=ok_fail)
def image_exists():
r = system("docker images -q %s" % (IMAGE, ), capture=True)
return len(r.strip().splitlines()) >= 1
def tests_on_docker():
res = docker_run("bash -lc 'python /home/vimtest/run-tests inside-docker'", ok_fail=True)
if res == 0:
print "Tests OK"
else:
print "Tests Failed"
sys.exit(1)
def inside_docker():
res = system("/vim-build/bin/vim80 --not-a-term '+Vader! test/*.vader'", ok_fail=True)
if res != 0:
sys.exit(1)
def run_with_vimrc(vimrc):
res = system("vim -u %s --not-a-term '+Vader! test/*.vader'" % (vimrc, ), ok_fail=True)
if res != 0:
sys.exit(1)
def main():
if sys.argv[1:] == ["inside-docker"]:
inside_docker()
return
if sys.argv[1:2] == ["run-with-vimrc"]:
run_with_vimrc(sys.argv[2])
return
if not image_exists():
print "Need to take image from remote"
system("docker pull %s" % (IMAGE, ))
if "-i" in sys.argv[1:]:
docker_run("bash -l", interactive=True)
return
tests_on_docker()
if __name__ == "__main__":
main()

View file

View file

@ -0,0 +1,30 @@
" vint: -ProhibitSetNoCompatible
"
set nocompatible
filetype off
" This script is currently designed to be run from within Docker, the
" following paths are intrinsic to the container:
source /rtp.vim
" Paths need prepending (instead of what is originally done
" in vim-testbed) in order to supersede the rust.vim that is
" supplied with Vim.
exec 'set runtimepath=/vader,/testplugin,' . &runtimepath
cd /testplugin
filetype plugin indent on
syntax on
set nocompatible
set tabstop=8
set softtabstop=4
set shiftwidth=4
set expandtab
set backspace=2
set nofoldenable
set foldmethod=syntax
set foldlevelstart=10
set foldnestmax=10
set ttimeoutlen=0