1
0
forked from aniani/vim

runtime(rust): sync rust runtime files with upstream (#13075)

Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Gregory Anders 2023-09-12 13:23:38 -05:00 committed by GitHub
parent f5356bf675
commit fc93594d56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1840 additions and 786 deletions

149
runtime/autoload/cargo.vim Normal file
View File

@ -0,0 +1,149 @@
" Last Modified: 2023-09-11
function! cargo#Load()
" Utility call to get this script loaded, for debugging
endfunction
function! cargo#cmd(args) abort
" Trim trailing spaces. This is necessary since :terminal command parses
" trailing spaces as an empty argument.
let args = substitute(a:args, '\s\+$', '', '')
if exists('g:cargo_shell_command_runner')
let cmd = g:cargo_shell_command_runner
elseif has('terminal')
let cmd = 'terminal'
elseif has('nvim')
let cmd = 'noautocmd new | terminal'
else
let cmd = '!'
endif
execute cmd 'cargo' args
endfunction
function! s:nearest_cargo(...) abort
" If the second argument is not specified, the first argument determines
" whether we will start from the current directory or the directory of the
" current buffer, otherwise, we start with the provided path on the
" second argument.
let l:is_getcwd = get(a:, 1, 0)
if l:is_getcwd
let l:starting_path = get(a:, 2, getcwd())
else
let l:starting_path = get(a:, 2, expand('%:p:h'))
endif
return findfile('Cargo.toml', l:starting_path . ';')
endfunction
function! cargo#nearestCargo(is_getcwd) abort
return s:nearest_cargo(a:is_getcwd)
endfunction
function! cargo#nearestWorkspaceCargo(is_getcwd) abort
let l:nearest = s:nearest_cargo(a:is_getcwd)
while l:nearest !=# ''
for l:line in readfile(l:nearest, '', 0x100)
if l:line =~# '\V[workspace]'
return l:nearest
endif
endfor
let l:next = fnamemodify(l:nearest, ':p:h:h')
let l:nearest = s:nearest_cargo(0, l:next)
endwhile
return ''
endfunction
function! cargo#nearestRootCargo(is_getcwd) abort
" Try to find a workspace Cargo.toml, and if not found, take the nearest
" regular Cargo.toml
let l:workspace_cargo = cargo#nearestWorkspaceCargo(a:is_getcwd)
if l:workspace_cargo !=# ''
return l:workspace_cargo
endif
return s:nearest_cargo(a:is_getcwd)
endfunction
function! cargo#build(args)
call cargo#cmd("build " . a:args)
endfunction
function! cargo#check(args)
call cargo#cmd("check " . a:args)
endfunction
function! cargo#clean(args)
call cargo#cmd("clean " . a:args)
endfunction
function! cargo#doc(args)
call cargo#cmd("doc " . a:args)
endfunction
function! cargo#new(args)
call cargo#cmd("new " . a:args)
cd `=a:args`
endfunction
function! cargo#init(args)
call cargo#cmd("init " . a:args)
endfunction
function! cargo#run(args)
call cargo#cmd("run " . a:args)
endfunction
function! cargo#test(args)
call cargo#cmd("test " . a:args)
endfunction
function! cargo#bench(args)
call cargo#cmd("bench " . a:args)
endfunction
function! cargo#update(args)
call cargo#cmd("update " . a:args)
endfunction
function! cargo#search(args)
call cargo#cmd("search " . a:args)
endfunction
function! cargo#publish(args)
call cargo#cmd("publish " . a:args)
endfunction
function! cargo#install(args)
call cargo#cmd("install " . a:args)
endfunction
function! cargo#runtarget(args)
let l:filename = expand('%:p')
let l:read_manifest = system('cargo read-manifest')
let l:metadata = json_decode(l:read_manifest)
let l:targets = get(l:metadata, 'targets', [])
let l:did_run = 0
for l:target in l:targets
let l:src_path = get(l:target, 'src_path', '')
let l:kinds = get(l:target, 'kind', [])
let l:name = get(l:target, 'name', '')
if l:src_path == l:filename
if index(l:kinds, 'example') != -1
let l:did_run = 1
call cargo#run("--example " . shellescape(l:name) . " " . a:args)
return
elseif index(l:kinds, 'bin') != -1
let l:did_run = 1
call cargo#run("--bin " . shellescape(l:name) . " " . a:args)
return
endif
endif
endfor
if l:did_run != 1
call cargo#run(a:args)
return
endif
endfunction
" vim: set et sw=4 sts=4 ts=8:

View File

@ -0,0 +1,29 @@
" Last Modified: 2023-09-11
function! cargo#quickfix#CmdPre() abort
if &filetype ==# 'rust' && get(b:, 'current_compiler', '') ==# 'cargo' &&
\ &makeprg =~ '\V\^cargo\ \.\*'
" Preserve the current directory, and 'lcd' to the nearest Cargo file.
let b:rust_compiler_cargo_qf_has_lcd = haslocaldir()
let b:rust_compiler_cargo_qf_prev_cd = getcwd()
let b:rust_compiler_cargo_qf_prev_cd_saved = 1
let l:nearest = fnamemodify(cargo#nearestRootCargo(0), ':h')
execute 'lchdir! '.l:nearest
else
let b:rust_compiler_cargo_qf_prev_cd_saved = 0
endif
endfunction
function! cargo#quickfix#CmdPost() abort
if exists("b:rust_compiler_cargo_qf_prev_cd_saved") && b:rust_compiler_cargo_qf_prev_cd_saved
" Restore the current directory.
if b:rust_compiler_cargo_qf_has_lcd
execute 'lchdir! '.b:rust_compiler_cargo_qf_prev_cd
else
execute 'chdir! '.b:rust_compiler_cargo_qf_prev_cd
endif
let b:rust_compiler_cargo_qf_prev_cd_saved = 0
endif
endfunction
" vim: set et sw=4 sts=4 ts=8:

View File

@ -1,8 +1,59 @@
" Author: Lily Ballard
" Description: Helper functions for Rust commands/mappings " Description: Helper functions for Rust commands/mappings
" Last Modified: May 27, 2014 " Last Modified: 2023-09-11
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim " For bugs, patches and license go to https://github.com/rust-lang/rust.vim
function! rust#Load()
" Utility call to get this script loaded, for debugging
endfunction
function! rust#GetConfigVar(name, default)
" Local buffer variable with same name takes predeence over global
if has_key(b:, a:name)
return get(b:, a:name)
endif
if has_key(g:, a:name)
return get(g:, a:name)
endif
return a:default
endfunction
" Include expression {{{1
function! rust#IncludeExpr(fname) abort
" Remove leading 'crate::' to deal with 2018 edition style 'use'
" statements
let l:fname = substitute(a:fname, '^crate::', '', '')
" Remove trailing colons arising from lines like
"
" use foo::{Bar, Baz};
let l:fname = substitute(l:fname, ':\+$', '', '')
" Replace '::' with '/'
let l:fname = substitute(l:fname, '::', '/', 'g')
" When we have
"
" use foo::bar::baz;
"
" we can't tell whether baz is a module or a function; and we can't tell
" which modules correspond to files.
"
" So we work our way up, trying
"
" foo/bar/baz.rs
" foo/bar.rs
" foo.rs
while l:fname !=# '.'
let l:path = findfile(l:fname)
if !empty(l:path)
return l:fname
endif
let l:fname = fnamemodify(l:fname, ':h')
endwhile
return l:fname
endfunction
" Jump {{{1 " Jump {{{1
function! rust#Jump(mode, function) range function! rust#Jump(mode, function) range
@ -68,7 +119,7 @@ function! s:Run(dict, rustc_args, args)
let pwd = a:dict.istemp ? a:dict.tmpdir : '' let pwd = a:dict.istemp ? a:dict.tmpdir : ''
let output = s:system(pwd, shellescape(rustc) . " " . join(map(rustc_args, 'shellescape(v:val)'))) let output = s:system(pwd, shellescape(rustc) . " " . join(map(rustc_args, 'shellescape(v:val)')))
if output != '' if output !=# ''
echohl WarningMsg echohl WarningMsg
echo output echo output
echohl None echohl None
@ -135,7 +186,7 @@ function! s:Expand(dict, pretty, args)
endfunction endfunction
function! rust#CompleteExpand(lead, line, pos) function! rust#CompleteExpand(lead, line, pos)
if a:line[: a:pos-1] =~ '^RustExpand!\s*\S*$' if a:line[: a:pos-1] =~# '^RustExpand!\s*\S*$'
" first argument and it has a ! " first argument and it has a !
let list = ["normal", "expanded", "typed", "expanded,identified", "flowgraph=", "everybody_loops"] let list = ["normal", "expanded", "typed", "expanded,identified", "flowgraph=", "everybody_loops"]
if !empty(a:lead) if !empty(a:lead)
@ -164,7 +215,7 @@ function! s:Emit(dict, type, args)
let args = [relpath, '--emit', a:type, '-o', output_path] + a:args let args = [relpath, '--emit', a:type, '-o', output_path] + a:args
let pwd = a:dict.istemp ? a:dict.tmpdir : '' let pwd = a:dict.istemp ? a:dict.tmpdir : ''
let output = s:system(pwd, shellescape(rustc) . " " . join(map(args, 'shellescape(v:val)'))) let output = s:system(pwd, shellescape(rustc) . " " . join(map(args, 'shellescape(v:val)')))
if output != '' if output !=# ''
echohl WarningMsg echohl WarningMsg
echo output echo output
echohl None echohl None
@ -174,10 +225,10 @@ function! s:Emit(dict, type, args)
exe 'silent keepalt read' fnameescape(output_path) exe 'silent keepalt read' fnameescape(output_path)
1 1
d d
if a:type == "llvm-ir" if a:type ==# "llvm-ir"
setl filetype=llvm setl filetype=llvm
let extension = 'll' let extension = 'll'
elseif a:type == "asm" elseif a:type ==# "asm"
setl filetype=asm setl filetype=asm
let extension = 's' let extension = 's'
endif endif
@ -243,8 +294,8 @@ function! s:WithPath(func, ...)
let dict.tmpdir_relpath = filename let dict.tmpdir_relpath = filename
let dict.path = dict.tmpdir.'/'.filename let dict.path = dict.tmpdir.'/'.filename
let saved.mod = &mod let saved.mod = &modified
set nomod set nomodified
silent exe 'keepalt write! ' . fnameescape(dict.path) silent exe 'keepalt write! ' . fnameescape(dict.path)
if pathisempty if pathisempty
@ -325,7 +376,7 @@ function! s:ShellTokenize(text)
endif endif
let l:state = 3 let l:state = 3
elseif l:state == 5 " single-quoted elseif l:state == 5 " single-quoted
if l:c == "'" if l:c ==# "'"
let l:state = 1 let l:state = 1
else else
let l:current .= l:c let l:current .= l:c
@ -343,11 +394,20 @@ function! s:RmDir(path)
if empty(a:path) if empty(a:path)
echoerr 'Attempted to delete empty path' echoerr 'Attempted to delete empty path'
return 0 return 0
elseif a:path == '/' || a:path == $HOME elseif a:path ==# '/' || a:path ==# $HOME
let l:path = expand(a:path)
if l:path ==# '/' || l:path ==# $HOME
echoerr 'Attempted to delete protected path: ' . a:path echoerr 'Attempted to delete protected path: ' . a:path
return 0 return 0
endif endif
return system("rm -rf " . shellescape(a:path)) endif
if !isdirectory(a:path)
return 0
endif
" delete() returns 0 when removing file successfully
return delete(a:path, 'rf') == 0
endfunction endfunction
" Executes {cmd} with the cwd set to {pwd}, without changing Vim's cwd. " Executes {cmd} with the cwd set to {pwd}, without changing Vim's cwd.
@ -396,20 +456,115 @@ function! rust#Play(count, line1, line2, ...) abort
call setreg('"', save_regcont, save_regtype) call setreg('"', save_regcont, save_regtype)
endif endif
let body = l:rust_playpen_url."?code=".webapi#http#encodeURI(content) let url = l:rust_playpen_url."?code=".webapi#http#encodeURI(content)
if strlen(body) > 5000 if strlen(url) > 5000
echohl ErrorMsg | echomsg 'Buffer too large, max 5000 encoded characters ('.strlen(body).')' | echohl None echohl ErrorMsg | echomsg 'Buffer too large, max 5000 encoded characters ('.strlen(url).')' | echohl None
return return
endif endif
let payload = "format=simple&url=".webapi#http#encodeURI(body) let payload = "format=simple&url=".webapi#http#encodeURI(url)
let res = webapi#http#post(l:rust_shortener_url.'create.php', payload, {}) let res = webapi#http#post(l:rust_shortener_url.'create.php', payload, {})
if res.status[0] ==# '2'
let url = res.content let url = res.content
endif
redraw | echomsg 'Done: '.url let footer = ''
if exists('g:rust_clip_command')
call system(g:rust_clip_command, url)
if !v:shell_error
let footer = ' (copied to clipboard)'
endif
endif
redraw | echomsg 'Done: '.url.footer
endfunction
" Run a test under the cursor or all tests {{{1
" Finds a test function name under the cursor. Returns empty string when a
" test function is not found.
function! s:SearchTestFunctionNameUnderCursor() abort
let cursor_line = line('.')
" Find #[test] attribute
if search('\m\C#\[test\]', 'bcW') is 0
return ''
endif
" Move to an opening brace of the test function
let test_func_line = search('\m\C^\s*fn\s\+\h\w*\s*(.\+{$', 'eW')
if test_func_line is 0
return ''
endif
" Search the end of test function (closing brace) to ensure that the
" cursor position is within function definition
if maparg('<Plug>(MatchitNormalForward)') ==# ''
keepjumps normal! %
else
" Prefer matchit.vim official plugin to native % since the plugin
" provides better behavior than original % (#391)
" To load the plugin, run:
" :packadd matchit
execute 'keepjumps' 'normal' "\<Plug>(MatchitNormalForward)"
endif
if line('.') < cursor_line
return ''
endif
return matchstr(getline(test_func_line), '\m\C^\s*fn\s\+\zs\h\w*')
endfunction
function! rust#Test(mods, winsize, all, options) abort
let manifest = findfile('Cargo.toml', expand('%:p:h') . ';')
if manifest ==# ''
return rust#Run(1, '--test ' . a:options)
endif
" <count> defaults to 0, but we prefer an empty string
let winsize = a:winsize ? a:winsize : ''
if has('terminal')
if has('patch-8.0.910')
let cmd = printf('%s noautocmd %snew | terminal ++curwin ', a:mods, winsize)
else
let cmd = printf('%s terminal ', a:mods)
endif
elseif has('nvim')
let cmd = printf('%s noautocmd %snew | terminal ', a:mods, winsize)
else
let cmd = '!'
let manifest = shellescape(manifest)
endif
if a:all
if a:options ==# ''
execute cmd . 'cargo test --manifest-path' manifest
else
execute cmd . 'cargo test --manifest-path' manifest a:options
endif
return
endif
let saved = getpos('.')
try
let func_name = s:SearchTestFunctionNameUnderCursor()
finally
call setpos('.', saved)
endtry
if func_name ==# ''
echohl ErrorMsg
echomsg 'No test function was found under the cursor. Please add ! to command if you want to run all tests'
echohl None
return
endif
if a:options ==# ''
execute cmd . 'cargo test --manifest-path' manifest func_name
else
execute cmd . 'cargo test --manifest-path' manifest func_name a:options
endif
endfunction endfunction
" }}}1 " }}}1
" vim: set noet sw=8 ts=8: " vim: set et sw=4 sts=4 ts=8:

View File

@ -0,0 +1,105 @@
" Last Modified: 2023-09-11
" For debugging, inspired by https://github.com/w0rp/rust/blob/master/autoload/rust/debugging.vim
let s:global_variable_list = [
\ '_rustfmt_autosave_because_of_config',
\ 'ftplugin_rust_source_path',
\ 'loaded_syntastic_rust_cargo_checker',
\ 'loaded_syntastic_rust_filetype',
\ 'loaded_syntastic_rust_rustc_checker',
\ 'rust_bang_comment_leader',
\ 'rust_cargo_avoid_whole_workspace',
\ 'rust_clip_command',
\ 'rust_conceal',
\ 'rust_conceal_mod_path',
\ 'rust_conceal_pub',
\ 'rust_fold',
\ 'rust_last_args',
\ 'rust_last_rustc_args',
\ 'rust_original_delimitMate_excluded_regions',
\ 'rust_playpen_url',
\ 'rust_prev_delimitMate_quotes',
\ 'rust_recent_nearest_cargo_tol',
\ 'rust_recent_root_cargo_toml',
\ 'rust_recommended_style',
\ 'rust_set_conceallevel',
\ 'rust_set_conceallevel=1',
\ 'rust_set_foldmethod',
\ 'rust_set_foldmethod=1',
\ 'rust_shortener_url',
\ 'rustc_makeprg_no_percent',
\ 'rustc_path',
\ 'rustfmt_autosave',
\ 'rustfmt_autosave_if_config_present',
\ 'rustfmt_command',
\ 'rustfmt_emit_files',
\ 'rustfmt_fail_silently',
\ 'rustfmt_options',
\ 'syntastic_extra_filetypes',
\ 'syntastic_rust_cargo_fname',
\]
function! s:Echo(message) abort
execute 'echo a:message'
endfunction
function! s:EchoGlobalVariables() abort
for l:key in s:global_variable_list
if l:key !~# '^_'
call s:Echo('let g:' . l:key . ' = ' . string(get(g:, l:key, v:null)))
endif
if has_key(b:, l:key)
call s:Echo('let b:' . l:key . ' = ' . string(b:[l:key]))
endif
endfor
endfunction
function! rust#debugging#Info() abort
call cargo#Load()
call rust#Load()
call rustfmt#Load()
call s:Echo('rust.vim Global Variables:')
call s:Echo('')
call s:EchoGlobalVariables()
silent let l:output = system(g:rustfmt_command . ' --version')
echo l:output
let l:rustc = exists("g:rustc_path") ? g:rustc_path : "rustc"
silent let l:output = system(l:rustc . ' --version')
echo l:output
silent let l:output = system('cargo --version')
echo l:output
version
if exists(":SyntasticInfo")
echo "----"
echo "Info from Syntastic:"
execute "SyntasticInfo"
endif
endfunction
function! rust#debugging#InfoToClipboard() abort
redir @"
silent call rust#debugging#Info()
redir END
call s:Echo('RustInfo copied to your clipboard')
endfunction
function! rust#debugging#InfoToFile(filename) abort
let l:expanded_filename = expand(a:filename)
redir => l:output
silent call rust#debugging#Info()
redir END
call writefile(split(l:output, "\n"), l:expanded_filename)
call s:Echo('RustInfo written to ' . l:expanded_filename)
endfunction
" vim: set et sw=4 sts=4 ts=8:

View File

@ -1,4 +1,5 @@
" Author: Stephen Sugden <stephen@stephensugden.com> " Author: Stephen Sugden <stephen@stephensugden.com>
" Last Modified: 2023-09-11
" "
" Adapted from https://github.com/fatih/vim-go " Adapted from https://github.com/fatih/vim-go
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim " For bugs, patches and license go to https://github.com/rust-lang/rust.vim
@ -19,89 +20,242 @@ if !exists("g:rustfmt_fail_silently")
let g:rustfmt_fail_silently = 0 let g:rustfmt_fail_silently = 0
endif endif
function! rustfmt#DetectVersion()
" Save rustfmt '--help' for feature inspection
silent let s:rustfmt_help = system(g:rustfmt_command . " --help")
let s:rustfmt_unstable_features = s:rustfmt_help =~# "--unstable-features"
" Build a comparable rustfmt version varible out of its `--version` output:
silent let l:rustfmt_version_full = system(g:rustfmt_command . " --version")
let l:rustfmt_version_list = matchlist(l:rustfmt_version_full,
\ '\vrustfmt ([0-9]+[.][0-9]+[.][0-9]+)')
if len(l:rustfmt_version_list) < 3
let s:rustfmt_version = "0"
else
let s:rustfmt_version = l:rustfmt_version_list[1]
endif
return s:rustfmt_version
endfunction
call rustfmt#DetectVersion()
if !exists("g:rustfmt_emit_files")
let g:rustfmt_emit_files = s:rustfmt_version >= "0.8.2"
endif
if !exists("g:rustfmt_file_lines")
let g:rustfmt_file_lines = s:rustfmt_help =~# "--file-lines JSON"
endif
let s:got_fmt_error = 0 let s:got_fmt_error = 0
function! s:RustfmtCommandRange(filename, line1, line2) function! rustfmt#Load()
let l:arg = {"file": shellescape(a:filename), "range": [a:line1, a:line2]} " Utility call to get this script loaded, for debugging
return printf("%s %s --write-mode=overwrite --file-lines '[%s]'", g:rustfmt_command, g:rustfmt_options, json_encode(l:arg))
endfunction endfunction
function! s:RustfmtCommand(filename) function! s:RustfmtWriteMode()
return g:rustfmt_command . " --write-mode=overwrite " . g:rustfmt_options . " " . shellescape(a:filename) if g:rustfmt_emit_files
endfunction return "--emit=files"
function! s:RunRustfmt(command, curw, tmpname)
if exists("*systemlist")
let out = systemlist(a:command)
else else
let out = split(system(a:command), '\r\?\n') return "--write-mode=overwrite"
endif
endfunction
function! s:RustfmtConfigOptions()
let l:rustfmt_toml = findfile('rustfmt.toml', expand('%:p:h') . ';')
if l:rustfmt_toml !=# ''
return '--config-path '.shellescape(fnamemodify(l:rustfmt_toml, ":p"))
endif endif
if v:shell_error == 0 || v:shell_error == 3 let l:_rustfmt_toml = findfile('.rustfmt.toml', expand('%:p:h') . ';')
if l:_rustfmt_toml !=# ''
return '--config-path '.shellescape(fnamemodify(l:_rustfmt_toml, ":p"))
endif
" Default to edition 2018 in case no rustfmt.toml was found.
return '--edition 2018'
endfunction
function! s:RustfmtCommandRange(filename, line1, line2)
if g:rustfmt_file_lines == 0
echo "--file-lines is not supported in the installed `rustfmt` executable"
return
endif
let l:arg = {"file": shellescape(a:filename), "range": [a:line1, a:line2]}
let l:write_mode = s:RustfmtWriteMode()
let l:rustfmt_config = s:RustfmtConfigOptions()
" FIXME: When --file-lines gets to be stable, add version range checking
" accordingly.
let l:unstable_features = s:rustfmt_unstable_features ? '--unstable-features' : ''
let l:cmd = printf("%s %s %s %s %s --file-lines '[%s]' %s", g:rustfmt_command,
\ l:write_mode, g:rustfmt_options,
\ l:unstable_features, l:rustfmt_config,
\ json_encode(l:arg), shellescape(a:filename))
return l:cmd
endfunction
function! s:RustfmtCommand()
let write_mode = g:rustfmt_emit_files ? '--emit=stdout' : '--write-mode=display'
let config = s:RustfmtConfigOptions()
return join([g:rustfmt_command, write_mode, config, g:rustfmt_options])
endfunction
function! s:DeleteLines(start, end) abort
silent! execute a:start . ',' . a:end . 'delete _'
endfunction
function! s:RunRustfmt(command, tmpname, from_writepre)
let l:view = winsaveview()
let l:stderr_tmpname = tempname()
call writefile([], l:stderr_tmpname)
let l:command = a:command . ' 2> ' . l:stderr_tmpname
if a:tmpname ==# ''
" Rustfmt in stdin/stdout mode
" chdir to the directory of the file
let l:has_lcd = haslocaldir()
let l:prev_cd = getcwd()
execute 'lchdir! '.expand('%:h')
let l:buffer = getline(1, '$')
if exists("*systemlist")
silent let out = systemlist(l:command, l:buffer)
else
silent let out = split(system(l:command,
\ join(l:buffer, "\n")), '\r\?\n')
endif
else
if exists("*systemlist")
silent let out = systemlist(l:command)
else
silent let out = split(system(l:command), '\r\?\n')
endif
endif
let l:stderr = readfile(l:stderr_tmpname)
call delete(l:stderr_tmpname)
let l:open_lwindow = 0
if v:shell_error == 0
if a:from_writepre
" remove undo point caused via BufWritePre " remove undo point caused via BufWritePre
try | silent undojoin | catch | endtry try | silent undojoin | catch | endtry
endif
" Replace current file with temp file, then reload buffer if a:tmpname ==# ''
call rename(a:tmpname, expand('%')) let l:content = l:out
silent edit! else
let &syntax = &syntax " take the tmpfile's content, this is better than rename
" because it preserves file modes.
let l:content = readfile(a:tmpname)
endif
call s:DeleteLines(len(l:content), line('$'))
call setline(1, l:content)
" only clear location list if it was previously filled to prevent " only clear location list if it was previously filled to prevent
" clobbering other additions " clobbering other additions
if s:got_fmt_error if s:got_fmt_error
let s:got_fmt_error = 0 let s:got_fmt_error = 0
call setloclist(0, []) call setloclist(0, [])
lwindow let l:open_lwindow = 1
endif endif
elseif g:rustfmt_fail_silently == 0 elseif g:rustfmt_fail_silently == 0 && !a:from_writepre
" otherwise get the errors and put them in the location list " otherwise get the errors and put them in the location list
let errors = [] let l:errors = []
for line in out let l:prev_line = ""
" src/lib.rs:13:5: 13:10 error: expected `,`, or `}`, found `value` for l:line in l:stderr
let tokens = matchlist(line, '^\(.\{-}\):\(\d\+\):\(\d\+\):\s*\(\d\+:\d\+\s*\)\?\s*error: \(.*\)') " error: expected one of `;` or `as`, found `extern`
" --> src/main.rs:2:1
let tokens = matchlist(l:line, '^\s\+-->\s\(.\{-}\):\(\d\+\):\(\d\+\)$')
if !empty(tokens) if !empty(tokens)
call add(errors, {"filename": @%, call add(l:errors, {"filename": @%,
\"lnum": tokens[2], \"lnum": tokens[2],
\"col": tokens[3], \"col": tokens[3],
\"text": tokens[5]}) \"text": l:prev_line})
endif endif
let l:prev_line = l:line
endfor endfor
if empty(errors) if !empty(l:errors)
% | " Couldn't detect rustfmt error format, output errors call setloclist(0, l:errors, 'r')
endif
if !empty(errors)
call setloclist(0, errors, 'r')
echohl Error | echomsg "rustfmt returned error" | echohl None echohl Error | echomsg "rustfmt returned error" | echohl None
else
echo "rust.vim: was not able to parse rustfmt messages. Here is the raw output:"
echo "\n"
for l:line in l:stderr
echo l:line
endfor
endif endif
let s:got_fmt_error = 1 let s:got_fmt_error = 1
lwindow let l:open_lwindow = 1
" We didn't use the temp file, so clean up
call delete(a:tmpname)
endif endif
call winrestview(a:curw) " Restore the current directory if needed
if a:tmpname ==# ''
if l:has_lcd
execute 'lchdir! '.l:prev_cd
else
execute 'chdir! '.l:prev_cd
endif
endif
" Open lwindow after we have changed back to the previous directory
if l:open_lwindow == 1
lwindow
endif
call winrestview(l:view)
endfunction endfunction
function! rustfmt#FormatRange(line1, line2) function! rustfmt#FormatRange(line1, line2)
let l:curw = winsaveview() let l:tmpname = tempname()
let l:tmpname = expand("%:p:h") . "/." . expand("%:p:t") . ".rustfmt"
call writefile(getline(1, '$'), l:tmpname) call writefile(getline(1, '$'), l:tmpname)
let command = s:RustfmtCommandRange(l:tmpname, a:line1, a:line2) let command = s:RustfmtCommandRange(l:tmpname, a:line1, a:line2)
call s:RunRustfmt(command, l:tmpname, v:false)
call s:RunRustfmt(command, l:curw, l:tmpname) call delete(l:tmpname)
endfunction endfunction
function! rustfmt#Format() function! rustfmt#Format()
let l:curw = winsaveview() call s:RunRustfmt(s:RustfmtCommand(), '', v:false)
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 endfunction
function! rustfmt#Cmd()
" Mainly for debugging
return s:RustfmtCommand()
endfunction
function! rustfmt#PreWrite()
if !filereadable(expand("%@"))
return
endif
if rust#GetConfigVar('rustfmt_autosave_if_config_present', 0)
if findfile('rustfmt.toml', '.;') !=# '' || findfile('.rustfmt.toml', '.;') !=# ''
let b:rustfmt_autosave = 1
let b:_rustfmt_autosave_because_of_config = 1
endif
else
if has_key(b:, '_rustfmt_autosave_because_of_config')
unlet b:_rustfmt_autosave_because_of_config
unlet b:rustfmt_autosave
endif
endif
if !rust#GetConfigVar("rustfmt_autosave", 0)
return
endif
call s:RunRustfmt(s:RustfmtCommand(), '', v:true)
endfunction
" vim: set et sw=4 sts=4 ts=8:

View File

@ -1,7 +1,7 @@
" Vim compiler file " Vim compiler file
" Compiler: Cargo Compiler " Compiler: Cargo Compiler
" Maintainer: Damien Radtke <damienradtke@gmail.com> " Maintainer: Damien Radtke <damienradtke@gmail.com>
" Latest Revision: 2014 Sep 24 " Latest Revision: 2023-09-11
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim " For bugs, patches and license go to https://github.com/rust-lang/rust.vim
if exists('current_compiler') if exists('current_compiler')
@ -10,8 +10,10 @@ endif
runtime compiler/rustc.vim runtime compiler/rustc.vim
let current_compiler = "cargo" let current_compiler = "cargo"
" vint: -ProhibitAbbreviationOption
let s:save_cpo = &cpo let s:save_cpo = &cpo
set cpo&vim set cpo&vim
" vint: +ProhibitAbbreviationOption
if exists(':CompilerSet') != 2 if exists(':CompilerSet') != 2
command -nargs=* CompilerSet setlocal <args> command -nargs=* CompilerSet setlocal <args>
@ -23,13 +25,27 @@ else
CompilerSet makeprg=cargo\ $* CompilerSet makeprg=cargo\ $*
endif endif
augroup RustCargoQuickFixHooks
autocmd!
autocmd QuickFixCmdPre make call cargo#quickfix#CmdPre()
autocmd QuickFixCmdPost make call cargo#quickfix#CmdPost()
augroup END
" Ignore general cargo progress messages " Ignore general cargo progress messages
CompilerSet errorformat+= CompilerSet errorformat+=
\%-G%\\s%#Downloading%.%#, \%-G%\\s%#Downloading%.%#,
\%-G%\\s%#Checking%.%#,
\%-G%\\s%#Compiling%.%#, \%-G%\\s%#Compiling%.%#,
\%-G%\\s%#Finished%.%#, \%-G%\\s%#Finished%.%#,
\%-G%\\s%#error:\ Could\ not\ compile\ %.%#, \%-G%\\s%#error:\ Could\ not\ compile\ %.%#,
\%-G%\\s%#To\ learn\ more\\,%.%# \%-G%\\s%#To\ learn\ more\\,%.%#,
\%-G%\\s%#For\ more\ information\ about\ this\ error\\,%.%#,
\%-Gnote:\ Run\ with\ \`RUST_BACKTRACE=%.%#,
\%.%#panicked\ at\ \\'%m\\'\\,\ %f:%l:%c
" vint: -ProhibitAbbreviationOption
let &cpo = s:save_cpo let &cpo = s:save_cpo
unlet s:save_cpo unlet s:save_cpo
" vint: +ProhibitAbbreviationOption
" vim: set et sw=4 sts=4 ts=8:

View File

@ -1,7 +1,7 @@
" Vim compiler file " Vim compiler file
" Compiler: Rust Compiler " Compiler: Rust Compiler
" Maintainer: Chris Morgan <me@chrismorgan.info> " Maintainer: Chris Morgan <me@chrismorgan.info>
" Latest Revision: 2013 Jul 12 " Latest Revision: 2023-09-11
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim " For bugs, patches and license go to https://github.com/rust-lang/rust.vim
if exists("current_compiler") if exists("current_compiler")
@ -9,30 +9,27 @@ if exists("current_compiler")
endif endif
let current_compiler = "rustc" let current_compiler = "rustc"
let s:cpo_save = &cpo " vint: -ProhibitAbbreviationOption
let s:save_cpo = &cpo
set cpo&vim set cpo&vim
" vint: +ProhibitAbbreviationOption
if exists(":CompilerSet") != 2 if exists(":CompilerSet") != 2
command -nargs=* CompilerSet setlocal <args> command -nargs=* CompilerSet setlocal <args>
endif endif
if exists("g:rustc_makeprg_no_percent") && g:rustc_makeprg_no_percent != 0 if get(g:, 'rustc_makeprg_no_percent', 0)
CompilerSet makeprg=rustc CompilerSet makeprg=rustc
else else
if has('patch-7.4.191')
CompilerSet makeprg=rustc\ \%:S CompilerSet makeprg=rustc\ \%:S
else
CompilerSet makeprg=rustc\ \"%\"
endif
endif 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) " New errorformat (after nightly 2016/08/10)
CompilerSet errorformat+= CompilerSet errorformat=
\%-G, \%-G,
\%-Gerror:\ aborting\ %.%#, \%-Gerror:\ aborting\ %.%#,
\%-Gerror:\ Could\ not\ compile\ %.%#, \%-Gerror:\ Could\ not\ compile\ %.%#,
@ -40,7 +37,21 @@ CompilerSet errorformat+=
\%Eerror[E%n]:\ %m, \%Eerror[E%n]:\ %m,
\%Wwarning:\ %m, \%Wwarning:\ %m,
\%Inote:\ %m, \%Inote:\ %m,
\%C\ %#-->\ %f:%l:%c \%C\ %#-->\ %f:%l:%c,
\%E\ \ left:%m,%C\ right:%m\ %f:%l:%c,%Z
let &cpo = s:cpo_save " Old errorformat (before nightly 2016/08/10)
unlet s:cpo_save CompilerSet errorformat+=
\%f:%l:%c:\ %t%*[^:]:\ %m,
\%f:%l:%c:\ %*\\d:%*\\d\ %t%*[^:]:\ %m,
\%-G%f:%l\ %s,
\%-G%*[\ ]^,
\%-G%*[\ ]^%*[~],
\%-G%*[\ ]...
" vint: -ProhibitAbbreviationOption
let &cpo = s:save_cpo
unlet s:save_cpo
" vint: +ProhibitAbbreviationOption
" vim: set et sw=4 sts=4 ts=8:

View File

@ -1,6 +1,4 @@
*ft_rust.txt* For Vim version 9.0. Last change: 2022 Oct 17 *ft_rust.txt* Filetype plugin for Rust
This is documentation for the Rust filetype plugin.
============================================================================== ==============================================================================
CONTENTS *rust* CONTENTS *rust*
@ -14,7 +12,8 @@ CONTENTS *rust*
INTRODUCTION *rust-intro* INTRODUCTION *rust-intro*
This plugin provides syntax and supporting functionality for the Rust This plugin provides syntax and supporting functionality for the Rust
filetype. filetype. It requires Vim 8 or higher for full functionality. Some commands
will not work on earlier versions.
============================================================================== ==============================================================================
SETTINGS *rust-settings* SETTINGS *rust-settings*
@ -22,11 +21,14 @@ SETTINGS *rust-settings*
This plugin has a few variables you can define in your vimrc that change the This plugin has a few variables you can define in your vimrc that change the
behavior of the plugin. behavior of the plugin.
Some variables can be set buffer local (`:b` prefix), and the buffer local
will take precedence over the global `g:` counterpart.
*g:rustc_path* *g:rustc_path*
g:rustc_path~ g:rustc_path~
Set this option to the path to rustc for use in the |:RustRun| and Set this option to the path to rustc for use in the |:RustRun| and
|:RustExpand| commands. If unset, "rustc" will be located in $PATH: > |:RustExpand| commands. If unset, "rustc" will be located in $PATH: >
let g:rustc_path = $HOME .. "/bin/rustc" let g:rustc_path = $HOME."/bin/rustc"
< <
*g:rustc_makeprg_no_percent* *g:rustc_makeprg_no_percent*
@ -83,11 +85,30 @@ g:rust_bang_comment_leader~
let g:rust_bang_comment_leader = 1 let g:rust_bang_comment_leader = 1
< <
*g:rust_use_custom_ctags_defs*
g:rust_use_custom_ctags_defs~
Set this option to 1 if you have customized ctags definitions for Rust
and do not wish for those included with rust.vim to be used: >
let g:rust_use_custom_ctags_defs = 1
<
NOTE: rust.vim's built-in definitions are only used for the Tagbar Vim
plugin, if you have it installed, AND if Universal Ctags is not
detected. This is because Universal Ctags already has built-in
support for Rust when used with Tagbar.
Also, note that when using ctags other than Universal Ctags, it is not
automatically used when generating |tags| files that Vim can use to
navigate to definitions across different source files. Feel free to
copy `rust.vim/ctags/rust.ctags` into your own `~/.ctags` if you wish
to generate |tags| files.
*g:ftplugin_rust_source_path* *g:ftplugin_rust_source_path*
g:ftplugin_rust_source_path~ g:ftplugin_rust_source_path~
Set this option to a path that should be prepended to 'path' for Rust Set this option to a path that should be prepended to 'path' for Rust
source files: > source files: >
let g:ftplugin_rust_source_path = $HOME .. '/dev/rust' let g:ftplugin_rust_source_path = $HOME.'/dev/rust'
< <
*g:rustfmt_command* *g:rustfmt_command*
@ -102,6 +123,22 @@ g:rustfmt_autosave~
buffer. If not specified it defaults to 0 : > buffer. If not specified it defaults to 0 : >
let g:rustfmt_autosave = 0 let g:rustfmt_autosave = 0
< <
There is also a buffer-local b:rustfmt_autosave that can be set for
the same purpose, and can override the global setting.
*g:rustfmt_autosave_if_config_present*
g:rustfmt_autosave_if_config_present~
Set this option to 1 to have *b:rustfmt_autosave* be set automatically
if a `rustfmt.toml` file is present in any parent directly leading to
the file being edited. If not set, default to 0: >
let g:rustfmt_autosave_if_config_present = 0
<
This is useful to have `rustfmt` only execute on save, on projects
that have `rustfmt.toml` configuration.
There is also a buffer-local b:rustfmt_autosave_if_config_present
that can be set for the same purpose, which can overrides the global
setting.
*g:rustfmt_fail_silently* *g:rustfmt_fail_silently*
g:rustfmt_fail_silently~ g:rustfmt_fail_silently~
Set this option to 1 to prevent 'rustfmt' from populating the Set this option to 1 to prevent 'rustfmt' from populating the
@ -115,23 +152,228 @@ g:rustfmt_options~
defaults to '' : > defaults to '' : >
let g:rustfmt_options = '' let g:rustfmt_options = ''
< <
*g:rustfmt_emit_files*
g:rustfmt_emit_files~
If not specified rust.vim tries to detect the right parameter to
pass to rustfmt based on its reported version. Otherwise, it
determines whether to run rustfmt with '--emit=files' (when 1 is
provided) instead of '--write-mode=overwrite'. >
let g:rustfmt_emit_files = 0
*g:rust_playpen_url* *g:rust_playpen_url*
g:rust_playpen_url~ g:rust_playpen_url~
Set this option to override the URL for the playpen to use: > Set this option to override the url for the playpen to use: >
let g:rust_playpen_url = 'https://play.rust-lang.org/' let g:rust_playpen_url = 'https://play.rust-lang.org/'
< <
*g:rust_shortener_url* *g:rust_shortener_url*
g:rust_shortener_url~ g:rust_shortener_url~
Set this option to override the URL for the URL shortener: > Set this option to override the url for the url shortener: >
let g:rust_shortener_url = 'https://is.gd/' let g:rust_shortener_url = 'https://is.gd/'
< <
*g:rust_clip_command*
g:rust_clip_command~
Set this option to the command used in your OS to copy the Rust Play
url to the clipboard: >
let g:rust_clip_command = 'xclip -selection clipboard'
<
*g:cargo_makeprg_params*
g:cargo_makeprg_params~
Set this option to the string of parameters to pass to cargo. If not
specified it defaults to '$*' : >
let g:cargo_makeprg_params = 'build'
<
*g:cargo_shell_command_runner*
g:cargo_shell_command_runner~
Set this option to change how to run shell commands for cargo commands
|:Cargo|, |:Cbuild|, |:Crun|, ...
By default, |:terminal| is used to run shell command in terminal window
asynchronously. But if you prefer |:!| for running the commands, it can
be specified: >
let g:cargo_shell_command_runner = '!'
<
Integration with Syntastic *rust-syntastic*
--------------------------
This plugin automatically integrates with the Syntastic checker. There are two
checkers provided: 'rustc', and 'cargo'. The latter invokes 'Cargo' in order to
build code, and the former delivers a single edited '.rs' file as a compilation
target directly to the Rust compiler, `rustc`.
Because Cargo is almost exclusively being used for building Rust code these
days, 'cargo' is the default checker. >
let g:syntastic_rust_checkers = ['cargo']
<
If you would like to change it, you can set `g:syntastic_rust_checkers` to a
different value.
*g:rust_cargo_avoid_whole_workspace*
*b:rust_cargo_avoid_whole_workspace*
g:rust_cargo_avoid_whole_workspace~
When editing a crate that is part of a Cargo workspace, and this
option is set to 1 (the default), then 'cargo' will be executed
directly in that crate directory instead of in the workspace
directory. Setting 0 prevents this behavior - however be aware that if
you are working in large workspace, Cargo commands may take more time,
plus the Syntastic error list may include all the crates in the
workspace. >
let g:rust_cargo_avoid_whole_workspace = 0
<
*g:rust_cargo_check_all_targets*
*b:rust_cargo_check_all_targets*
g:rust_cargo_check_all_targets~
When set to 1, the `--all-targets` option will be passed to cargo when
Syntastic executes it, allowing the linting of all targets under the
package.
The default is 0.
*g:rust_cargo_check_all_features*
*b:rust_cargo_check_all_features*
g:rust_cargo_check_all_features~
When set to 1, the `--all-features` option will be passed to cargo when
Syntastic executes it, allowing the linting of all features of the
package.
The default is 0.
*g:rust_cargo_check_examples*
*b:rust_cargo_check_examples*
g:rust_cargo_check_examples~
When set to 1, the `--examples` option will be passed to cargo when
Syntastic executes it, to prevent the exclusion of examples from
linting. The examples are normally under the `examples/` directory of
the crate.
The default is 0.
*g:rust_cargo_check_tests*
*b:rust_cargo_check_tests*
g:rust_cargo_check_tests~
When set to 1, the `--tests` option will be passed to cargo when
Syntastic executes it, to prevent the exclusion of tests from linting.
The tests are normally under the `tests/` directory of the crate.
The default is 0.
*g:rust_cargo_check_benches*
*b:rust_cargo_check_benches*
g:rust_cargo_check_benches~
When set to 1, the `--benches` option will be passed to cargo when
Syntastic executes it. The benches are normally under the `benches/`
directory of the crate.
The default is 0.
Integration with auto-pairs *rust-auto-pairs*
---------------------------
This plugin automatically configures the auto-pairs plugin not to duplicate
single quotes, which are used more often for lifetime annotations than for
single character literals.
*g:rust_keep_autopairs_default*
g:rust_keep_autopairs_default~
Don't override auto-pairs default for the Rust filetype. The default
is 0.
============================================================================== ==============================================================================
COMMANDS *rust-commands* COMMANDS *rust-commands*
Invoking Cargo
--------------
This plug defines very simple shortcuts for invoking Cargo from with Vim.
:Cargo <args> *:Cargo*
Runs 'cargo' with the provided arguments.
:Cbuild <args> *:Cbuild*
Shortcut for 'cargo build`.
:Cclean <args> *:Cclean*
Shortcut for 'cargo clean`.
:Cdoc <args> *:Cdoc*
Shortcut for 'cargo doc`.
:Cinit <args> *:Cinit*
Shortcut for 'cargo init`.
:Crun <args> *:Crun*
Shortcut for 'cargo run`.
:Ctest <args> *:Ctest*
Shortcut for 'cargo test`.
:Cupdate <args> *:Cupdate*
Shortcut for 'cargo update`.
:Cbench <args> *:Cbench*
Shortcut for 'cargo bench`.
:Csearch <args> *:Csearch*
Shortcut for 'cargo search`.
:Cpublish <args> *:Cpublish*
Shortcut for 'cargo publish`.
:Cinstall <args> *:Cinstall*
Shortcut for 'cargo install`.
:Cruntarget <args> *:Cruntarget*
Shortcut for 'cargo run --bin' or 'cargo run --example',
depending on the currently open buffer.
Formatting
----------
: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.
Playpen integration
-------------------
: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/"
|g:rust_clip_command| is the command to run to copy the
playpen url to the clipboard of your system.
Evaluation of a single Rust file
--------------------------------
NOTE: These commands are useful only when working with standalone Rust files,
which is usually not the case for common Rust development. If you wish to
building Rust crates from with Vim can should use Vim's make, Syntastic, or
functionality from other plugins.
:RustRun [args] *:RustRun* :RustRun [args] *:RustRun*
:RustRun! [rustc-args] [--] [args] :RustRun! [rustc-args] [--] [args]
Compiles and runs the current file. If it has unsaved changes, Compiles and runs the current file. If it has unsaved changes,
@ -191,49 +433,54 @@ COMMANDS *rust-commands*
If |g:rustc_path| is defined, it is used as the path 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. 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 Running test(s)
"https://play.rust-lang.org/". ---------------
|g:rust_shortener_url| is the base URL for the shortener, by :[N]RustTest[!] [options] *:RustTest*
default "https://is.gd/" Runs a test under the cursor when the current buffer is in a
cargo project with "cargo test" command. If the command did
not find any test function under the cursor, it stops with an
error message.
:RustFmt *:RustFmt* When N is given, adjust the size of the new window to N lines
Runs |g:rustfmt_command| on the current buffer. If or columns.
|g:rustfmt_options| is set then those will be passed to the
executable.
If |g:rustfmt_fail_silently| is 0 (the default) then it When ! is given, runs all tests regardless of current cursor
will populate the |location-list| with the errors from position.
|g:rustfmt_command|. If |g:rustfmt_fail_silently| is set to 1
then it will not populate the |location-list|.
:RustFmtRange *:RustFmtRange* When [options] is given, it is passed to "cargo" command
Runs |g:rustfmt_command| with selected range. See arguments.
|:RustFmt| for any other information.
When the current buffer is outside cargo project, the command
runs "rustc --test" command instead of "cargo test" as
fallback. All tests are run regardless of adding ! since there
is no way to run specific test function with rustc. [options]
is passed to "rustc" command arguments in the case.
Takes optional modifiers (see |<mods>|): >
:tab RustTest
:belowright 16RustTest
:leftabove vert 80RustTest
<
rust.vim Debugging
------------------
:RustInfo *:RustInfo*
Emits debugging info of the Vim Rust plugin.
:RustInfoToClipboard *:RustInfoClipboard*
Saves debugging info of the Vim Rust plugin to the default
register.
:RustInfoToFile [filename] *:RustInfoToFile*
Saves debugging info of the Vim Rust plugin to the the given
file, overwritting it.
============================================================================== ==============================================================================
MAPPINGS *rust-mappings* MAPPINGS *rust-mappings*
This plugin defines mappings for |[[| and |]]| to support hanging indents. 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:ts=8:noet:ft=help:norl: vim:tw=78:sw=4:noet:ts=8:ft=help:norl:

View File

@ -1,8 +1,7 @@
" Language: Rust " Language: Rust
" Description: Vim ftplugin for Rust " Description: Vim ftplugin for Rust
" Maintainer: Chris Morgan <me@chrismorgan.info> " Maintainer: Chris Morgan <me@chrismorgan.info>
" Maintainer: Lily Ballard <lily@ballards.net> " Last Change: 2023-09-11
" Last Change: June 08, 2016
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim " For bugs, patches and license go to https://github.com/rust-lang/rust.vim
if exists("b:did_ftplugin") if exists("b:did_ftplugin")
@ -10,11 +9,18 @@ if exists("b:did_ftplugin")
endif endif
let b:did_ftplugin = 1 let b:did_ftplugin = 1
" vint: -ProhibitAbbreviationOption
let s:save_cpo = &cpo let s:save_cpo = &cpo
set cpo&vim set cpo&vim
" vint: +ProhibitAbbreviationOption
augroup rust.vim if get(b:, 'current_compiler', '') ==# ''
autocmd! if strlen(findfile('Cargo.toml', '.;')) > 0
compiler cargo
else
compiler rustc
endif
endif
" Variables {{{1 " Variables {{{1
@ -22,13 +28,13 @@ autocmd!
" comments, so we'll use that as our default, but make it easy to switch. " 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 " This does not affect indentation at all (I tested it with and without
" leader), merely whether a leader is inserted by default or not. " leader), merely whether a leader is inserted by default or not.
if exists("g:rust_bang_comment_leader") && g:rust_bang_comment_leader != 0 if get(g:, 'rust_bang_comment_leader', 0)
" Why is the `,s0:/*,mb:\ ,ex:*/` there, you ask? I don't understand why, " 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 " but without it, */ gets indented one space even if there were no
" leaders. I'm fairly sure that's a Vim bug. " leaders. I'm fairly sure that's a Vim bug.
setlocal comments=s1:/*,mb:*,ex:*/,s0:/*,mb:\ ,ex:*/,:///,://!,:// setlocal comments=s1:/*,mb:*,ex:*/,s0:/*,mb:\ ,ex:*/,:///,://!,://
else else
setlocal comments=s0:/*!,m:\ ,ex:*/,s1:/*,mb:*,ex:*/,:///,://!,:// setlocal comments=s0:/*!,ex:*/,s1:/*,mb:*,ex:*/,:///,://!,://
endif endif
setlocal commentstring=//%s setlocal commentstring=//%s
setlocal formatoptions-=t formatoptions+=croqnl setlocal formatoptions-=t formatoptions+=croqnl
@ -39,13 +45,14 @@ silent! setlocal formatoptions+=j
" otherwise it's better than nothing. " otherwise it's better than nothing.
setlocal smartindent nocindent setlocal smartindent nocindent
if !exists("g:rust_recommended_style") || g:rust_recommended_style != 0 if get(g:, 'rust_recommended_style', 1)
setlocal tabstop=4 shiftwidth=4 softtabstop=4 expandtab let b:rust_set_style = 1
setlocal shiftwidth=4 softtabstop=4 expandtab
setlocal textwidth=99 setlocal textwidth=99
endif endif
" This includeexpr isn't perfect, but it's a good start setlocal include=\\v^\\s*(pub\\s+)?use\\s+\\zs(\\f\|:)+
setlocal includeexpr=substitute(v:fname,'::','/','g') setlocal includeexpr=rust#IncludeExpr(v:fname)
setlocal suffixesadd=.rs setlocal suffixesadd=.rs
@ -58,35 +65,20 @@ if exists("g:loaded_delimitMate")
let b:rust_original_delimitMate_excluded_regions = b:delimitMate_excluded_regions let b:rust_original_delimitMate_excluded_regions = b:delimitMate_excluded_regions
endif endif
let s:delimitMate_extra_excluded_regions = ',rustLifetimeCandidate,rustGenericLifetimeCandidate' augroup rust.vim.DelimitMate
autocmd!
" For this buffer, when delimitMate issues the `User delimitMate_map` autocmd User delimitMate_map :call rust#delimitmate#onMap()
" event in the autocommand system, add the above-defined extra excluded autocmd User delimitMate_unmap :call rust#delimitmate#onUnmap()
" regions to delimitMate's state, if they have not already been added. augroup END
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 endif
if has("folding") && exists('g:rust_fold') && g:rust_fold != 0 " Integration with auto-pairs (https://github.com/jiangmiao/auto-pairs)
if exists("g:AutoPairsLoaded") && !get(g:, 'rust_keep_autopairs_default', 0)
let b:AutoPairs = {'(':')', '[':']', '{':'}','"':'"', '`':'`'}
endif
if has("folding") && get(g:, 'rust_fold', 0)
let b:rust_set_foldmethod=1 let b:rust_set_foldmethod=1
setlocal foldmethod=syntax setlocal foldmethod=syntax
if g:rust_fold == 2 if g:rust_fold == 2
@ -96,7 +88,7 @@ if has("folding") && exists('g:rust_fold') && g:rust_fold != 0
endif endif
endif endif
if has('conceal') && exists('g:rust_conceal') && g:rust_conceal != 0 if has('conceal') && get(g:, 'rust_conceal', 0)
let b:rust_set_conceallevel=1 let b:rust_set_conceallevel=1
setlocal conceallevel=2 setlocal conceallevel=2
endif endif
@ -126,20 +118,25 @@ command! -nargs=* -buffer RustEmitIr call rust#Emit("llvm-ir", <q-args>)
command! -nargs=* -buffer RustEmitAsm call rust#Emit("asm", <q-args>) command! -nargs=* -buffer RustEmitAsm call rust#Emit("asm", <q-args>)
" See |:RustPlay| for docs " See |:RustPlay| for docs
command! -range=% RustPlay :call rust#Play(<count>, <line1>, <line2>, <f-args>) command! -range=% -buffer RustPlay :call rust#Play(<count>, <line1>, <line2>, <f-args>)
" See |:RustFmt| for docs " See |:RustFmt| for docs
command! -buffer RustFmt call rustfmt#Format() command! -bar -buffer RustFmt call rustfmt#Format()
" See |:RustFmtRange| for docs " See |:RustFmtRange| for docs
command! -range -buffer RustFmtRange call rustfmt#FormatRange(<line1>, <line2>) command! -range -buffer RustFmtRange call rustfmt#FormatRange(<line1>, <line2>)
" Mappings {{{1 " See |:RustInfo| for docs
command! -bar -buffer RustInfo call rust#debugging#Info()
" Bind ⌘R in MacVim to :RustRun " See |:RustInfoToClipboard| for docs
nnoremap <silent> <buffer> <D-r> :RustRun<CR> command! -bar -buffer RustInfoToClipboard call rust#debugging#InfoToClipboard()
" 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> " See |:RustInfoToFile| for docs
command! -bar -nargs=1 -buffer RustInfoToFile call rust#debugging#InfoToFile(<f-args>)
" See |:RustTest| for docs
command! -buffer -nargs=* -count -bang RustTest call rust#Test(<q-mods>, <count>, <bang>0, <q-args>)
if !exists("b:rust_last_rustc_args") || !exists("b:rust_last_args") if !exists("b:rust_last_rustc_args") || !exists("b:rust_last_args")
let b:rust_last_rustc_args = [] let b:rust_last_rustc_args = []
@ -149,8 +146,10 @@ endif
" Cleanup {{{1 " Cleanup {{{1
let b:undo_ftplugin = " let b:undo_ftplugin = "
\ setlocal formatoptions< comments< commentstring< includeexpr< suffixesadd< \ setlocal formatoptions< comments< commentstring< include< includeexpr< suffixesadd<
\|if exists('b:rust_set_style')
\|setlocal tabstop< shiftwidth< softtabstop< expandtab< textwidth< \|setlocal tabstop< shiftwidth< softtabstop< expandtab< textwidth<
\|endif
\|if exists('b:rust_original_delimitMate_excluded_regions') \|if exists('b:rust_original_delimitMate_excluded_regions')
\|let b:delimitMate_excluded_regions = b:rust_original_delimitMate_excluded_regions \|let b:delimitMate_excluded_regions = b:rust_original_delimitMate_excluded_regions
\|unlet b:rust_original_delimitMate_excluded_regions \|unlet b:rust_original_delimitMate_excluded_regions
@ -166,32 +165,75 @@ let b:undo_ftplugin = "
\|unlet b:rust_set_conceallevel \|unlet b:rust_set_conceallevel
\|endif \|endif
\|unlet! b:rust_last_rustc_args b:rust_last_args \|unlet! b:rust_last_rustc_args b:rust_last_args
\|delcommand RustRun \|delcommand -buffer RustRun
\|delcommand RustExpand \|delcommand -buffer RustExpand
\|delcommand RustEmitIr \|delcommand -buffer RustEmitIr
\|delcommand RustEmitAsm \|delcommand -buffer RustEmitAsm
\|delcommand RustPlay \|delcommand -buffer RustPlay
\|nunmap <buffer> <D-r> \|delcommand -buffer RustFmt
\|nunmap <buffer> <D-R> \|delcommand -buffer RustFmtRange
\|delcommand -buffer RustInfo
\|delcommand -buffer RustInfoToClipboard
\|delcommand -buffer RustInfoToFile
\|delcommand -buffer RustTest
\|nunmap <buffer> [[ \|nunmap <buffer> [[
\|nunmap <buffer> ]] \|nunmap <buffer> ]]
\|xunmap <buffer> [[ \|xunmap <buffer> [[
\|xunmap <buffer> ]] \|xunmap <buffer> ]]
\|ounmap <buffer> [[ \|ounmap <buffer> [[
\|ounmap <buffer> ]] \|ounmap <buffer> ]]
\|set matchpairs-=<:> \|setlocal matchpairs-=<:>
\|unlet b:match_skip
\" \"
" }}}1 " }}}1
" Code formatting on save " Code formatting on save
if get(g:, "rustfmt_autosave", 0) augroup rust.vim.PreWrite
autocmd BufWritePre *.rs silent! call rustfmt#Format() autocmd!
endif autocmd BufWritePre *.rs silent! call rustfmt#PreWrite()
augroup END augroup END
setlocal matchpairs+=<:>
" For matchit.vim (rustArrow stops `Fn() -> X` messing things up)
let b:match_skip = 's:comment\|string\|rustCharacter\|rustArrow'
command! -buffer -nargs=+ Cargo call cargo#cmd(<q-args>)
command! -buffer -nargs=* Cbuild call cargo#build(<q-args>)
command! -buffer -nargs=* Ccheck call cargo#check(<q-args>)
command! -buffer -nargs=* Cclean call cargo#clean(<q-args>)
command! -buffer -nargs=* Cdoc call cargo#doc(<q-args>)
command! -buffer -nargs=+ Cnew call cargo#new(<q-args>)
command! -buffer -nargs=* Cinit call cargo#init(<q-args>)
command! -buffer -nargs=* Crun call cargo#run(<q-args>)
command! -buffer -nargs=* Ctest call cargo#test(<q-args>)
command! -buffer -nargs=* Cbench call cargo#bench(<q-args>)
command! -buffer -nargs=* Cupdate call cargo#update(<q-args>)
command! -buffer -nargs=* Csearch call cargo#search(<q-args>)
command! -buffer -nargs=* Cpublish call cargo#publish(<q-args>)
command! -buffer -nargs=* Cinstall call cargo#install(<q-args>)
command! -buffer -nargs=* Cruntarget call cargo#runtarget(<q-args>)
let b:undo_ftplugin .= '
\|delcommand -buffer Cargo
\|delcommand -buffer Cbuild
\|delcommand -buffer Ccheck
\|delcommand -buffer Cclean
\|delcommand -buffer Cdoc
\|delcommand -buffer Cnew
\|delcommand -buffer Cinit
\|delcommand -buffer Crun
\|delcommand -buffer Ctest
\|delcommand -buffer Cbench
\|delcommand -buffer Cupdate
\|delcommand -buffer Csearch
\|delcommand -buffer Cpublish
\|delcommand -buffer Cinstall
\|delcommand -buffer Cruntarget'
" vint: -ProhibitAbbreviationOption
let &cpo = s:save_cpo let &cpo = s:save_cpo
unlet s:save_cpo unlet s:save_cpo
" vint: +ProhibitAbbreviationOption
" vim: set noet sw=8 ts=8: " vim: set et sw=4 sts=4 ts=8:

View File

@ -1,8 +1,7 @@
" Vim indent file " Vim indent file
" Language: Rust " Language: Rust
" Author: Chris Morgan <me@chrismorgan.info> " Author: Chris Morgan <me@chrismorgan.info>
" Last Change: 2017 Jun 13 " Last Change: 2023-09-11
" 2023 Aug 28 by Vim Project (undo_indent)
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim " For bugs, patches and license go to https://github.com/rust-lang/rust.vim
" Only load this indent file when no other was loaded. " Only load this indent file when no other was loaded.
@ -12,16 +11,16 @@ endif
let b:did_indent = 1 let b:did_indent = 1
setlocal cindent setlocal cindent
setlocal cinoptions=L0,(0,Ws,J1,j1 setlocal cinoptions=L0,(s,Ws,J1,j1,m1
setlocal cinkeys=0{,0},!^F,o,O,0[,0] setlocal cinkeys=0{,0},!^F,o,O,0[,0],0(,0)
" Don't think cinwords will actually do anything at all... never mind " 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 setlocal cinwords=for,if,else,while,loop,impl,mod,unsafe,trait,struct,enum,fn,extern,macro
" Some preliminary settings " Some preliminary settings
setlocal nolisp " Make sure lisp indenting doesn't supersede us setlocal nolisp " Make sure lisp indenting doesn't supersede us
setlocal autoindent " indentexpr isn't much help otherwise setlocal autoindent " indentexpr isn't much help otherwise
" Also do indentkeys, otherwise # gets shoved to column 0 :-/ " Also do indentkeys, otherwise # gets shoved to column 0 :-/
setlocal indentkeys=0{,0},!^F,o,O,0[,0] setlocal indentkeys=0{,0},!^F,o,O,0[,0],0(,0)
setlocal indentexpr=GetRustIndent(v:lnum) setlocal indentexpr=GetRustIndent(v:lnum)
@ -32,8 +31,10 @@ if exists("*GetRustIndent")
finish finish
endif endif
" vint: -ProhibitAbbreviationOption
let s:save_cpo = &cpo let s:save_cpo = &cpo
set cpo&vim set cpo&vim
" vint: +ProhibitAbbreviationOption
" Come here when loading the script the first time. " Come here when loading the script the first time.
@ -47,12 +48,12 @@ function! s:get_line_trimmed(lnum)
" If the last character in the line is a comment, do a binary search for " 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 " the start of the comment. synID() is slow, a linear search would take
" too long on a long line. " too long on a long line.
if synIDattr(synID(a:lnum, line_len, 1), "name") =~ 'Comment\|Todo' if synIDattr(synID(a:lnum, line_len, 1), "name") =~? 'Comment\|Todo'
let min = 1 let min = 1
let max = line_len let max = line_len
while min < max while min < max
let col = (min + max) / 2 let col = (min + max) / 2
if synIDattr(synID(a:lnum, col, 1), "name") =~ 'Comment\|Todo' if synIDattr(synID(a:lnum, col, 1), "name") =~? 'Comment\|Todo'
let max = col let max = col
else else
let min = col + 1 let min = col + 1
@ -72,7 +73,7 @@ function! s:is_string_comment(lnum, col)
if has('syntax_items') if has('syntax_items')
for id in synstack(a:lnum, a:col) for id in synstack(a:lnum, a:col)
let synname = synIDattr(id, "name") let synname = synIDattr(id, "name")
if synname == "rustString" || synname =~ "^rustComment" if synname ==# "rustString" || synname =~# "^rustComment"
return 1 return 1
endif endif
endfor endfor
@ -82,8 +83,17 @@ function! s:is_string_comment(lnum, col)
endif endif
endfunction endfunction
function GetRustIndent(lnum) if exists('*shiftwidth')
function! s:shiftwidth()
return shiftwidth()
endfunc
else
function! s:shiftwidth()
return &shiftwidth
endfunc
endif
function GetRustIndent(lnum)
" Starting assumption: cindent (called at the end) will do it right " Starting assumption: cindent (called at the end) will do it right
" normally. We just want to fix up a few cases. " normally. We just want to fix up a few cases.
@ -91,13 +101,13 @@ function GetRustIndent(lnum)
if has('syntax_items') if has('syntax_items')
let synname = synIDattr(synID(a:lnum, 1, 1), "name") let synname = synIDattr(synID(a:lnum, 1, 1), "name")
if synname == "rustString" if synname ==# "rustString"
" If the start of the line is in a string, don't change the indent " If the start of the line is in a string, don't change the indent
return -1 return -1
elseif synname =~ '\(Comment\|Todo\)' elseif synname =~? '\(Comment\|Todo\)'
\ && line !~ '^\s*/\*' " not /* opening line \ && line !~# '^\s*/\*' " not /* opening line
if synname =~ "CommentML" " multi-line if synname =~? "CommentML" " multi-line
if line !~ '^\s*\*' && getline(a:lnum - 1) =~ '^\s*/\*' if line !~# '^\s*\*' && getline(a:lnum - 1) =~# '^\s*/\*'
" This is (hopefully) the line after a /*, and it has no " This is (hopefully) the line after a /*, and it has no
" leader, so the correct indentation is that of the " leader, so the correct indentation is that of the
" previous line. " previous line.
@ -124,38 +134,78 @@ function GetRustIndent(lnum)
" Search backwards for the previous non-empty line. " Search backwards for the previous non-empty line.
let prevlinenum = prevnonblank(a:lnum - 1) let prevlinenum = prevnonblank(a:lnum - 1)
let prevline = s:get_line_trimmed(prevlinenum) let prevline = s:get_line_trimmed(prevlinenum)
while prevlinenum > 1 && prevline !~ '[^[:blank:]]' while prevlinenum > 1 && prevline !~# '[^[:blank:]]'
let prevlinenum = prevnonblank(prevlinenum - 1) let prevlinenum = prevnonblank(prevlinenum - 1)
let prevline = s:get_line_trimmed(prevlinenum) let prevline = s:get_line_trimmed(prevlinenum)
endwhile endwhile
" A standalone '{', '}', or 'where'
let l:standalone_open = line =~# '\V\^\s\*{\s\*\$'
let l:standalone_close = line =~# '\V\^\s\*}\s\*\$'
let l:standalone_where = line =~# '\V\^\s\*where\s\*\$'
if l:standalone_open || l:standalone_close || l:standalone_where
" ToDo: we can search for more items than 'fn' and 'if'.
let [l:found_line, l:col, l:submatch] =
\ searchpos('\<\(fn\)\|\(if\)\>', 'bnWp')
if l:found_line !=# 0
" Now we count the number of '{' and '}' in between the match
" locations and the current line (there is probably a better
" way to compute this).
let l:i = l:found_line
let l:search_line = strpart(getline(l:i), l:col - 1)
let l:opens = 0
let l:closes = 0
while l:i < a:lnum
let l:search_line2 = substitute(l:search_line, '\V{', '', 'g')
let l:opens += strlen(l:search_line) - strlen(l:search_line2)
let l:search_line3 = substitute(l:search_line2, '\V}', '', 'g')
let l:closes += strlen(l:search_line2) - strlen(l:search_line3)
let l:i += 1
let l:search_line = getline(l:i)
endwhile
if l:standalone_open || l:standalone_where
if l:opens ==# l:closes
return indent(l:found_line)
endif
else
" Expect to find just one more close than an open
if l:opens ==# l:closes + 1
return indent(l:found_line)
endif
endif
endif
endif
" A standalone 'where' adds a shift.
let l:standalone_prevline_where = prevline =~# '\V\^\s\*where\s\*\$'
if l:standalone_prevline_where
return indent(prevlinenum) + 4
endif
" Handle where clauses nicely: subsequent values should line up nicely. " Handle where clauses nicely: subsequent values should line up nicely.
if prevline[len(prevline) - 1] == "," if prevline[len(prevline) - 1] ==# ","
\ && prevline =~# '^\s*where\s' \ && prevline =~# '^\s*where\s'
return indent(prevlinenum) + 6 return indent(prevlinenum) + 6
endif endif
"match newline after struct with generic bound like let l:last_prevline_character = prevline[len(prevline) - 1]
"struct SomeThing<T>
"| <-- newline indent should same as prevline " A line that ends with '.<expr>;' is probably an end of a long list
if prevline[len(prevline) - 1] == ">" " of method operations.
\ && prevline =~# "\s*struct.*>$" if prevline =~# '\V\^\s\*.' && l:last_prevline_character ==# ';'
return indent(prevlinenum) call cursor(a:lnum - 1, 1)
let l:scope_start = searchpair('{\|(', '', '}\|)', 'nbW',
\ 's:is_string_comment(line("."), col("."))')
if l:scope_start != 0 && l:scope_start < a:lnum
return indent(l:scope_start) + 4
endif
endif endif
"match newline after where like: if l:last_prevline_character ==# ","
"struct SomeThing<T> \ && s:get_line_trimmed(a:lnum) !~# '^\s*[\[\]{})]'
"where \ && prevline !~# '^\s*fn\s'
" T: Display, \ && prevline !~# '([^()]\+,$'
if prevline =~# '^\s*where$' \ && s:get_line_trimmed(a:lnum) !~# '^\s*\S\+\s*=>'
return indent(prevlinenum) + 4
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 " 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 " take this too far... For now, let's normally use the previous line's
" indent. " indent.
@ -214,11 +264,11 @@ function GetRustIndent(lnum)
else else
" At the module scope, inside square brackets only " At the module scope, inside square brackets only
"if getline(a:lnum)[0] == ']' || search('\[', '', '\]', 'nW') == a:lnum "if getline(a:lnum)[0] == ']' || search('\[', '', '\]', 'nW') == a:lnum
if line =~ "^\\s*]" if line =~# "^\\s*]"
" It's the closing line, dedent it " It's the closing line, dedent it
return 0 return 0
else else
return shiftwidth() return &shiftwidth
endif endif
endif endif
endif endif
@ -228,5 +278,9 @@ function GetRustIndent(lnum)
return cindent(a:lnum) return cindent(a:lnum)
endfunction endfunction
" vint: -ProhibitAbbreviationOption
let &cpo = s:save_cpo let &cpo = s:save_cpo
unlet s:save_cpo unlet s:save_cpo
" vint: +ProhibitAbbreviationOption
" vim: set et sw=4 sts=4 ts=8:

View File

@ -3,7 +3,7 @@
" Maintainer: Patrick Walton <pcwalton@mozilla.com> " Maintainer: Patrick Walton <pcwalton@mozilla.com>
" Maintainer: Ben Blum <bblum@cs.cmu.edu> " Maintainer: Ben Blum <bblum@cs.cmu.edu>
" Maintainer: Chris Morgan <me@chrismorgan.info> " Maintainer: Chris Morgan <me@chrismorgan.info>
" Last Change: Feb 24, 2016 " Last Change: 2023-09-11
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim " For bugs, patches and license go to https://github.com/rust-lang/rust.vim
if version < 600 if version < 600
@ -15,32 +15,45 @@ endif
" Syntax definitions {{{1 " Syntax definitions {{{1
" Basic keywords {{{2 " Basic keywords {{{2
syn keyword rustConditional match if else syn keyword rustConditional match if else
syn keyword rustRepeat for loop while syn keyword rustRepeat loop while
" `:syn match` must be used to prioritize highlighting `for` keyword.
syn match rustRepeat /\<for\>/
" Highlight `for` keyword in `impl ... for ... {}` statement. This line must
" be put after previous `syn match` line to overwrite it.
syn match rustKeyword /\%(\<impl\>.\+\)\@<=\<for\>/
syn keyword rustRepeat in
syn keyword rustTypedef type nextgroup=rustIdentifier skipwhite skipempty syn keyword rustTypedef type nextgroup=rustIdentifier skipwhite skipempty
syn keyword rustStructure struct enum nextgroup=rustIdentifier skipwhite skipempty syn keyword rustStructure struct enum nextgroup=rustIdentifier skipwhite skipempty
syn keyword rustUnion union nextgroup=rustIdentifier skipwhite skipempty contained 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 match rustUnionContextual /\<union\_s\+\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*/ transparent contains=rustUnion
syn keyword rustOperator as syn keyword rustOperator as
syn keyword rustExistential existential nextgroup=rustTypedef skipwhite skipempty contained
syn match rustExistentialContextual /\<existential\_s\+type/ transparent contains=rustExistential,rustTypedef
syn match rustAssert "\<assert\(\w\)*!" contained syn match rustAssert "\<assert\(\w\)*!" contained
syn match rustPanic "\<panic\(\w\)*!" contained syn match rustPanic "\<panic\(\w\)*!" contained
syn match rustAsync "\<async\%(\s\|\n\)\@="
syn keyword rustKeyword break syn keyword rustKeyword break
syn keyword rustKeyword box nextgroup=rustBoxPlacement skipwhite skipempty syn keyword rustKeyword box
syn keyword rustKeyword continue syn keyword rustKeyword continue
syn keyword rustKeyword crate
syn keyword rustKeyword extern nextgroup=rustExternCrate,rustObsoleteExternMod skipwhite skipempty syn keyword rustKeyword extern nextgroup=rustExternCrate,rustObsoleteExternMod skipwhite skipempty
syn keyword rustKeyword fn nextgroup=rustFuncName skipwhite skipempty syn keyword rustKeyword fn nextgroup=rustFuncName skipwhite skipempty
syn keyword rustKeyword in impl let syn keyword rustKeyword impl let
syn keyword rustKeyword macro
syn keyword rustKeyword pub nextgroup=rustPubScope skipwhite skipempty syn keyword rustKeyword pub nextgroup=rustPubScope skipwhite skipempty
syn keyword rustKeyword return syn keyword rustKeyword return
syn keyword rustKeyword yield
syn keyword rustSuper super syn keyword rustSuper super
syn keyword rustKeyword unsafe where syn keyword rustKeyword where
syn keyword rustUnsafeKeyword unsafe
syn keyword rustKeyword use nextgroup=rustModPath skipwhite skipempty syn keyword rustKeyword use nextgroup=rustModPath skipwhite skipempty
" FIXME: Scoped impl's name is also fallen in this category " FIXME: Scoped impl's name is also fallen in this category
syn keyword rustKeyword mod trait nextgroup=rustIdentifier skipwhite skipempty syn keyword rustKeyword mod trait nextgroup=rustIdentifier skipwhite skipempty
syn keyword rustStorage move mut ref static const syn keyword rustStorage move mut ref static const
syn match rustDefault /\<default\ze\_s\+\(impl\|fn\|type\|const\)\>/ syn match rustDefault /\<default\ze\_s\+\(impl\|fn\|type\|const\)\>/
syn keyword rustAwait await
syn keyword rustInvalidBareKeyword crate syn match rustKeyword /\<try\>!\@!/ display
syn keyword rustPubScopeCrate crate contained syn keyword rustPubScopeCrate crate contained
syn match rustPubScopeDelim /[()]/ contained syn match rustPubScopeDelim /[()]/ contained
@ -52,22 +65,14 @@ syn match rustExternCrateString /".*"\_s*as/ contained nextgroup=rustIdentifie
syn keyword rustObsoleteExternMod mod contained nextgroup=rustIdentifier skipwhite skipempty 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 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 match rustFuncName "\%(r#\)\=\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained
syn region rustBoxPlacement matchgroup=rustBoxPlacementParens start="(" end=")" contains=TOP contained syn region rustMacroRepeat matchgroup=rustMacroRepeatDelimiters start="$(" end="),\=[*+]" contains=TOP
" 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\+" syn match rustMacroVariable "$\w\+"
syn match rustRawIdent "\<r#\h\w*" contains=NONE
" Reserved (but not yet used) keywords {{{2 " 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 syn keyword rustReservedKeyword become do priv typeof unsized abstract virtual final override
" Built-in types {{{2 " Built-in types {{{2
syn keyword rustType isize usize char bool u8 u16 u32 u64 u128 f32 syn keyword rustType isize usize char bool u8 u16 u32 u64 u128 f32
@ -138,18 +143,37 @@ syn match rustMacro '#\w\(\w\)*' contains=rustAssert,rustPanic
syn match rustEscapeError display contained /\\./ syn match rustEscapeError display contained /\\./
syn match rustEscape display contained /\\\([nrt0\\'"]\|x\x\{2}\)/ syn match rustEscape display contained /\\\([nrt0\\'"]\|x\x\{2}\)/
syn match rustEscapeUnicode display contained /\\u{\x\{1,6}}/ syn match rustEscapeUnicode display contained /\\u{\%(\x_*\)\{1,6}}/
syn match rustStringContinuation display contained /\\\n\s*/ syn match rustStringContinuation display contained /\\\n\s*/
syn region rustString start=+b"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeError,rustStringContinuation syn region rustString matchgroup=rustStringDelimiter start=+b"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeError,rustStringContinuation
syn region rustString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeUnicode,rustEscapeError,rustStringContinuation,@Spell syn region rustString matchgroup=rustStringDelimiter start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeUnicode,rustEscapeError,rustStringContinuation,@Spell
syn region rustString start='b\?r\z(#*\)"' end='"\z1' contains=@Spell syn region rustString matchgroup=rustStringDelimiter start='b\?r\z(#*\)"' end='"\z1' contains=@Spell
syn region rustAttribute start="#!\?\[" end="\]" contains=rustString,rustDerive,rustCommentLine,rustCommentBlock,rustCommentLineDocError,rustCommentBlockDocError " Match attributes with either arbitrary syntax or special highlighting for
" derives. We still highlight strings and comments inside of the attribute.
syn region rustAttribute start="#!\?\[" end="\]" contains=@rustAttributeContents,rustAttributeParenthesizedParens,rustAttributeParenthesizedCurly,rustAttributeParenthesizedBrackets,rustDerive
syn region rustAttributeParenthesizedParens matchgroup=rustAttribute start="\w\%(\w\)*("rs=e end=")"re=s transparent contained contains=rustAttributeBalancedParens,@rustAttributeContents
syn region rustAttributeParenthesizedCurly matchgroup=rustAttribute start="\w\%(\w\)*{"rs=e end="}"re=s transparent contained contains=rustAttributeBalancedCurly,@rustAttributeContents
syn region rustAttributeParenthesizedBrackets matchgroup=rustAttribute start="\w\%(\w\)*\["rs=e end="\]"re=s transparent contained contains=rustAttributeBalancedBrackets,@rustAttributeContents
syn region rustAttributeBalancedParens matchgroup=rustAttribute start="("rs=e end=")"re=s transparent contained contains=rustAttributeBalancedParens,@rustAttributeContents
syn region rustAttributeBalancedCurly matchgroup=rustAttribute start="{"rs=e end="}"re=s transparent contained contains=rustAttributeBalancedCurly,@rustAttributeContents
syn region rustAttributeBalancedBrackets matchgroup=rustAttribute start="\["rs=e end="\]"re=s transparent contained contains=rustAttributeBalancedBrackets,@rustAttributeContents
syn cluster rustAttributeContents contains=rustString,rustCommentLine,rustCommentBlock,rustCommentLineDocError,rustCommentBlockDocError
syn region rustDerive start="derive(" end=")" contained contains=rustDeriveTrait syn region rustDerive start="derive(" end=")" contained contains=rustDeriveTrait
" This list comes from src/libsyntax/ext/deriving/mod.rs " This list comes from src/libsyntax/ext/deriving/mod.rs
" Some are deprecated (Encodable, Decodable) or to be removed after a new snapshot (Show). " 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 syn keyword rustDeriveTrait contained Clone Hash RustcEncodable RustcDecodable Encodable Decodable PartialEq Eq PartialOrd Ord Rand Show Debug Default FromPrimitive Send Sync Copy
" dyn keyword: It's only a keyword when used inside a type expression, so
" we make effort here to highlight it only when Rust identifiers follow it
" (not minding the case of pre-2018 Rust where a path starting with :: can
" follow).
"
" This is so that uses of dyn variable names such as in 'let &dyn = &2'
" and 'let dyn = 2' will not get highlighted as a keyword.
syn match rustKeyword "\<dyn\ze\_s\+\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)" contains=rustDynKeyword
syn keyword rustDynKeyword dyn contained
" Number literals " Number literals
syn match rustDecNumber display "\<[0-9][0-9_]*\%([iu]\%(size\|8\|16\|32\|64\|128\)\)\=" 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 rustHexNumber display "\<0x[a-fA-F0-9_]\+\%([iu]\%(size\|8\|16\|32\|64\|128\)\)\="
@ -168,29 +192,31 @@ syn match rustFloat display "\<[0-9][0-9_]*\%(\.[0-9][0-9_]*\)\=\%([eE
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 " 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 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 rustGenericRegion display start=/<\%('\|[^[:cntrl:][:space:][:punct:]]\)\@=')\S\@=/ end=/>/ contains=rustGenericLifetimeCandidate
syn region rustGenericLifetimeCandidate display start=/\%(<\|,\s*\)\@<='/ end=/[[:cntrl:][:space:][:punct:]]\@=\|$/ contains=rustSigil,rustLifetime 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 "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 rustLifetime display "\'\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*"
syn match rustLabel display "\'\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*:" syn match rustLabel display "\'\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*:"
syn match rustLabel display "\%(\<\%(break\|continue\)\s*\)\@<=\'\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*"
syn match rustCharacterInvalid display contained /b\?'\zs[\n\r\t']\ze'/ 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). " 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 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 /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 rustCharacter /'\([^\\]\|\\\(.\|x\x\{2}\|u{\%(\x_*\)\{1,6}}\)\)'/ contains=rustEscape,rustEscapeUnicode,rustEscapeError,rustCharacterInvalid
syn match rustShebang /\%^#![^[].*/ syn match rustShebang /\%^#![^[].*/
syn region rustCommentLine start="//" end="$" contains=rustTodo,@Spell syn region rustCommentLine start="//" end="$" contains=rustTodo,@Spell
syn region rustCommentLineDoc start="//\%(//\@!\|!\)" end="$" contains=rustTodo,@Spell syn region rustCommentLineDoc start="//\%(//\@!\|!\)" end="$" contains=rustTodo,@Spell
syn region rustCommentLineDocError start="//\%(//\@!\|!\)" end="$" contains=rustTodo,@Spell contained syn region rustCommentLineDocError start="//\%(//\@!\|!\)" end="$" contains=rustTodo,@Spell contained
syn region rustCommentBlock matchgroup=rustCommentBlock start="/\*\%(!\|\*[*/]\@!\)\@!" end="\*/" contains=rustTodo,rustCommentBlockNest,@Spell syn region rustCommentBlock matchgroup=rustCommentBlock start="/\*\%(!\|\*[*/]\@!\)\@!" end="\*/" contains=rustTodo,rustCommentBlockNest,@Spell
syn region rustCommentBlockDoc matchgroup=rustCommentBlockDoc start="/\*\%(!\|\*[*/]\@!\)" end="\*/" contains=rustTodo,rustCommentBlockDocNest,@Spell syn region rustCommentBlockDoc matchgroup=rustCommentBlockDoc start="/\*\%(!\|\*[*/]\@!\)" end="\*/" contains=rustTodo,rustCommentBlockDocNest,rustCommentBlockDocRustCode,@Spell
syn region rustCommentBlockDocError matchgroup=rustCommentBlockDocError start="/\*\%(!\|\*[*/]\@!\)" end="\*/" contains=rustTodo,rustCommentBlockDocNestError,@Spell contained 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 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 rustCommentBlockDocNest matchgroup=rustCommentBlockDoc start="/\*" end="\*/" contains=rustTodo,rustCommentBlockDocNest,@Spell contained transparent
syn region rustCommentBlockDocNestError matchgroup=rustCommentBlockDocError start="/\*" end="\*/" contains=rustTodo,rustCommentBlockDocNestError,@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 " FIXME: this is a really ugly and not fully correct implementation. Most
" importantly, a case like ``/* */*`` should have the final ``*`` not being in " importantly, a case like ``/* */*`` should have the final ``*`` not being in
" a comment, but in practice at present it leaves comments open two levels " a comment, but in practice at present it leaves comments open two levels
@ -203,13 +229,67 @@ syn region rustCommentBlockDocNestError matchgroup=rustCommentBlockDocError star
" then you must deal with cases like ``/*/**/*/``. And don't try making it " then you must deal with cases like ``/*/**/*/``. And don't try making it
" worse with ``\%(/\@<!\*\)\@<!``, either... " worse with ``\%(/\@<!\*\)\@<!``, either...
syn keyword rustTodo contained TODO FIXME XXX NB NOTE syn keyword rustTodo contained TODO FIXME XXX NB NOTE SAFETY
" asm! macro {{{2
syn region rustAsmMacro matchgroup=rustMacro start="\<asm!\s*(" end=")" contains=rustAsmDirSpec,rustAsmSym,rustAsmConst,rustAsmOptionsGroup,rustComment.*,rustString.*
" Clobbered registers
syn keyword rustAsmDirSpec in out lateout inout inlateout contained nextgroup=rustAsmReg skipwhite skipempty
syn region rustAsmReg start="(" end=")" contained contains=rustString
" Symbol operands
syn keyword rustAsmSym sym contained nextgroup=rustAsmSymPath skipwhite skipempty
syn region rustAsmSymPath start="\S" end=",\|)"me=s-1 contained contains=rustComment.*,rustIdentifier
" Const
syn region rustAsmConstBalancedParens start="("ms=s+1 end=")" contained contains=@rustAsmConstExpr
syn cluster rustAsmConstExpr contains=rustComment.*,rust.*Number,rustString,rustAsmConstBalancedParens
syn region rustAsmConst start="const" end=",\|)"me=s-1 contained contains=rustStorage,@rustAsmConstExpr
" Options
syn region rustAsmOptionsGroup start="options\s*(" end=")" contained contains=rustAsmOptions,rustAsmOptionsKey
syn keyword rustAsmOptionsKey options contained
syn keyword rustAsmOptions pure nomem readonly preserves_flags noreturn nostack att_syntax contained
" Folding rules {{{2 " Folding rules {{{2
" Trivial folding rules to begin with. " Trivial folding rules to begin with.
" FIXME: use the AST to make really good folding " FIXME: use the AST to make really good folding
syn region rustFoldBraces start="{" end="}" transparent fold syn region rustFoldBraces start="{" end="}" transparent fold
if !exists("b:current_syntax_embed")
let b:current_syntax_embed = 1
syntax include @RustCodeInComment <sfile>:p:h/rust.vim
unlet b:current_syntax_embed
" Currently regions marked as ```<some-other-syntax> will not get
" highlighted at all. In the future, we can do as vim-markdown does and
" highlight with the other syntax. But for now, let's make sure we find
" the closing block marker, because the rules below won't catch it.
syn region rustCommentLinesDocNonRustCode matchgroup=rustCommentDocCodeFence start='^\z(\s*//[!/]\s*```\).\+$' end='^\z1$' keepend contains=rustCommentLineDoc
" We borrow the rules from rusts src/librustdoc/html/markdown.rs, so that
" we only highlight as Rust what it would perceive as Rust (almost; its
" possible to trick it if you try hard, and indented code blocks arent
" supported because Markdown is a menace to parse and only mad dogs and
" Englishmen would try to handle that case correctly in this syntax file).
syn region rustCommentLinesDocRustCode matchgroup=rustCommentDocCodeFence start='^\z(\s*//[!/]\s*```\)[^A-Za-z0-9_-]*\%(\%(should_panic\|no_run\|ignore\|allow_fail\|rust\|test_harness\|compile_fail\|E\d\{4}\|edition201[58]\)\%([^A-Za-z0-9_-]\+\|$\)\)*$' end='^\z1$' keepend contains=@RustCodeInComment,rustCommentLineDocLeader
syn region rustCommentBlockDocRustCode matchgroup=rustCommentDocCodeFence start='^\z(\%(\s*\*\)\?\s*```\)[^A-Za-z0-9_-]*\%(\%(should_panic\|no_run\|ignore\|allow_fail\|rust\|test_harness\|compile_fail\|E\d\{4}\|edition201[58]\)\%([^A-Za-z0-9_-]\+\|$\)\)*$' end='^\z1$' keepend contains=@RustCodeInComment,rustCommentBlockDocStar
" Strictly, this may or may not be correct; this code, for example, would
" mishighlight:
"
" /**
" ```rust
" println!("{}", 1
" * 1);
" ```
" */
"
" … but I dont care. Balance of probability, and all that.
syn match rustCommentBlockDocStar /^\s*\*\s\?/ contained
syn match rustCommentLineDocLeader "^\s*//\%(//\@!\|!\)" contained
endif
" Default highlighting {{{1 " Default highlighting {{{1
hi def link rustDecNumber rustNumber hi def link rustDecNumber rustNumber
hi def link rustHexNumber rustNumber hi def link rustHexNumber rustNumber
@ -219,7 +299,6 @@ hi def link rustIdentifierPrime rustIdentifier
hi def link rustTrait rustType hi def link rustTrait rustType
hi def link rustDeriveTrait rustTrait hi def link rustDeriveTrait rustTrait
hi def link rustMacroRepeatCount rustMacroRepeatDelimiters
hi def link rustMacroRepeatDelimiters Macro hi def link rustMacroRepeatDelimiters Macro
hi def link rustMacroVariable Define hi def link rustMacroVariable Define
hi def link rustSigil StorageClass hi def link rustSigil StorageClass
@ -228,6 +307,7 @@ hi def link rustEscapeUnicode rustEscape
hi def link rustEscapeError Error hi def link rustEscapeError Error
hi def link rustStringContinuation Special hi def link rustStringContinuation Special
hi def link rustString String hi def link rustString String
hi def link rustStringDelimiter String
hi def link rustCharacterInvalid Error hi def link rustCharacterInvalid Error
hi def link rustCharacterInvalidUnicode rustCharacterInvalid hi def link rustCharacterInvalidUnicode rustCharacterInvalid
hi def link rustCharacter Character hi def link rustCharacter Character
@ -241,12 +321,15 @@ hi def link rustFloat Float
hi def link rustArrowCharacter rustOperator hi def link rustArrowCharacter rustOperator
hi def link rustOperator Operator hi def link rustOperator Operator
hi def link rustKeyword Keyword hi def link rustKeyword Keyword
hi def link rustDynKeyword rustKeyword
hi def link rustTypedef Keyword " More precise is Typedef, but it doesn't feel right for Rust 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 rustStructure Keyword " More precise is Structure
hi def link rustUnion rustStructure hi def link rustUnion rustStructure
hi def link rustExistential rustKeyword
hi def link rustPubScopeDelim Delimiter hi def link rustPubScopeDelim Delimiter
hi def link rustPubScopeCrate rustKeyword hi def link rustPubScopeCrate rustKeyword
hi def link rustSuper rustKeyword hi def link rustSuper rustKeyword
hi def link rustUnsafeKeyword Exception
hi def link rustReservedKeyword Error hi def link rustReservedKeyword Error
hi def link rustRepeat Conditional hi def link rustRepeat Conditional
hi def link rustConditional Conditional hi def link rustConditional Conditional
@ -260,10 +343,13 @@ hi def link rustFuncCall Function
hi def link rustShebang Comment hi def link rustShebang Comment
hi def link rustCommentLine Comment hi def link rustCommentLine Comment
hi def link rustCommentLineDoc SpecialComment hi def link rustCommentLineDoc SpecialComment
hi def link rustCommentLineDocLeader rustCommentLineDoc
hi def link rustCommentLineDocError Error hi def link rustCommentLineDocError Error
hi def link rustCommentBlock rustCommentLine hi def link rustCommentBlock rustCommentLine
hi def link rustCommentBlockDoc rustCommentLineDoc hi def link rustCommentBlockDoc rustCommentLineDoc
hi def link rustCommentBlockDocStar rustCommentBlockDoc
hi def link rustCommentBlockDocError Error hi def link rustCommentBlockDocError Error
hi def link rustCommentDocCodeFence rustCommentLineDoc
hi def link rustAssert PreCondit hi def link rustAssert PreCondit
hi def link rustPanic PreCondit hi def link rustPanic PreCondit
hi def link rustMacro Macro hi def link rustMacro Macro
@ -276,11 +362,15 @@ hi def link rustStorage StorageClass
hi def link rustObsoleteStorage Error hi def link rustObsoleteStorage Error
hi def link rustLifetime Special hi def link rustLifetime Special
hi def link rustLabel Label hi def link rustLabel Label
hi def link rustInvalidBareKeyword Error
hi def link rustExternCrate rustKeyword hi def link rustExternCrate rustKeyword
hi def link rustObsoleteExternMod Error hi def link rustObsoleteExternMod Error
hi def link rustBoxPlacementParens Delimiter
hi def link rustQuestionMark Special hi def link rustQuestionMark Special
hi def link rustAsync rustKeyword
hi def link rustAwait rustKeyword
hi def link rustAsmDirSpec rustKeyword
hi def link rustAsmSym rustKeyword
hi def link rustAsmOptions rustKeyword
hi def link rustAsmOptionsKey rustAttribute
" Other Suggestions: " Other Suggestions:
" hi rustAttribute ctermfg=cyan " hi rustAttribute ctermfg=cyan
@ -293,3 +383,5 @@ syn sync minlines=200
syn sync maxlines=500 syn sync maxlines=500
let b:current_syntax = "rust" let b:current_syntax = "rust"
" vim: set et sw=4 sts=4 ts=8: