diff --git a/pack/acp/start/rust.vim/.travis.yml b/pack/acp/start/rust.vim/.travis.yml new file mode 100644 index 0000000..fa69300 --- /dev/null +++ b/pack/acp/start/rust.vim/.travis.yml @@ -0,0 +1,7 @@ +--- +sudo: required +services: + - docker +language: generic +script: | + cd test && ./run-tests diff --git a/pack/acp/start/rust.vim/.vintrc.yml b/pack/acp/start/rust.vim/.vintrc.yml new file mode 100644 index 0000000..0914f1b --- /dev/null +++ b/pack/acp/start/rust.vim/.vintrc.yml @@ -0,0 +1,10 @@ +cmdargs: + # Checking more strictly + severity: style_problem + +policies: + # Disable a violation + ProhibitUnnecessaryDoubleQuote: + enabled: false + ProhibitImplicitScopeVariable: + enabled: false diff --git a/pack/acp/start/rust.vim/ISSUE_TEMPLATE.md b/pack/acp/start/rust.vim/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..10afd15 --- /dev/null +++ b/pack/acp/start/rust.vim/ISSUE_TEMPLATE.md @@ -0,0 +1,27 @@ + + +* rust.vim version: + +Steps to reproduce: + + +_?_ + +Expected vs. actual behavior: + +_?_ + +Paste debugging info from the Rust Vim plugin via _one_ of the following +commands: `:RustInfo`, `:RustInfoToClipboard`, or `:RustInfoToFile `. + +_?_ diff --git a/pack/acp/start/rust.vim/README.md b/pack/acp/start/rust.vim/README.md index 9fe8968..aaba3da 100644 --- a/pack/acp/start/rust.vim/README.md +++ b/pack/acp/start/rust.vim/README.md @@ -3,42 +3,46 @@ ## Description 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 -### Using [Vundle][v] +Use one of the following package managers: -1. Add `Plugin 'rust-lang/rust.vim'` to `~/.vimrc` -2. `:PluginInstall` or `$ vim +PluginInstall +qall` - -*Note:* Vundle will not automatically detect Rust files properly if `filetype +* [Vim8 packages][vim8pack]: + * `git clone https://github.com/rust-lang/rust.vim ~/.vim/pack/plugins/start/rust.vim` +* [Vundle][v]: + * 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 -details. - -### Using [Pathogen][p] - -```shell -git clone --depth=1 https://github.com/rust-lang/rust.vim.git ~/.vim/bundle/rust.vim -``` - -### Using [NeoBundle][nb] - -1. Add `NeoBundle 'rust-lang/rust.vim'` to `~/.vimrc` -2. 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` +details. Errors such as `Not an editor command: RustFmt` may occur if Vundle +is misconfigured with this plugin. +* [Pathogen][p]: + * `git clone --depth=1 https://github.com/rust-lang/rust.vim.git ~/.vim/bundle/rust.vim` +* [vim-plug][vp]: + * Add `Plug 'rust-lang/rust.vim'` to `~/.vimrc` + * `:PlugInstall` or `$ vim +PlugInstall +qall` +* [dein.vim][d]: + * Add `call dein#add('rust-lang/rust.vim')` to `~/.vimrc` + * `:call dein#install()` +* [NeoBundle][nb]: + * Add `NeoBundle 'rust-lang/rust.vim'` to `~/.vimrc` + * Re-open vim or execute `:source ~/.vimrc` ## Features ### Error checking with [Syntastic][syn] -`rust.vim` automatically registers `rustc` as a syntax checker -with [Syntastic][syn]. Check Syntastic's documentation for -information on how to customize its behaviour. +`rust.vim` automatically registers `cargo` as a syntax checker with +[Syntastic][syn], if nothing else is specified. See `:help rust-syntastic` +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] @@ -58,7 +62,20 @@ options. The `:RustPlay` command will send the current selection, or if 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 @@ -81,7 +98,10 @@ LICENSE-MIT for details. [p]: https://github.com/tpope/vim-pathogen [nb]: https://github.com/Shougo/neobundle.vim [vp]: https://github.com/junegunn/vim-plug +[d]: https://github.com/Shougo/dein.vim [rfmt]: https://github.com/rust-lang-nursery/rustfmt [syn]: https://github.com/scrooloose/syntastic +[tgbr]: https://github.com/majutsushi/tagbar [wav]: https://github.com/mattn/webapi-vim [pp]: https://play.rust-lang.org/ +[vim8pack]: http://vimhelp.appspot.com/repeat.txt.html#packages diff --git a/pack/acp/start/rust.vim/after/syntax/rust.vim b/pack/acp/start/rust.vim/after/syntax/rust.vim index b0f7e62..62bfc65 100644 --- a/pack/acp/start/rust.vim/after/syntax/rust.vim +++ b/pack/acp/start/rust.vim/after/syntax/rust.vim @@ -1,10 +1,12 @@ -if !exists('g:rust_conceal') || g:rust_conceal == 0 || !has('conceal') || &enc != 'utf-8' - finish +scriptencoding utf-8 + +if !get(g:, 'rust_conceal', 0) || !has('conceal') || &encoding !=# 'utf-8' + finish endif " For those who don't want to see `::`... -if exists('g:rust_conceal_mod_path') && g:rust_conceal_mod_path != 0 - syn match rustNiceOperator "::" conceal cchar=ㆍ +if get(g:, 'rust_conceal_mod_path', 0) + syn match rustNiceOperator "::" conceal cchar=ㆍ endif syn match rustRightArrowHead contained ">" conceal cchar=  @@ -18,7 +20,7 @@ syn match rustNiceOperator "=>" contains=rustFatRightArrowHead,rustFatRightArrow syn match rustNiceOperator /\<\@!_\(_*\>\)\@=/ conceal cchar=′ " 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 rustPublicRest contained "b" conceal cchar=  syn match rustNiceOperator "pub " contains=rustPublicSigil,rustPublicRest @@ -26,9 +28,14 @@ endif 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 - " And keep it after a colorscheme change - au ColorScheme hi! link Conceal Operator + augroup rust.vim.after + autocmd! + " And keep it after a colorscheme change + autocmd ColorScheme hi! link Conceal Operator + augroup END endif + +" vim: set et sw=4 sts=4 ts=8: diff --git a/pack/acp/start/rust.vim/autoload/cargo.vim b/pack/acp/start/rust.vim/autoload/cargo.vim new file mode 100644 index 0000000..b5d40e2 --- /dev/null +++ b/pack/acp/start/rust.vim/autoload/cargo.vim @@ -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: diff --git a/pack/acp/start/rust.vim/autoload/cargo/quickfix.vim b/pack/acp/start/rust.vim/autoload/cargo/quickfix.vim new file mode 100644 index 0000000..fb16fc7 --- /dev/null +++ b/pack/acp/start/rust.vim/autoload/cargo/quickfix.vim @@ -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: diff --git a/pack/acp/start/rust.vim/autoload/rust.vim b/pack/acp/start/rust.vim/autoload/rust.vim index 477f3c4..4ec13dc 100644 --- a/pack/acp/start/rust.vim/autoload/rust.vim +++ b/pack/acp/start/rust.vim/autoload/rust.vim @@ -1,206 +1,259 @@ " Author: Kevin Ballard " Description: Helper functions for Rust commands/mappings " 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 function! rust#Jump(mode, function) range - let cnt = v:count1 - normal! m' - if a:mode ==# 'v' - norm! gv - endif - let foldenable = &foldenable - set nofoldenable - while cnt > 0 - execute "call Jump_" . a:function . "()" - let cnt = cnt - 1 - endwhile - let &foldenable = foldenable + let cnt = v:count1 + normal! m' + if a:mode ==# 'v' + norm! gv + endif + let foldenable = &foldenable + set nofoldenable + while cnt > 0 + execute "call Jump_" . a:function . "()" + let cnt = cnt - 1 + endwhile + let &foldenable = foldenable endfunction function! s:Jump_Back() - call search('{', 'b') - keepjumps normal! w99[{ + call search('{', 'b') + keepjumps normal! w99[{ endfunction function! s:Jump_Forward() - normal! j0 - call search('{', 'b') - keepjumps normal! w99[{% - call search('{') + normal! j0 + call search('{', 'b') + keepjumps normal! w99[{% + call search('{') endfunction " Run {{{1 function! rust#Run(bang, args) - let args = s:ShellTokenize(a:args) - if a:bang - let idx = index(l:args, '--') - if idx != -1 - let rustc_args = idx == 0 ? [] : l:args[:idx-1] - let args = l:args[idx+1:] - else - let rustc_args = l:args - let args = [] - endif - else - let rustc_args = [] - endif + let args = s:ShellTokenize(a:args) + if a:bang + let idx = index(l:args, '--') + if idx != -1 + let rustc_args = idx == 0 ? [] : l:args[:idx-1] + let args = l:args[idx+1:] + else + let rustc_args = l:args + let args = [] + endif + else + let rustc_args = [] + endif - let b:rust_last_rustc_args = l:rustc_args - let b:rust_last_args = l:args + let b:rust_last_rustc_args = l:rustc_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 function! s:Run(dict, rustc_args, args) - let exepath = a:dict.tmpdir.'/'.fnamemodify(a:dict.path, ':t:r') - if has('win32') - let exepath .= '.exe' - endif + let exepath = a:dict.tmpdir.'/'.fnamemodify(a:dict.path, ':t:r') + if has('win32') + let exepath .= '.exe' + endif - let relpath = get(a:dict, 'tmpdir_relpath', a:dict.path) - let rustc_args = [relpath, '-o', exepath] + a:rustc_args + let relpath = get(a:dict, 'tmpdir_relpath', a:dict.path) + 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 output = s:system(pwd, shellescape(rustc) . " " . join(map(rustc_args, 'shellescape(v:val)'))) - if output != '' - echohl WarningMsg - echo output - echohl None - endif - if !v:shell_error - exe '!' . shellescape(exepath) . " " . join(map(a:args, 'shellescape(v:val)')) - endif + let pwd = a:dict.istemp ? a:dict.tmpdir : '' + let output = s:system(pwd, shellescape(rustc) . " " . join(map(rustc_args, 'shellescape(v:val)'))) + if output !=# '' + echohl WarningMsg + echo output + echohl None + endif + if !v:shell_error + exe '!' . shellescape(exepath) . " " . join(map(a:args, 'shellescape(v:val)')) + endif endfunction " Expand {{{1 function! rust#Expand(bang, args) - let args = s:ShellTokenize(a:args) - if a:bang && !empty(l:args) - let pretty = remove(l:args, 0) - else - let pretty = "expanded" - endif - call s:WithPath(function("s:Expand"), pretty, args) + let args = s:ShellTokenize(a:args) + if a:bang && !empty(l:args) + let pretty = remove(l:args, 0) + else + let pretty = "expanded" + endif + call s:WithPath(function("s:Expand"), pretty, args) endfunction function! s:Expand(dict, pretty, args) - try - let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc" + try + let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc" - if a:pretty =~? '^\%(everybody_loops$\|flowgraph=\)' - let flag = '--xpretty' - else - let flag = '--pretty' - endif - let relpath = get(a:dict, 'tmpdir_relpath', a:dict.path) - let args = [relpath, '-Z', 'unstable-options', l:flag, a:pretty] + a:args - let pwd = a:dict.istemp ? a:dict.tmpdir : '' - let output = s:system(pwd, shellescape(rustc) . " " . join(map(args, 'shellescape(v:val)'))) - if v:shell_error - echohl WarningMsg - echo output - echohl None - else - new - silent put =output - 1 - d - setl filetype=rust - setl buftype=nofile - setl bufhidden=hide - setl noswapfile - " give the buffer a nice name - let suffix = 1 - let basename = fnamemodify(a:dict.path, ':t:r') - while 1 - let bufname = basename - if suffix > 1 | let bufname .= ' ('.suffix.')' | endif - let bufname .= '.pretty.rs' - if bufexists(bufname) - let suffix += 1 - continue - endif - exe 'silent noautocmd keepalt file' fnameescape(bufname) - break - endwhile - endif - endtry + if a:pretty =~? '^\%(everybody_loops$\|flowgraph=\)' + let flag = '--xpretty' + else + let flag = '--pretty' + endif + let relpath = get(a:dict, 'tmpdir_relpath', a:dict.path) + let args = [relpath, '-Z', 'unstable-options', l:flag, a:pretty] + a:args + let pwd = a:dict.istemp ? a:dict.tmpdir : '' + let output = s:system(pwd, shellescape(rustc) . " " . join(map(args, 'shellescape(v:val)'))) + if v:shell_error + echohl WarningMsg + echo output + echohl None + else + new + silent put =output + 1 + d + setl filetype=rust + setl buftype=nofile + setl bufhidden=hide + setl noswapfile + " give the buffer a nice name + let suffix = 1 + let basename = fnamemodify(a:dict.path, ':t:r') + while 1 + let bufname = basename + if suffix > 1 | let bufname .= ' ('.suffix.')' | endif + let bufname .= '.pretty.rs' + if bufexists(bufname) + let suffix += 1 + continue + endif + exe 'silent noautocmd keepalt file' fnameescape(bufname) + break + endwhile + endif + endtry endfunction function! rust#CompleteExpand(lead, line, pos) - if a:line[: a:pos-1] =~ '^RustExpand!\s*\S*$' - " first argument and it has a ! - let list = ["normal", "expanded", "typed", "expanded,identified", "flowgraph=", "everybody_loops"] - if !empty(a:lead) - call filter(list, "v:val[:len(a:lead)-1] == a:lead") - endif - return list - endif + if a:line[: a:pos-1] =~# '^RustExpand!\s*\S*$' + " first argument and it has a ! + let list = ["normal", "expanded", "typed", "expanded,identified", "flowgraph=", "everybody_loops"] + if !empty(a:lead) + call filter(list, "v:val[:len(a:lead)-1] == a:lead") + endif + return list + endif - return glob(escape(a:lead, "*?[") . '*', 0, 1) + return glob(escape(a:lead, "*?[") . '*', 0, 1) endfunction " Emit {{{1 function! rust#Emit(type, args) - let args = s:ShellTokenize(a:args) - call s:WithPath(function("s:Emit"), a:type, args) + let args = s:ShellTokenize(a:args) + call s:WithPath(function("s:Emit"), a:type, args) endfunction function! s:Emit(dict, type, args) - try - let output_path = a:dict.tmpdir.'/output' + try + 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 args = [relpath, '--emit', a:type, '-o', output_path] + a:args - let pwd = a:dict.istemp ? a:dict.tmpdir : '' - let output = s:system(pwd, shellescape(rustc) . " " . join(map(args, 'shellescape(v:val)'))) - if output != '' - echohl WarningMsg - echo output - echohl None - endif - if !v:shell_error - new - exe 'silent keepalt read' fnameescape(output_path) - 1 - d - if a:type == "llvm-ir" - setl filetype=llvm - let extension = 'll' - elseif a:type == "asm" - setl filetype=asm - let extension = 's' - endif - setl buftype=nofile - setl bufhidden=hide - setl noswapfile - if exists('l:extension') - " give the buffer a nice name - let suffix = 1 - let basename = fnamemodify(a:dict.path, ':t:r') - while 1 - let bufname = basename - if suffix > 1 | let bufname .= ' ('.suffix.')' | endif - let bufname .= '.'.extension - if bufexists(bufname) - let suffix += 1 - continue - endif - exe 'silent noautocmd keepalt file' fnameescape(bufname) - break - endwhile - endif - endif - endtry + let relpath = get(a:dict, 'tmpdir_relpath', a:dict.path) + let args = [relpath, '--emit', a:type, '-o', output_path] + a:args + let pwd = a:dict.istemp ? a:dict.tmpdir : '' + let output = s:system(pwd, shellescape(rustc) . " " . join(map(args, 'shellescape(v:val)'))) + if output !=# '' + echohl WarningMsg + echo output + echohl None + endif + if !v:shell_error + new + exe 'silent keepalt read' fnameescape(output_path) + 1 + d + if a:type ==# "llvm-ir" + setl filetype=llvm + let extension = 'll' + elseif a:type ==# "asm" + setl filetype=asm + let extension = 's' + endif + setl buftype=nofile + setl bufhidden=hide + setl noswapfile + if exists('l:extension') + " give the buffer a nice name + let suffix = 1 + let basename = fnamemodify(a:dict.path, ':t:r') + while 1 + let bufname = basename + if suffix > 1 | let bufname .= ' ('.suffix.')' | endif + let bufname .= '.'.extension + if bufexists(bufname) + let suffix += 1 + continue + endif + exe 'silent noautocmd keepalt file' fnameescape(bufname) + break + endwhile + endif + endif + endtry endfunction " Utility functions {{{1 @@ -218,145 +271,145 @@ endfunction " existing path of the current buffer. If the path is inside of {dict.tmpdir} " then it is guaranteed to have a '.rs' extension. function! s:WithPath(func, ...) - let buf = bufnr('') - let saved = {} - let dict = {} - try - let saved.write = &write - set write - let dict.path = expand('%') - let pathisempty = empty(dict.path) + let buf = bufnr('') + let saved = {} + let dict = {} + try + let saved.write = &write + set write + let dict.path = expand('%') + let pathisempty = empty(dict.path) - " Always create a tmpdir in case the wrapped command wants it - let dict.tmpdir = tempname() - call mkdir(dict.tmpdir) + " Always create a tmpdir in case the wrapped command wants it + let dict.tmpdir = tempname() + call mkdir(dict.tmpdir) - if pathisempty || !saved.write - let dict.istemp = 1 - " if we're doing this because of nowrite, preserve the filename - if !pathisempty - let filename = expand('%:t:r').".rs" - else - let filename = 'unnamed.rs' - endif - let dict.tmpdir_relpath = filename - let dict.path = dict.tmpdir.'/'.filename + if pathisempty || !saved.write + let dict.istemp = 1 + " if we're doing this because of nowrite, preserve the filename + if !pathisempty + let filename = expand('%:t:r').".rs" + else + let filename = 'unnamed.rs' + endif + let dict.tmpdir_relpath = filename + let dict.path = dict.tmpdir.'/'.filename - let saved.mod = &mod - set nomod + let saved.mod = &modified + set nomodified - silent exe 'keepalt write! ' . fnameescape(dict.path) - if pathisempty - silent keepalt 0file - endif - else - let dict.istemp = 0 - update - endif + silent exe 'keepalt write! ' . fnameescape(dict.path) + if pathisempty + silent keepalt 0file + endif + else + let dict.istemp = 0 + update + endif - call call(a:func, [dict] + a:000) - finally - if bufexists(buf) - for [opt, value] in items(saved) - silent call setbufvar(buf, '&'.opt, value) - unlet value " avoid variable type mismatches - endfor - endif - if has_key(dict, 'tmpdir') | silent call s:RmDir(dict.tmpdir) | endif - endtry + call call(a:func, [dict] + a:000) + finally + if bufexists(buf) + for [opt, value] in items(saved) + silent call setbufvar(buf, '&'.opt, value) + unlet value " avoid variable type mismatches + endfor + endif + if has_key(dict, 'tmpdir') | silent call s:RmDir(dict.tmpdir) | endif + endtry endfunction function! rust#AppendCmdLine(text) - call setcmdpos(getcmdpos()) - let cmd = getcmdline() . a:text - return cmd + call setcmdpos(getcmdpos()) + let cmd = getcmdline() . a:text + return cmd endfunction " Tokenize the string according to sh parsing rules function! s:ShellTokenize(text) - " states: - " 0: start of word - " 1: unquoted - " 2: unquoted backslash - " 3: double-quote - " 4: double-quoted backslash - " 5: single-quote - let l:state = 0 - let l:current = '' - let l:args = [] - for c in split(a:text, '\zs') - if l:state == 0 || l:state == 1 " unquoted - if l:c ==# ' ' - if l:state == 0 | continue | endif - call add(l:args, l:current) - let l:current = '' - let l:state = 0 - elseif l:c ==# '\' - let l:state = 2 - elseif l:c ==# '"' - let l:state = 3 - elseif l:c ==# "'" - let l:state = 5 - else - let l:current .= l:c - let l:state = 1 - endif - elseif l:state == 2 " unquoted backslash - if l:c !=# "\n" " can it even be \n? - let l:current .= l:c - endif - let l:state = 1 - elseif l:state == 3 " double-quote - if l:c ==# '\' - let l:state = 4 - elseif l:c ==# '"' - let l:state = 1 - else - let l:current .= l:c - endif - elseif l:state == 4 " double-quoted backslash - if stridx('$`"\', l:c) >= 0 - let l:current .= l:c - elseif l:c ==# "\n" " is this even possible? - " skip it - else - let l:current .= '\'.l:c - endif - let l:state = 3 - elseif l:state == 5 " single-quoted - if l:c == "'" - let l:state = 1 - else - let l:current .= l:c - endif - endif - endfor - if l:state != 0 - call add(l:args, l:current) - endif - return l:args + " states: + " 0: start of word + " 1: unquoted + " 2: unquoted backslash + " 3: double-quote + " 4: double-quoted backslash + " 5: single-quote + let l:state = 0 + let l:current = '' + let l:args = [] + for c in split(a:text, '\zs') + if l:state == 0 || l:state == 1 " unquoted + if l:c ==# ' ' + if l:state == 0 | continue | endif + call add(l:args, l:current) + let l:current = '' + let l:state = 0 + elseif l:c ==# '\' + let l:state = 2 + elseif l:c ==# '"' + let l:state = 3 + elseif l:c ==# "'" + let l:state = 5 + else + let l:current .= l:c + let l:state = 1 + endif + elseif l:state == 2 " unquoted backslash + if l:c !=# "\n" " can it even be \n? + let l:current .= l:c + endif + let l:state = 1 + elseif l:state == 3 " double-quote + if l:c ==# '\' + let l:state = 4 + elseif l:c ==# '"' + let l:state = 1 + else + let l:current .= l:c + endif + elseif l:state == 4 " double-quoted backslash + if stridx('$`"\', l:c) >= 0 + let l:current .= l:c + elseif l:c ==# "\n" " is this even possible? + " skip it + else + let l:current .= '\'.l:c + endif + let l:state = 3 + elseif l:state == 5 " single-quoted + if l:c ==# "'" + let l:state = 1 + else + let l:current .= l:c + endif + endif + endfor + if l:state != 0 + call add(l:args, l:current) + endif + return l:args endfunction function! s:RmDir(path) - " sanity check; make sure it's not empty, /, or $HOME - if empty(a:path) - echoerr 'Attempted to delete empty path' - return 0 - elseif a:path == '/' || a:path == $HOME - echoerr 'Attempted to delete protected path: ' . a:path - return 0 - endif - return system("rm -rf " . shellescape(a:path)) + " sanity check; make sure it's not empty, /, or $HOME + if empty(a:path) + echoerr 'Attempted to delete empty path' + return 0 + elseif a:path ==# '/' || a:path ==# $HOME + echoerr 'Attempted to delete protected path: ' . a:path + return 0 + endif + return system("rm -rf " . shellescape(a:path)) endfunction " 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. function! s:system(pwd, cmd) - let cmd = a:cmd - if !empty(a:pwd) - let cmd = 'cd ' . shellescape(a:pwd) . ' && ' . cmd - endif - return system(cmd) + let cmd = a:cmd + if !empty(a:pwd) + let cmd = 'cd ' . shellescape(a:pwd) . ' && ' . cmd + endif + return system(cmd) endfunction " Playpen Support {{{1 @@ -364,51 +417,130 @@ endfunction " gist.vim available under the BSD license, available at " http://github.com/mattn/gist-vim function! s:has_webapi() - if !exists("*webapi#http#post") - try - call webapi#http#post() - catch - endtry - endif - return exists("*webapi#http#post") + if !exists("*webapi#http#post") + try + call webapi#http#post() + catch + endtry + endif + return exists("*webapi#http#post") endfunction 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_shortener_url = get(g:, 'rust_shortener_url', 'https://is.gd/') + 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/') - if !s:has_webapi() - echohl ErrorMsg | echomsg ':RustPlay depends on webapi.vim (https://github.com/mattn/webapi-vim)' | echohl None - return - endif + if !s:has_webapi() + echohl ErrorMsg | echomsg ':RustPlay depends on webapi.vim (https://github.com/mattn/webapi-vim)' | echohl None + return + endif - let bufname = bufname('%') - if a:count < 1 - let content = join(getline(a:line1, a:line2), "\n") - else - let save_regcont = @" - let save_regtype = getregtype('"') - silent! normal! gvy - let content = @" - call setreg('"', save_regcont, save_regtype) - endif + let bufname = bufname('%') + if a:count < 1 + let content = join(getline(a:line1, a:line2), "\n") + else + let save_regcont = @" + let save_regtype = getregtype('"') + silent! normal! gvy + let content = @" + call setreg('"', save_regcont, save_regtype) + 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 - echohl ErrorMsg | echomsg 'Buffer too large, max 5000 encoded characters ('.strlen(body).')' | echohl None - return - endif + if strlen(url) > 5000 + echohl ErrorMsg | echomsg 'Buffer too large, max 5000 encoded characters ('.strlen(url).')' | echohl None + return + endif - let payload = "format=simple&url=".webapi#http#encodeURI(body) - let res = webapi#http#post(l:rust_shortener_url.'create.php', payload, {}) - let url = res.content + let payload = "format=simple&url=".webapi#http#encodeURI(url) + let res = webapi#http#post(l:rust_shortener_url.'create.php', payload, {}) + 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 " }}}1 -" vim: set noet sw=4 ts=4: +" vim: set et sw=4 sts=4 ts=8: diff --git a/pack/acp/start/rust.vim/autoload/rust/debugging.vim b/pack/acp/start/rust.vim/autoload/rust/debugging.vim new file mode 100644 index 0000000..ae307a0 --- /dev/null +++ b/pack/acp/start/rust.vim/autoload/rust/debugging.vim @@ -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: diff --git a/pack/acp/start/rust.vim/autoload/rust/delimitmate.vim b/pack/acp/start/rust.vim/autoload/rust/delimitmate.vim new file mode 100644 index 0000000..7056d53 --- /dev/null +++ b/pack/acp/start/rust.vim/autoload/rust/delimitmate.vim @@ -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: + diff --git a/pack/acp/start/rust.vim/autoload/rustfmt.vim b/pack/acp/start/rust.vim/autoload/rustfmt.vim index e5f9830..650f212 100644 --- a/pack/acp/start/rust.vim/autoload/rustfmt.vim +++ b/pack/acp/start/rust.vim/autoload/rustfmt.vim @@ -1,9 +1,10 @@ " Author: Stephen Sugden " " 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") - let g:rustfmt_autosave = 0 + let g:rustfmt_autosave = 0 endif if !exists("g:rustfmt_command") @@ -11,96 +12,246 @@ if !exists("g:rustfmt_command") endif if !exists("g:rustfmt_options") - let g:rustfmt_options = "" + let g:rustfmt_options = "" endif 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 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) - let l:arg = {"file": shellescape(a:filename), "range": [a:line1, a:line2]} - return printf("%s %s --write-mode=overwrite --file-lines '[%s]'", g:rustfmt_command, g:rustfmt_options, json_encode(l:arg)) + if g:rustfmt_file_lines == 0 + 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 -function! s:RustfmtCommand(filename) - return g:rustfmt_command . " --write-mode=overwrite " . g:rustfmt_options . " " . shellescape(a:filename) +function! s:RustfmtCommand() + 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 -function! s:RunRustfmt(command, curw, tmpname) - if exists("*systemlist") - let out = systemlist(a:command) - else - let out = split(system(a:command), '\r\?\n') - endif +function! s:DeleteLines(start, end) abort + silent! execute a:start . ',' . a:end . 'delete _' +endfunction - if v:shell_error == 0 || v:shell_error == 3 - " remove undo point caused via BufWritePre - try | silent undojoin | catch | endtry +function! s:RunRustfmt(command, tmpname, fail_silently) + mkview! - " Replace current file with temp file, then reload buffer - call rename(a:tmpname, expand('%')) - silent edit! - let &syntax = &syntax + let l:stderr_tmpname = tempname() + call writefile([], l:stderr_tmpname) - " only clear location list if it was previously filled to prevent - " clobbering other additions - if s:got_fmt_error - let s:got_fmt_error = 0 - call setloclist(0, []) - lwindow - endif - elseif g:rustfmt_fail_silently == 0 - " otherwise get the errors and put them in the location list - let errors = [] + let l:command = a:command . ' 2> ' . l:stderr_tmpname - for line in out - " src/lib.rs:13:5: 13:10 error: expected `,`, or `}`, found `value` - let tokens = matchlist(line, '^\(.\{-}\):\(\d\+\):\(\d\+\):\s*\(\d\+:\d\+\s*\)\?\s*error: \(.*\)') - if !empty(tokens) - call add(errors, {"filename": @%, - \"lnum": tokens[2], - \"col": tokens[3], - \"text": tokens[5]}) - endif - endfor + if a:tmpname ==# '' + " Rustfmt in stdin/stdout mode - if empty(errors) - % | " Couldn't detect rustfmt error format, output errors + " chdir to the directory of the file + 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 - if !empty(errors) - call setloclist(0, errors, 'r') - echohl Error | echomsg "rustfmt returned error" | echohl None + let l:stderr = readfile(l:stderr_tmpname) + + 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 - let s:got_fmt_error = 1 - lwindow - " We didn't use the temp file, so clean up - call delete(a:tmpname) - endif + " Restore the current directory if needed + if a:tmpname ==# '' + if l:has_lcd + execute 'lchdir! '.l:prev_cd + 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 function! rustfmt#FormatRange(line1, line2) - let l:curw = winsaveview() - let l:tmpname = expand("%:p:h") . "/." . expand("%:p:t") . ".rustfmt" - call writefile(getline(1, '$'), l:tmpname) - - let command = s:RustfmtCommandRange(l:tmpname, a:line1, a:line2) - - call s:RunRustfmt(command, l:curw, l:tmpname) + let l:tmpname = tempname() + call writefile(getline(1, '$'), l:tmpname) + let command = s:RustfmtCommandRange(l:tmpname, a:line1, a:line2) + call s:RunRustfmt(command, l:tmpname, 0) + call delete(l:tmpname) endfunction function! rustfmt#Format() - let l:curw = winsaveview() - let l:tmpname = expand("%:p:h") . "/." . expand("%:p:t") . ".rustfmt" - call writefile(getline(1, '$'), l:tmpname) - - let command = s:RustfmtCommand(l:tmpname) - - call s:RunRustfmt(command, l:curw, l:tmpname) + call s:RunRustfmt(s:RustfmtCommand(), '', 0) 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: diff --git a/pack/acp/start/rust.vim/compiler/cargo.vim b/pack/acp/start/rust.vim/compiler/cargo.vim index 029c5c7..87de609 100644 --- a/pack/acp/start/rust.vim/compiler/cargo.vim +++ b/pack/acp/start/rust.vim/compiler/cargo.vim @@ -2,13 +2,19 @@ " Compiler: Cargo Compiler " Maintainer: Damien Radtke " Latest Revision: 2014 Sep 24 +" For bugs, patches and license go to https://github.com/rust-lang/rust.vim if exists('current_compiler') - finish + finish endif runtime compiler/rustc.vim let current_compiler = "cargo" +" vint: -ProhibitAbbreviationOption +let s:save_cpo = &cpo +set cpo&vim +" vint: +ProhibitAbbreviationOption + if exists(':CompilerSet') != 2 command -nargs=* CompilerSet setlocal endif @@ -19,10 +25,25 @@ else CompilerSet makeprg=cargo\ $* 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 CompilerSet errorformat+= - \%-G%\\s%#Downloading%.%#, - \%-G%\\s%#Compiling%.%#, - \%-G%\\s%#Finished%.%#, - \%-G%\\s%#error:\ Could\ not\ compile\ %.%#, - \%-G%\\s%#To\ learn\ more\\,%.%# + \%-G%\\s%#Downloading%.%#, + \%-G%\\s%#Compiling%.%#, + \%-G%\\s%#Finished%.%#, + \%-G%\\s%#error:\ Could\ not\ compile\ %.%#, + \%-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: diff --git a/pack/acp/start/rust.vim/compiler/rustc.vim b/pack/acp/start/rust.vim/compiler/rustc.vim index ba29133..6114b74 100644 --- a/pack/acp/start/rust.vim/compiler/rustc.vim +++ b/pack/acp/start/rust.vim/compiler/rustc.vim @@ -2,44 +2,52 @@ " Compiler: Rust Compiler " Maintainer: Chris Morgan " Latest Revision: 2013 Jul 12 +" For bugs, patches and license go to https://github.com/rust-lang/rust.vim if exists("current_compiler") - finish + finish endif let current_compiler = "rustc" -let s:cpo_save = &cpo +" vint: -ProhibitAbbreviationOption +let s:save_cpo = &cpo set cpo&vim +" vint: +ProhibitAbbreviationOption if exists(":CompilerSet") != 2 - command -nargs=* CompilerSet setlocal + command -nargs=* CompilerSet setlocal endif -if exists("g:rustc_makeprg_no_percent") && g:rustc_makeprg_no_percent != 0 - CompilerSet makeprg=rustc +if get(g:, 'rustc_makeprg_no_percent', 0) + CompilerSet makeprg=rustc else - CompilerSet makeprg=rustc\ \% + CompilerSet makeprg=rustc\ \% 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) -CompilerSet errorformat+= - \%-G, - \%-Gerror:\ aborting\ %.%#, - \%-Gerror:\ Could\ not\ compile\ %.%#, - \%Eerror:\ %m, - \%Eerror[E%n]:\ %m, - \%Wwarning:\ %m, - \%Inote:\ %m, - \%C\ %#-->\ %f:%l:%c +CompilerSet errorformat= + \%-G, + \%-Gerror:\ aborting\ %.%#, + \%-Gerror:\ Could\ not\ compile\ %.%#, + \%Eerror:\ %m, + \%Eerror[E%n]:\ %m, + \%Wwarning:\ %m, + \%Inote:\ %m, + \%C\ %#-->\ %f:%l:%c, + \%E\ \ left:%m,%C\ right:%m\ %f:%l:%c,%Z -let &cpo = s:cpo_save -unlet s:cpo_save +" 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%*[\ ]... + +" vint: -ProhibitAbbreviationOption +let &cpo = s:save_cpo +unlet s:save_cpo +" vint: +ProhibitAbbreviationOption + +" vim: set et sw=4 sts=4 ts=8: diff --git a/pack/acp/start/rust.vim/ctags/rust.ctags b/pack/acp/start/rust.vim/ctags/rust.ctags new file mode 100644 index 0000000..d4f474e --- /dev/null +++ b/pack/acp/start/rust.vim/ctags/rust.ctags @@ -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/ diff --git a/pack/acp/start/rust.vim/doc/rust.txt b/pack/acp/start/rust.vim/doc/rust.txt index 68fc1da..b11d418 100644 --- a/pack/acp/start/rust.vim/doc/rust.txt +++ b/pack/acp/start/rust.vim/doc/rust.txt @@ -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| 2. Settings |rust-settings| @@ -12,7 +12,8 @@ CONTENTS *rust* *ft-rust* INTRODUCTION *rust-intro* 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* @@ -20,6 +21,9 @@ SETTINGS *rust-settings* This plugin has a few variables you can define in your vimrc that change the 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~ 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 < + *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~ 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 : > 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~ Set this option to 1 to prevent 'rustfmt' from populating the @@ -113,6 +148,13 @@ g:rustfmt_options~ defaults to '' : > 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~ @@ -126,10 +168,196 @@ g:rust_shortener_url~ 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* +Invoking Cargo +-------------- + +This plug defines very simple shortcuts for invoking Cargo from with Vim. + +:Cargo *:Cargo* + Runs 'cargo' with the provided arguments. + +:Cbuild *:Cbuild* + Shortcut for 'cargo build`. + +:Cclean *:Cclean* + Shortcut for 'cargo clean`. + +:Cdoc *:Cdoc* + Shortcut for 'cargo doc`. + +:Cinit *:Cinit* + Shortcut for 'cargo init`. + +:Crun *:Crun* + Shortcut for 'cargo run`. + +:Ctest *:Ctest* + Shortcut for 'cargo test`. + +:Cupdate *:Cupdate* + Shortcut for 'cargo update`. + +:Cbench *:Cbench* + Shortcut for 'cargo bench`. + +:Csearch *:Csearch* + Shortcut for 'cargo search`. + +:Cpublish *:Cpublish* + Shortcut for 'cargo publish`. + +:Cinstall *:Cinstall* + Shortcut for 'cargo install`. + +:Cruntarget *: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! [rustc-args] [--] [args] 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. 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 - "https://play.rust-lang.org/". +Running test(s) +--------------- - |g:rust_shortener_url| is the base url for the shorterner, by - default "https://is.gd/" +:RustTest[!] [options] *:RustTest* + 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* - Runs |g:rustfmt_command| on the current buffer. If - |g:rustfmt_options| is set then those will be passed to the - executable. + When ! is given, runs all tests regardless of current cursor + position. - 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|. + When [options] is given, it is passed to "cargo" command + arguments. -:RustFmtRange *:RustFmtRange* - Runs |g:rustfmt_command| with selected range. See - |:RustFmt| for any other information. + When the current buffer is outside cargo project, the command + runs "rustc --test" command instead of "cargo test" as + 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* This plugin defines mappings for |[[| and |]]| to support hanging indents. -It also has a few other mappings: - - *rust_* - Executes |:RustRun| with no arguments. - Note: This binding is only available in MacVim. - - *rust_* - 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: diff --git a/pack/acp/start/rust.vim/ftdetect/rust.vim b/pack/acp/start/rust.vim/ftdetect/rust.vim index bf685d4..d552b96 100644 --- a/pack/acp/start/rust.vim/ftdetect/rust.vim +++ b/pack/acp/start/rust.vim/ftdetect/rust.vim @@ -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: diff --git a/pack/acp/start/rust.vim/ftplugin/rust.vim b/pack/acp/start/rust.vim/ftplugin/rust.vim index 4e3cd4f..adf2d4b 100644 --- a/pack/acp/start/rust.vim/ftplugin/rust.vim +++ b/pack/acp/start/rust.vim/ftplugin/rust.vim @@ -1,19 +1,27 @@ " Language: Rust -" Description: Vim syntax file for Rust +" Description: Vim ftplugin for Rust " Maintainer: Chris Morgan " Maintainer: Kevin Ballard " Last Change: June 08, 2016 +" For bugs, patches and license go to https://github.com/rust-lang/rust.vim if exists("b:did_ftplugin") - finish + finish endif let b:did_ftplugin = 1 +" vint: -ProhibitAbbreviationOption let s:save_cpo = &cpo set cpo&vim +" vint: +ProhibitAbbreviationOption -augroup rust.vim -autocmd! +if get(b:, 'current_compiler', '') ==# '' + if strlen(findfile('Cargo.toml', '.;')) > 0 + compiler cargo + else + compiler rustc + endif +endif " Variables {{{1 @@ -21,13 +29,13 @@ autocmd! " 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 " leader), merely whether a leader is inserted by default or not. -if exists("g:rust_bang_comment_leader") && g:rust_bang_comment_leader != 0 - " 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 - " leaders. I'm fairly sure that's a Vim bug. - setlocal comments=s1:/*,mb:*,ex:*/,s0:/*,mb:\ ,ex:*/,:///,://!,:// +if get(g:, 'rust_bang_comment_leader', 0) + " 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 + " leaders. I'm fairly sure that's a Vim bug. + setlocal comments=s1:/*,mb:*,ex:*/,s0:/*,mb:\ ,ex:*/,:///,://!,:// else - setlocal comments=s0:/*!,m:\ ,ex:*/,s1:/*,mb:*,ex:*/,:///,://!,:// + setlocal comments=s0:/*!,m:\ ,ex:*/,s1:/*,mb:*,ex:*/,:///,://!,:// endif setlocal commentstring=//%s setlocal formatoptions-=t formatoptions+=croqnl @@ -38,13 +46,14 @@ silent! setlocal formatoptions+=j " otherwise it's better than nothing. setlocal smartindent nocindent -if !exists("g:rust_recommended_style") || g:rust_recommended_style != 0 - setlocal tabstop=4 shiftwidth=4 softtabstop=4 expandtab - setlocal textwidth=99 +if get(g:, 'rust_recommended_style', 1) + let b:rust_set_style = 1 + setlocal tabstop=8 shiftwidth=4 softtabstop=4 expandtab + setlocal textwidth=99 endif -" This includeexpr isn't perfect, but it's a good start -setlocal includeexpr=substitute(v:fname,'::','/','g') +setlocal include=\\v^\\s*(pub\\s+)?use\\s+\\zs(\\f\|:)+ +setlocal includeexpr=rust#IncludeExpr(v:fname) setlocal suffixesadd=.rs @@ -53,51 +62,36 @@ if exists("g:ftplugin_rust_source_path") endif if exists("g:loaded_delimitMate") - if exists("b:delimitMate_excluded_regions") - let b:rust_original_delimitMate_excluded_regions = b:delimitMate_excluded_regions - endif + if exists("b:delimitMate_excluded_regions") + let b:rust_original_delimitMate_excluded_regions = b:delimitMate_excluded_regions + endif - let s:delimitMate_extra_excluded_regions = ',rustLifetimeCandidate,rustGenericLifetimeCandidate' + augroup rust.vim.DelimitMate + autocmd! - " 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. - autocmd User - \ if expand('') ==# '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 - \ if expand('') ==# 'delimitMate_unmap' - \| let b:delimitMate_excluded_regions = substitute( - \ delimitMate#Get("excluded_regions"), - \ '\C\V' . s:delimitMate_extra_excluded_regions, - \ '', 'g') - \|endif + autocmd User delimitMate_map :call rust#delimitmate#onMap() + autocmd User delimitMate_unmap :call rust#delimitmate#onUnmap() + augroup END endif -if has("folding") && exists('g:rust_fold') && g:rust_fold != 0 - let b:rust_set_foldmethod=1 - setlocal foldmethod=syntax - if g:rust_fold == 2 - setlocal foldlevel< - else - setlocal foldlevel=99 - endif +" Integration with auto-pairs (https://github.com/jiangmiao/auto-pairs) +if exists("g:AutoPairsLoaded") && !get(g:, 'rust_keep_autopairs_default', 0) + let b:AutoPairs = {'(':')', '[':']', '{':'}','"':'"', '`':'`'} endif -if has('conceal') && exists('g:rust_conceal') && g:rust_conceal != 0 - let b:rust_set_conceallevel=1 - setlocal conceallevel=2 +if has("folding") && get(g:, 'rust_fold', 0) + let b:rust_set_foldmethod=1 + 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 " Motion Commands {{{1 @@ -133,75 +127,75 @@ command! -buffer RustFmt call rustfmt#Format() " See |:RustFmtRange| for docs command! -range -buffer RustFmtRange call rustfmt#FormatRange(, ) -" Mappings {{{1 +" See |:RustInfo| for docs +command! -bar RustInfo call rust#debugging#Info() -" Bind ⌘R in MacVim to :RustRun -nnoremap :RustRun -" Bind ⌘⇧R in MacVim to :RustRun! pre-filled with the last args -nnoremap :RustRun! =join(b:rust_last_rustc_args)erust#AppendCmdLine(' -- ' . join(b:rust_last_args)) +" See |:RustInfoToClipboard| for docs +command! -bar RustInfoToClipboard call rust#debugging#InfoToClipboard() + +" See |:RustInfoToFile| for docs +command! -bar -nargs=1 RustInfoToFile call rust#debugging#InfoToFile() + +" See |:RustTest| for docs +command! -buffer -nargs=* -bang RustTest call rust#Test(0, ) if !exists("b:rust_last_rustc_args") || !exists("b:rust_last_args") - let b:rust_last_rustc_args = [] - let b:rust_last_args = [] + let b:rust_last_rustc_args = [] + let b:rust_last_args = [] endif " Cleanup {{{1 let b:undo_ftplugin = " - \ setlocal formatoptions< comments< commentstring< includeexpr< suffixesadd< - \|setlocal tabstop< shiftwidth< softtabstop< expandtab< textwidth< - \|if exists('b:rust_original_delimitMate_excluded_regions') - \|let b:delimitMate_excluded_regions = b:rust_original_delimitMate_excluded_regions - \|unlet b:rust_original_delimitMate_excluded_regions - \|else - \|unlet! b:delimitMate_excluded_regions - \|endif - \|if exists('b:rust_set_foldmethod') - \|setlocal foldmethod< foldlevel< - \|unlet b:rust_set_foldmethod - \|endif - \|if exists('b:rust_set_conceallevel') - \|setlocal conceallevel< - \|unlet b:rust_set_conceallevel - \|endif - \|unlet! b:rust_last_rustc_args b:rust_last_args - \|delcommand RustRun - \|delcommand RustExpand - \|delcommand RustEmitIr - \|delcommand RustEmitAsm - \|delcommand RustPlay - \|nunmap - \|nunmap - \|nunmap [[ - \|nunmap ]] - \|xunmap [[ - \|xunmap ]] - \|ounmap [[ - \|ounmap ]] - \|set matchpairs-=<:> - \|unlet b:match_skip - \" + \ setlocal formatoptions< comments< commentstring< include< includeexpr< suffixesadd< + \|if exists('b:rust_set_style') + \|setlocal tabstop< shiftwidth< softtabstop< expandtab< textwidth< + \|endif + \|if exists('b:rust_original_delimitMate_excluded_regions') + \|let b:delimitMate_excluded_regions = b:rust_original_delimitMate_excluded_regions + \|unlet b:rust_original_delimitMate_excluded_regions + \|else + \|unlet! b:delimitMate_excluded_regions + \|endif + \|if exists('b:rust_set_foldmethod') + \|setlocal foldmethod< foldlevel< + \|unlet b:rust_set_foldmethod + \|endif + \|if exists('b:rust_set_conceallevel') + \|setlocal conceallevel< + \|unlet b:rust_set_conceallevel + \|endif + \|unlet! b:rust_last_rustc_args b:rust_last_args + \|delcommand RustRun + \|delcommand RustExpand + \|delcommand RustEmitIr + \|delcommand RustEmitAsm + \|delcommand RustPlay + \|nunmap [[ + \|nunmap ]] + \|xunmap [[ + \|xunmap ]] + \|ounmap [[ + \|ounmap ]] + \|setlocal matchpairs-=<:> + \|unlet b:match_skip + \" " }}}1 " Code formatting on save -if get(g:, "rustfmt_autosave", 0) - autocmd BufWritePre *.rs silent! call rustfmt#Format() -endif - +augroup rust.vim.PreWrite + autocmd! + autocmd BufWritePre *.rs silent! call rustfmt#PreWrite() augroup END -" %-matching. <:> is handy for generics. -set matchpairs+=<:> -" 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. +setlocal matchpairs+=<:> +" For matchit.vim (rustArrow stops `Fn() -> X` messing things up) let b:match_skip = 's:comment\|string\|rustArrow' -source $VIMRUNTIME/macros/matchit.vim +" vint: -ProhibitAbbreviationOption let &cpo = 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: diff --git a/pack/acp/start/rust.vim/ftplugin/rust/tagbar.vim b/pack/acp/start/rust.vim/ftplugin/rust/tagbar.vim new file mode 100644 index 0000000..9cb1b48 --- /dev/null +++ b/pack/acp/start/rust.vim/ftplugin/rust/tagbar.vim @@ -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(':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: diff --git a/pack/acp/start/rust.vim/indent/rust.vim b/pack/acp/start/rust.vim/indent/rust.vim index 774133d..91192c3 100644 --- a/pack/acp/start/rust.vim/indent/rust.vim +++ b/pack/acp/start/rust.vim/indent/rust.vim @@ -1,19 +1,20 @@ " Vim indent file " Language: Rust " Author: Chris Morgan -" 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. if exists("b:did_indent") - finish + finish endif let b:did_indent = 1 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] " 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 setlocal nolisp " Make sure lisp indenting doesn't supersede us @@ -25,182 +26,194 @@ setlocal indentexpr=GetRustIndent(v:lnum) " Only define the function once. if exists("*GetRustIndent") - finish + finish endif +" vint: -ProhibitAbbreviationOption +let s:save_cpo = &cpo +set cpo&vim +" vint: +ProhibitAbbreviationOption + " Come here when loading the script the first time. function! s:get_line_trimmed(lnum) - " Get the line and remove a trailing comment. - " Use syntax highlighting attributes when possible. - " NOTE: this is not accurate; /* */ or a line continuation could trick it - let line = getline(a:lnum) - let line_len = strlen(line) - if has('syntax_items') - " 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 - " too long on a long line. - if synIDattr(synID(a:lnum, line_len, 1), "name") =~ 'Comment\|Todo' - let min = 1 - let max = line_len - while min < max - let col = (min + max) / 2 - if synIDattr(synID(a:lnum, col, 1), "name") =~ 'Comment\|Todo' - let max = col - else - let min = col + 1 - endif - endwhile - let line = strpart(line, 0, min - 1) - endif - return substitute(line, "\s*$", "", "") - else - " Sorry, this is not complete, nor fully correct (e.g. string "//"). - " Such is life. - return substitute(line, "\s*//.*$", "", "") - endif + " Get the line and remove a trailing comment. + " Use syntax highlighting attributes when possible. + " NOTE: this is not accurate; /* */ or a line continuation could trick it + let line = getline(a:lnum) + let line_len = strlen(line) + if has('syntax_items') + " 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 + " too long on a long line. + if synIDattr(synID(a:lnum, line_len, 1), "name") =~? 'Comment\|Todo' + let min = 1 + let max = line_len + while min < max + let col = (min + max) / 2 + if synIDattr(synID(a:lnum, col, 1), "name") =~? 'Comment\|Todo' + let max = col + else + let min = col + 1 + endif + endwhile + let line = strpart(line, 0, min - 1) + endif + return substitute(line, "\s*$", "", "") + else + " Sorry, this is not complete, nor fully correct (e.g. string "//"). + " Such is life. + return substitute(line, "\s*//.*$", "", "") + endif endfunction function! s:is_string_comment(lnum, col) - if has('syntax_items') - for id in synstack(a:lnum, a:col) - let synname = synIDattr(id, "name") - if synname == "rustString" || synname =~ "^rustComment" - return 1 - endif - endfor - else - " without syntax, let's not even try - return 0 - endif + if has('syntax_items') + for id in synstack(a:lnum, a:col) + let synname = synIDattr(id, "name") + if synname ==# "rustString" || synname =~# "^rustComment" + return 1 + endif + endfor + else + " without syntax, let's not even try + return 0 + endif endfunction function GetRustIndent(lnum) - " Starting assumption: cindent (called at the end) will do it right - " normally. We just want to fix up a few cases. + " Starting assumption: cindent (called at the end) will do it right + " normally. We just want to fix up a few cases. - let line = getline(a:lnum) + let line = getline(a:lnum) - if has('syntax_items') - let synname = synIDattr(synID(a:lnum, 1, 1), "name") - if synname == "rustString" - " If the start of the line is in a string, don't change the indent - return -1 - elseif synname =~ '\(Comment\|Todo\)' - \ && line !~ '^\s*/\*' " not /* opening line - if synname =~ "CommentML" " multi-line - if line !~ '^\s*\*' && getline(a:lnum - 1) =~ '^\s*/\*' - " This is (hopefully) the line after a /*, and it has no - " leader, so the correct indentation is that of the - " previous line. - return GetRustIndent(a:lnum - 1) - endif - endif - " 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 - " "* " as the code below would otherwise cause for module scope - " Fun fact: " /*\n*\n*/" takes two calls to get right! - return cindent(a:lnum) - endif - endif + if has('syntax_items') + let synname = synIDattr(synID(a:lnum, 1, 1), "name") + if synname ==# "rustString" + " If the start of the line is in a string, don't change the indent + return -1 + elseif synname =~? '\(Comment\|Todo\)' + \ && line !~# '^\s*/\*' " not /* opening line + if synname =~? "CommentML" " multi-line + if line !~# '^\s*\*' && getline(a:lnum - 1) =~# '^\s*/\*' + " This is (hopefully) the line after a /*, and it has no + " leader, so the correct indentation is that of the + " previous line. + return GetRustIndent(a:lnum - 1) + endif + endif + " 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 + " "* " as the code below would otherwise cause for module scope + " Fun fact: " /*\n*\n*/" takes two calls to get right! + return cindent(a:lnum) + endif + endif - " cindent gets second and subsequent match patterns/struct members wrong, - " as it treats the comma as indicating an unfinished statement:: - " - " match a { - " b => c, - " d => e, - " f => g, - " }; + " cindent gets second and subsequent match patterns/struct members wrong, + " as it treats the comma as indicating an unfinished statement:: + " + " match a { + " b => c, + " d => e, + " f => g, + " }; - " Search backwards for the previous non-empty line. - let prevlinenum = prevnonblank(a:lnum - 1) - let prevline = s:get_line_trimmed(prevlinenum) - while prevlinenum > 1 && prevline !~ '[^[:blank:]]' - let prevlinenum = prevnonblank(prevlinenum - 1) - let prevline = s:get_line_trimmed(prevlinenum) - endwhile + " Search backwards for the previous non-empty line. + let prevlinenum = prevnonblank(a:lnum - 1) + let prevline = s:get_line_trimmed(prevlinenum) + while prevlinenum > 1 && prevline !~# '[^[:blank:]]' + let prevlinenum = prevnonblank(prevlinenum - 1) + let prevline = s:get_line_trimmed(prevlinenum) + endwhile - " Handle where clauses nicely: subsequent values should line up nicely. - if prevline[len(prevline) - 1] == "," - \ && prevline =~# '^\s*where\s' - return indent(prevlinenum) + 6 - endif + " Handle where clauses nicely: subsequent values should line up nicely. + if prevline[len(prevline) - 1] ==# "," + \ && prevline =~# '^\s*where\s' + return indent(prevlinenum) + 6 + endif - if prevline[len(prevline) - 1] == "," - \ && s:get_line_trimmed(a:lnum) !~ '^\s*[\[\]{}]' - \ && prevline !~ '^\s*fn\s' - \ && prevline !~ '([^()]\+,$' - \ && s:get_line_trimmed(a:lnum) !~ '^\s*\S\+\s*=>' - " 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 - " indent. + if prevline[len(prevline) - 1] ==# "," + \ && s:get_line_trimmed(a:lnum) !~# '^\s*[\[\]{}]' + \ && prevline !~# '^\s*fn\s' + \ && prevline !~# '([^()]\+,$' + \ && s:get_line_trimmed(a:lnum) !~# '^\s*\S\+\s*=>' + " 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 + " indent. - " 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 - " further. - " - " Another case where we don't want to is one like a function - " definition with arguments spread over multiple lines: - " - " fn foo(baz: Baz, - " baz: Baz) // <-- cindent gets this right by itself - " - " Another case is similar to the previous, except calling a function - " instead of defining it, or any conditional expression that leaves - " an open paren: - " - " foo(baz, - " baz); - " - " if baz && (foo || - " bar) { - " - " 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 - " well. Add them as needed. - return indent(prevlinenum) - endif + " 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 + " further. + " + " Another case where we don't want to is one like a function + " definition with arguments spread over multiple lines: + " + " fn foo(baz: Baz, + " baz: Baz) // <-- cindent gets this right by itself + " + " Another case is similar to the previous, except calling a function + " instead of defining it, or any conditional expression that leaves + " an open paren: + " + " foo(baz, + " baz); + " + " if baz && (foo || + " bar) { + " + " 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 + " well. Add them as needed. + return indent(prevlinenum) + endif - if !has("patch-7.4.355") - " cindent before 7.4.355 doesn't do the module scope well at all; e.g.:: - " - " static FOO : &'static [bool] = [ - " true, - " false, - " false, - " true, - " ]; - " - " uh oh, next statement is indented further! + if !has("patch-7.4.355") + " cindent before 7.4.355 doesn't do the module scope well at all; e.g.:: + " + " static FOO : &'static [bool] = [ + " true, + " false, + " false, + " true, + " ]; + " + " uh oh, next statement is indented further! - " 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 - " start with these two main cases (square brackets and not returning to - " column zero) + " 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 + " start with these two main cases (square brackets and not returning to + " column zero) - call cursor(a:lnum, 1) - if searchpair('{\|(', '', '}\|)', 'nbW', - \ 's:is_string_comment(line("."), col("."))') == 0 - if searchpair('\[', '', '\]', 'nbW', - \ 's:is_string_comment(line("."), col("."))') == 0 - " Global scope, should be zero - return 0 - else - " At the module scope, inside square brackets only - "if getline(a:lnum)[0] == ']' || search('\[', '', '\]', 'nW') == a:lnum - if line =~ "^\\s*]" - " It's the closing line, dedent it - return 0 - else - return &shiftwidth - endif - endif - endif - endif + call cursor(a:lnum, 1) + if searchpair('{\|(', '', '}\|)', 'nbW', + \ 's:is_string_comment(line("."), col("."))') == 0 + if searchpair('\[', '', '\]', 'nbW', + \ 's:is_string_comment(line("."), col("."))') == 0 + " Global scope, should be zero + return 0 + else + " At the module scope, inside square brackets only + "if getline(a:lnum)[0] == ']' || search('\[', '', '\]', 'nW') == a:lnum + if line =~# "^\\s*]" + " It's the closing line, dedent it + return 0 + else + return &shiftwidth + endif + endif + endif + endif - " Fall back on cindent, which does it mostly right - return cindent(a:lnum) + " Fall back on cindent, which does it mostly right + return cindent(a:lnum) endfunction + +" vint: -ProhibitAbbreviationOption +let &cpo = s:save_cpo +unlet s:save_cpo +" vint: +ProhibitAbbreviationOption + +" vim: set et sw=4 sts=4 ts=8: diff --git a/pack/acp/start/rust.vim/plugin/cargo.vim b/pack/acp/start/rust.vim/plugin/cargo.vim new file mode 100644 index 0000000..5cd413c --- /dev/null +++ b/pack/acp/start/rust.vim/plugin/cargo.vim @@ -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() +command! -nargs=* Cbuild call cargo#build() +command! -nargs=* Cclean call cargo#clean() +command! -nargs=* Cdoc call cargo#doc() +command! -nargs=+ Cnew call cargo#new() +command! -nargs=* Cinit call cargo#init() +command! -nargs=* Crun call cargo#run() +command! -nargs=* Ctest call cargo#test() +command! -nargs=* Cbench call cargo#bench() +command! -nargs=* Cupdate call cargo#update() +command! -nargs=* Csearch call cargo#search() +command! -nargs=* Cpublish call cargo#publish() +command! -nargs=* Cinstall call cargo#install() +command! -nargs=* Cruntarget call cargo#runtarget() + +let &cpoptions = s:save_cpo +unlet s:save_cpo + +" vim: set et sw=4 sts=4 ts=8: diff --git a/pack/acp/start/rust.vim/plugin/rust.vim b/pack/acp/start/rust.vim/plugin/rust.vim index 4ec4f33..5fe77cc 100644 --- a/pack/acp/start/rust.vim/plugin/rust.vim +++ b/pack/acp/start/rust.vim/plugin/rust.vim @@ -2,12 +2,12 @@ " Language: Rust " Maintainer: Andrew Gallant -if exists("g:loaded_syntastic_rust_filetype") - finish +if exists('g:loaded_rust_vim') + finish endif -let g:loaded_syntastic_rust_filetype = 1 -let s:save_cpo = &cpo -set cpo&vim +let g:loaded_rust_vim = 1 +let s:save_cpo = &cpoptions +set cpoptions&vim " This is to let Syntastic know about the Rust filetype. " It enables tab completion for the 'SyntasticInfo' command. @@ -18,5 +18,11 @@ else let g:syntastic_extra_filetypes = ['rust'] 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 + +" vim: set et sw=4 sts=4 ts=8: diff --git a/pack/acp/start/rust.vim/syntax/rust.vim b/pack/acp/start/rust.vim/syntax/rust.vim index 8c73462..4a419f4 100644 --- a/pack/acp/start/rust.vim/syntax/rust.vim +++ b/pack/acp/start/rust.vim/syntax/rust.vim @@ -4,11 +4,12 @@ " Maintainer: Ben Blum " Maintainer: Chris Morgan " Last Change: Feb 24, 2016 +" For bugs, patches and license go to https://github.com/rust-lang/rust.vim if version < 600 - syntax clear + syntax clear elseif exists("b:current_syntax") - finish + finish endif " 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 match rustUnionContextual /\/ -syn keyword rustInvalidBareKeyword crate - syn keyword rustPubScopeCrate crate contained syn match rustPubScopeDelim /[()]/ contained syn match rustPubScope /([^()]*)/ contained contains=rustPubScopeDelim,rustPubScopeCrate,rustSuper,rustModPath,rustModPathSep,rustSelf transparent @@ -66,7 +72,7 @@ syn match rustMacroRepeatCount ".\?[*+]" contained syn match rustMacroVariable "$\w\+" " 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 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 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 region rustString start=+b"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeError,rustStringContinuation 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). 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 "\/ contains=rustGenericLifetimeCandidate +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 rustGenericLifetimeCandidate display start=/\%(<\|,\s*\)\@<='/ end=/[[:cntrl:][:space:][:punct:]]\@=\|$/ contains=rustSigil,rustLifetime "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). 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 /'\([^\\]\|\\\(.\|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 region rustCommentLine start="//" end="$" contains=rustTodo,@Spell syn region rustCommentLineDoc start="//\%(//\@!\|!\)" end="$" contains=rustTodo,@Spell syn region rustCommentLineDocError start="//\%(//\@!\|!\)" end="$" contains=rustTodo,@Spell contained 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 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 rustCommentBlockDocNestError matchgroup=rustCommentBlockDocError start="/\*" end="\*/" contains=rustTodo,rustCommentBlockDocNestError,@Spell contained transparent + " FIXME: this is a really ugly and not fully correct implementation. Most " importantly, a case like ``/* */*`` should have the final ``*`` not being in " 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 syn region rustFoldBraces start="{" end="}" transparent fold +if !exists("b:current_syntax_embed") + let b:current_syntax_embed = 1 + syntax include @RustCodeInComment :p:h/rust.vim + unlet b:current_syntax_embed + + " Currently regions marked as ``` 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 rust’s src/librustdoc/html/markdown.rs, so that + " we only highlight as Rust what it would perceive as Rust (almost; it’s + " possible to trick it if you try hard, and indented code blocks aren’t + " 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 don’t care. Balance of probability, and all that. + syn match rustCommentBlockDocStar /^\s*\*\s\?/ contained + syn match rustCommentLineDocLeader "^\s*//\%(//\@!\|!\)" contained +endif + " Default highlighting {{{1 hi def link rustDecNumber rustNumber hi def link rustHexNumber rustNumber @@ -240,12 +290,15 @@ hi def link rustFloat Float hi def link rustArrowCharacter rustOperator hi def link rustOperator Operator 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 rustStructure Keyword " More precise is Structure hi def link rustUnion rustStructure +hi def link rustExistential rustKeyword hi def link rustPubScopeDelim Delimiter hi def link rustPubScopeCrate rustKeyword hi def link rustSuper rustKeyword +hi def link rustUnsafeKeyword Exception hi def link rustReservedKeyword Error hi def link rustRepeat Conditional hi def link rustConditional Conditional @@ -259,10 +312,13 @@ hi def link rustFuncCall Function hi def link rustShebang Comment hi def link rustCommentLine Comment hi def link rustCommentLineDoc SpecialComment +hi def link rustCommentLineDocLeader rustCommentLineDoc hi def link rustCommentLineDocError Error hi def link rustCommentBlock rustCommentLine hi def link rustCommentBlockDoc rustCommentLineDoc +hi def link rustCommentBlockDocStar rustCommentBlockDoc hi def link rustCommentBlockDocError Error +hi def link rustCommentDocCodeFence rustCommentLineDoc hi def link rustAssert PreCondit hi def link rustPanic PreCondit hi def link rustMacro Macro @@ -275,7 +331,6 @@ hi def link rustStorage StorageClass hi def link rustObsoleteStorage Error hi def link rustLifetime Special hi def link rustLabel Label -hi def link rustInvalidBareKeyword Error hi def link rustExternCrate rustKeyword hi def link rustObsoleteExternMod Error hi def link rustBoxPlacementParens Delimiter @@ -292,3 +347,5 @@ syn sync minlines=200 syn sync maxlines=500 let b:current_syntax = "rust" + +" vim: set et sw=4 sts=4 ts=8: diff --git a/pack/acp/start/rust.vim/syntax_checkers/rust/cargo.vim b/pack/acp/start/rust.vim/syntax_checkers/rust/cargo.vim new file mode 100644 index 0000000..f7b6953 --- /dev/null +++ b/pack/acp/start/rust.vim/syntax_checkers/rust/cargo.vim @@ -0,0 +1,93 @@ +" Vim syntastic plugin +" Language: Rust +" Maintainer: Julien Levesy +" +" 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: diff --git a/pack/acp/start/rust.vim/syntax_checkers/rust/rustc.vim b/pack/acp/start/rust.vim/syntax_checkers/rust/rustc.vim index 006e715..d60a3d3 100644 --- a/pack/acp/start/rust.vim/syntax_checkers/rust/rustc.vim +++ b/pack/acp/start/rust.vim/syntax_checkers/rust/rustc.vim @@ -10,39 +10,45 @@ if exists("g:loaded_syntastic_rust_rustc_checker") endif let g:loaded_syntastic_rust_rustc_checker = 1 +" vint: -ProhibitAbbreviationOption let s:save_cpo = &cpo set cpo&vim +" vint: +ProhibitAbbreviationOption function! SyntaxCheckers_rust_rustc_GetLocList() dict let makeprg = self.makeprgBuild({}) " Old errorformat (before nightly 2016/08/10) let errorformat = - \ '%E%f:%l:%c: %\d%#:%\d%# %.%\{-}error:%.%\{-} %m,' . - \ '%W%f:%l:%c: %\d%#:%\d%# %.%\{-}warning:%.%\{-} %m,' . - \ '%C%f:%l %m' - + \ '%E%f:%l:%c: %\d%#:%\d%# %.%\{-}error:%.%\{-} %m,' . + \ '%W%f:%l:%c: %\d%#:%\d%# %.%\{-}warning:%.%\{-} %m,' . + \ '%C%f:%l %m' + " New errorformat (after nightly 2016/08/10) let errorformat .= - \ ',' . - \ '%-G,' . - \ '%-Gerror: aborting %.%#,' . - \ '%-Gerror: Could not compile %.%#,' . - \ '%Eerror: %m,' . - \ '%Eerror[E%n]: %m,' . - \ '%-Gwarning: the option `Z` is unstable %.%#,' . - \ '%Wwarning: %m,' . - \ '%Inote: %m,' . - \ '%C %#--> %f:%l:%c' + \ ',' . + \ '%-G,' . + \ '%-Gerror: aborting %.%#,' . + \ '%-Gerror: Could not compile %.%#,' . + \ '%Eerror: %m,' . + \ '%Eerror[E%n]: %m,' . + \ '%-Gwarning: the option `Z` is unstable %.%#,' . + \ '%Wwarning: %m,' . + \ '%Inote: %m,' . + \ '%C %#--> %f:%l:%c' return SyntasticMake({ - \ 'makeprg': makeprg, - \ 'errorformat': errorformat }) + \ 'makeprg': makeprg, + \ 'errorformat': errorformat }) endfunction call g:SyntasticRegistry.CreateAndRegisterChecker({ - \ 'filetype': 'rust', - \ 'name': 'rustc'}) + \ 'filetype': 'rust', + \ 'name': 'rustc'}) +" vint: -ProhibitAbbreviationOption let &cpo = s:save_cpo unlet s:save_cpo +" vint: +ProhibitAbbreviationOption + +" vim: set et sw=4 sts=4 ts=8: diff --git a/pack/acp/start/rust.vim/test/.gitignore b/pack/acp/start/rust.vim/test/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/pack/acp/start/rust.vim/test/Dockerfile b/pack/acp/start/rust.vim/test/Dockerfile new file mode 100644 index 0000000..c84c49e --- /dev/null +++ b/pack/acp/start/rust.vim/test/Dockerfile @@ -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 diff --git a/pack/acp/start/rust.vim/test/coverage.vader b/pack/acp/start/rust.vim/test/coverage.vader new file mode 100644 index 0000000..84734e7 --- /dev/null +++ b/pack/acp/start/rust.vim/test/coverage.vader @@ -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 + AssertEqual 1,(@" =~# '\V.section') + bd + call delete('test.rs') + +# TODO: a lot more tests diff --git a/pack/acp/start/rust.vim/test/run-tests b/pack/acp/start/rust.vim/test/run-tests new file mode 100644 index 0000000..a8c63b6 --- /dev/null +++ b/pack/acp/start/rust.vim/test/run-tests @@ -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() diff --git a/pack/acp/start/rust.vim/test/sample.rs b/pack/acp/start/rust.vim/test/sample.rs new file mode 100644 index 0000000..e69de29 diff --git a/pack/acp/start/rust.vim/test/vimrc b/pack/acp/start/rust.vim/test/vimrc new file mode 100644 index 0000000..f7f1533 --- /dev/null +++ b/pack/acp/start/rust.vim/test/vimrc @@ -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