summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/autoload/rust.vim415
-rw-r--r--runtime/autoload/rustfmt.vim107
-rw-r--r--runtime/compiler/cargo.vim35
-rw-r--r--runtime/compiler/rustc.vim46
-rw-r--r--runtime/doc/Makefile2
-rw-r--r--runtime/doc/eval.txt7
-rw-r--r--runtime/doc/filetype.txt8
-rw-r--r--runtime/doc/fold.txt6
-rw-r--r--runtime/doc/ft_rust.txt237
-rw-r--r--runtime/doc/helphelp.txt5
-rw-r--r--runtime/doc/remote.txt3
-rw-r--r--runtime/doc/tags36
-rw-r--r--runtime/doc/todo.txt17
-rw-r--r--runtime/doc/usr_41.txt4
-rw-r--r--runtime/ftplugin/hamster.vim3
-rw-r--r--runtime/ftplugin/rust.vim197
-rw-r--r--runtime/indent/javascript.vim243
-rw-r--r--runtime/indent/rust.vim213
-rw-r--r--runtime/syntax/rust.vim295
19 files changed, 1737 insertions, 142 deletions
diff --git a/runtime/autoload/rust.vim b/runtime/autoload/rust.vim
new file mode 100644
index 000000000..34a3b4177
--- /dev/null
+++ b/runtime/autoload/rust.vim
@@ -0,0 +1,415 @@
+" Author: Kevin Ballard
+" Description: Helper functions for Rust commands/mappings
+" Last Modified: May 27, 2014
+" For bugs, patches and license go to https://github.com/rust-lang/rust.vim
+
+" 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)
+ 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 <mattn.jp@gmail.com> 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=8 ts=8:
diff --git a/runtime/autoload/rustfmt.vim b/runtime/autoload/rustfmt.vim
new file mode 100644
index 000000000..a689b5e00
--- /dev/null
+++ b/runtime/autoload/rustfmt.vim
@@ -0,0 +1,107 @@
+" Author: Stephen Sugden <stephen@stephensugden.com>
+"
+" Adapted from https://github.com/fatih/vim-go
+" For bugs, patches and license go to https://github.com/rust-lang/rust.vim
+
+if !exists("g:rustfmt_autosave")
+ let g:rustfmt_autosave = 0
+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/runtime/compiler/cargo.vim b/runtime/compiler/cargo.vim
new file mode 100644
index 000000000..bd48666bc
--- /dev/null
+++ b/runtime/compiler/cargo.vim
@@ -0,0 +1,35 @@
+" Vim compiler file
+" Compiler: Cargo Compiler
+" Maintainer: Damien Radtke <damienradtke@gmail.com>
+" Latest Revision: 2014 Sep 24
+" For bugs, patches and license go to https://github.com/rust-lang/rust.vim
+
+if exists('current_compiler')
+ finish
+endif
+runtime compiler/rustc.vim
+let current_compiler = "cargo"
+
+let s:save_cpo = &cpo
+set cpo&vim
+
+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
+
+" 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\\,%.%#
+
+let &cpo = s:save_cpo
+unlet s:save_cpo
diff --git a/runtime/compiler/rustc.vim b/runtime/compiler/rustc.vim
new file mode 100644
index 000000000..c27bdc9c0
--- /dev/null
+++ b/runtime/compiler/rustc.vim
@@ -0,0 +1,46 @@
+" Vim compiler file
+" Compiler: Rust Compiler
+" Maintainer: Chris Morgan <me@chrismorgan.info>
+" Latest Revision: 2013 Jul 12
+" For bugs, patches and license go to https://github.com/rust-lang/rust.vim
+
+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 != 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/runtime/doc/Makefile b/runtime/doc/Makefile
index 33a09be42..1a0e84197 100644
--- a/runtime/doc/Makefile
+++ b/runtime/doc/Makefile
@@ -30,6 +30,7 @@ DOCS = \
filetype.txt \
fold.txt \
ft_ada.txt \
+ ft_rust.txt \
ft_sql.txt \
gui.txt \
gui_w32.txt \
@@ -165,6 +166,7 @@ HTMLS = \
filetype.html \
fold.html \
ft_ada.html \
+ ft_rust.html \
ft_sql.html \
gui.html \
gui_w32.html \
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index ff1b71fee..db0a7561f 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1,4 +1,4 @@
-*eval.txt* For Vim version 8.0. Last change: 2017 Mar 18
+*eval.txt* For Vim version 8.0. Last change: 2017 Mar 21
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -2261,12 +2261,13 @@ readfile({fname} [, {binary} [, {max}]])
reltime([{start} [, {end}]]) List get time value
reltimefloat({time}) Float turn the time value into a Float
reltimestr({time}) String turn time value into a String
-remote_expr({server}, {string} [, {idvar}])
+remote_expr({server}, {string} [, {idvar} [, {timeout}]])
String send expression
remote_foreground({server}) Number bring Vim server to the foreground
remote_peek({serverid} [, {retvar}])
Number check for reply string
-remote_read({serverid}) String read reply string
+remote_read({serverid} [, {timeout}])
+ String read reply string
remote_send({server}, {string} [, {idvar}])
String send key sequence
remote_startserver({name}) none become server {name}
diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt
index 4b0a185da..8f58d76d9 100644
--- a/runtime/doc/filetype.txt
+++ b/runtime/doc/filetype.txt
@@ -1,4 +1,4 @@
-*filetype.txt* For Vim version 8.0. Last change: 2017 Jan 04
+*filetype.txt* For Vim version 8.0. Last change: 2017 Mar 21
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -663,6 +663,12 @@ Since the text for this plugin is rather long it has been put in a separate
file: |pi_spec.txt|.
+RUST *ft-rust*
+
+Since the text for this plugin is rather long it has been put in a separate
+file: |ft_rust.txt|.
+
+
SQL *ft-sql*
Since the text for this plugin is rather long it has been put in a separate
diff --git a/runtime/doc/fold.txt b/runtime/doc/fold.txt
index c3f413232..bdf4a4851 100644
--- a/runtime/doc/fold.txt
+++ b/runtime/doc/fold.txt
@@ -1,4 +1,4 @@
-*fold.txt* For Vim version 8.0. Last change: 2016 Jan 02
+*fold.txt* For Vim version 8.0. Last change: 2017 Mar 18
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -79,7 +79,7 @@ This will call a function to compute the fold level: >
:set foldexpr=MyFoldLevel(v:lnum)
This will make a fold out of paragraphs separated by blank lines: >
:set foldexpr=getline(v:lnum)=~'^\\s*$'&&getline(v:lnum+1)=~'\\S'?'<1':1
-this does the same: >
+This does the same: >
:set foldexpr=getline(v:lnum-1)=~'^\\s*$'&&getline(v:lnum)=~'\\S'?'>1':1
Note that backslashes must be used to escape characters that ":set" handles
@@ -203,7 +203,7 @@ and the level given by the marker:
1. If a marker with the same fold level is encountered, the previous fold
ends and another fold with the same level starts.
2. If a marker with a higher fold level is found, a nested fold is started.
-3. if a marker with a lower fold level is found, all folds up to and including
+3. If a marker with a lower fold level is found, all folds up to and including
this level end and a fold with the specified level starts.
The number indicates the fold level. A zero cannot be used (a marker with
diff --git a/runtime/doc/ft_rust.txt b/runtime/doc/ft_rust.txt
new file mode 100644
index 000000000..b6e974e37
--- /dev/null
+++ b/runtime/doc/ft_rust.txt
@@ -0,0 +1,237 @@
+*ft_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_<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:
diff --git a/runtime/doc/helphelp.txt b/runtime/doc/helphelp.txt
index 20f1ed861..80fc70c3b 100644
--- a/runtime/doc/helphelp.txt
+++ b/runtime/doc/helphelp.txt
@@ -1,4 +1,4 @@
-*helphelp.txt* For Vim version 8.0. Last change: 2017 Feb 09
+*helphelp.txt* For Vim version 8.0. Last change: 2017 Mar 19
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -142,7 +142,8 @@ Help on help files *helphelp*
already opened, then the location list for that window
is used. Otherwise, a new help window is opened and
the location list for that window is set. The
- location list for the current window is not changed.
+ location list for the current window is not changed
+ then.
*:exu* *:exusage*
:exu[sage] Show help on Ex commands. Added to simulate the Nvi
diff --git a/runtime/doc/remote.txt b/runtime/doc/remote.txt
index 86fdd495e..cecdd6a8a 100644
--- a/runtime/doc/remote.txt
+++ b/runtime/doc/remote.txt
@@ -1,4 +1,4 @@
-*remote.txt* For Vim version 8.0. Last change: 2015 Mar 01
+*remote.txt* For Vim version 8.0. Last change: 2017 Mar 18
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -149,6 +149,7 @@ the description in |eval.txt| or use CTRL-] on the function name to jump to
the full explanation.
synopsis explanation ~
+ remote_startserver( name) run a server
remote_expr( server, string, idvar) send expression
remote_send( server, string, idvar) send key sequence
serverlist() get a list of available servers
diff --git a/runtime/doc/tags b/runtime/doc/tags
index 68c611b75..6e74c66f0 100644
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -1927,6 +1927,13 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX*
:Print various.txt /*:Print*
:Rexplore pi_netrw.txt /*:Rexplore*
:RmVimball pi_vimball.txt /*:RmVimball*
+:RustEmitAsm ft_rust.txt /*:RustEmitAsm*
+:RustEmitIr ft_rust.txt /*:RustEmitIr*
+:RustExpand ft_rust.txt /*:RustExpand*
+:RustFmt ft_rust.txt /*:RustFmt*
+:RustFmtRange ft_rust.txt /*:RustFmtRange*
+:RustPlay ft_rust.txt /*:RustPlay*
+:RustRun ft_rust.txt /*:RustRun*
:Sexplore pi_netrw.txt /*:Sexplore*
:TOhtml syntax.txt /*:TOhtml*
:TarDiff pi_tar.txt /*:TarDiff*
@@ -4505,6 +4512,8 @@ E938 eval.txt /*E938*
E939 change.txt /*E939*
E94 windows.txt /*E94*
E940 eval.txt /*E940*
+E941 eval.txt /*E941*
+E942 eval.txt /*E942*
E95 message.txt /*E95*
E96 diff.txt /*E96*
E97 diff.txt /*E97*
@@ -5013,6 +5022,7 @@ assert_inrange() eval.txt /*assert_inrange()*
assert_match() eval.txt /*assert_match()*
assert_notequal() eval.txt /*assert_notequal()*
assert_notmatch() eval.txt /*assert_notmatch()*
+assert_report() eval.txt /*assert_report()*
assert_true() eval.txt /*assert_true()*
at motion.txt /*at*
atan() eval.txt /*atan()*
@@ -6128,6 +6138,8 @@ ft-rexx-syntax syntax.txt /*ft-rexx-syntax*
ft-rst-syntax syntax.txt /*ft-rst-syntax*
ft-ruby-omni insert.txt /*ft-ruby-omni*
ft-ruby-syntax syntax.txt /*ft-ruby-syntax*
+ft-rust filetype.txt /*ft-rust*
+ft-rust ft_rust.txt /*ft-rust*
ft-scheme-syntax syntax.txt /*ft-scheme-syntax*
ft-sdl-syntax syntax.txt /*ft-sdl-syntax*
ft-sed-syntax syntax.txt /*ft-sed-syntax*
@@ -6160,6 +6172,7 @@ ft-xpm-syntax syntax.txt /*ft-xpm-syntax*
ft-yaml-syntax syntax.txt /*ft-yaml-syntax*
ft-zsh-syntax syntax.txt /*ft-zsh-syntax*
ft_ada.txt ft_ada.txt /*ft_ada.txt*
+ft_rust.txt ft_rust.txt /*ft_rust.txt*
ft_sql.txt ft_sql.txt /*ft_sql.txt*
ftdetect filetype.txt /*ftdetect*
ftp pi_netrw.txt /*ftp*
@@ -6237,6 +6250,7 @@ g:decada.Make_Command ft_ada.txt /*g:decada.Make_Command*
g:decada.Unit_Name() ft_ada.txt /*g:decada.Unit_Name()*
g:filetype_csh syntax.txt /*g:filetype_csh*
g:filetype_r syntax.txt /*g:filetype_r*
+g:ftplugin_rust_source_path ft_rust.txt /*g:ftplugin_rust_source_path*
g:gnat ft_ada.txt /*g:gnat*
g:gnat.Error_Format ft_ada.txt /*g:gnat.Error_Format*
g:gnat.Find() ft_ada.txt /*g:gnat.Find()*
@@ -6366,6 +6380,20 @@ g:netrw_win95ftp pi_netrw.txt /*g:netrw_win95ftp*
g:netrw_winsize pi_netrw.txt /*g:netrw_winsize*
g:netrw_wiw pi_netrw.txt /*g:netrw_wiw*
g:netrw_xstrlen pi_netrw.txt /*g:netrw_xstrlen*
+g:rust_bang_comment_leader ft_rust.txt /*g:rust_bang_comment_leader*
+g:rust_conceal ft_rust.txt /*g:rust_conceal*
+g:rust_conceal_mod_path ft_rust.txt /*g:rust_conceal_mod_path*
+g:rust_conceal_pub ft_rust.txt /*g:rust_conceal_pub*
+g:rust_fold ft_rust.txt /*g:rust_fold*
+g:rust_playpen_url ft_rust.txt /*g:rust_playpen_url*
+g:rust_recommended_style ft_rust.txt /*g:rust_recommended_style*
+g:rust_shortener_url ft_rust.txt /*g:rust_shortener_url*
+g:rustc_makeprg_no_percent ft_rust.txt /*g:rustc_makeprg_no_percent*
+g:rustc_path ft_rust.txt /*g:rustc_path*
+g:rustfmt_autosave ft_rust.txt /*g:rustfmt_autosave*
+g:rustfmt_command ft_rust.txt /*g:rustfmt_command*
+g:rustfmt_fail_silently ft_rust.txt /*g:rustfmt_fail_silently*
+g:rustfmt_options ft_rust.txt /*g:rustfmt_options*
g:syntax_on syntax.txt /*g:syntax_on*
g:tar_browseoptions pi_tar.txt /*g:tar_browseoptions*
g:tar_cmd pi_tar.txt /*g:tar_cmd*
@@ -8019,6 +8047,7 @@ remote_foreground() eval.txt /*remote_foreground()*
remote_peek() eval.txt /*remote_peek()*
remote_read() eval.txt /*remote_read()*
remote_send() eval.txt /*remote_send()*
+remote_startserver() eval.txt /*remote_startserver()*
remove() eval.txt /*remove()*
remove-filetype filetype.txt /*remove-filetype*
remove-option-flags options.txt /*remove-option-flags*
@@ -8074,6 +8103,13 @@ russian-issues russian.txt /*russian-issues*
russian-keymap russian.txt /*russian-keymap*
russian-l18n russian.txt /*russian-l18n*
russian.txt russian.txt /*russian.txt*
+rust ft_rust.txt /*rust*
+rust-commands ft_rust.txt /*rust-commands*
+rust-intro ft_rust.txt /*rust-intro*
+rust-mappings ft_rust.txt /*rust-mappings*
+rust-settings ft_rust.txt /*rust-settings*
+rust_<D-R> ft_rust.txt /*rust_<D-R>*
+rust_<D-r> ft_rust.txt /*rust_<D-r>*
rview starting.txt /*rview*
rvim starting.txt /*rvim*
rxvt syntax.txt /*rxvt*
diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt
index 67a00bed2..281cbc0e9 100644
--- a/runtime/doc/todo.txt
+++ b/runtime/doc/todo.txt
@@ -1,4 +1,4 @@
-*todo.txt* For Vim version 8.0. Last change: 2017 Mar 16
+*todo.txt* For Vim version 8.0. Last change: 2017 Mar 21
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -35,12 +35,6 @@ entered there will not be repeated below, unless there is extra information.
*known-bugs*
-------------------- Known bugs and current work -----------------------
-Using "g<" after ":for x in [1,2,3]|echom x|endfor" looks wrong. (Marcin
-Szamotulski, 2017 Mar 12)
-Also, using Ctrl-C clears the last part.
-
-Test 45 fails on MS-Windows only before resetting 'sw'. Why?
-
+channel:
- Try out background make plugin:
https://github.com/AndrewVos/vim-make-background
@@ -116,13 +110,8 @@ manager. Problem with Motif?
Memory leak in test97? The string is actually freed. Weird.
-Include rust files. Got all permissions?
-
-dict_add_list and dict_add_dict may free item when failing. (2017 Mar 12,
-Nikolai Pavlov, #1555)
-
-Patch to add buffer name argument to taglist().
-Ordering of tags in result of taglist call. (Duncan McDougall, #1194)
+Patch to make "start" work better: Use ShellExecute in !start (Katsuya Hino,
+#1570)
Add a toolbar in the terminal. Can be global, above all windows, or specific
for one window.
diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt
index 4bffb477c..5bf855cde 100644
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -1,4 +1,4 @@
-*usr_41.txt* For Vim version 8.0. Last change: 2017 Mar 09
+*usr_41.txt* For Vim version 8.0. Last change: 2017 Mar 18
VIM USER MANUAL - by Bram Moolenaar
@@ -889,6 +889,7 @@ GUI: *gui-functions*
Vim server: *server-functions*
serverlist() return the list of server names
+ remote_startserve() run a server
remote_send() send command characters to a Vim server
remote_expr() evaluate an expression in a Vim server
server2client() send a reply to a client of a Vim server
@@ -920,6 +921,7 @@ Testing: *test-functions*
assert_true() assert that an expression is true
assert_exception() assert that a command throws an exception
assert_fails() assert that a function call fails
+ assert_report() report a test failure
test_alloc_fail() make memory allocation fail
test_autochdir() enable 'autochdir' during startup
test_override() test with Vim internal overrides
diff --git a/runtime/ftplugin/hamster.vim b/runtime/ftplugin/hamster.vim
index 29711fb09..6c0630fe0 100644
--- a/runtime/ftplugin/hamster.vim
+++ b/runtime/ftplugin/hamster.vim
@@ -2,7 +2,7 @@
" Language: Hamster Script
" Version: 2.0.6.0
" Maintainer: David Fishburn <dfishburn dot vim at gmail dot com>
-" Last Change: 2017 Mar 07
+" Last Change: 2017 Mar 18
" Only do this when not done yet for this buffer
if exists("b:did_ftplugin")
@@ -14,7 +14,6 @@ let b:did_ftplugin = 1
let s:cpo_save = &cpo
set cpo&vim
-set cpo-=C
let b:undo_ftplugin = "setl fo< com< tw< commentstring<"
\ . "| unlet! b:match_ignorecase b:match_words b:match_skip"
diff --git a/runtime/ftplugin/rust.vim b/runtime/ftplugin/rust.vim
new file mode 100644
index 000000000..7efca5985
--- /dev/null
+++ b/runtime/ftplugin/rust.vim
@@ -0,0 +1,197 @@
+" Language: Rust
+" Description: Vim ftplugin for Rust
+" Maintainer: Chris Morgan <me@chrismorgan.info>
+" Maintainer: Kevin Ballard <kevin@sb.org>
+" Last Change: June 08, 2016
+" For bugs, patches and license go to https://github.com/rust-lang/rust.vim
+
+if exists("b:did_ftplugin")
+ finish
+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 <buffer>
+ \ if expand('<afile>') ==# 'delimitMate_map' && match(
+ \ delimitMate#Get("excluded_regions"),
+ \ s:delimitMate_extra_excluded_regions) == -1
+ \| let b:delimitMate_excluded_regions =
+ \ delimitMate#Get("excluded_regions")
+ \ . s:delimitMate_extra_excluded_regions
+ \|endif
+
+ " For this buffer, when delimitMate issues the `User delimitMate_unmap`
+ " event in the autocommand system, delete the above-defined extra excluded
+ " regions from delimitMate's state (the deletion being idempotent and
+ " having no effect if the extra excluded regions are not present in the
+ " targeted part of delimitMate's state).
+ autocmd User <buffer>
+ \ if expand('<afile>') ==# 'delimitMate_unmap'
+ \| let b:delimitMate_excluded_regions = substitute(
+ \ delimitMate#Get("excluded_regions"),
+ \ '\C\V' . s:delimitMate_extra_excluded_regions,
+ \ '', 'g')
+ \|endif
+endif
+
+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 <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 -buffer RustRun call rust#Run(<bang>0, <q-args>)
+
+" See |:RustExpand| for docs
+command! -nargs=* -complete=customlist,rust#CompleteExpand -bang -buffer RustExpand call rust#Expand(<bang>0, <q-args>)
+
+" See |:RustEmitIr| for docs
+command! -nargs=* -buffer RustEmitIr call rust#Emit("llvm-ir", <q-args>)
+
+" See |:RustEmitAsm| for docs
+command! -nargs=* -buffer RustEmitAsm call rust#Emit("asm", <q-args>)
+
+" See |:RustPlay| for docs
+command! -range=% RustPlay :call rust#Play(<count>, <line1>, <line2>, <f-args>)
+
+" See |:RustFmt| for docs
+command! -buffer RustFmt call rustfmt#Format()
+
+" See |:RustFmtRange| for docs
+command! -range -buffer RustFmtRange call rustfmt#FormatRange(<line1>, <line2>)
+
+" 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
+ \|delcommand RustPlay
+ \|nunmap <buffer> <D-r>
+ \|nunmap <buffer> <D-R>
+ \|nunmap <buffer> [[
+ \|nunmap <buffer> ]]
+ \|xunmap <buffer> [[
+ \|xunmap <buffer> ]]
+ \|ounmap <buffer> [[
+ \|ounmap <buffer> ]]
+ \|set matchpairs-=<:>
+ \"
+
+" }}}1
+
+" Code formatting on save
+if get(g:, "rustfmt_autosave", 0)
+ autocmd BufWritePre *.rs silent! call rustfmt#Format()
+endif
+
+augroup END
+
+let &cpo = s:save_cpo
+unlet s:save_cpo
+
+" vim: set noet sw=8 ts=8:
diff --git a/runtime/indent/javascript.vim b/runtime/indent/javascript.vim
index a6f1e1a8f..304c0fe24 100644
--- a/runtime/indent/javascript.vim
+++ b/runtime/indent/javascript.vim
@@ -2,7 +2,7 @@
" Language: Javascript
" Maintainer: Chris Paul ( https://github.com/bounceme )
" URL: https://github.com/pangloss/vim-javascript
-" Last Change: December 31, 2016
+" Last Change: March 21, 2017
" Only load this indent file when no other was loaded.
if exists('b:did_indent')
@@ -14,6 +14,10 @@ let b:did_indent = 1
setlocal indentexpr=GetJavascriptIndent()
setlocal autoindent nolisp nosmartindent
setlocal indentkeys+=0],0)
+" Testable with something like:
+" vim -eNs "+filetype plugin indent on" "+syntax on" "+set ft=javascript" \
+" "+norm! gg=G" '+%print' '+:q!' testfile.js \
+" | diff -uBZ testfile.js -
let b:undo_indent = 'setlocal indentexpr< smartindent< autoindent< indentkeys<'
@@ -32,10 +36,14 @@ if exists('*shiftwidth')
endfunction
else
function s:sw()
- return &sw
+ return &l:shiftwidth == 0 ? &l:tabstop : &l:shiftwidth
endfunction
endif
+" Performance for forwards search(): start search at pos rather than masking
+" matches before pos.
+let s:z = has('patch-7.4.984') ? 'z' : ''
+
" searchpair() wrapper
if has('reltime')
function s:GetPair(start,end,flags,skip,time,...)
@@ -48,34 +56,41 @@ else
endif
" Regex of syntax group names that are or delimit string or are comments.
-let s:syng_strcom = 'string\|comment\|regex\|special\|doc\|template'
-let s:syng_str = 'string\|template'
+let s:syng_strcom = 'string\|comment\|regex\|special\|doc\|template\%(braces\)\@!'
+let s:syng_str = 'string\|template\|special'
let s:syng_com = 'comment\|doc'
" Expression used to check whether we should skip a match with searchpair().
let s:skip_expr = "synIDattr(synID(line('.'),col('.'),0),'name') =~? '".s:syng_strcom."'"
+function s:parse_cino(f) abort
+ return float2nr(eval(substitute(substitute(join(split(
+ \ matchstr(&cino,'.*'.a:f.'\zs[^,]*'), 's',1), '*'.s:W)
+ \ , '^-\=\zs\*','',''), '^-\=\zs\.','0.','')))
+endfunction
+
function s:skip_func()
- if !s:free || search('\m`\|\*\/','nW',s:looksyn)
- let s:free = !eval(s:skip_expr)
- let s:looksyn = s:free ? line('.') : s:looksyn
- return !s:free
+ if getline('.') =~ '\%<'.col('.').'c\/.\{-}\/\|\%>'.col('.').'c[''"]\|\\$'
+ return eval(s:skip_expr)
+ elseif s:checkIn || search('\m`\|\${\|\*\/','nW'.s:z,s:looksyn)
+ let s:checkIn = eval(s:skip_expr)
endif
let s:looksyn = line('.')
- return (search('\m\/','nbW',s:looksyn) || search('\m[''"]\|\\$','nW',s:looksyn)) && eval(s:skip_expr)
+ return s:checkIn
endfunction
function s:alternatePair(stop)
let pos = getpos('.')[1:2]
- while search('\m[][(){}]','bW',a:stop)
- if !s:skip_func()
- let idx = stridx('])}',s:looking_at())
- if idx + 1
- if !s:GetPair(['\[','(','{'][idx], '])}'[idx],'bW','s:skip_func()',2000,a:stop)
- break
- endif
- else
- return
+ let pat = '[][(){};]'
+ while search('\m'.pat,'bW',a:stop)
+ if s:skip_func() | continue | endif
+ let idx = stridx('])};',s:looking_at())
+ if idx is 3 | let pat = '[{}()]' | continue | endif
+ if idx + 1
+ if s:GetPair(['\[','(','{'][idx], '])}'[idx],'bW','s:skip_func()',2000,a:stop) <= 0
+ break
endif
+ else
+ return
endif
endwhile
call call('cursor',pos)
@@ -100,93 +115,91 @@ function s:token()
return s:looking_at() =~ '\k' ? expand('<cword>') : s:looking_at()
endfunction
-function s:b_token()
- if s:looking_at() =~ '\k'
- call search('\m\<','cbW')
- endif
- return search('\m\S','bW')
-endfunction
-
function s:previous_token()
- let l:n = line('.')
- while s:b_token()
- if (s:looking_at() == '/' || line('.') != l:n && search('\m\/\/','nbW',
- \ line('.'))) && s:syn_at(line('.'),col('.')) =~? s:syng_com
- call search('\m\_[^/]\zs\/[/*]','bW')
+ let l:pos = getpos('.')[1:2]
+ if search('\m\k\{1,}\zs\k\|\S','bW')
+ if (getline('.')[col('.')-2:col('.')-1] == '*/' || line('.') != l:pos[0] &&
+ \ getline('.') =~ '\%<'.col('.').'c\/\/') && s:syn_at(line('.'),col('.')) =~? s:syng_com
+ while search('\m\S\ze\_s*\/[/*]','bW')
+ if s:syn_at(line('.'),col('.')) !~? s:syng_com
+ return s:token()
+ endif
+ endwhile
else
return s:token()
endif
- endwhile
+ endif
+ call call('cursor',l:pos)
return ''
endfunction
-function s:others(p)
- return "((line2byte(line('.')) + col('.')) <= ".(line2byte(a:p[0]) + a:p[1]).") || ".s:skip_expr
-endfunction
-
-function s:tern_skip(p)
- return s:GetPair('{','}','nbW',s:others(a:p),200,a:p[0]) > 0
-endfunction
-
-function s:tern_col(p)
- return s:GetPair('?',':\@<!::\@!','nbW',s:others(a:p)
- \ .' || s:tern_skip('.string(a:p).')',200,a:p[0]) > 0
-endfunction
-
-function s:label_col()
- let pos = getpos('.')[1:2]
- let [s:looksyn,s:free] = pos
- call s:alternatePair(0)
- if s:save_pos('s:IsBlock')
- let poss = getpos('.')[1:2]
- return call('cursor',pos) || !s:tern_col(poss)
- elseif s:looking_at() == ':'
- return !s:tern_col([0,0])
+function s:expr_col()
+ if getline('.')[col('.')-2] == ':'
+ return 1
endif
+ let bal = 0
+ while search('\m[{}?:;]','bW')
+ if eval(s:skip_expr) | continue | endif
+ " switch (looking_at())
+ exe { '}': "if s:GetPair('{','}','bW',s:skip_expr,200) <= 0 | return | endif",
+ \ ';': "return",
+ \ '{': "return getpos('.')[1:2] != b:js_cache[1:] && !s:IsBlock()",
+ \ ':': "let bal -= getline('.')[max([col('.')-2,0]):col('.')] !~ '::'",
+ \ '?': "let bal += 1 | if bal > 0 | return 1 | endif" }[s:looking_at()]
+ endwhile
endfunction
" configurable regexes that define continuation lines, not including (, {, or [.
let s:opfirst = '^' . get(g:,'javascript_opfirst',
- \ '\%([<>=,?^%|*/&]\|\([-.:+]\)\1\@!\|!=\|in\%(stanceof\)\=\>\)')
+ \ '\C\%([<>=,?^%|*/&]\|\([-.:+]\)\1\@!\|!=\|in\%(stanceof\)\=\>\)')
let s:continuation = get(g:,'javascript_continuation',
- \ '\%([<=,.~!?/*^%|&:]\|+\@<!+\|-\@<!-\|=\@<!>\|\<\%(typeof\|delete\|void\|in\|instanceof\)\)') . '$'
+ \ '\C\%([-+<>=,.~!?/*^%|&:]\|\<\%(typeof\|new\|delete\|void\|in\|instanceof\|await\)\)') . '$'
function s:continues(ln,con)
- return !cursor(a:ln, match(' '.a:con,s:continuation)) &&
- \ eval((['s:syn_at(line("."),col(".")) !~? "regex"'] +
- \ repeat(['s:previous_token() != "."'],5) + [1])[
- \ index(split('/ typeof in instanceof void delete'),s:token())])
+ if !cursor(a:ln, match(' '.a:con,s:continuation))
+ let teol = s:looking_at()
+ if teol == '/'
+ return s:syn_at(line('.'),col('.')) !~? 'regex'
+ elseif teol =~ '[-+>]'
+ return getline('.')[col('.')-2] != tr(teol,'>','=')
+ elseif teol =~ '\l'
+ return s:previous_token() != '.'
+ elseif teol == ':'
+ return s:expr_col()
+ endif
+ return 1
+ endif
endfunction
" get the line of code stripped of comments and move cursor to the last
" non-comment char.
function s:Trim(ln)
let pline = substitute(getline(a:ln),'\s*$','','')
- let l:max = max([match(pline,'.*[^/]\zs\/[/*]'),0])
- while l:max && s:syn_at(a:ln, strlen(pline)) =~? s:syng_com
- let pline = substitute(strpart(pline, 0, l:max),'\s*$','','')
- let l:max = max([match(pline,'.*[^/]\zs\/[/*]'),0])
+ let l:max = max([strridx(pline,'//'), strridx(pline,'/*')])
+ while l:max != -1 && s:syn_at(a:ln, strlen(pline)) =~? s:syng_com
+ let pline = pline[: l:max]
+ let l:max = max([strridx(pline,'//'), strridx(pline,'/*')])
+ let pline = substitute(pline[:-2],'\s*$','','')
endwhile
- return cursor(a:ln,strlen(pline)) ? pline : pline
+ return pline is '' || cursor(a:ln,strlen(pline)) ? pline : pline
endfunction
" Find line above 'lnum' that isn't empty or in a comment
function s:PrevCodeLine(lnum)
- let l:n = prevnonblank(a:lnum)
+ let [l:pos, l:n] = [getpos('.')[1:2], prevnonblank(a:lnum)]
while l:n
if getline(l:n) =~ '^\s*\/[/*]'
- if (stridx(getline(l:n),'`') > 0 || getline(l:n-1)[-1:] == '\') &&
- \ s:syn_at(l:n,1) =~? s:syng_str
- return l:n
- endif
let l:n = prevnonblank(l:n-1)
- elseif s:syn_at(l:n,1) =~? s:syng_com
- let l:n = s:save_pos('eval',
- \ 'cursor('.l:n.',1) + search(''\m\/\*'',"bW")')
+ elseif stridx(getline(l:n), '*/') + 1 && s:syn_at(l:n,1) =~? s:syng_com
+ call cursor(l:n,1)
+ keepjumps norm! [*
+ let l:n = search('\m\S','nbW')
else
- return l:n
+ break
endif
endwhile
+ call call('cursor',l:pos)
+ return l:n
endfunction
" Check if line 'lnum' has a balanced amount of parentheses.
@@ -201,7 +214,9 @@ function s:Balanced(lnum)
return
endif
endif
- let pos = match(l:line, '[][(){}]', pos + 1)
+ let pos = match(l:line, (l:open ?
+ \ '['.escape(tr(l:line[pos],'({[]})',')}][{(').l:line[pos],']').']' :
+ \ '[][(){}]'), pos + 1)
endwhile
return !l:open
endfunction
@@ -210,11 +225,11 @@ function s:OneScope(lnum)
let pline = s:Trim(a:lnum)
let kw = 'else do'
if pline[-1:] == ')' && s:GetPair('(', ')', 'bW', s:skip_expr, 100) > 0
- call s:previous_token()
- let kw = 'for if let while with'
- if index(split('await each'),s:token()) + 1
+ if s:previous_token() =~# '^\%(await\|each\)$'
call s:previous_token()
let kw = 'for'
+ else
+ let kw = 'for if let while with'
endif
endif
return pline[-2:] == '=>' || index(split(kw),s:token()) + 1 &&
@@ -246,18 +261,23 @@ function s:IsBlock()
if s:looking_at() == '{'
let l:n = line('.')
let char = s:previous_token()
- let syn = char =~ '[{>/]' ? s:syn_at(line('.'),col('.')-(char == '{')) : ''
- if syn =~? 'xml\|jsx'
+ if match(s:stack,'\cxml\|jsx') + 1 && s:syn_at(line('.'),col('.')-1) =~? 'xml\|jsx'
return char != '{'
elseif char =~ '\k'
- return index(split('return const let import export yield default delete var await void typeof throw case new in instanceof')
- \ ,char) < (line('.') != l:n) || s:previous_token() == '.'
+ if char ==# 'type'
+ return s:previous_token() !~# '^\%(im\|ex\)port$'
+ endif
+ return index(split('return const let import export extends yield default delete var await void typeof throw case new of in instanceof')
+ \ ,char) < (line('.') != l:n) || s:save_pos('s:previous_token') == '.'
elseif char == '>'
- return getline('.')[col('.')-2] == '=' || syn =~? '^jsflow'
+ return getline('.')[col('.')-2] == '=' || s:syn_at(line('.'),col('.')) =~? '^jsflow'
elseif char == ':'
- return getline('.')[col('.')-2] != ':' && s:label_col()
+ return !s:save_pos('s:expr_col')
+ elseif char == '/'
+ return s:syn_at(line('.'),col('.')) =~? 'regex'
endif
- return syn =~? 'regex' || char !~ '[-=~!<*+,/?^%|&([]'
+ return char !~ '[=~!<*,?^%|&([]' &&
+ \ (char !~ '[-+]' || l:n != line('.') && getline('.')[col('.')-2] == char)
endif
endfunction
@@ -266,7 +286,9 @@ function GetJavascriptIndent()
" Get the current line.
call cursor(v:lnum,1)
let l:line = getline('.')
- let syns = s:syn_at(v:lnum, 1)
+ " use synstack as it validates syn state and works in an empty line
+ let s:stack = map(synstack(v:lnum,1),"synIDattr(v:val,'name')")
+ let syns = get(s:stack,-1,'')
" start with strings,comments,etc.
if syns =~? s:syng_com
@@ -275,7 +297,7 @@ function GetJavascriptIndent()
elseif l:line !~ '^\s*\/[/*]'
return -1
endif
- elseif syns =~? s:syng_str && l:line !~ '^[''"]'
+ elseif syns =~? s:syng_str
if b:js_cache[0] == v:lnum - 1 && s:Balanced(v:lnum-1)
let b:js_cache[0] = v:lnum
endif
@@ -295,69 +317,60 @@ function GetJavascriptIndent()
endif
" the containing paren, bracket, or curly. Many hacks for performance
- let idx = strlen(l:line) ? stridx('])}',l:line[0]) : -1
+ let idx = index([']',')','}'],l:line[0])
if b:js_cache[0] >= l:lnum && b:js_cache[0] < v:lnum &&
\ (b:js_cache[0] > l:lnum || s:Balanced(l:lnum))
call call('cursor',b:js_cache[1:])
else
- let [s:looksyn, s:free, top] = [v:lnum - 1, 1, (!indent(l:lnum) &&
+ let [s:looksyn, s:checkIn, top] = [v:lnum - 1, 0, (!indent(l:lnum) &&
\ s:syn_at(l:lnum,1) !~? s:syng_str) * l:lnum]
if idx + 1
- call s:GetPair(['\[','(','{'][idx], '])}'[idx],'bW','s:skip_func()',2000,top)
- elseif indent(v:lnum) && syns =~? 'block'
+ call s:GetPair(['\[','(','{'][idx],'])}'[idx],'bW','s:skip_func()',2000,top)
+ elseif getline(v:lnum) !~ '^\S' && syns =~? 'block'
call s:GetPair('{','}','bW','s:skip_func()',2000,top)
else
call s:alternatePair(top)
endif
endif
- if idx + 1 || l:line[:1] == '|}'
- if idx == 2 && search('\m\S','bW',line('.')) && s:looking_at() == ')'
- call s:GetPair('(',')','bW',s:skip_expr,200)
- endif
- return indent('.')
- endif
-
let b:js_cache = [v:lnum] + (line('.') == v:lnum ? [0,0] : getpos('.')[1:2])
let num = b:js_cache[1]
let [s:W, isOp, bL, switch_offset] = [s:sw(),0,0,0]
if !num || s:IsBlock()
+ let ilnum = line('.')
let pline = s:save_pos('s:Trim',l:lnum)
if num && s:looking_at() == ')' && s:GetPair('(', ')', 'bW', s:skip_expr, 100) > 0
- let num = line('.')
- if s:previous_token() ==# 'switch' && s:previous_token() != '.'
- if &cino !~ ':' || !has('float')
+ let num = ilnum == num ? line('.') : num
+ if idx < 0 && s:previous_token() ==# 'switch' && s:previous_token() != '.'
+ if &cino !~ ':'
let switch_offset = s:W
else
- let cinc = matchlist(&cino,'.*:\(-\)\=\([0-9.]*\)\(s\)\=\C')
- let switch_offset = float2nr(str2float(cinc[1].(strlen(cinc[2]) ? cinc[2] : strlen(cinc[3])))
- \ * (strlen(cinc[3]) ? s:W : 1))
+ let switch_offset = max([-indent(num),s:parse_cino(':')])
endif
if pline[-1:] != '.' && l:line =~# '^\%(default\|case\)\>'
return indent(num) + switch_offset
endif
endif
endif
- if pline[-1:] !~ '[{;]'
- if pline =~# ':\@<!:$'
- call cursor(l:lnum,strlen(pline))
- let isOp = s:tern_col(b:js_cache[1:2])
- else
- let isOp = l:line =~# s:opfirst || s:continues(l:lnum,pline)
- endif
- let bL = s:iscontOne(l:lnum,num,isOp)
+ if idx < 0 && pline[-1:] !~ '[{;]'
+ let isOp = (l:line =~# s:opfirst || s:continues(l:lnum,pline)) * s:W
+ let bL = s:iscontOne(l:lnum,b:js_cache[1],isOp)
let bL -= (bL && l:line[0] == '{') * s:W
endif
+ elseif idx < 0 && getline(b:js_cache[1])[b:js_cache[2]-1] == '(' && &cino =~ '('
+ let pval = s:parse_cino('(')
+ return !pval ? (s:parse_cino('w') ? 0 : -(!!search('\m\S','W'.s:z,num))) + virtcol('.') :
+ \ max([indent('.') + pval + (s:GetPair('(',')','nbrmW',s:skip_expr,100,num) * s:W),0])
endif
" main return
- if isOp
- return (num ? indent(num) : -s:W) + (s:W * 2) + switch_offset + bL
+ if l:line =~ '^\%([])}]\||}\)'
+ return max([indent(num),0])
elseif num
- return indent(num) + s:W + switch_offset + bL
+ return indent(num) + s:W + switch_offset + bL + isOp
endif
- return bL
+ return bL + isOp
endfunction
let &cpo = s:cpo_save
diff --git a/runtime/indent/rust.vim b/runtime/indent/rust.vim
new file mode 100644
index 000000000..a3051f0b0
--- /dev/null
+++ b/runtime/indent/rust.vim
@@ -0,0 +1,213 @@
+" Vim indent file
+" Language: Rust
+" Author: Chris Morgan <me@chrismorgan.info>
+" Last Change: 2017 Mar 21
+" For bugs, patches and license go to https://github.com/rust-lang/rust.vim
+
+" Only load this indent file when no other was loaded.
+if exists("b:did_indent")
+ finish
+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
+
+let s:save_cpo = &cpo
+set cpo&vim
+
+" 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
+
+let &cpo = s:save_cpo
+unlet s:save_cpo
diff --git a/runtime/syntax/rust.vim b/runtime/syntax/rust.vim
new file mode 100644
index 000000000..57343301e
--- /dev/null
+++ b/runtime/syntax/rust.vim
@@ -0,0 +1,295 @@
+" 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: Feb 24, 2016
+" For bugs, patches and license go to https://github.com/rust-lang/rust.vim
+
+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 /\<union\_s\+\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*/ transparent contains=rustUnion
+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 in impl let
+syn keyword rustKeyword pub nextgroup=rustPubScope skipwhite skipempty
+syn keyword rustKeyword return
+syn keyword rustSuper super
+syn keyword rustKeyword unsafe where
+syn keyword rustKeyword use nextgroup=rustModPath skipwhite skipempty
+" FIXME: Scoped impl's name is also fallen in this category
+syn keyword rustKeyword mod trait nextgroup=rustIdentifier skipwhite skipempty
+syn keyword rustStorage move mut ref static const
+syn match rustDefault /\<default\ze\_s\+\(impl\|fn\|type\|const\)\>/
+
+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::<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 "&&\|||"
+" 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 ``\*\@<!`` 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 rustDeriveTrait rustTrait
+
+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 rustArrowCharacter rustOperator
+hi def link rustOperator Operator
+hi def link rustKeyword Keyword
+hi def link rustTypedef Keyword " More precise is Typedef, but it doesn't feel right for Rust
+hi def link rustStructure Keyword " More precise is Structure
+hi def link rustUnion rustStructure
+hi def link rustPubScopeDelim Delimiter
+hi def link rustPubScopeCrate rustKeyword
+hi def link rustSuper rustKeyword
+hi def link rustReservedKeyword Error
+hi def link rustRepeat Conditional
+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 rustShebang Comment
+hi def link rustCommentLine Comment
+hi def link rustCommentLineDoc SpecialComment
+hi def link rustCommentLineDocError Error
+hi def link rustCommentBlock rustCommentLine
+hi def link rustCommentBlockDoc rustCommentLineDoc
+hi def link rustCommentBlockDocError Error
+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 rustDefault StorageClass
+hi def link rustStorage StorageClass
+hi def link rustObsoleteStorage Error
+hi def link rustLifetime Special
+hi def link rustLabel Label
+hi def link rustInvalidBareKeyword Error
+hi def link rustExternCrate rustKeyword
+hi def link rustObsoleteExternMod Error
+hi def link rustBoxPlacementParens Delimiter
+hi def link rustQuestionMark Special
+
+" 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"