1
0
Fork 0
mirror of synced 2024-11-23 09:15:35 -05:00

Add plugins for Rust support.

This commit is contained in:
Isaac Andrade 2016-02-05 00:52:39 -07:00 committed by Siew Yi Liang
parent f1da3b2e38
commit c1aa392b3c
17 changed files with 1565 additions and 0 deletions

View file

@ -0,0 +1 @@
/doc/tags

View file

@ -0,0 +1,30 @@
# rust.vim
## Description
This is a vim plugin provides [Rust][r] file detection and syntax highlighting.
It is synchronized daily to the vim support code in [rust-lang/rust][rr]'s
master branch via cronjob.
## Installation
### Using [Vundle][v]
1. Add `Plugin 'wting/rust.vim'` to `~/.vimrc`
2. `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]
1. `cd ~/.vim/bundle`
2. `git clone https://github.com/wting/rust.vim.git`
[rr]: https://github.com/rust-lang/rust
[p]: https://github.com/tpope/vim-pathogen
[r]: https://en.wikipedia.org/wiki/Rust_language
[v]: https://github.com/gmarik/vundle
[vqs]: https://github.com/gmarik/vundle#quick-start

View file

@ -0,0 +1,31 @@
if !exists('g:rust_conceal') || !has('conceal') || &enc != 'utf-8'
finish
endif
" For those who don't want to see `::`...
if exists('g:rust_conceal_mod_path')
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')
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')
hi! link Conceal Operator
endif

View file

@ -0,0 +1,225 @@
" 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 <SID>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)
if a:bang
let idx = index(a:args, '--')
if idx != -1
let rustc_args = idx == 0 ? [] : a:args[:idx-1]
let args = a:args[idx+1:]
else
let rustc_args = a:args
let args = []
endif
else
let rustc_args = []
let args = a:args
endif
let b:rust_last_rustc_args = rustc_args
let b:rust_last_args = args
call s:WithPath(function("s:Run"), rustc_args, args)
endfunction
function! s:Run(path, rustc_args, args)
try
let exepath = tempname()
if has('win32')
let exepath .= '.exe'
endif
let rustc_args = [a:path, '-o', exepath] + a:rustc_args
let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc"
let output = system(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
finally
if exists("exepath")
silent! call delete(exepath)
endif
endtry
endfunction
" Expand {{{1
function! rust#Expand(bang, args)
if a:bang && !empty(a:args)
let pretty = a:args[0]
let args = a:args[1:]
else
let pretty = "expanded"
let args = a:args
endif
call s:WithPath(function("s:Expand"), pretty, args)
endfunction
function! s:Expand(path, pretty, args)
try
let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc"
let args = [a:path, '--pretty', a:pretty] + a:args
let output = system(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
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="]
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)
call s:WithPath(function("s:Emit"), a:type, a:args)
endfunction
function! s:Emit(path, type, args)
try
let rustc = exists("g:rustc_path") ? g:rustc_path : "rustc"
let args = [a:path, '--emit', a:type, '-o', '-'] + a:args
let output = system(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
if a:type == "ir"
setl filetype=llvm
elseif a:type == "asm"
setl filetype=asm
endif
setl buftype=nofile
setl bufhidden=hide
setl noswapfile
endif
endtry
endfunction
" Utility functions {{{1
function! s:WithPath(func, ...)
try
let save_write = &write
set write
let path = expand('%')
let pathisempty = empty(path)
if pathisempty || !save_write
" use a temporary file named 'unnamed.rs' inside a temporary
" directory. This produces better error messages
let tmpdir = tempname()
call mkdir(tmpdir)
let save_cwd = getcwd()
silent exe 'lcd' fnameescape(tmpdir)
let path = 'unnamed.rs'
let save_mod = &mod
set nomod
silent exe 'keepalt write! ' . fnameescape(path)
if pathisempty
silent keepalt 0file
endif
else
update
endif
call call(a:func, [path] + a:000)
finally
if exists("save_mod") | let &mod = save_mod | endif
if exists("save_write") | let &write = save_write | endif
if exists("save_cwd") | silent exe 'lcd' fnameescape(save_cwd) | endif
if exists("tmpdir") | silent call s:RmDir(tmpdir) | endif
endtry
endfunction
function! rust#AppendCmdLine(text)
call setcmdpos(getcmdpos())
let cmd = getcmdline() . a:text
return cmd
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
silent exe "!rm -rf " . shellescape(a:path)
endfunction
" }}}1
" vim: set noet sw=4 ts=4:

View file

@ -0,0 +1,65 @@
" Vim compiler file
" Compiler: Cargo Compiler
" Maintainer: Damien Radtke <damienradtke@gmail.com>
" 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 <args>
endif
if exists('g:cargo_makeprg_params')
execute 'CompilerSet makeprg=cargo\ '.escape(g:cargo_makeprg_params, ' \|"').'\ $*'
else
CompilerSet makeprg=cargo\ $*
endif
" Allow a configurable global Cargo.toml name. This makes it easy to
" support variations like 'cargo.toml'.
let s:cargo_manifest_name = get(g:, 'cargo_manifest_name', 'Cargo.toml')
function! s:is_absolute(path)
return a:path[0] == '/' || a:path =~ '[A-Z]\+:'
endfunction
let s:local_manifest = findfile(s:cargo_manifest_name, '.;')
if s:local_manifest != ''
let s:local_manifest = fnamemodify(s:local_manifest, ':p:h').'/'
augroup cargo
au!
au QuickfixCmdPost make call s:FixPaths()
augroup END
" FixPaths() is run after Cargo, and is used to change the file paths
" to be relative to the current directory instead of Cargo.toml.
function! s:FixPaths()
let qflist = getqflist()
let manifest = s:local_manifest
for qf in qflist
if !qf.valid
let m = matchlist(qf.text, '(file://\(.*\))$')
if !empty(m)
let manifest = m[1].'/'
" Manually strip another slash if needed; usually just an
" issue on Windows.
if manifest =~ '^/[A-Z]\+:/'
let manifest = manifest[1:]
endif
endif
continue
endif
let filename = bufname(qf.bufnr)
if s:is_absolute(filename)
continue
endif
let qf.filename = simplify(manifest.filename)
call remove(qf, 'bufnr')
endfor
call setqflist(qflist, 'r')
endfunction
endif

View file

@ -0,0 +1,33 @@
" Vim compiler file
" Compiler: Rust Compiler
" Maintainer: Chris Morgan <me@chrismorgan.info>
" 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 <args>
endif
if exists("g:rustc_makeprg_no_percent") && g:rustc_makeprg_no_percent == 1
CompilerSet makeprg=rustc
else
CompilerSet makeprg=rustc\ \%
endif
CompilerSet errorformat=
\%f:%l:%c:\ %t%*[^:]:\ %m,
\%f:%l:%c:\ %*\\d:%*\\d\ %t%*[^:]:\ %m,
\%-G%f:%l\ %s,
\%-G%*[\ ]^,
\%-G%*[\ ]^%*[~],
\%-G%*[\ ]...
let &cpo = s:cpo_save
unlet s:cpo_save

View file

@ -0,0 +1,178 @@
*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:cargo_manifest_name*
g:cargo_manifest_name~
Set this option to the name of the manifest file for your projects. If
not specified it defaults to 'Cargo.toml' : >
let g:cargo_manifest_name = 'Cargo.toml'
<
==============================================================================
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.
==============================================================================
MAPPINGS *rust-mappings*
This plugin defines mappings for |[[| and |]]| to support hanging indents.
It also has a few other mappings:
*rust_<D-r>*
<D-r> Executes |:RustRun| with no arguments.
Note: This binding is only available in MacVim.
*rust_<D-R>*
<D-R> Populates the command line with |:RustRun|! using the
arguments given to the last invocation, but does not
execute it.
Note: This binding is only available in MacVim.
==============================================================================
vim:tw=78:sw=4:noet:ts=8:ft=help:norl:

View file

@ -0,0 +1 @@
au BufRead,BufNewFile *.rs set filetype=rust

View file

@ -0,0 +1,150 @@
" Language: Rust
" Description: Vim syntax file for Rust
" Maintainer: Chris Morgan <me@chrismorgan.info>
" Maintainer: Kevin Ballard <kevin@sb.org>
" Last Change: Jul 07, 2014
if exists("b:did_ftplugin")
finish
endif
let b:did_ftplugin = 1
let s:save_cpo = &cpo
set cpo&vim
" 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 == 1
" 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 == 1
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')
" NOT adding .rc as it's being phased out (0.7)
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 b:delimitMate_excluded_regions = delimitMate#Get("excluded_regions") . ',rustLifetimeCandidate,rustGenericLifetimeCandidate'
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')
let b:rust_set_conceallevel=1
setlocal conceallevel=2
endif
" Motion Commands {{{1
" Bind motion commands to support hanging indents
nnoremap <silent> <buffer> [[ :call rust#Jump('n', 'Back')<CR>
nnoremap <silent> <buffer> ]] :call rust#Jump('n', 'Forward')<CR>
xnoremap <silent> <buffer> [[ :call rust#Jump('v', 'Back')<CR>
xnoremap <silent> <buffer> ]] :call rust#Jump('v', 'Forward')<CR>
onoremap <silent> <buffer> [[ :call rust#Jump('o', 'Back')<CR>
onoremap <silent> <buffer> ]] :call rust#Jump('o', 'Forward')<CR>
" Commands {{{1
" See |:RustRun| for docs
command! -nargs=* -complete=file -bang -bar -buffer RustRun call rust#Run(<bang>0, [<f-args>])
" See |:RustExpand| for docs
command! -nargs=* -complete=customlist,rust#CompleteExpand -bang -bar -buffer RustExpand call rust#Expand(<bang>0, [<f-args>])
" See |:RustEmitIr| for docs
command! -nargs=* -bar -buffer RustEmitIr call rust#Emit("ir", [<f-args>])
" See |:RustEmitAsm| for docs
command! -nargs=* -bar -buffer RustEmitAsm call rust#Emit("asm", [<f-args>])
" Mappings {{{1
" Bind ⌘R in MacVim to :RustRun
nnoremap <silent> <buffer> <D-r> :RustRun<CR>
" Bind ⌘⇧R in MacVim to :RustRun! pre-filled with the last args
nnoremap <buffer> <D-R> :RustRun! <C-r>=join(b:rust_last_rustc_args)<CR><C-\>erust#AppendCmdLine(' -- ' . join(b:rust_last_args))<CR>
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
\|nunmap <buffer> <D-r>
\|nunmap <buffer> <D-R>
\|nunmap <buffer> [[
\|nunmap <buffer> ]]
\|xunmap <buffer> [[
\|xunmap <buffer> ]]
\|ounmap <buffer> [[
\|ounmap <buffer> ]]
\"
" }}}1
let &cpo = s:save_cpo
unlet s:save_cpo
" vim: set noet sw=4 ts=4:

View file

@ -0,0 +1,196 @@
" Vim indent file
" Language: Rust
" Author: Chris Morgan <me@chrismorgan.info>
" Last Change: 2014 Sep 13
" 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
if prevline[len(prevline) - 1] == ","
\ && s:get_line_trimmed(a:lnum) !~ '^\s*[\[\]{}]'
\ && prevline !~ '^\s*fn\s'
\ && prevline !~ '([^()]\+,$'
" 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) {
"
" 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

View file

@ -0,0 +1,22 @@
" Vim syntastic plugin helper
" Language: Rust
" Maintainer: Andrew Gallant <jamslam@gmail.com>
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

View file

@ -0,0 +1,262 @@
" Vim syntax file
" Language: Rust
" Maintainer: Patrick Walton <pcwalton@mozilla.com>
" Maintainer: Ben Blum <bblum@cs.cmu.edu>
" Maintainer: Chris Morgan <me@chrismorgan.info>
" Last Change: January 5, 2015
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 rustOperator as
syn match rustAssert "\<assert\(\w\)*!" contained
syn match rustPanic "\<panic\(\w\)*!" contained
syn keyword rustKeyword break
syn keyword rustKeyword box nextgroup=rustBoxPlacement skipwhite skipempty
syn keyword rustKeyword continue
syn keyword rustKeyword extern nextgroup=rustExternCrate,rustObsoleteExternMod skipwhite skipempty
syn keyword rustKeyword fn nextgroup=rustFuncName skipwhite skipempty
syn keyword rustKeyword for in if impl let
syn keyword rustKeyword loop once pub
syn keyword rustKeyword return super
syn keyword rustKeyword unsafe virtual where while
syn keyword rustKeyword use nextgroup=rustModPath skipwhite skipempty
" FIXME: Scoped impl's name is also fallen in this category
syn keyword rustKeyword mod trait struct enum type nextgroup=rustIdentifier skipwhite skipempty
syn keyword rustStorage move mut ref static const
syn keyword rustInvalidBareKeyword crate
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
syn keyword rustBoxPlacementExpr GC containedin=rustBoxPlacement
" 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 be do offsetof priv pure sizeof typeof unsized yield abstract final override macro
" Built-in types {{{2
syn keyword rustType isize usize float char bool u8 u16 u32 u64 f32
syn keyword rustType f64 i8 i16 i32 i64 str Self
" Things from the prelude (src/libstd/prelude.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
syn keyword rustFunction drop
" Reexported types and traits {{{3
syn keyword rustTrait Box
syn keyword rustTrait CharExt
syn keyword rustTrait Clone
syn keyword rustTrait PartialEq PartialOrd Eq Ord
syn keyword rustTrait DoubleEndedIterator
syn keyword rustTrait ExactSizeIterator
syn keyword rustTrait Iterator IteratorExt Extend
syn keyword rustEnum Option
syn keyword rustEnumVariant Some None
syn keyword rustTrait PtrExt MutPtrExt
syn keyword rustEnum Result
syn keyword rustEnumVariant Ok Err
syn keyword rustTrait AsSlice
syn keyword rustTrait SliceExt SliceConcatExt
syn keyword rustTrait Str StrExt
syn keyword rustTrait String ToString
syn keyword rustTrait Vec
" FIXME: remove when path reform lands
syn keyword rustTrait Path GenericPath
" FIXME: remove when I/O reform lands
syn keyword rustTrait Buffer Writer Reader Seek BufferPrelude
" 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::<T>();
" 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 "&&\|||"
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\{4}\|U\x\{8}\)/
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
syn region rustDerive start="derive(" end=")" contained contains=rustTrait
" Number literals
syn match rustDecNumber display "\<[0-9][0-9_]*\%([iu]\%(s\|8\|16\|32\|64\)\)\="
syn match rustHexNumber display "\<0x[a-fA-F0-9_]\+\%([iu]\%(s\|8\|16\|32\|64\)\)\="
syn match rustOctNumber display "\<0o[0-7_]\+\%([iu]\%(s\|8\|16\|32\|64\)\)\="
syn match rustBinNumber display "\<0b[01_]\+\%([iu]\%(s\|8\|16\|32\|64\)\)\="
" 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\{4}\|U\x\{8}\)\)'\)\@!/ 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 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\{4}\|U\x\{8}\|u{\x\{1,6}}\)\)'/ contains=rustEscape,rustEscapeUnicode,rustEscapeError,rustCharacterInvalid
syn region rustCommentLine start="//" end="$" contains=rustTodo,@Spell
syn region rustCommentLineDoc start="//\%(//\@!\|!\)" end="$" contains=rustTodo,@Spell
syn region rustCommentBlock matchgroup=rustCommentBlock start="/\*\%(!\|\*[*/]\@!\)\@!" end="\*/" contains=rustTodo,rustCommentBlockNest,@Spell
syn region rustCommentBlockDoc matchgroup=rustCommentBlockDoc start="/\*\%(!\|\*[*/]\@!\)" end="\*/" contains=rustTodo,rustCommentBlockDocNest,@Spell
syn region rustCommentBlockNest matchgroup=rustCommentBlock start="/\*" end="\*/" contains=rustTodo,rustCommentBlockNest,@Spell contained transparent
syn region rustCommentBlockDocNest matchgroup=rustCommentBlockDoc start="/\*" end="\*/" contains=rustTodo,rustCommentBlockDocNest,@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 ``\*\@<!`` at the start of them; it makes it worse, as
" then you must deal with cases like ``/*/**/*/``. And don't try making it
" worse with ``\%(/\@<!\*\)\@<!``, either...
syn keyword rustTodo contained TODO FIXME XXX NB NOTE
" Folding rules {{{2
" Trivial folding rules to begin with.
" FIXME: use the AST to make really good folding
syn region rustFoldBraces start="{" end="}" transparent fold
" Default highlighting {{{1
hi def link rustDecNumber rustNumber
hi def link rustHexNumber rustNumber
hi def link rustOctNumber rustNumber
hi def link rustBinNumber rustNumber
hi def link rustIdentifierPrime rustIdentifier
hi def link rustTrait rustType
hi def link rustMacroRepeatCount rustMacroRepeatDelimiters
hi def link rustMacroRepeatDelimiters Macro
hi def link rustMacroVariable Define
hi def link rustSigil StorageClass
hi def link rustEscape Special
hi def link rustEscapeUnicode rustEscape
hi def link rustEscapeError Error
hi def link rustStringContinuation Special
hi def link rustString String
hi def link rustCharacterInvalid Error
hi def link rustCharacterInvalidUnicode rustCharacterInvalid
hi def link rustCharacter Character
hi def link rustNumber Number
hi def link rustBoolean Boolean
hi def link rustEnum rustType
hi def link rustEnumVariant rustConstant
hi def link rustConstant Constant
hi def link rustSelf Constant
hi def link rustFloat Float
hi def link rustOperator Operator
hi def link rustKeyword Keyword
hi def link rustReservedKeyword Error
hi def link rustConditional Conditional
hi def link rustIdentifier Identifier
hi def link rustCapsIdent rustIdentifier
hi def link rustModPath Include
hi def link rustModPathSep Delimiter
hi def link rustFunction Function
hi def link rustFuncName Function
hi def link rustFuncCall Function
hi def link rustCommentLine Comment
hi def link rustCommentLineDoc SpecialComment
hi def link rustCommentBlock rustCommentLine
hi def link rustCommentBlockDoc rustCommentLineDoc
hi def link rustAssert PreCondit
hi def link rustPanic PreCondit
hi def link rustMacro Macro
hi def link rustType Type
hi def link rustTodo Todo
hi def link rustAttribute PreProc
hi def link rustDerive PreProc
hi def link rustStorage StorageClass
hi def link rustObsoleteStorage Error
hi def link rustLifetime Special
hi def link rustInvalidBareKeyword Error
hi def link rustExternCrate rustKeyword
hi def link rustObsoleteExternMod Error
hi def link rustBoxPlacementParens Delimiter
hi def link rustBoxPlacementExpr rustKeyword
" Other Suggestions:
" hi rustAttribute ctermfg=cyan
" hi rustDerive ctermfg=cyan
" hi rustAssert ctermfg=yellow
" hi rustPanic ctermfg=red
" hi rustMacro ctermfg=magenta
syn sync minlines=200
syn sync maxlines=500
let b:current_syntax = "rust"

View file

@ -0,0 +1,35 @@
" Vim syntastic plugin
" Language: Rust
" Maintainer: Andrew Gallant <jamslam@gmail.com>
"
" See for details on how to add an external Syntastic checker:
" https://github.com/scrooloose/syntastic/wiki/Syntax-Checker-Guide#external
if exists("g:loaded_syntastic_rust_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({ 'args': '-Zparse-only' })
let errorformat =
\ '%E%f:%l:%c: %\d%#:%\d%# %.%\{-}error:%.%\{-} %m,' .
\ '%W%f:%l:%c: %\d%#:%\d%# %.%\{-}warning:%.%\{-} %m,' .
\ '%C%f:%l %m,' .
\ '%-Z%.%#'
return SyntasticMake({
\ 'makeprg': makeprg,
\ 'errorformat': errorformat })
endfunction
call g:SyntasticRegistry.CreateAndRegisterChecker({
\ 'filetype': 'rust',
\ 'name': 'rustc'})
let &cpo = s:save_cpo
unlet s:save_cpo

View file

@ -0,0 +1 @@
*.pyc

View file

@ -0,0 +1,36 @@
# Vim Racer Plugin
This plugin allows vim to use [Racer](http://github.com/phildawes/racer) for Rust code completion and navigation.
## Installation
1. Build / Install [Racer](http://github.com/phildawes/racer)
1. Install using Pathogen, Vundle or NeoBundle. Or, copy `plugin/racer.vim` into your `~/.vim/plugin` directory.
Vundle users:
```
Plugin 'racer-rust/vim-racer'
```
NeoBundle users:
```
NeoBundle 'racer-rust/vim-racer'
```
vim-plug users:
```
Plug 'racer-rust/vim-racer'
```
2. Add `g:racer_cmd` and `$RUST_SRC_PATH` variables to your `.vimrc`. Also it's worth turning on 'hidden' mode for buffers otherwise you need to save the current buffer every time you do a goto-definition. E.g.:
```
set hidden
let g:racer_cmd = "<path-to-racer>/target/release/racer"
let $RUST_SRC_PATH="<path-to-rust-srcdir>/src/"
```
3. In insert mode use `C-x-C-o` to search for completions
4. In normal mode type `gd` to go to a definition

View file

@ -0,0 +1,196 @@
" Vim plugin for Racer
" (by Phil Dawes)
"
" 1. Edit the variables below (or override in .vimrc)
" 2. copy this file into .vim/plugin/
" 3. - now in insert mode do 'C-x C-o' to autocomplete the thing at the cursor
" - in normal mode do 'gd' to go to definition
" - 'gD' goes to the definition in a new vertical split
"
" (This plugin is best used with the 'hidden' option enabled so that switching buffers doesn't force you to save)
if exists('g:loaded_racer')
finish
endif
let g:loaded_racer = 1
let s:save_cpo = &cpo
set cpo&vim
if !exists('g:racer_cmd')
let path = escape(expand('<sfile>:p:h'), '\') . '/../target/release/'
if isdirectory(path)
let s:pathsep = has("win32") ? ';' : ':'
let $PATH .= s:pathsep . path
endif
let g:racer_cmd = 'racer'
if !(executable(g:racer_cmd))
echohl WarningMsg | echomsg "No racer executable found in $PATH (" . $PATH . ")"
endif
endif
if !exists('$RUST_SRC_PATH')
let s:rust_src_default = 1
if isdirectory("/usr/local/src/rust/src")
let $RUST_SRC_PATH="/usr/local/src/rust/src"
endif
if isdirectory("/usr/src/rust/src")
let $RUST_SRC_PATH="/usr/src/rust/src"
endif
if isdirectory("C:\\rust\\src")
let $RUST_SRC_PATH="C:\\rust\\src"
endif
endif
if !isdirectory($RUST_SRC_PATH)
if exists('s:rust_src_default')
echohl WarningMsg | echomsg "No RUST_SRC_PATH environment variable present, nor could default installation be found at: " . $RUST_SRC_PATH
else
echohl WarningMsg | echomsg "No directory was found at provided RUST_SRC_PATH: " . $RUST_SRC_PATH
endif
endif
if !exists('g:racer_experimental_completer')
let g:racer_experimental_completer = 0
endif
if !exists('g:racer_insert_paren')
let g:racer_insert_paren = 1
endif
function! RacerGetPrefixCol(base)
let col = col(".")-1
let b:racer_col = col
let b:tmpfname = tempname()
call writefile(RacerGetBufferContents(a:base), b:tmpfname)
let cmd = g:racer_cmd." prefix ".line(".")." ".col." ".b:tmpfname
let res = system(cmd)
let prefixline = split(res, "\\n")[0]
let startcol = split(prefixline[7:], ",")[0]
return startcol
endfunction
function! RacerGetExpCompletions(base)
let col = strlen(getline('.')) + strlen(a:base) " use the column from the previous RacerGetPrefixCol() call, since vim ammends it afterwards
call writefile(RacerGetBufferContents(a:base), b:tmpfname)
let fname = expand("%:p")
let cmd = g:racer_cmd." complete ".line(".")." ".col." ".fname." ".b:tmpfname
let res = system(cmd)
let typeMap = {
\ 'Struct' : 's', 'Module' : 'M', 'Function' : 'f',
\ 'Crate' : 'C', 'Let' : 'v', 'StructField' : 'm',
\ 'Impl' : 'i', 'Enum' : 'e', 'EnumVariant' : 'E',
\ 'Type' : 't', 'FnArg' : 'v', 'Trait' : 'T'
\ }
let lines = split(res, "\\n")
let out = []
for line in lines
if line =~ "^MATCH"
let completions = split(line[6:], ",")
let kind = get(typeMap, completions[4])
let completion = {'kind' : kind, 'word' : completions[0], 'dup':1 }
if kind ==# 'f' " function
let completion['menu'] = substitute(substitute(substitute(join(completions[5:], ','), '\(pub\|fn\) ',"","g"), '{*$', "", ""), ' where\s\?.*$', "", "")
if g:racer_insert_paren == 1
let completion['abbr'] = completions[0]
let completion['word'] .= "("
endif
let completion['info'] = join(completions[5:], ',')
elseif kind ==# 's' " struct
let completion['menu'] = substitute(substitute(join(completions[5:], ','), '\(pub\|struct\) ',"","g"), '{*$', "", "")
endif
let out = add(out, completion)
endif
endfor
call delete(b:tmpfname)
return out
endfunction
function! RacerGetCompletions(base)
let col = strlen(getline('.')) + strlen(a:base) " use the column from the previous RacerGetPrefixCol() call, since vim ammends it afterwards
call writefile(RacerGetBufferContents(a:base), b:tmpfname)
let fname = expand("%:p")
let cmd = g:racer_cmd." complete ".line(".")." ".col." ".fname." ".b:tmpfname
let res = system(cmd)
let lines = split(res, "\\n")
let out = []
for line in lines
if line =~ "^MATCH"
let completion = split(line[6:], ",")[0]
let out = add(out, completion)
endif
endfor
call delete(b:tmpfname)
return out
endfunction
function! RacerGoToDefinition()
let col = col(".")-1
let b:racer_col = col
let fname = expand("%:p")
let tmpfname = tempname()
call writefile(getline(1, '$'), tmpfname)
let cmd = g:racer_cmd." find-definition ".line(".")." ".col." ".fname." ".tmpfname
let res = system(cmd)
let lines = split(res, "\\n")
for line in lines
if line =~ "^MATCH"
let linenum = split(line[6:], ",")[1]
let colnum = split(line[6:], ",")[2]
let fname = split(line[6:], ",")[3]
call RacerJumpToLocation(fname, linenum, colnum)
break
endif
endfor
call delete(tmpfname)
endfunction
function! RacerGetBufferContents(base)
" Re-combine the completion base word from omnicomplete with the current
" line contents. Since the base word gets remove from the buffer before
" this function is invoked we have to put it back in to out tmpfile.
let col = col(".")-1
let buf_lines = getline(1, '$')
let line_contents = getline('.')
let buf_lines[line('.') - 1] = strpart(line_contents, 0, col).a:base.strpart(line_contents, col, len(line_contents))
return buf_lines
endfunction
function! RacerJumpToLocation(filename, linenum, colnum)
if(a:filename != '')
" Record jump mark
normal! m`
if a:filename != bufname('%')
exec 'keepjumps e ' . fnameescape(a:filename)
endif
call cursor(a:linenum, a:colnum+1)
" Center definition on screen
normal! zz
endif
endfunction
function! RacerComplete(findstart, base)
if a:findstart
return RacerGetPrefixCol(a:base)
else
if g:racer_experimental_completer == 1
return RacerGetExpCompletions(a:base)
else
return RacerGetCompletions(a:base)
endif
endif
endfunction
autocmd FileType rust setlocal omnifunc=RacerComplete
autocmd FileType rust nnoremap <buffer>gd :call RacerGoToDefinition()<cr>
autocmd FileType rust nnoremap <buffer>gD :vsplit<cr>:call RacerGoToDefinition()<cr>
let &cpo = s:save_cpo
unlet s:save_cpo

View file

@ -0,0 +1,103 @@
#=============================================================================
# FILE: racer.py
# AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
# License: MIT license {{{
# 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.
# }}}
#=============================================================================
import re
import os
import subprocess
from .base import Base
class Source(Base):
def __init__(self, vim):
Base.__init__(self, vim)
self.name = 'racer'
self.mark = '[racer]'
self.filetypes = ['rust']
self.input_pattern = r'(\.|::)\w*'
self.__executable_racer = self.vim.funcs.executable(
self.vim.eval('g:racer_cmd'))
self.__racer = self.vim.eval('g:racer_cmd')
self.__encoding = self.vim.eval('&encoding')
def get_complete_position(self, context):
if not self.__executable_racer:
return -1
results = self.get_results('prefix', self.vim.funcs.col('.'))
if not results:
return -1
prefixline = results[0]
return int(prefixline[7:].split(',')[0])
def gather_candidates(self, context):
typeMap = {
'Struct': 's', 'Module': 'M', 'Function': 'f',
'Crate': 'C', 'Let': 'v', 'StructField': 'm',
'Impl': 'i', 'Enum': 'e', 'EnumVariant': 'E',
'Type': 't', 'FnArg': 'v', 'Trait': 'T'
}
candidates = []
insert_paren = int(self.vim.eval('g:racer_insert_paren'))
for line in [l[6:] for l
in self.get_results('complete-with-snippet',
context['complete_position'] + 1)
if l.startswith('MATCH')]:
completions = line.split(';', 6)
kind = typeMap[completions[5]]
completion = { 'kind': kind, 'word': completions[0], 'dup': 1 }
if kind == 'f': # function
completion['menu'] = completions[6].replace(
'pub ', '').replace('fn ', '').rstrip('{')
if ' where ' in completion['menu'] or completion[
'menu'].endswith(' where') :
where = completion['menu'].rindex(' where')
completion['menu'] = completion['menu'][: where]
if insert_paren:
completion['abbr'] = completions[0]
completion['word'] += '('
elif kind == 's' : # struct
completion['menu'] = completions[6].replace(
'pub ', '').replace( 'struct ', '').rstrip('{')
candidates.append(completion)
return candidates
def get_results(self, command, col):
temp = self.vim.funcs.tempname()
with open(temp, 'w') as f:
for l in self.vim.current.buffer:
f.write(l + "\n")
try:
results = subprocess.check_output([
self.__racer, command,
str(self.vim.funcs.line('.')),
str(col - 1),
temp
]).decode(self.__encoding).splitlines()
except subprocess.CalledProcessError:
return []
finally:
os.remove(temp)
return results