From c012f55efda29f09179e921cf148d79deb57616e Mon Sep 17 00:00:00 2001 From: Nick Shipp Date: Sun, 7 May 2017 09:04:01 -0400 Subject: Much maturering of vim configs --- vim/bundle/rust.vim/.gitignore | 1 + vim/bundle/rust.vim/LICENSE-APACHE | 201 ++++++++++ vim/bundle/rust.vim/LICENSE-MIT | 25 ++ vim/bundle/rust.vim/README.md | 87 +++++ vim/bundle/rust.vim/after/syntax/rust.vim | 34 ++ vim/bundle/rust.vim/autoload/rust.vim | 414 +++++++++++++++++++++ vim/bundle/rust.vim/autoload/rustfmt.vim | 106 ++++++ vim/bundle/rust.vim/compiler/cargo.vim | 28 ++ vim/bundle/rust.vim/compiler/rustc.vim | 45 +++ vim/bundle/rust.vim/doc/rust.txt | 237 ++++++++++++ vim/bundle/rust.vim/ftdetect/rust.vim | 1 + vim/bundle/rust.vim/ftplugin/rust.vim | 207 +++++++++++ vim/bundle/rust.vim/indent/rust.vim | 206 ++++++++++ vim/bundle/rust.vim/plugin/rust.vim | 22 ++ vim/bundle/rust.vim/syntax/rust.vim | 294 +++++++++++++++ vim/bundle/rust.vim/syntax_checkers/rust/rustc.vim | 48 +++ 16 files changed, 1956 insertions(+) create mode 100644 vim/bundle/rust.vim/.gitignore create mode 100644 vim/bundle/rust.vim/LICENSE-APACHE create mode 100644 vim/bundle/rust.vim/LICENSE-MIT create mode 100644 vim/bundle/rust.vim/README.md create mode 100644 vim/bundle/rust.vim/after/syntax/rust.vim create mode 100644 vim/bundle/rust.vim/autoload/rust.vim create mode 100644 vim/bundle/rust.vim/autoload/rustfmt.vim create mode 100644 vim/bundle/rust.vim/compiler/cargo.vim create mode 100644 vim/bundle/rust.vim/compiler/rustc.vim create mode 100644 vim/bundle/rust.vim/doc/rust.txt create mode 100644 vim/bundle/rust.vim/ftdetect/rust.vim create mode 100644 vim/bundle/rust.vim/ftplugin/rust.vim create mode 100644 vim/bundle/rust.vim/indent/rust.vim create mode 100644 vim/bundle/rust.vim/plugin/rust.vim create mode 100644 vim/bundle/rust.vim/syntax/rust.vim create mode 100644 vim/bundle/rust.vim/syntax_checkers/rust/rustc.vim (limited to 'vim/bundle/rust.vim') diff --git a/vim/bundle/rust.vim/.gitignore b/vim/bundle/rust.vim/.gitignore new file mode 100644 index 0000000..0a56e3f --- /dev/null +++ b/vim/bundle/rust.vim/.gitignore @@ -0,0 +1 @@ +/doc/tags diff --git a/vim/bundle/rust.vim/LICENSE-APACHE b/vim/bundle/rust.vim/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/vim/bundle/rust.vim/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vim/bundle/rust.vim/LICENSE-MIT b/vim/bundle/rust.vim/LICENSE-MIT new file mode 100644 index 0000000..e69282e --- /dev/null +++ b/vim/bundle/rust.vim/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2015 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vim/bundle/rust.vim/README.md b/vim/bundle/rust.vim/README.md new file mode 100644 index 0000000..9fe8968 --- /dev/null +++ b/vim/bundle/rust.vim/README.md @@ -0,0 +1,87 @@ +# rust.vim + +## Description + +This is a Vim plugin that provides [Rust][r] file detection, syntax highlighting, formatting, +[Syntastic][syn] integration, and more. + +## Installation + +### Using [Vundle][v] + +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 +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` + +## 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. + +### Formatting with [rustfmt][rfmt] + +The `:RustFmt` command will format your code with +[rustfmt][rfmt] if installed. + +Placing `let g:rustfmt_autosave = 1` in your `~/.vimrc` will +enable automatic running of `:RustFmt` when you save a buffer. + +Do `:help :RustFmt` for further formatting help and customization +options. + +### [Playpen][pp] integration + +*Note:* This feature requires [webapi-vim][wav] to be installed. + +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/ + +## Help + +Further help can be found in the documentation with `:Helptags` then `:help rust`. + +Detailed help can be found in the documentation with `:help rust`. +Helptags (`:help helptags`) need to be generated for this plugin +in order to navigate the help. Most plugin managers will do this +automatically, but check their documentation if that is not the case. + +## License + +Like Rust, rust.vim is primarily distributed under the terms of both the MIT +license and the Apache License (Version 2.0). See LICENSE-APACHE and +LICENSE-MIT for details. + +[r]: https://www.rust-lang.org +[v]: https://github.com/gmarik/vundle +[vqs]: https://github.com/gmarik/vundle#quick-start +[p]: https://github.com/tpope/vim-pathogen +[nb]: https://github.com/Shougo/neobundle.vim +[vp]: https://github.com/junegunn/vim-plug +[rfmt]: https://github.com/rust-lang-nursery/rustfmt +[syn]: https://github.com/scrooloose/syntastic +[wav]: https://github.com/mattn/webapi-vim +[pp]: https://play.rust-lang.org/ diff --git a/vim/bundle/rust.vim/after/syntax/rust.vim b/vim/bundle/rust.vim/after/syntax/rust.vim new file mode 100644 index 0000000..b0f7e62 --- /dev/null +++ b/vim/bundle/rust.vim/after/syntax/rust.vim @@ -0,0 +1,34 @@ +if !exists('g:rust_conceal') || g:rust_conceal == 0 || !has('conceal') || &enc != '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=ㆍ +endif + +syn match rustRightArrowHead contained ">" conceal cchar=  +syn match rustRightArrowTail contained "-" conceal cchar=⟶ +syn match rustNiceOperator "->" contains=rustRightArrowHead,rustRightArrowTail + +syn match rustFatRightArrowHead contained ">" conceal cchar=  +syn match rustFatRightArrowTail contained "=" conceal cchar=⟹ +syn match rustNiceOperator "=>" contains=rustFatRightArrowHead,rustFatRightArrowTail + +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 + syn match rustPublicSigil contained "pu" conceal cchar=* + syn match rustPublicRest contained "b" conceal cchar=  + syn match rustNiceOperator "pub " contains=rustPublicSigil,rustPublicRest +endif + +hi link rustNiceOperator Operator + +if !(exists('g:rust_conceal_mod_path') && g:rust_conceal_mod_path != 0) + hi! link Conceal Operator + + " And keep it after a colorscheme change + au ColorScheme hi! link Conceal Operator +endif diff --git a/vim/bundle/rust.vim/autoload/rust.vim b/vim/bundle/rust.vim/autoload/rust.vim new file mode 100644 index 0000000..477f3c4 --- /dev/null +++ b/vim/bundle/rust.vim/autoload/rust.vim @@ -0,0 +1,414 @@ +" Author: Kevin Ballard +" Description: Helper functions for Rust commands/mappings +" Last Modified: May 27, 2014 + +" 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 +endfunction + +function! s:Jump_Back() + call search('{', 'b') + keepjumps normal! w99[{ +endfunction + +function! s:Jump_Forward() + 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 b:rust_last_rustc_args = l:rustc_args + let b:rust_last_args = l: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 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 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) +endfunction + +function! s:Expand(dict, pretty, args) + 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 +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 + + 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) +endfunction + +function! s:Emit(dict, type, args) + try + let output_path = a:dict.tmpdir.'/output' + + 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 +endfunction + +" Utility functions {{{1 + +" Invokes func(dict, ...) +" Where {dict} is a dictionary with the following keys: +" 'path' - The path to the file +" 'tmpdir' - The path to a temporary directory that will be deleted when the +" function returns. +" 'istemp' - 1 if the path is a file inside of {dict.tmpdir} or 0 otherwise. +" If {istemp} is 1 then an additional key is provided: +" 'tmpdir_relpath' - The {path} relative to the {tmpdir}. +" +" {dict.path} may be a path to a file inside of {dict.tmpdir} or it may be the +" 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) + + " 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 + + let saved.mod = &mod + set nomod + + 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 +endfunction + +function! rust#AppendCmdLine(text) + 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 +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)) +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) +endfunction + +" Playpen Support {{{1 +" Parts of gist.vim by Yasuhiro Matsumoto reused +" 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") +endfunction + +function! rust#Play(count, line1, line2, ...) abort + 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/') + + 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 body = 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 + + 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 + + redraw | echomsg 'Done: '.url +endfunction + +" }}}1 + +" vim: set noet sw=4 ts=4: diff --git a/vim/bundle/rust.vim/autoload/rustfmt.vim b/vim/bundle/rust.vim/autoload/rustfmt.vim new file mode 100644 index 0000000..e5f9830 --- /dev/null +++ b/vim/bundle/rust.vim/autoload/rustfmt.vim @@ -0,0 +1,106 @@ +" Author: Stephen Sugden +" +" Adapted from https://github.com/fatih/vim-go + +if !exists("g:rustfmt_autosave") + let g:rustfmt_autosave = 0 +endif + +if !exists("g:rustfmt_command") + let g:rustfmt_command = "rustfmt" +endif + +if !exists("g:rustfmt_options") + let g:rustfmt_options = "" +endif + +if !exists("g:rustfmt_fail_silently") + let g:rustfmt_fail_silently = 0 +endif + +let s:got_fmt_error = 0 + +function! 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)) +endfunction + +function! s:RustfmtCommand(filename) + return g:rustfmt_command . " --write-mode=overwrite " . g:rustfmt_options . " " . shellescape(a:filename) +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 + + if v:shell_error == 0 || v:shell_error == 3 + " remove undo point caused via BufWritePre + try | silent undojoin | catch | endtry + + " Replace current file with temp file, then reload buffer + call rename(a:tmpname, expand('%')) + silent edit! + let &syntax = &syntax + + " only clear location list if it was previously filled to prevent + " clobbering other additions + if s:got_fmt_error + let s:got_fmt_error = 0 + call setloclist(0, []) + lwindow + endif + elseif g:rustfmt_fail_silently == 0 + " otherwise get the errors and put them in the location list + let errors = [] + + for line in out + " src/lib.rs:13:5: 13:10 error: expected `,`, or `}`, found `value` + let tokens = matchlist(line, '^\(.\{-}\):\(\d\+\):\(\d\+\):\s*\(\d\+:\d\+\s*\)\?\s*error: \(.*\)') + if !empty(tokens) + call add(errors, {"filename": @%, + \"lnum": tokens[2], + \"col": tokens[3], + \"text": tokens[5]}) + endif + endfor + + if empty(errors) + % | " Couldn't detect rustfmt error format, output errors + endif + + if !empty(errors) + call setloclist(0, errors, 'r') + echohl Error | echomsg "rustfmt returned error" | echohl None + endif + + let s:got_fmt_error = 1 + lwindow + " We didn't use the temp file, so clean up + call delete(a:tmpname) + endif + + call winrestview(a:curw) +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) +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) +endfunction diff --git a/vim/bundle/rust.vim/compiler/cargo.vim b/vim/bundle/rust.vim/compiler/cargo.vim new file mode 100644 index 0000000..029c5c7 --- /dev/null +++ b/vim/bundle/rust.vim/compiler/cargo.vim @@ -0,0 +1,28 @@ +" Vim compiler file +" Compiler: Cargo Compiler +" Maintainer: Damien Radtke +" Latest Revision: 2014 Sep 24 + +if exists('current_compiler') + finish +endif +runtime compiler/rustc.vim +let current_compiler = "cargo" + +if exists(':CompilerSet') != 2 + command -nargs=* CompilerSet setlocal +endif + +if exists('g:cargo_makeprg_params') + execute 'CompilerSet makeprg=cargo\ '.escape(g:cargo_makeprg_params, ' \|"').'\ $*' +else + CompilerSet makeprg=cargo\ $* +endif + +" 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\\,%.%# diff --git a/vim/bundle/rust.vim/compiler/rustc.vim b/vim/bundle/rust.vim/compiler/rustc.vim new file mode 100644 index 0000000..ba29133 --- /dev/null +++ b/vim/bundle/rust.vim/compiler/rustc.vim @@ -0,0 +1,45 @@ +" Vim compiler file +" Compiler: Rust Compiler +" Maintainer: Chris Morgan +" Latest Revision: 2013 Jul 12 + +if exists("current_compiler") + finish +endif +let current_compiler = "rustc" + +let s:cpo_save = &cpo +set cpo&vim + +if exists(":CompilerSet") != 2 + command -nargs=* CompilerSet setlocal +endif + +if exists("g:rustc_makeprg_no_percent") && g:rustc_makeprg_no_percent != 0 + CompilerSet makeprg=rustc +else + 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 + +let &cpo = s:cpo_save +unlet s:cpo_save diff --git a/vim/bundle/rust.vim/doc/rust.txt b/vim/bundle/rust.vim/doc/rust.txt new file mode 100644 index 0000000..68fc1da --- /dev/null +++ b/vim/bundle/rust.vim/doc/rust.txt @@ -0,0 +1,237 @@ +*rust.txt* Filetype plugin for Rust + +============================================================================== +CONTENTS *rust* *ft-rust* + +1. Introduction |rust-intro| +2. Settings |rust-settings| +3. Commands |rust-commands| +4. Mappings |rust-mappings| + +============================================================================== +INTRODUCTION *rust-intro* + +This plugin provides syntax and supporting functionality for the Rust +filetype. + +============================================================================== +SETTINGS *rust-settings* + +This plugin has a few variables you can define in your vimrc that change the +behavior of the plugin. + + *g:rustc_path* +g:rustc_path~ + Set this option to the path to rustc for use in the |:RustRun| and + |:RustExpand| commands. If unset, "rustc" will be located in $PATH: > + let g:rustc_path = $HOME."/bin/rustc" +< + + *g:rustc_makeprg_no_percent* +g:rustc_makeprg_no_percent~ + Set this option to 1 to have 'makeprg' default to "rustc" instead of + "rustc %": > + let g:rustc_makeprg_no_percent = 1 +< + + *g:rust_conceal* +g:rust_conceal~ + Set this option to turn on the basic |conceal| support: > + let g:rust_conceal = 1 +< + + *g:rust_conceal_mod_path* +g:rust_conceal_mod_path~ + Set this option to turn on |conceal| for the path connecting token + "::": > + let g:rust_conceal_mod_path = 1 +< + + *g:rust_conceal_pub* +g:rust_conceal_pub~ + Set this option to turn on |conceal| for the "pub" token: > + let g:rust_conceal_pub = 1 +< + + *g:rust_recommended_style* +g:rust_recommended_style~ + Set this option to enable vim indentation and textwidth settings to + conform to style conventions of the rust standard library (i.e. use 4 + spaces for indents and sets 'textwidth' to 99). This option is enabled + by default. To disable it: > + let g:rust_recommended_style = 0 +< + + *g:rust_fold* +g:rust_fold~ + Set this option to turn on |folding|: > + let g:rust_fold = 1 +< + Value Effect ~ + 0 No folding + 1 Braced blocks are folded. All folds are open by + default. + 2 Braced blocks are folded. 'foldlevel' is left at the + global value (all folds are closed by default). + + *g:rust_bang_comment_leader* +g:rust_bang_comment_leader~ + Set this option to 1 to preserve the leader on multi-line doc comments + using the /*! syntax: > + let g:rust_bang_comment_leader = 1 +< + + *g:ftplugin_rust_source_path* +g:ftplugin_rust_source_path~ + Set this option to a path that should be prepended to 'path' for Rust + source files: > + let g:ftplugin_rust_source_path = $HOME.'/dev/rust' +< + + *g:rustfmt_command* +g:rustfmt_command~ + Set this option to the name of the 'rustfmt' executable in your $PATH. If + not specified it defaults to 'rustfmt' : > + let g:rustfmt_command = 'rustfmt' +< + *g:rustfmt_autosave* +g:rustfmt_autosave~ + Set this option to 1 to run |:RustFmt| automatically when saving a + buffer. If not specified it defaults to 0 : > + let g:rustfmt_autosave = 0 +< + *g:rustfmt_fail_silently* +g:rustfmt_fail_silently~ + Set this option to 1 to prevent 'rustfmt' from populating the + |location-list| with errors. If not specified it defaults to 0: > + let g:rustfmt_fail_silently = 0 +< + *g:rustfmt_options* +g:rustfmt_options~ + Set this option to a string of options to pass to 'rustfmt'. The + write-mode is already set to 'overwrite'. If not specified it + defaults to '' : > + let g:rustfmt_options = '' +< + + *g:rust_playpen_url* +g:rust_playpen_url~ + Set this option to override the url for the playpen to use: > + let g:rust_playpen_url = 'https://play.rust-lang.org/' +< + + *g:rust_shortener_url* +g:rust_shortener_url~ + Set this option to override the url for the url shortener: > + let g:rust_shortener_url = 'https://is.gd/' +< + + +============================================================================== +COMMANDS *rust-commands* + +:RustRun [args] *:RustRun* +:RustRun! [rustc-args] [--] [args] + Compiles and runs the current file. If it has unsaved changes, + it will be saved first using |:update|. If the current file is + an unnamed buffer, it will be written to a temporary file + first. The compiled binary is always placed in a temporary + directory, but is run from the current directory. + + The arguments given to |:RustRun| will be passed to the + compiled binary. + + If ! is specified, the arguments are passed to rustc instead. + A "--" argument will separate the rustc arguments from the + arguments passed to the binary. + + If |g:rustc_path| is defined, it is used as the path to rustc. + Otherwise it is assumed rustc can be found in $PATH. + +:RustExpand [args] *:RustExpand* +:RustExpand! [TYPE] [args] + Expands the current file using --pretty and displays the + results in a new split. If the current file has unsaved + changes, it will be saved first using |:update|. If the + current file is an unnamed buffer, it will be written to a + temporary file first. + + The arguments given to |:RustExpand| will be passed to rustc. + This is largely intended for specifying various --cfg + configurations. + + If ! is specified, the first argument is the expansion type to + pass to rustc --pretty. Otherwise it will default to + "expanded". + + If |g:rustc_path| is defined, it is used as the path to rustc. + Otherwise it is assumed rustc can be found in $PATH. + +:RustEmitIr [args] *:RustEmitIr* + Compiles the current file to LLVM IR and displays the results + in a new split. If the current file has unsaved changes, it + will be saved first using |:update|. If the current file is an + unnamed buffer, it will be written to a temporary file first. + + The arguments given to |:RustEmitIr| will be passed to rustc. + + If |g:rustc_path| is defined, it is used as the path to rustc. + Otherwise it is assumed rustc can be found in $PATH. + +:RustEmitAsm [args] *:RustEmitAsm* + Compiles the current file to assembly and displays the results + in a new split. If the current file has unsaved changes, it + will be saved first using |:update|. If the current file is an + unnamed buffer, it will be written to a temporary file first. + + The arguments given to |:RustEmitAsm| will be passed to rustc. + + If |g:rustc_path| is defined, it is used as the path to rustc. + Otherwise it is assumed rustc can be found in $PATH. + +: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/" + +: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. + +============================================================================== +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/vim/bundle/rust.vim/ftdetect/rust.vim b/vim/bundle/rust.vim/ftdetect/rust.vim new file mode 100644 index 0000000..bf685d4 --- /dev/null +++ b/vim/bundle/rust.vim/ftdetect/rust.vim @@ -0,0 +1 @@ +au BufRead,BufNewFile *.rs set filetype=rust diff --git a/vim/bundle/rust.vim/ftplugin/rust.vim b/vim/bundle/rust.vim/ftplugin/rust.vim new file mode 100644 index 0000000..4e3cd4f --- /dev/null +++ b/vim/bundle/rust.vim/ftplugin/rust.vim @@ -0,0 +1,207 @@ +" Language: Rust +" Description: Vim syntax file for Rust +" Maintainer: Chris Morgan +" Maintainer: Kevin Ballard +" Last Change: June 08, 2016 + +if exists("b:did_ftplugin") + finish +endif +let b:did_ftplugin = 1 + +let s:save_cpo = &cpo +set cpo&vim + +augroup rust.vim +autocmd! + +" Variables {{{1 + +" The rust source code at present seems to typically omit a leader on /*! +" 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:*/,:///,://!,:// +else + setlocal comments=s0:/*!,m:\ ,ex:*/,s1:/*,mb:*,ex:*/,:///,://!,:// +endif +setlocal commentstring=//%s +setlocal formatoptions-=t formatoptions+=croqnl +" j was only added in 7.3.541, so stop complaints about its nonexistence +silent! setlocal formatoptions+=j + +" smartindent will be overridden by indentexpr if filetype indent is on, but +" 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 +endif + +" This includeexpr isn't perfect, but it's a good start +setlocal includeexpr=substitute(v:fname,'::','/','g') + +setlocal suffixesadd=.rs + +if exists("g:ftplugin_rust_source_path") + let &l:path=g:ftplugin_rust_source_path . ',' . &l: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 + + 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. + 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 +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 +endif + +if has('conceal') && exists('g:rust_conceal') && g:rust_conceal != 0 + let b:rust_set_conceallevel=1 + setlocal conceallevel=2 +endif + +" Motion Commands {{{1 + +" Bind motion commands to support hanging indents +nnoremap [[ :call rust#Jump('n', 'Back') +nnoremap ]] :call rust#Jump('n', 'Forward') +xnoremap [[ :call rust#Jump('v', 'Back') +xnoremap ]] :call rust#Jump('v', 'Forward') +onoremap [[ :call rust#Jump('o', 'Back') +onoremap ]] :call rust#Jump('o', 'Forward') + +" Commands {{{1 + +" See |:RustRun| for docs +command! -nargs=* -complete=file -bang -buffer RustRun call rust#Run(0, ) + +" See |:RustExpand| for docs +command! -nargs=* -complete=customlist,rust#CompleteExpand -bang -buffer RustExpand call rust#Expand(0, ) + +" See |:RustEmitIr| for docs +command! -nargs=* -buffer RustEmitIr call rust#Emit("llvm-ir", ) + +" See |:RustEmitAsm| for docs +command! -nargs=* -buffer RustEmitAsm call rust#Emit("asm", ) + +" See |:RustPlay| for docs +command! -range=% RustPlay :call rust#Play(, , , ) + +" See |:RustFmt| for docs +command! -buffer RustFmt call rustfmt#Format() + +" See |:RustFmtRange| for docs +command! -range -buffer RustFmtRange call rustfmt#FormatRange(, ) + +" Mappings {{{1 + +" 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)) + +if !exists("b:rust_last_rustc_args") || !exists("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 + \" + +" }}}1 + +" Code formatting on save +if get(g:, "rustfmt_autosave", 0) + autocmd BufWritePre *.rs silent! call rustfmt#Format() +endif + +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. +let b:match_skip = 's:comment\|string\|rustArrow' +source $VIMRUNTIME/macros/matchit.vim + +let &cpo = s:save_cpo +unlet s:save_cpo + +" vim: set noet sw=4 ts=4: diff --git a/vim/bundle/rust.vim/indent/rust.vim b/vim/bundle/rust.vim/indent/rust.vim new file mode 100644 index 0000000..774133d --- /dev/null +++ b/vim/bundle/rust.vim/indent/rust.vim @@ -0,0 +1,206 @@ +" Vim indent file +" Language: Rust +" Author: Chris Morgan +" Last Change: 2016 Jul 15 + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal cindent +setlocal cinoptions=L0,(0,Ws,J1,j1 +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 + +" Some preliminary settings +setlocal nolisp " Make sure lisp indenting doesn't supersede us +setlocal autoindent " indentexpr isn't much help otherwise +" Also do indentkeys, otherwise # gets shoved to column 0 :-/ +setlocal indentkeys=0{,0},!^F,o,O,0[,0] + +setlocal indentexpr=GetRustIndent(v:lnum) + +" Only define the function once. +if exists("*GetRustIndent") + finish +endif + +" 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 +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 +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. + + 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 + + " 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 + + " 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. + + " 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! + + " 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 + + " Fall back on cindent, which does it mostly right + return cindent(a:lnum) +endfunction diff --git a/vim/bundle/rust.vim/plugin/rust.vim b/vim/bundle/rust.vim/plugin/rust.vim new file mode 100644 index 0000000..4ec4f33 --- /dev/null +++ b/vim/bundle/rust.vim/plugin/rust.vim @@ -0,0 +1,22 @@ +" Vim syntastic plugin helper +" Language: Rust +" Maintainer: Andrew Gallant + +if exists("g:loaded_syntastic_rust_filetype") + finish +endif +let g:loaded_syntastic_rust_filetype = 1 +let s:save_cpo = &cpo +set cpo&vim + +" This is to let Syntastic know about the Rust filetype. +" It enables tab completion for the 'SyntasticInfo' command. +" (This does not actually register the syntax checker.) +if exists('g:syntastic_extra_filetypes') + call add(g:syntastic_extra_filetypes, 'rust') +else + let g:syntastic_extra_filetypes = ['rust'] +endif + +let &cpo = s:save_cpo +unlet s:save_cpo diff --git a/vim/bundle/rust.vim/syntax/rust.vim b/vim/bundle/rust.vim/syntax/rust.vim new file mode 100644 index 0000000..8c73462 --- /dev/null +++ b/vim/bundle/rust.vim/syntax/rust.vim @@ -0,0 +1,294 @@ +" Vim syntax file +" Language: Rust +" Maintainer: Patrick Walton +" Maintainer: Ben Blum +" Maintainer: Chris Morgan +" Last Change: Feb 24, 2016 + +if version < 600 + syntax clear +elseif exists("b:current_syntax") + finish +endif + +" Syntax definitions {{{1 +" Basic keywords {{{2 +syn keyword rustConditional match if else +syn keyword rustRepeat for loop while +syn keyword rustTypedef type nextgroup=rustIdentifier skipwhite skipempty +syn keyword rustStructure struct enum nextgroup=rustIdentifier skipwhite skipempty +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 + +syn keyword rustExternCrate crate contained nextgroup=rustIdentifier,rustExternCrateString skipwhite skipempty +" This is to get the `bar` part of `extern crate "foo" as bar;` highlighting. +syn match rustExternCrateString /".*"\_s*as/ contained nextgroup=rustIdentifier skipwhite transparent skipempty contains=rustString,rustOperator +syn keyword rustObsoleteExternMod mod contained nextgroup=rustIdentifier skipwhite skipempty + +syn match rustIdentifier contains=rustIdentifierPrime "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained +syn match rustFuncName "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained + +syn region rustBoxPlacement matchgroup=rustBoxPlacementParens start="(" end=")" contains=TOP contained +" Ideally we'd have syntax rules set up to match arbitrary expressions. Since +" we don't, we'll just define temporary contained rules to handle balancing +" delimiters. +syn region rustBoxPlacementBalance start="(" end=")" containedin=rustBoxPlacement transparent +syn region rustBoxPlacementBalance start="\[" end="\]" containedin=rustBoxPlacement transparent +" {} are handled by rustFoldBraces + +syn region rustMacroRepeat matchgroup=rustMacroRepeatDelimiters start="$(" end=")" contains=TOP nextgroup=rustMacroRepeatCount +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 + +" Built-in types {{{2 +syn keyword rustType isize usize char bool u8 u16 u32 u64 u128 f32 +syn keyword rustType f64 i8 i16 i32 i64 i128 str Self + +" Things from the libstd v1 prelude (src/libstd/prelude/v1.rs) {{{2 +" This section is just straight transformation of the contents of the prelude, +" to make it easy to update. + +" Reexported core operators {{{3 +syn keyword rustTrait Copy Send Sized Sync +syn keyword rustTrait Drop Fn FnMut FnOnce + +" Reexported functions {{{3 +" There’s no point in highlighting these; when one writes drop( or drop::< it +" gets the same highlighting anyway, and if someone writes `let drop = …;` we +" don’t really want *that* drop to be highlighted. +"syn keyword rustFunction drop + +" Reexported types and traits {{{3 +syn keyword rustTrait Box +syn keyword rustTrait ToOwned +syn keyword rustTrait Clone +syn keyword rustTrait PartialEq PartialOrd Eq Ord +syn keyword rustTrait AsRef AsMut Into From +syn keyword rustTrait Default +syn keyword rustTrait Iterator Extend IntoIterator +syn keyword rustTrait DoubleEndedIterator ExactSizeIterator +syn keyword rustEnum Option +syn keyword rustEnumVariant Some None +syn keyword rustEnum Result +syn keyword rustEnumVariant Ok Err +syn keyword rustTrait SliceConcatExt +syn keyword rustTrait String ToString +syn keyword rustTrait Vec + +" Other syntax {{{2 +syn keyword rustSelf self +syn keyword rustBoolean true false + +" If foo::bar changes to foo.bar, change this ("::" to "\."). +" If foo::bar changes to Foo::bar, change this (first "\w" to "\u"). +syn match rustModPath "\w\(\w\)*::[^<]"he=e-3,me=e-3 +syn match rustModPathSep "::" + +syn match rustFuncCall "\w\(\w\)*("he=e-1,me=e-1 +syn match rustFuncCall "\w\(\w\)*::<"he=e-3,me=e-3 " foo::(); + +" This is merely a convention; note also the use of [A-Z], restricting it to +" latin identifiers rather than the full Unicode uppercase. I have not used +" [:upper:] as it depends upon 'noignorecase' +"syn match rustCapsIdent display "[A-Z]\w\(\w\)*" + +syn match rustOperator display "\%(+\|-\|/\|*\|=\|\^\|&\||\|!\|>\|<\|%\)=\?" +" This one isn't *quite* right, as we could have binary-& with a reference +syn match rustSigil display /&\s\+[&~@*][^)= \t\r\n]/he=e-1,me=e-1 +syn match rustSigil display /[&~@*][^)= \t\r\n]/he=e-1,me=e-1 +" This isn't actually correct; a closure with no arguments can be `|| { }`. +" Last, because the & in && isn't a sigil +syn match rustOperator display "&&\|||" +" This is rustArrowCharacter rather than rustArrow for the sake of matchparen, +" so it skips the ->; see http://stackoverflow.com/a/30309949 for details. +syn match rustArrowCharacter display "->" +syn match rustQuestionMark display "?\([a-zA-Z]\+\)\@!" + +syn match rustMacro '\w\(\w\)*!' contains=rustAssert,rustPanic +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 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 +syn region rustString start='b\?r\z(#*\)"' end='"\z1' contains=@Spell + +syn region rustAttribute start="#!\?\[" end="\]" contains=rustString,rustDerive,rustCommentLine,rustCommentBlock,rustCommentLineDocError,rustCommentBlockDocError +syn region rustDerive start="derive(" end=")" contained contains=rustDeriveTrait +" This list comes from src/libsyntax/ext/deriving/mod.rs +" 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 + +" Number literals +syn match rustDecNumber display "\<[0-9][0-9_]*\%([iu]\%(size\|8\|16\|32\|64\|128\)\)\=" +syn match rustHexNumber display "\<0x[a-fA-F0-9_]\+\%([iu]\%(size\|8\|16\|32\|64\|128\)\)\=" +syn match rustOctNumber display "\<0o[0-7_]\+\%([iu]\%(size\|8\|16\|32\|64\|128\)\)\=" +syn match rustBinNumber display "\<0b[01_]\+\%([iu]\%(size\|8\|16\|32\|64\|128\)\)\=" + +" Special case for numbers of the form "1." which are float literals, unless followed by +" an identifier, which makes them integer literals with a method call or field access, +" or by another ".", which makes them integer literals followed by the ".." token. +" (This must go first so the others take precedence.) +syn match rustFloat display "\<[0-9][0-9_]*\.\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\|\.\)\@!" +" To mark a number as a normal float, it must have at least one of the three things integral values don't have: +" a decimal point and more numbers; an exponent; and a type suffix. +syn match rustFloat display "\<[0-9][0-9_]*\%(\.[0-9][0-9_]*\)\%([eE][+-]\=[0-9_]\+\)\=\(f32\|f64\)\=" +syn match rustFloat display "\<[0-9][0-9_]*\%(\.[0-9][0-9_]*\)\=\%([eE][+-]\=[0-9_]\+\)\(f32\|f64\)\=" +syn match rustFloat display "\<[0-9][0-9_]*\%(\.[0-9][0-9_]*\)\=\%([eE][+-]\=[0-9_]\+\)\=\(f32\|f64\)" + +" For the benefit of delimitMate +syn region rustLifetimeCandidate display start=/&'\%(\([^'\\]\|\\\(['nrt0\\\"]\|x\x\{2}\|u{\x\{1,6}}\)\)'\)\@!/ end=/[[:cntrl:][:space:][:punct:]]\@=\|$/ contains=rustSigil,rustLifetime +syn region 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 +syn match rustLifetime display "\'\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" +syn match rustLabel display "\'\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*:" +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 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 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 +" deep. But as long as you stay away from that particular case, I *believe* +" the highlighting is correct. Due to the way Vim's syntax engine works +" (greedy for start matches, unlike Rust's tokeniser which is searching for +" the earliest-starting match, start or end), I believe this cannot be solved. +" Oh you who would fix it, don't bother with things like duplicating the Block +" rules and putting ``\*\@ +" +" 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_rustc_checker") + finish +endif +let g:loaded_syntastic_rust_rustc_checker = 1 + +let s:save_cpo = &cpo +set cpo&vim + +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' + + " 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' + + return SyntasticMake({ + \ 'makeprg': makeprg, + \ 'errorformat': errorformat }) +endfunction + +call g:SyntasticRegistry.CreateAndRegisterChecker({ + \ 'filetype': 'rust', + \ 'name': 'rustc'}) + +let &cpo = s:save_cpo +unlet s:save_cpo -- cgit v1.2.3-70-g09d2