]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
Update runtime files. Add Rust support.
authorBram Moolenaar <Bram@vim.org>
Tue, 21 Mar 2017 18:18:29 +0000 (19:18 +0100)
committerBram Moolenaar <Bram@vim.org>
Tue, 21 Mar 2017 18:18:29 +0000 (19:18 +0100)
19 files changed:
runtime/autoload/rust.vim [new file with mode: 0644]
runtime/autoload/rustfmt.vim [new file with mode: 0644]
runtime/compiler/cargo.vim [new file with mode: 0644]
runtime/compiler/rustc.vim [new file with mode: 0644]
runtime/doc/Makefile
runtime/doc/eval.txt
runtime/doc/filetype.txt
runtime/doc/fold.txt
runtime/doc/ft_rust.txt [new file with mode: 0644]
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 [new file with mode: 0644]
runtime/indent/javascript.vim
runtime/indent/rust.vim [new file with mode: 0644]
runtime/syntax/rust.vim [new file with mode: 0644]

diff --git a/runtime/autoload/rust.vim b/runtime/autoload/rust.vim
new file mode 100644 (file)
index 0000000..34a3b41
--- /dev/null
@@ -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 (file)
index 0000000..a689b5e
--- /dev/null
@@ -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 (file)
index 0000000..bd48666
--- /dev/null
@@ -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 (file)
index 0000000..c27bdc9
--- /dev/null
@@ -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
index 33a09be42944ae2469bbe2603a8435f066e53bd2..1a0e841973a16f46608fec5597d79e33cf975bc2 100644 (file)
@@ -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 \
index ff1b71feebdb7c6e55d9e2627a0b2d0251dcd6e9..db0a7561fef9f622c55290a0ce6982a2eaf410e4 100644 (file)
@@ -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}
index 4b0a185da2d58a5f6aff4117c5f6e86497758c67..8f58d76d9cd84388884c342b36b7e91b3ebf25e2 100644 (file)
@@ -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
index c3f413232afafc5bd35d41d047adb724e1b988cb..bdf4a48514ff60573f602331a39fa78681ba21a8 100644 (file)
@@ -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 (file)
index 0000000..b6e974e
--- /dev/null
@@ -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:
index 20f1ed861d4a99fb1f269043f0a3b3e91b9dde29..80fc70c3b5f674450b9eb7a7aea88259f165c355 100644 (file)
@@ -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
index 86fdd495e460dc7b45d6f15dcc4c522d273e1f82..cecdd6a8a48e0cef87bda0ecaee01cce360ff374 100644 (file)
@@ -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
index 68c611b75b1e67efef8e6793275eb90b40345623..6e74c66f00b62029117275e92cb010935ef9fa0e 100644 (file)
@@ -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*
index 67a00bed200b0a8975cdf107c154f2473ca8a8ec..281cbc0e93e163d7aa33d9910fcbfb84975b2378 100644 (file)
@@ -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.
index 4bffb477c9230f65e34b5efc592dec3d935376a0..5bf855cde51d8c0d5a8d5a1ad6f848ff3bea96fa 100644 (file)
@@ -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
index 29711fb0936196bd967c752289d048d8f91ccf65..6c0630fe048a8f0f2bde18905ee76c27937dd3a2 100644 (file)
@@ -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 (file)
index 0000000..7efca59
--- /dev/null
@@ -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:
index a6f1e1a8f821a50f92fea2f82df87ede1a87d87d..304c0fe24f4c14853a6eb99ee763df774a9f7d88 100644 (file)
@@ -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 (file)
index 0000000..a3051f0
--- /dev/null
@@ -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 (file)
index 0000000..5734330
--- /dev/null
@@ -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"