changeset 11229:146a1e213b60

Update runtime files. Add Rust support. commit https://github.com/vim/vim/commit/3c2881dc1195f53ebafc387378399ddd6cb677a7 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Mar 21 19:18:29 2017 +0100 Update runtime files. Add Rust support.
author Christian Brabandt <cb@256bit.org>
date Tue, 21 Mar 2017 19:30:06 +0100
parents 641b98249145
children a3ea65af63cf
files runtime/autoload/rust.vim runtime/autoload/rustfmt.vim runtime/compiler/cargo.vim runtime/compiler/rustc.vim runtime/doc/Makefile runtime/doc/eval.txt runtime/doc/filetype.txt runtime/doc/fold.txt runtime/doc/ft_rust.txt runtime/doc/helphelp.txt runtime/doc/remote.txt runtime/doc/tags runtime/doc/todo.txt runtime/doc/usr_41.txt runtime/ftplugin/hamster.vim runtime/ftplugin/rust.vim runtime/indent/javascript.vim runtime/indent/rust.vim runtime/syntax/rust.vim
diffstat 19 files changed, 1737 insertions(+), 142 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /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:
new file mode 100644
--- /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
new file mode 100644
--- /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
new file mode 100644
--- /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
--- 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 \
--- 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}
--- 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
 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
--- 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
 	: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
new file mode 100644
--- /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:
--- 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 @@ 1. Help commands					*online-help*
 			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
--- 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 CTR
 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
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -1927,6 +1927,13 @@ 90.5	usr_90.txt	/*90.5*
 :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_inran
 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-synt
 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:dec
 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_
 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_fo
 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-iss
 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*
--- 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
 							*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.
--- 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
--- 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"
new file mode 100644
--- /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:
--- 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
new file mode 100644
--- /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
new file mode 100644
--- /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"