aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/autoload/cargo.vim149
-rw-r--r--runtime/autoload/cargo/quickfix.vim29
-rw-r--r--runtime/autoload/rust.vim773
-rw-r--r--runtime/autoload/rust/debugging.vim105
-rw-r--r--runtime/autoload/rustfmt.vim300
-rw-r--r--runtime/compiler/cargo.vim36
-rw-r--r--runtime/compiler/rustc.vim63
-rw-r--r--runtime/doc/develop.txt16
-rw-r--r--runtime/doc/ft_rust.txt434
-rw-r--r--runtime/doc/lua.txt274
-rw-r--r--runtime/ftplugin/rust.vim252
-rw-r--r--runtime/indent/rust.vim432
-rw-r--r--runtime/lua/vim/iter.lua187
-rw-r--r--runtime/lua/vim/treesitter/_fold.lua4
-rw-r--r--runtime/lua/vim/treesitter/dev.lua8
-rw-r--r--runtime/lua/vim/treesitter/languagetree.lua43
-rw-r--r--runtime/syntax/i3config.vim466
-rw-r--r--runtime/syntax/rust.vim166
-rw-r--r--runtime/syntax/swayconfig.vim196
-rw-r--r--scripts/gen_help_html.lua14
-rwxr-xr-xscripts/gen_vimdoc.py28
21 files changed, 2574 insertions, 1401 deletions
diff --git a/runtime/autoload/cargo.vim b/runtime/autoload/cargo.vim
new file mode 100644
index 0000000000..6696b3105f
--- /dev/null
+++ b/runtime/autoload/cargo.vim
@@ -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:
diff --git a/runtime/autoload/cargo/quickfix.vim b/runtime/autoload/cargo/quickfix.vim
new file mode 100644
index 0000000000..f2a006f6c5
--- /dev/null
+++ b/runtime/autoload/cargo/quickfix.vim
@@ -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:
diff --git a/runtime/autoload/rust.vim b/runtime/autoload/rust.vim
index 4230332fa7..5ccbf4b382 100644
--- a/runtime/autoload/rust.vim
+++ b/runtime/autoload/rust.vim
@@ -1,207 +1,258 @@
-" Author: Lily Ballard
" 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
+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
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
+ 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[{
+ call search('{', 'b')
+ keepjumps normal! w99[{
endfunction
function! s:Jump_Forward()
- normal! j0
- call search('{', 'b')
- keepjumps normal! w99[{%
- call search('{')
+ 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)
+ 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
+ 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)
+ 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
+ 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)
+ 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)
+ 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
+ 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
@@ -219,145 +270,154 @@ endfunction
" 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
+ 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 = &modified
+ set nomodified
+
+ 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
+ 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
+ " 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))
+ " 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
+ let l:path = expand(a:path)
+ if l:path ==# '/' || l:path ==# $HOME
+ echoerr 'Attempted to delete protected path: ' . a:path
+ return 0
+ endif
+ endif
+
+ if !isdirectory(a:path)
+ return 0
+ endif
+
+ " delete() returns 0 when removing file successfully
+ return delete(a:path, 'rf') == 0
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)
+ let cmd = a:cmd
+ if !empty(a:pwd)
+ let cmd = 'cd ' . shellescape(a:pwd) . ' && ' . cmd
+ endif
+ return system(cmd)
endfunction
" Playpen Support {{{1
@@ -366,10 +426,10 @@ endfunction
" http://github.com/mattn/gist-vim
function! s:has_webapi()
if !exists("*webapi#http#post")
- try
- call webapi#http#post()
- catch
- endtry
+ try
+ call webapi#http#post()
+ catch
+ endtry
endif
return exists("*webapi#http#post")
endfunction
@@ -381,35 +441,130 @@ function! rust#Play(count, line1, line2, ...) abort
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
+ 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")
+ 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)
+ 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)
+ let url = 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
+ if strlen(url) > 5000
+ echohl ErrorMsg | echomsg 'Buffer too large, max 5000 encoded characters ('.strlen(url).')' | echohl None
+ return
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 url = res.content
+ if res.status[0] ==# '2'
+ let url = res.content
+ endif
+
+ 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('.')
- redraw | echomsg 'Done: '.url
+ " 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
" }}}1
-" vim: set noet sw=8 ts=8:
+" vim: set et sw=4 sts=4 ts=8:
diff --git a/runtime/autoload/rust/debugging.vim b/runtime/autoload/rust/debugging.vim
new file mode 100644
index 0000000000..0e84183172
--- /dev/null
+++ b/runtime/autoload/rust/debugging.vim
@@ -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:
diff --git a/runtime/autoload/rustfmt.vim b/runtime/autoload/rustfmt.vim
index a689b5e00d..652e6af33a 100644
--- a/runtime/autoload/rustfmt.vim
+++ b/runtime/autoload/rustfmt.vim
@@ -1,107 +1,261 @@
" Author: Stephen Sugden <stephen@stephensugden.com>
+" Last Modified: 2023-09-11
"
" 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
+ let g:rustfmt_autosave = 0
endif
if !exists("g:rustfmt_command")
- let g:rustfmt_command = "rustfmt"
+ let g:rustfmt_command = "rustfmt"
endif
if !exists("g:rustfmt_options")
- let g:rustfmt_options = ""
+ let g:rustfmt_options = ""
endif
if !exists("g:rustfmt_fail_silently")
- let g:rustfmt_fail_silently = 0
+ let g:rustfmt_fail_silently = 0
+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
+function! rustfmt#Load()
+ " Utility call to get this script loaded, for debugging
+endfunction
+
+function! s:RustfmtWriteMode()
+ if g:rustfmt_emit_files
+ return "--emit=files"
+ else
+ 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
+
+ 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)
- 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))
+ 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(filename)
- return g:rustfmt_command . " --write-mode=overwrite " . g:rustfmt_options . " " . shellescape(a:filename)
+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: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)
+function! s:DeleteLines(start, end) abort
+ silent! execute a:start . ',' . a:end . 'delete _'
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)
+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
- let command = s:RustfmtCommandRange(l:tmpname, a:line1, a:line2)
+ if a:tmpname ==# ''
+ " Rustfmt in stdin/stdout mode
- call s:RunRustfmt(command, l:curw, l:tmpname)
+ " 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
+ try | silent undojoin | catch | endtry
+ endif
+
+ if a:tmpname ==# ''
+ let l:content = l:out
+ else
+ " 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
+ " clobbering other additions
+ if s:got_fmt_error
+ let s:got_fmt_error = 0
+ call setloclist(0, [])
+ let l:open_lwindow = 1
+ endif
+ elseif g:rustfmt_fail_silently == 0 && !a:from_writepre
+ " otherwise get the errors and put them in the location list
+ let l:errors = []
+
+ let l:prev_line = ""
+ for l:line in l:stderr
+ " 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)
+ call add(l:errors, {"filename": @%,
+ \"lnum": tokens[2],
+ \"col": tokens[3],
+ \"text": l:prev_line})
+ endif
+ let l:prev_line = l:line
+ endfor
+
+ if !empty(l:errors)
+ call setloclist(0, l:errors, 'r')
+ 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
+
+ let s:got_fmt_error = 1
+ let l:open_lwindow = 1
+ endif
+
+ " 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
+
+function! rustfmt#FormatRange(line1, line2)
+ let l:tmpname = tempname()
+ call writefile(getline(1, '$'), l:tmpname)
+ let command = s:RustfmtCommandRange(l:tmpname, a:line1, a:line2)
+ call s:RunRustfmt(command, l:tmpname, v:false)
+ call delete(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)
+ call s:RunRustfmt(s:RustfmtCommand(), '', v:false)
+endfunction
- let command = s:RustfmtCommand(l:tmpname)
+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(command, l:curw, l:tmpname)
+ call s:RunRustfmt(s:RustfmtCommand(), '', v:true)
endfunction
+
+
+" vim: set et sw=4 sts=4 ts=8:
diff --git a/runtime/compiler/cargo.vim b/runtime/compiler/cargo.vim
index bd48666bc9..aa9b01e93c 100644
--- a/runtime/compiler/cargo.vim
+++ b/runtime/compiler/cargo.vim
@@ -1,35 +1,51 @@
" Vim compiler file
" Compiler: Cargo Compiler
" 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
if exists('current_compiler')
- finish
+ finish
endif
runtime compiler/rustc.vim
let current_compiler = "cargo"
+" vint: -ProhibitAbbreviationOption
let s:save_cpo = &cpo
set cpo&vim
+" vint: +ProhibitAbbreviationOption
if exists(':CompilerSet') != 2
- command -nargs=* CompilerSet setlocal <args>
+ command -nargs=* CompilerSet setlocal <args>
endif
if exists('g:cargo_makeprg_params')
- execute 'CompilerSet makeprg=cargo\ '.escape(g:cargo_makeprg_params, ' \|"').'\ $*'
+ execute 'CompilerSet makeprg=cargo\ '.escape(g:cargo_makeprg_params, ' \|"').'\ $*'
else
- CompilerSet makeprg=cargo\ $*
+ CompilerSet makeprg=cargo\ $*
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
CompilerSet errorformat+=
- \%-G%\\s%#Downloading%.%#,
- \%-G%\\s%#Compiling%.%#,
- \%-G%\\s%#Finished%.%#,
- \%-G%\\s%#error:\ Could\ not\ compile\ %.%#,
- \%-G%\\s%#To\ learn\ more\\,%.%#
+ \%-G%\\s%#Downloading%.%#,
+ \%-G%\\s%#Checking%.%#,
+ \%-G%\\s%#Compiling%.%#,
+ \%-G%\\s%#Finished%.%#,
+ \%-G%\\s%#error:\ Could\ not\ compile\ %.%#,
+ \%-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
unlet s:save_cpo
+" vint: +ProhibitAbbreviationOption
+
+" vim: set et sw=4 sts=4 ts=8:
diff --git a/runtime/compiler/rustc.vim b/runtime/compiler/rustc.vim
index 5e5b9a4e0a..efcf24ed80 100644
--- a/runtime/compiler/rustc.vim
+++ b/runtime/compiler/rustc.vim
@@ -1,46 +1,57 @@
" Vim compiler file
" Compiler: Rust Compiler
" 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
if exists("current_compiler")
- finish
+ finish
endif
let current_compiler = "rustc"
-let s:cpo_save = &cpo
+" vint: -ProhibitAbbreviationOption
+let s:save_cpo = &cpo
set cpo&vim
+" vint: +ProhibitAbbreviationOption
if exists(":CompilerSet") != 2
- command -nargs=* CompilerSet setlocal <args>
+ command -nargs=* CompilerSet setlocal <args>
endif
-if exists("g:rustc_makeprg_no_percent") && g:rustc_makeprg_no_percent != 0
- CompilerSet makeprg=rustc
+if get(g:, 'rustc_makeprg_no_percent', 0)
+ CompilerSet makeprg=rustc
else
- CompilerSet makeprg=rustc\ \%:S
+ if has('patch-7.4.191')
+ CompilerSet makeprg=rustc\ \%:S
+ else
+ CompilerSet makeprg=rustc\ \"%\"
+ endif
endif
-" Old errorformat (before nightly 2016/08/10)
+" New errorformat (after 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%*[\ ]...
+ \%-G,
+ \%-Gerror:\ aborting\ %.%#,
+ \%-Gerror:\ Could\ not\ compile\ %.%#,
+ \%Eerror:\ %m,
+ \%Eerror[E%n]:\ %m,
+ \%Wwarning:\ %m,
+ \%Inote:\ %m,
+ \%C\ %#-->\ %f:%l:%c,
+ \%E\ \ left:%m,%C\ right:%m\ %f:%l:%c,%Z
-" New errorformat (after nightly 2016/08/10)
+" Old errorformat (before 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
+ \%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:
diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt
index b3f7d1fadc..0ed537c248 100644
--- a/runtime/doc/develop.txt
+++ b/runtime/doc/develop.txt
@@ -192,7 +192,7 @@ Docstring format:
`@note`, `@param`, `@returns`
- Limited markdown is supported.
- List-items start with `-` (useful to nest or "indent")
-- Use `<pre>` for code samples.
+- Use ``` for code samples.
Code samples can be annotated as `vim` or `lua`
Example: the help for |nvim_open_win()| is generated from a docstring defined
@@ -202,10 +202,16 @@ in src/nvim/api/win_config.c like this: >
/// ...
///
/// Example (Lua): window-relative float
- /// <pre>lua
- /// vim.api.nvim_open_win(0, false,
- /// {relative='win', row=3, col=3, width=12, height=3})
- /// </pre>
+ ///
+ /// ```lua
+ /// vim.api.nvim_open_win(0, false, {
+ /// relative='win',
+ /// row=3,
+ /// col=3,
+ /// width=12,
+ /// height=3,
+ /// })
+ /// ```
///
/// @param buffer Buffer to display
/// @param enter Enter the window
diff --git a/runtime/doc/ft_rust.txt b/runtime/doc/ft_rust.txt
index a5d5b558dc..b912f732b6 100644
--- a/runtime/doc/ft_rust.txt
+++ b/runtime/doc/ft_rust.txt
@@ -1,72 +1,74 @@
-*ft_rust.txt* Nvim
-
-This is documentation for the Rust filetype plugin.
+*ft_rust.txt* Filetype plugin for Rust
==============================================================================
-CONTENTS *rust*
+CONTENTS *rust*
-1. Introduction |rust-intro|
-2. Settings |rust-settings|
-3. Commands |rust-commands|
-4. Mappings |rust-mappings|
+1. Introduction |rust-intro|
+2. Settings |rust-settings|
+3. Commands |rust-commands|
+4. Mappings |rust-mappings|
==============================================================================
-INTRODUCTION *rust-intro*
+INTRODUCTION *rust-intro*
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*
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~
+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 ~
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"
+ |:RustExpand| commands. If unset, `rustc` will be located in $PATH: >vim
+ 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 %": >
+ *g:rustc_makeprg_no_percent*
+g:rustc_makeprg_no_percent ~
+ Set this option to 1 to have 'makeprg' default to `rustc` instead of
+ `rustc %`: >vim
let g:rustc_makeprg_no_percent = 1
<
- *g:rust_conceal*
-g:rust_conceal~
- Set this option to turn on the basic |conceal| support: >
+ *g:rust_conceal*
+g:rust_conceal ~
+ Set this option to turn on the basic |conceal| support: >vim
let g:rust_conceal = 1
<
- *g:rust_conceal_mod_path*
-g:rust_conceal_mod_path~
+ *g:rust_conceal_mod_path*
+g:rust_conceal_mod_path ~
Set this option to turn on |conceal| for the path connecting token
- "::": >
+ "::": >vim
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: >
+ *g:rust_conceal_pub*
+g:rust_conceal_pub ~
+ Set this option to turn on |conceal| for the "pub" token: >vim
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: >
+ *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: >vim
let g:rust_recommended_style = 0
<
- *g:rust_fold*
-g:rust_fold~
- Set this option to turn on |folding|: >
+ *g:rust_fold*
+g:rust_fold ~
+ Set this option to turn on |folding|: >vim
let g:rust_fold = 1
<
Value Effect ~
@@ -77,62 +79,297 @@ g:rust_fold~
global value (all folds are closed by default).
*g:rust_bang_comment_leader*
-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: >
+ using the `/*!` syntax: >vim
let g:rust_bang_comment_leader = 1
<
- *g:ftplugin_rust_source_path*
-g:ftplugin_rust_source_path~
+ *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: >vim
+ 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 ~
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'
+ source files: >vim
+ let g:ftplugin_rust_source_path = $HOME . '/dev/rust'
<
*g:rustfmt_command*
-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" : >
+ not specified it defaults to "rustfmt" : >vim
let g:rustfmt_command = 'rustfmt'
<
*g:rustfmt_autosave*
-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 : >
+ buffer. If not specified it defaults to 0 : >vim
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: >vim
+ 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 ~
Set this option to 1 to prevent "rustfmt" from populating the
- |location-list| with errors. If not specified it defaults to 0: >
+ |location-list| with errors. If not specified it defaults to 0: >vim
let g:rustfmt_fail_silently = 0
<
*g:rustfmt_options*
-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 '' : >
+ defaults to '' : >vim
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'. >vim
+ let g:rustfmt_emit_files = 0
+<
*g:rust_playpen_url*
-g:rust_playpen_url~
- Set this option to override the URL for the playpen to use: >
+g:rust_playpen_url ~
+ Set this option to override the url for the playpen to use: >vim
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: >
+g:rust_shortener_url ~
+ Set this option to override the url for the url shortener: >vim
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: >vim
+ 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 `$*` : >vim
+ 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: >vim
+ 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. >vim
+
+ 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. >vim
+ 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|.
-:RustRun [args] *:RustRun*
+: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! [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
@@ -150,26 +387,26 @@ COMMANDS *rust-commands*
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 [args] *:RustExpand*
:RustExpand! [TYPE] [args]
- Expands the current file using --pretty and displays the
+ 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
+ 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
+ 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*
+: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
@@ -180,7 +417,7 @@ COMMANDS *rust-commands*
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*
+: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
@@ -191,49 +428,52 @@ COMMANDS *rust-commands*
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/".
+Running test(s) ~
- |g:rust_shortener_url| is the base URL for the shortener, by
- default "https://is.gd/"
+:[N]RustTest[!] [options] *:RustTest*
+ 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*
- Runs |g:rustfmt_command| on the current buffer. If
- |g:rustfmt_options| is set then those will be passed to the
- executable.
+ When N is given, adjust the size of the new window to N lines
+ or columns.
- 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|.
+ When ! is given, runs all tests regardless of current cursor
+ position.
-:RustFmtRange *:RustFmtRange*
- Runs |g:rustfmt_command| with selected range. See
- |:RustFmt| for any other information.
+ When [options] is given, it is passed to "cargo" command
+ arguments.
-==============================================================================
-MAPPINGS *rust-mappings*
+ 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.
-This plugin defines mappings for |[[| and |]]| to support hanging indents.
+ Takes optional modifiers (see |<mods>|): >vim
+ :tab RustTest
+ :belowright 16RustTest
+ :leftabove vert 80RustTest
+<
+rust.vim Debugging ~
-It also has a few other mappings:
+:RustInfo *:RustInfo*
+ Emits debugging info of the Vim Rust plugin.
- *rust_<D-r>*
-<D-r> Executes |:RustRun| with no arguments.
- Note: This binding is only available in MacVim.
+:RustInfoToClipboard *:RustInfoClipboard*
+ Saves debugging info of the Vim Rust plugin to the default
+ register.
- *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.
+:RustInfoToFile [filename] *:RustInfoToFile*
+ Saves debugging info of the Vim Rust plugin to the the given
+ file, overwritting it.
==============================================================================
- vim:tw=78:sw=4:ts=8:noet:ft=help:norl:
+MAPPINGS *rust-mappings*
+
+This plugin defines mappings for |[[| and |]]| to support hanging indents.
+
+
+vim:tw=78:sw=4:noet:ts=8:ft=help:norl:
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index 71f001f4fc..61afd4698a 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -3229,42 +3229,42 @@ first value returned by the function is nil).
Examples: >lua
- local it = vim.iter({ 1, 2, 3, 4, 5 })
- it:map(function(v)
- return v * 3
- end)
- it:rev()
- it:skip(2)
- it:totable()
- -- { 9, 6, 3 }
-
- -- ipairs() is a function iterator which returns both the index (i) and the value (v)
- vim.iter(ipairs({ 1, 2, 3, 4, 5 })):map(function(i, v)
- if i > 2 then return v end
- end):totable()
- -- { 3, 4, 5 }
-
- local it = vim.iter(vim.gsplit('1,2,3,4,5', ','))
- it:map(function(s) return tonumber(s) end)
- for i, d in it:enumerate() do
- print(string.format("Column %d is %d", i, d))
- end
- -- Column 1 is 1
- -- Column 2 is 2
- -- Column 3 is 3
- -- Column 4 is 4
- -- Column 5 is 5
-
- vim.iter({ a = 1, b = 2, c = 3, z = 26 }):any(function(k, v)
- return k == 'z'
- end)
- -- true
+ local it = vim.iter({ 1, 2, 3, 4, 5 })
+ it:map(function(v)
+ return v * 3
+ end)
+ it:rev()
+ it:skip(2)
+ it:totable()
+ -- { 9, 6, 3 }
+
+ -- ipairs() is a function iterator which returns both the index (i) and the value (v)
+ vim.iter(ipairs({ 1, 2, 3, 4, 5 })):map(function(i, v)
+ if i > 2 then return v end
+ end):totable()
+ -- { 3, 4, 5 }
+
+ local it = vim.iter(vim.gsplit('1,2,3,4,5', ','))
+ it:map(function(s) return tonumber(s) end)
+ for i, d in it:enumerate() do
+ print(string.format("Column %d is %d", i, d))
+ end
+ -- Column 1 is 1
+ -- Column 2 is 2
+ -- Column 3 is 3
+ -- Column 4 is 4
+ -- Column 5 is 5
+
+ vim.iter({ a = 1, b = 2, c = 3, z = 26 }):any(function(k, v)
+ return k == 'z'
+ end)
+ -- true
- local rb = vim.ringbuf(3)
- rb:push("a")
- rb:push("b")
- vim.iter(rb):totable()
- -- { "a", "b" }
+ local rb = vim.ringbuf(3)
+ rb:push("a")
+ rb:push("b")
+ vim.iter(rb):totable()
+ -- { "a", "b" }
<
@@ -3276,7 +3276,7 @@ filter({f}, {src}, {...}) *vim.iter.filter()*
This is a convenience function that performs: >lua
- vim.iter(src):filter(f):totable()
+ vim.iter(src):filter(f):totable()
<
Parameters: ~
@@ -3326,25 +3326,25 @@ Iter:enumerate() *Iter:enumerate()*
For list tables, prefer >lua
- vim.iter(ipairs(t))
+ vim.iter(ipairs(t))
<
over >lua
- vim.iter(t):enumerate()
+ vim.iter(t):enumerate()
<
as the former is faster.
Example: >lua
- local it = vim.iter(vim.gsplit('abc', '')):enumerate()
- it:next()
- -- 1 'a'
- it:next()
- -- 2 'b'
- it:next()
- -- 3 'c'
+ local it = vim.iter(vim.gsplit('abc', '')):enumerate()
+ it:next()
+ -- 1 'a'
+ it:next()
+ -- 2 'b'
+ it:next()
+ -- 3 'c'
<
Return: ~
@@ -3355,7 +3355,7 @@ Iter:filter({f}) *Iter:filter()*
Example: >lua
- local bufs = vim.iter(vim.api.nvim_list_bufs()):filter(vim.api.nvim_buf_is_loaded)
+ local bufs = vim.iter(vim.api.nvim_list_bufs()):filter(vim.api.nvim_buf_is_loaded)
<
Parameters: ~
@@ -3374,17 +3374,17 @@ Iter:find({f}) *Iter:find()*
Examples: >lua
- local it = vim.iter({ 3, 6, 9, 12 })
- it:find(12)
- -- 12
+ local it = vim.iter({ 3, 6, 9, 12 })
+ it:find(12)
+ -- 12
- local it = vim.iter({ 3, 6, 9, 12 })
- it:find(20)
- -- nil
+ local it = vim.iter({ 3, 6, 9, 12 })
+ it:find(20)
+ -- nil
- local it = vim.iter({ 3, 6, 9, 12 })
- it:find(function(v) return v % 4 == 0 end)
- -- 12
+ local it = vim.iter({ 3, 6, 9, 12 })
+ it:find(function(v) return v % 4 == 0 end)
+ -- 12
<
Return: ~
@@ -3395,15 +3395,15 @@ Iter:fold({init}, {f}) *Iter:fold()*
Examples: >lua
- -- Create a new table with only even values
- local t = { a = 1, b = 2, c = 3, d = 4 }
- local it = vim.iter(t)
- it:filter(function(k, v) return v % 2 == 0 end)
- it:fold({}, function(t, k, v)
- t[k] = v
- return t
- end)
- -- { b = 2, d = 4 }
+ -- Create a new table with only even values
+ local t = { a = 1, b = 2, c = 3, d = 4 }
+ local it = vim.iter(t)
+ it:filter(function(k, v) return v % 2 == 0 end)
+ it:fold({}, function(t, k, v)
+ t[k] = v
+ return t
+ end)
+ -- { b = 2, d = 4 }
<
Parameters: ~
@@ -3420,13 +3420,13 @@ Iter:last() *Iter:last()*
Example: >lua
- local it = vim.iter(vim.gsplit('abcdefg', ''))
- it:last()
- -- 'g'
+ local it = vim.iter(vim.gsplit('abcdefg', ''))
+ it:last()
+ -- 'g'
- local it = vim.iter({ 3, 6, 9, 12, 15 })
- it:last()
- -- 15
+ local it = vim.iter({ 3, 6, 9, 12, 15 })
+ it:last()
+ -- 15
<
Return: ~
@@ -3439,13 +3439,13 @@ Iter:map({f}) *Iter:map()*
Example: >lua
- local it = vim.iter({ 1, 2, 3, 4 }):map(function(v)
- if v % 2 == 0 then
- return v * 3
- end
- end)
- it:totable()
- -- { 6, 12 }
+ local it = vim.iter({ 1, 2, 3, 4 }):map(function(v)
+ if v % 2 == 0 then
+ return v * 3
+ end
+ end)
+ it:totable()
+ -- { 6, 12 }
<
Parameters: ~
@@ -3462,13 +3462,13 @@ Iter:next() *Iter:next()*
Example: >lua
- local it = vim.iter(string.gmatch('1 2 3', 'd+')):map(tonumber)
- it:next()
- -- 1
- it:next()
- -- 2
- it:next()
- -- 3
+ local it = vim.iter(string.gmatch('1 2 3', '%d+')):map(tonumber)
+ it:next()
+ -- 1
+ it:next()
+ -- 2
+ it:next()
+ -- 3
<
Return: ~
@@ -3481,11 +3481,11 @@ Iter:nextback() *Iter:nextback()*
Example: >lua
- local it = vim.iter({1, 2, 3, 4})
- it:nextback()
- -- 4
- it:nextback()
- -- 3
+ local it = vim.iter({1, 2, 3, 4})
+ it:nextback()
+ -- 4
+ it:nextback()
+ -- 3
<
Return: ~
@@ -3498,11 +3498,11 @@ Iter:nth({n}) *Iter:nth()*
Example: >lua
- local it = vim.iter({ 3, 6, 9, 12 })
- it:nth(2)
- -- 6
- it:nth(2)
- -- 12
+ local it = vim.iter({ 3, 6, 9, 12 })
+ it:nth(2)
+ -- 6
+ it:nth(2)
+ -- 12
<
Parameters: ~
@@ -3520,11 +3520,11 @@ Iter:nthback({n}) *Iter:nthback()*
Example: >lua
- local it = vim.iter({ 3, 6, 9, 12 })
- it:nthback(2)
- -- 9
- it:nthback(2)
- -- 3
+ local it = vim.iter({ 3, 6, 9, 12 })
+ it:nthback(2)
+ -- 9
+ it:nthback(2)
+ -- 3
<
Parameters: ~
@@ -3540,13 +3540,13 @@ Iter:peek() *Iter:peek()*
Example: >lua
- local it = vim.iter({ 3, 6, 9, 12 })
- it:peek()
- -- 3
- it:peek()
- -- 3
- it:next()
- -- 3
+ local it = vim.iter({ 3, 6, 9, 12 })
+ it:peek()
+ -- 3
+ it:peek()
+ -- 3
+ it:next()
+ -- 3
<
Return: ~
@@ -3559,13 +3559,13 @@ Iter:peekback() *Iter:peekback()*
Example: >lua
- local it = vim.iter({1, 2, 3, 4})
- it:peekback()
- -- 4
- it:peekback()
- -- 4
- it:nextback()
- -- 4
+ local it = vim.iter({1, 2, 3, 4})
+ it:peekback()
+ -- 4
+ it:peekback()
+ -- 4
+ it:nextback()
+ -- 4
<
Return: ~
@@ -3578,9 +3578,9 @@ Iter:rev() *Iter:rev()*
Example: >lua
- local it = vim.iter({ 3, 6, 9, 12 }):rev()
- it:totable()
- -- { 12, 9, 6, 3 }
+ local it = vim.iter({ 3, 6, 9, 12 }):rev()
+ it:totable()
+ -- { 12, 9, 6, 3 }
<
Return: ~
@@ -3597,11 +3597,11 @@ Iter:rfind({f}) *Iter:rfind()*
Examples: >lua
- local it = vim.iter({ 1, 2, 3, 2, 1 }):enumerate()
- it:rfind(1)
- -- 5 1
- it:rfind(1)
- -- 1 1
+ local it = vim.iter({ 1, 2, 3, 2, 1 }):enumerate()
+ it:rfind(1)
+ -- 5 1
+ it:rfind(1)
+ -- 1 1
<
Return: ~
@@ -3615,9 +3615,9 @@ Iter:skip({n}) *Iter:skip()*
Example: >lua
- local it = vim.iter({ 3, 6, 9, 12 }):skip(2)
- it:next()
- -- 9
+ local it = vim.iter({ 3, 6, 9, 12 }):skip(2)
+ it:next()
+ -- 9
<
Parameters: ~
@@ -3633,11 +3633,11 @@ Iter:skipback({n}) *Iter:skipback()*
Example: >lua
- local it = vim.iter({ 1, 2, 3, 4, 5 }):skipback(2)
- it:next()
- -- 1
- it:nextback()
- -- 3
+ local it = vim.iter({ 1, 2, 3, 4, 5 }):skipback(2)
+ it:next()
+ -- 1
+ it:nextback()
+ -- 3
<
Parameters: ~
@@ -3670,14 +3670,14 @@ Iter:totable() *Iter:totable()*
Examples: >lua
- vim.iter(string.gmatch('100 20 50', 'd+')):map(tonumber):totable()
- -- { 100, 20, 50 }
+ vim.iter(string.gmatch('100 20 50', '%d+')):map(tonumber):totable()
+ -- { 100, 20, 50 }
- vim.iter({ 1, 2, 3 }):map(function(v) return v, 2 * v end):totable()
- -- { { 1, 2 }, { 2, 4 }, { 3, 6 } }
+ vim.iter({ 1, 2, 3 }):map(function(v) return v, 2 * v end):totable()
+ -- { { 1, 2 }, { 2, 4 }, { 3, 6 } }
- vim.iter({ a = 1, b = 2, c = 3 }):filter(function(k, v) return v % 2 ~= 0 end):totable()
- -- { { 'a', 1 }, { 'c', 3 } }
+ vim.iter({ a = 1, b = 2, c = 3 }):filter(function(k, v) return v % 2 ~= 0 end):totable()
+ -- { { 'a', 1 }, { 'c', 3 } }
<
The generated table is a list-like table with consecutive, numeric
@@ -3692,7 +3692,7 @@ map({f}, {src}, {...}) *vim.iter.map()*
This is a convenience function that performs: >lua
- vim.iter(src):map(f):totable()
+ vim.iter(src):map(f):totable()
<
Parameters: ~
@@ -3712,7 +3712,7 @@ totable({f}, {...}) *vim.iter.totable()*
This is a convenience function that performs: >lua
- vim.iter(f):totable()
+ vim.iter(f):totable()
<
Parameters: ~
diff --git a/runtime/ftplugin/rust.vim b/runtime/ftplugin/rust.vim
index ececcced22..7f1a86ea95 100644
--- a/runtime/ftplugin/rust.vim
+++ b/runtime/ftplugin/rust.vim
@@ -1,20 +1,26 @@
" Language: Rust
" Description: Vim ftplugin for Rust
" Maintainer: Chris Morgan <me@chrismorgan.info>
-" Maintainer: Lily Ballard <lily@ballards.net>
-" Last Change: June 08, 2016
-" For bugs, patches and license go to https://github.com/rust-lang/rust.vim
+" Last Change: 2023-09-11
+" For bugs, patches and license go to https://github.com/rust-lang/rust.vim
if exists("b:did_ftplugin")
- finish
+ finish
endif
let b:did_ftplugin = 1
+" vint: -ProhibitAbbreviationOption
let s:save_cpo = &cpo
set cpo&vim
-
-augroup rust.vim
-autocmd!
+" vint: +ProhibitAbbreviationOption
+
+if get(b:, 'current_compiler', '') ==# ''
+ if strlen(findfile('Cargo.toml', '.;')) > 0
+ compiler cargo
+ else
+ compiler rustc
+ endif
+endif
" Variables {{{1
@@ -22,13 +28,13 @@ autocmd!
" 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:*/,:///,://!,://
+if get(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:*/,:///,://!,://
+ setlocal comments=s0:/*!,ex:*/,s1:/*,mb:*,ex:*/,:///,://!,://
endif
setlocal commentstring=//%s
setlocal formatoptions-=t formatoptions+=croqnl
@@ -39,13 +45,14 @@ silent! setlocal formatoptions+=j
" 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
+if get(g:, 'rust_recommended_style', 1)
+ let b:rust_set_style = 1
+ setlocal 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 include=\\v^\\s*(pub\\s+)?use\\s+\\zs(\\f\|:)+
+setlocal includeexpr=rust#IncludeExpr(v:fname)
setlocal suffixesadd=.rs
@@ -54,51 +61,36 @@ if exists("g:ftplugin_rust_source_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
+ if exists("b:delimitMate_excluded_regions")
+ let b:rust_original_delimitMate_excluded_regions = b:delimitMate_excluded_regions
+ endif
+
+ augroup rust.vim.DelimitMate
+ autocmd!
+
+ autocmd User delimitMate_map :call rust#delimitmate#onMap()
+ autocmd User delimitMate_unmap :call rust#delimitmate#onUnmap()
+ augroup END
+endif
+
+" 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") && 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
+if has("folding") && get(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
+if has('conceal') && get(g:, 'rust_conceal', 0)
+ let b:rust_set_conceallevel=1
+ setlocal conceallevel=2
endif
" Motion Commands {{{1
@@ -126,72 +118,122 @@ command! -nargs=* -buffer RustEmitIr call rust#Emit("llvm-ir", <q-args>)
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>)
+command! -range=% -buffer RustPlay :call rust#Play(<count>, <line1>, <line2>, <f-args>)
" See |:RustFmt| for docs
-command! -buffer RustFmt call rustfmt#Format()
+command! -bar -buffer RustFmt call rustfmt#Format()
" See |:RustFmtRange| for docs
command! -range -buffer RustFmtRange call rustfmt#FormatRange(<line1>, <line2>)
-" Mappings {{{1
+" See |:RustInfo| for docs
+command! -bar -buffer RustInfo call rust#debugging#Info()
+
+" See |:RustInfoToClipboard| for docs
+command! -bar -buffer RustInfoToClipboard call rust#debugging#InfoToClipboard()
+
+" See |:RustInfoToFile| for docs
+command! -bar -nargs=1 -buffer RustInfoToFile call rust#debugging#InfoToFile(<f-args>)
-" 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>
+" 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")
- let b:rust_last_rustc_args = []
- let 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-=<:>
- \"
+ \ setlocal formatoptions< comments< commentstring< include< includeexpr< suffixesadd<
+ \|if exists('b:rust_set_style')
+ \|setlocal tabstop< shiftwidth< softtabstop< expandtab< textwidth<
+ \|endif
+ \|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 -buffer RustRun
+ \|delcommand -buffer RustExpand
+ \|delcommand -buffer RustEmitIr
+ \|delcommand -buffer RustEmitAsm
+ \|delcommand -buffer RustPlay
+ \|delcommand -buffer RustFmt
+ \|delcommand -buffer RustFmtRange
+ \|delcommand -buffer RustInfo
+ \|delcommand -buffer RustInfoToClipboard
+ \|delcommand -buffer RustInfoToFile
+ \|delcommand -buffer RustTest
+ \|nunmap <buffer> [[
+ \|nunmap <buffer> ]]
+ \|xunmap <buffer> [[
+ \|xunmap <buffer> ]]
+ \|ounmap <buffer> [[
+ \|ounmap <buffer> ]]
+ \|setlocal matchpairs-=<:>
+ \|unlet b:match_skip
+ \"
" }}}1
" Code formatting on save
-if get(g:, "rustfmt_autosave", 0)
- autocmd BufWritePre *.rs silent! call rustfmt#Format()
-endif
-
+augroup rust.vim.PreWrite
+ autocmd!
+ autocmd BufWritePre *.rs silent! call rustfmt#PreWrite()
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
unlet s:save_cpo
+" vint: +ProhibitAbbreviationOption
-" vim: set noet sw=8 ts=8:
+" vim: set et sw=4 sts=4 ts=8:
diff --git a/runtime/indent/rust.vim b/runtime/indent/rust.vim
index b27d93c3a2..7c055ec739 100644
--- a/runtime/indent/rust.vim
+++ b/runtime/indent/rust.vim
@@ -1,27 +1,26 @@
" Vim indent file
" Language: Rust
" Author: Chris Morgan <me@chrismorgan.info>
-" Last Change: 2017 Jun 13
-" 2023 Aug 28 by Vim Project (undo_indent)
+" Last Change: 2023-09-11
" 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
+ 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]
+setlocal cinoptions=L0,(s,Ws,J1,j1,m1
+setlocal cinkeys=0{,0},!^F,o,O,0[,0],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
+setlocal cinwords=for,if,else,while,loop,impl,mod,unsafe,trait,struct,enum,fn,extern,macro
" 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 indentkeys=0{,0},!^F,o,O,0[,0],0(,0)
setlocal indentexpr=GetRustIndent(v:lnum)
@@ -29,204 +28,259 @@ let b:undo_indent = "setlocal cindent< cinoptions< cinkeys< cinwords< lisp< auto
" Only define the function once.
if exists("*GetRustIndent")
- finish
+ finish
endif
+" vint: -ProhibitAbbreviationOption
let s:save_cpo = &cpo
set cpo&vim
+" vint: +ProhibitAbbreviationOption
" 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
+ " 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
+ 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
+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
+ " 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
+
+ " 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.
+ if prevline[len(prevline) - 1] ==# ","
+ \ && prevline =~# '^\s*where\s'
+ return indent(prevlinenum) + 6
+ endif
- " 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
-
- "match newline after struct with generic bound like
- "struct SomeThing<T>
- "| <-- newline indent should same as prevline
- if prevline[len(prevline) - 1] == ">"
- \ && prevline =~# "\s*struct.*>$"
- return indent(prevlinenum)
- endif
-
- "match newline after where like:
- "struct SomeThing<T>
- "where
- " T: Display,
- if prevline =~# '^\s*where$'
- 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
- " 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)
+ let l:last_prevline_character = prevline[len(prevline) - 1]
+
+ " A line that ends with '.<expr>;' is probably an end of a long list
+ " of method operations.
+ if prevline =~# '\V\^\s\*.' && l:last_prevline_character ==# ';'
+ 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
+
+ if l:last_prevline_character ==# ","
+ \ && 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
+" vint: -ProhibitAbbreviationOption
let &cpo = s:save_cpo
unlet s:save_cpo
+" vint: +ProhibitAbbreviationOption
+
+" vim: set et sw=4 sts=4 ts=8:
diff --git a/runtime/lua/vim/iter.lua b/runtime/lua/vim/iter.lua
index 56c130dd0c..595baa7019 100644
--- a/runtime/lua/vim/iter.lua
+++ b/runtime/lua/vim/iter.lua
@@ -15,44 +15,45 @@
--- (for function iterators, this means that the first value returned by the function is nil).
---
--- Examples:
---- <pre>lua
---- local it = vim.iter({ 1, 2, 3, 4, 5 })
---- it:map(function(v)
---- return v * 3
---- end)
---- it:rev()
---- it:skip(2)
---- it:totable()
---- -- { 9, 6, 3 }
----
---- -- ipairs() is a function iterator which returns both the index (i) and the value (v)
---- vim.iter(ipairs({ 1, 2, 3, 4, 5 })):map(function(i, v)
---- if i > 2 then return v end
---- end):totable()
---- -- { 3, 4, 5 }
----
---- local it = vim.iter(vim.gsplit('1,2,3,4,5', ','))
---- it:map(function(s) return tonumber(s) end)
---- for i, d in it:enumerate() do
---- print(string.format("Column %d is %d", i, d))
---- end
---- -- Column 1 is 1
---- -- Column 2 is 2
---- -- Column 3 is 3
---- -- Column 4 is 4
---- -- Column 5 is 5
----
---- vim.iter({ a = 1, b = 2, c = 3, z = 26 }):any(function(k, v)
---- return k == 'z'
---- end)
---- -- true
----
---- local rb = vim.ringbuf(3)
---- rb:push("a")
---- rb:push("b")
---- vim.iter(rb):totable()
---- -- { "a", "b" }
---- </pre>
+---
+--- ```lua
+--- local it = vim.iter({ 1, 2, 3, 4, 5 })
+--- it:map(function(v)
+--- return v * 3
+--- end)
+--- it:rev()
+--- it:skip(2)
+--- it:totable()
+--- -- { 9, 6, 3 }
+---
+--- -- ipairs() is a function iterator which returns both the index (i) and the value (v)
+--- vim.iter(ipairs({ 1, 2, 3, 4, 5 })):map(function(i, v)
+--- if i > 2 then return v end
+--- end):totable()
+--- -- { 3, 4, 5 }
+---
+--- local it = vim.iter(vim.gsplit('1,2,3,4,5', ','))
+--- it:map(function(s) return tonumber(s) end)
+--- for i, d in it:enumerate() do
+--- print(string.format("Column %d is %d", i, d))
+--- end
+--- -- Column 1 is 1
+--- -- Column 2 is 2
+--- -- Column 3 is 3
+--- -- Column 4 is 4
+--- -- Column 5 is 5
+---
+--- vim.iter({ a = 1, b = 2, c = 3, z = 26 }):any(function(k, v)
+--- return k == 'z'
+--- end)
+--- -- true
+---
+--- local rb = vim.ringbuf(3)
+--- rb:push("a")
+--- rb:push("b")
+--- vim.iter(rb):totable()
+--- -- { "a", "b" }
+--- ```
---
--- In addition to the |vim.iter()| function, the |vim.iter| module provides
--- convenience functions like |vim.iter.filter()| and |vim.iter.totable()|.
@@ -140,9 +141,10 @@ end
--- Add a filter step to the iterator pipeline.
---
--- Example:
---- <pre>lua
+---
+--- ```lua
--- local bufs = vim.iter(vim.api.nvim_list_bufs()):filter(vim.api.nvim_buf_is_loaded)
---- </pre>
+--- ```
---
---@param f function(...):bool Takes all values returned from the previous stage
--- in the pipeline and returns false or nil if the
@@ -176,7 +178,8 @@ end
--- If the map function returns nil, the value is filtered from the iterator.
---
--- Example:
---- <pre>lua
+---
+--- ```lua
--- local it = vim.iter({ 1, 2, 3, 4 }):map(function(v)
--- if v % 2 == 0 then
--- return v * 3
@@ -184,7 +187,7 @@ end
--- end)
--- it:totable()
--- -- { 6, 12 }
---- </pre>
+--- ```
---
---@param f function(...):any Mapping function. Takes all values returned from
--- the previous stage in the pipeline as arguments
@@ -288,7 +291,8 @@ end
--- pipeline, each value will be included in a table.
---
--- Examples:
---- <pre>lua
+---
+--- ```lua
--- vim.iter(string.gmatch('100 20 50', '%d+')):map(tonumber):totable()
--- -- { 100, 20, 50 }
---
@@ -297,7 +301,7 @@ end
---
--- vim.iter({ a = 1, b = 2, c = 3 }):filter(function(k, v) return v % 2 ~= 0 end):totable()
--- -- { { 'a', 1 }, { 'c', 3 } }
---- </pre>
+--- ```
---
--- The generated table is a list-like table with consecutive, numeric indices.
--- To create a map-like table with arbitrary keys, use |Iter:fold()|.
@@ -352,7 +356,8 @@ end
--- Fold ("reduce") an iterator or table into a single value.
---
--- Examples:
---- <pre>lua
+---
+--- ```lua
--- -- Create a new table with only even values
--- local t = { a = 1, b = 2, c = 3, d = 4 }
--- local it = vim.iter(t)
@@ -362,7 +367,7 @@ end
--- return t
--- end)
--- -- { b = 2, d = 4 }
---- </pre>
+--- ```
---
---@generic A
---
@@ -398,7 +403,8 @@ end
--- Return the next value from the iterator.
---
--- Example:
---- <pre>lua
+---
+--- ```lua
---
--- local it = vim.iter(string.gmatch('1 2 3', '%d+')):map(tonumber)
--- it:next()
@@ -408,7 +414,7 @@ end
--- it:next()
--- -- 3
---
---- </pre>
+--- ```
---
---@return any
function Iter.next(self) -- luacheck: no unused args
@@ -431,13 +437,14 @@ end
--- Only supported for iterators on list-like tables.
---
--- Example:
---- <pre>lua
+---
+--- ```lua
---
--- local it = vim.iter({ 3, 6, 9, 12 }):rev()
--- it:totable()
--- -- { 12, 9, 6, 3 }
---
---- </pre>
+--- ```
---
---@return Iter
function Iter.rev(self)
@@ -457,7 +464,8 @@ end
--- Only supported for iterators on list-like tables.
---
--- Example:
---- <pre>lua
+---
+--- ```lua
---
--- local it = vim.iter({ 3, 6, 9, 12 })
--- it:peek()
@@ -467,7 +475,7 @@ end
--- it:next()
--- -- 3
---
---- </pre>
+--- ```
---
---@return any
function Iter.peek(self) -- luacheck: no unused args
@@ -486,7 +494,8 @@ end
--- Advances the iterator. Returns nil and drains the iterator if no value is found.
---
--- Examples:
---- <pre>lua
+---
+--- ```lua
---
--- local it = vim.iter({ 3, 6, 9, 12 })
--- it:find(12)
@@ -500,7 +509,7 @@ end
--- it:find(function(v) return v % 4 == 0 end)
--- -- 12
---
---- </pre>
+--- ```
---
---@return any
function Iter.find(self, f)
@@ -536,7 +545,8 @@ end
--- Only supported for iterators on list-like tables.
---
--- Examples:
---- <pre>lua
+---
+--- ```lua
---
--- local it = vim.iter({ 1, 2, 3, 2, 1 }):enumerate()
--- it:rfind(1)
@@ -544,7 +554,7 @@ end
--- it:rfind(1)
--- -- 1 1
---
---- </pre>
+--- ```
---
---@see Iter.find
---
@@ -578,13 +588,14 @@ end
--- Only supported for iterators on list-like tables.
---
--- Example:
---- <pre>lua
+---
+--- ```lua
--- local it = vim.iter({1, 2, 3, 4})
--- it:nextback()
--- -- 4
--- it:nextback()
--- -- 3
---- </pre>
+--- ```
---
---@return any
function Iter.nextback(self) -- luacheck: no unused args
@@ -604,7 +615,8 @@ end
--- Only supported for iterators on list-like tables.
---
--- Example:
---- <pre>lua
+---
+--- ```lua
--- local it = vim.iter({1, 2, 3, 4})
--- it:peekback()
--- -- 4
@@ -612,7 +624,7 @@ end
--- -- 4
--- it:nextback()
--- -- 4
---- </pre>
+--- ```
---
---@return any
function Iter.peekback(self) -- luacheck: no unused args
@@ -629,13 +641,14 @@ end
--- Skip values in the iterator.
---
--- Example:
---- <pre>lua
+---
+--- ```lua
---
--- local it = vim.iter({ 3, 6, 9, 12 }):skip(2)
--- it:next()
--- -- 9
---
---- </pre>
+--- ```
---
---@param n number Number of values to skip.
---@return Iter
@@ -661,13 +674,14 @@ end
--- Only supported for iterators on list-like tables.
---
--- Example:
---- <pre>lua
+---
+--- ```lua
--- local it = vim.iter({ 1, 2, 3, 4, 5 }):skipback(2)
--- it:next()
--- -- 1
--- it:nextback()
--- -- 3
---- </pre>
+--- ```
---
---@param n number Number of values to skip.
---@return Iter
@@ -691,7 +705,8 @@ end
--- This function advances the iterator.
---
--- Example:
---- <pre>lua
+---
+--- ```lua
---
--- local it = vim.iter({ 3, 6, 9, 12 })
--- it:nth(2)
@@ -699,7 +714,7 @@ end
--- it:nth(2)
--- -- 12
---
---- </pre>
+--- ```
---
---@param n number The index of the value to return.
---@return any
@@ -716,7 +731,8 @@ end
--- Only supported for iterators on list-like tables.
---
--- Example:
---- <pre>lua
+---
+--- ```lua
---
--- local it = vim.iter({ 3, 6, 9, 12 })
--- it:nthback(2)
@@ -724,7 +740,7 @@ end
--- it:nthback(2)
--- -- 3
---
---- </pre>
+--- ```
---
---@param n number The index of the value to return.
---@return any
@@ -805,7 +821,8 @@ end
--- Drains the iterator.
---
--- Example:
---- <pre>lua
+---
+--- ```lua
---
--- local it = vim.iter(vim.gsplit('abcdefg', ''))
--- it:last()
@@ -815,7 +832,7 @@ end
--- it:last()
--- -- 15
---
---- </pre>
+--- ```
---
---@return any
function Iter.last(self)
@@ -839,19 +856,22 @@ end
--- Add an iterator stage that returns the current iterator count as well as the iterator value.
---
--- For list tables, prefer
---- <pre>lua
+---
+--- ```lua
--- vim.iter(ipairs(t))
---- </pre>
+--- ```
---
--- over
---- <pre>lua
+---
+--- ```lua
--- vim.iter(t):enumerate()
---- </pre>
+--- ```
---
--- as the former is faster.
---
--- Example:
---- <pre>lua
+---
+--- ```lua
---
--- local it = vim.iter(vim.gsplit('abc', '')):enumerate()
--- it:next()
@@ -861,7 +881,7 @@ end
--- it:next()
--- -- 3 'c'
---
---- </pre>
+--- ```
---
---@return Iter
function Iter.enumerate(self)
@@ -959,9 +979,10 @@ end
--- Collect an iterator into a table.
---
--- This is a convenience function that performs:
---- <pre>lua
+---
+--- ```lua
--- vim.iter(f):totable()
---- </pre>
+--- ```
---
---@param f function Iterator function
---@return table
@@ -972,9 +993,10 @@ end
--- Filter a table or iterator.
---
--- This is a convenience function that performs:
---- <pre>lua
+---
+--- ```lua
--- vim.iter(src):filter(f):totable()
---- </pre>
+--- ```
---
---@see |Iter:filter()|
---
@@ -990,9 +1012,10 @@ end
--- Map and filter a table or iterator.
---
--- This is a convenience function that performs:
---- <pre>lua
+---
+--- ```lua
--- vim.iter(src):map(f):totable()
---- </pre>
+--- ```
---
---@see |Iter:map()|
---
diff --git a/runtime/lua/vim/treesitter/_fold.lua b/runtime/lua/vim/treesitter/_fold.lua
index d82e04a5a8..8bc08c9c2e 100644
--- a/runtime/lua/vim/treesitter/_fold.lua
+++ b/runtime/lua/vim/treesitter/_fold.lua
@@ -299,7 +299,9 @@ local function on_changedtree(bufnr, foldinfo, tree_changes)
local srow, _, erow = Range.unpack4(change)
get_folds_levels(bufnr, foldinfo, srow, erow)
end
- foldupdate(bufnr)
+ if #tree_changes > 0 then
+ foldupdate(bufnr)
+ end
end)
end
diff --git a/runtime/lua/vim/treesitter/dev.lua b/runtime/lua/vim/treesitter/dev.lua
index 72b6e3db4a..e7af259d28 100644
--- a/runtime/lua/vim/treesitter/dev.lua
+++ b/runtime/lua/vim/treesitter/dev.lua
@@ -101,18 +101,18 @@ function TSTreeView:new(bufnr, lang)
-- the root in the child tree to the {injections} table.
local root = parser:parse(true)[1]:root()
local injections = {} ---@type table<integer,table>
- parser:for_each_child(function(child, lang_)
- child:for_each_tree(function(tree)
+ for _, child in pairs(parser:children()) do
+ child:for_each_tree(function(tree, ltree)
local r = tree:root()
local node = root:named_descendant_for_range(r:range())
if node then
injections[node:id()] = {
- lang = lang_,
+ lang = ltree:lang(),
root = r,
}
end
end)
- end)
+ end
local nodes = traverse(root, 0, parser:lang(), injections, {})
diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua
index 3c60da7643..6037b17b20 100644
--- a/runtime/lua/vim/treesitter/languagetree.lua
+++ b/runtime/lua/vim/treesitter/languagetree.lua
@@ -897,6 +897,20 @@ function LanguageTree:_edit(
end
return true
end)
+
+ for _, child in pairs(self._children) do
+ child:_edit(
+ start_byte,
+ end_byte_old,
+ end_byte_new,
+ start_row,
+ start_col,
+ end_row_old,
+ end_col_old,
+ end_row_new,
+ end_col_new
+ )
+ end
end
---@package
@@ -943,20 +957,17 @@ function LanguageTree:_on_bytes(
)
-- Edit trees together BEFORE emitting a bytes callback.
- ---@private
- self:for_each_child(function(child)
- child:_edit(
- start_byte,
- start_byte + old_byte,
- start_byte + new_byte,
- start_row,
- start_col,
- start_row + old_row,
- old_end_col,
- start_row + new_row,
- new_end_col
- )
- end, true)
+ self:_edit(
+ start_byte,
+ start_byte + old_byte,
+ start_byte + new_byte,
+ start_row,
+ start_col,
+ start_row + old_row,
+ old_end_col,
+ start_row + new_row,
+ new_end_col
+ )
self:_do_callback(
'bytes',
@@ -1017,9 +1028,9 @@ function LanguageTree:register_cbs(cbs, recursive)
end
if recursive then
- self:for_each_child(function(child)
+ for _, child in pairs(self._children) do
child:register_cbs(cbs, true)
- end)
+ end
end
end
diff --git a/runtime/syntax/i3config.vim b/runtime/syntax/i3config.vim
index 1eddd60f7c..8bc2a6e03c 100644
--- a/runtime/syntax/i3config.vim
+++ b/runtime/syntax/i3config.vim
@@ -4,7 +4,7 @@
" Maintainer: Quentin Hibon (github user hiqua)
" Version: 0.4.22
" Reference version (JosefLitos/i3config.vim): 4.22
-" Last Change: 2023-09-09
+" Last Change: 2023-09-12
" References:
" http://i3wm.org/docs/userguide.html#configuring
@@ -24,284 +24,324 @@ syn match i3ConfigError /.\+/
" Todo
syn keyword i3ConfigTodo TODO FIXME XXX contained
-" Comment
-" Comments are started with a # and can only be used at the beginning of a line
-syn match i3ConfigComment /^\s*#.*$/ contains=i3ConfigTodo
-
-syn match i3ConfigOperator /[,;:]/ contained
+" Helper type definitions
+syn match i3ConfigSeparator /[,;]/ contained
syn match i3ConfigParen /[{}]/ contained
-
-" Font
-" A FreeType font description is composed by:
-" a font family, a style, a weight, a variant, a stretch and a size.
-syn keyword i3ConfigFontKeyword font contained
-syn match i3ConfigFontNamespace /\w\+:/ contained contains=i3ConfigOperator
-syn match i3ConfigFontContent /-\?\w\+\(-\+\|\s\+\|,\)/ contained contains=i3ConfigFontNamespace,i3ConfigFontKeyword,i3ConfigOperator
-syn match i3ConfigFontSize /\s\=\d\+\(px\)\?\s\?$/ contained
-syn match i3ConfigFont /^\s*font\s\+.*$/ contains=i3ConfigFontContent,i3ConfigFontSize,i3ConfigFontNamespace
-syn match i3ConfigFont /^\s*font\s\+.*\(\\\_.*\)\?$/ contains=i3ConfigFontContent,i3ConfigFontSize,i3ConfigFontNamespace
-syn match i3ConfigFont /^\s*font\s\+.*\(\\\_.*\)\?[^\\]\+$/ contains=i3ConfigFontContent,i3ConfigFontSize,i3ConfigFontNamespace
-syn match i3ConfigFont /^\s*font\s\+\(\(.*\\\_.*\)\|\(.*[^\\]\+$\)\)/ contains=i3ConfigFontContent,i3ConfigFontSize,i3ConfigFontNamespace
-
-" Common value types
syn keyword i3ConfigBoolean yes no enabled disabled on off true false contained
-syn region i3ConfigString start=/"/ skip=/\\"/ end=/"/ contained contains=i3ConfigShCommand,i3ConfigShDelim,i3ConfigShOper,i3ConfigShParam,i3ConfigNumber,i3ConfigVariable keepend extend
-syn region i3ConfigString start=/'/ end=/'/ contained contains=i3ConfigShCommand,i3ConfigShDelim,i3ConfigShOper,i3ConfigShParam,i3ConfigNumber,i3ConfigVariable keepend extend
+syn region i3ConfigString start=/\W\@<="/ skip=/\\"/ end=/"/ contained contains=i3ConfigShCommand,i3ConfigShDelim,i3ConfigShOper,i3ConfigShParam,i3ConfigNumber,i3ConfigVariable,i3ConfigExecAction keepend extend
+syn region i3ConfigString start=/\W\@<='/ end=/'/ contained contains=i3ConfigShCommand,i3ConfigShDelim,i3ConfigShOper,i3ConfigShParam,i3ConfigNumber,i3ConfigVariable,i3ConfigExecAction keepend extend
syn match i3ConfigColor /#\w\{3,8}/ contained
-syn match i3ConfigNumber /\([a-zA-Z0-9_$]\)\@<!\d\+\([a-zA-Z0-9_$]\)\@!/ contained
+syn match i3ConfigNumber /[a-zA-Z_$-]\@<!-\?\d\+\w\@!/ contained
-" Variables
-syn match i3ConfigVariable /\$[A-Z0-9a-z_:|[\]-]\+/
-syn keyword i3ConfigSetKeyword set contained
-syn match i3ConfigSet /^set \$.*$/ contains=i3ConfigVariable,i3ConfigSetKeyword,i3ConfigColor,i3ConfigString,i3ConfigNoStartupId,i3ConfigNumber,i3ConfigShCommand,i3ConfigShDelim,i3ConfigShParam,i3ConfigShOper
-
-" Include other config files
+" 4.1 Include directive
syn keyword i3ConfigIncludeKeyword include contained
-syn match i3ConfigCommandSubstitutionRegion /`[^`]*`/ contained contains=i3ConfigShDelim,i3ConfigShParam,i3ConfigShOper,i3ConfigShCommand
-syn match i3ConfigIncludePath /[~./a-zA-Z0-9`][^~]*$/ contained contains=i3ConfigCommandSubstitutionRegion
-syn match i3ConfigInclude /^include .[^~]*$/ contains=i3ConfigIncludeKeyword,i3ConfigString,i3ConfigVariable,i3ConfigIncludePath
-
-" Gaps
-syn keyword i3ConfigGapStyleKeyword inner outer horizontal vertical top right bottom left current all set plus minus toggle up down contained
-syn match i3ConfigGapStyle /^gaps \(inner\|outer\|horizontal\|vertical\|left\|top\|right\|bottom\)\(\s\+\(current\|all\)\)\?\(\s\+\(set\|plus\|minus\|toggle\)\)\?\(\s\+\(-\?\d\+\|\$.*\)\)$/ contains=i3ConfigGapStyleKeyword,i3ConfigNumber,i3ConfigVariable
-syn keyword i3ConfigSmartGapKeyword on inverse_outer contained
-syn match i3ConfigSmartGap /^smart_gaps \(on\|inverse_outer\)$/ contains=i3ConfigSmartGapKeyword
-syn keyword i3ConfigSmartBorderKeyword on no_gaps contained
-syn match i3ConfigSmartBorder /^smart_borders \(on\|no_gaps\)$/ contains=i3ConfigSmartBorderKeyword
+syn match i3ConfigIncludeCommand /`[^`]*`/ contained contains=i3ConfigShDelim,i3ConfigShParam,i3ConfigShOper,i3ConfigShCommand
+syn match i3ConfigInclude /^include .*$/ contains=i3ConfigIncludeKeyword,i3ConfigString,i3ConfigVariable,i3ConfigIncludeCommand
-" Commands useable in keybinds
-syn keyword i3ConfigAction move exit restart reload layout append_layout workspace focus kill open fullscreen sticky split floating mark unmark resize rename scratchpad swap mode bar gaps border nop contained
-syn keyword i3ConfigOption enable disable toggle mode_toggle key shrink grow height width restore container to left right up down position absolute relative window splitv splith tabbed stacked default on off inner outer current all set plus minus top bottom horizontal vertical auto none normal pixel prev next back_and_forth child parent show contained
-syn match i3ConfigUnit /\sp\(pt\|x\)/ contained
-syn match i3ConfigUnitOr /\sor/ contained
+" 4.2 Comments
+syn match i3ConfigComment /^\s*#.*$/ contains=i3ConfigTodo
+
+" 4.3 Fonts
+syn keyword i3ConfigFontKeyword font contained
+syn match i3ConfigColonOperator /:/ contained
+syn match i3ConfigFontNamespace /\w\+:/ contained contains=i3ConfigColonOperator
+syn match i3ConfigFontSize /\s\=\d\+\(px\)\?\s\?$/ contained
+syn region i3ConfigFont start=/^\s*font / skip=/\\$/ end=/$/ contains=i3ConfigFontKeyword,i3ConfigFontNamespace,i3ConfigFontSize,i3ConfigSeparator keepend
-" Keyboard bindings
+" 4.4-4.5 Keyboard/Mouse bindings
syn keyword i3ConfigBindKeyword bindsym bindcode contained
syn match i3ConfigBindArgument /--\(release\|border\|whole-window\|exclude-titlebar\)/ contained
syn match i3ConfigBindModifier /+/ contained
syn match i3ConfigBindModkey /Ctrl\|Shift\|Mod[1-5]/ contained
syn match i3ConfigBindCombo /[$a-zA-Z0-9_+]\+ / contained contains=i3ConfigBindModifier,i3ConfigVariable,i3ConfigBindModkey
syn match i3ConfigBindComboLine /bind\(sym\|code\)\( --[a-z-]\+\)* [$a-zA-Z0-9_+]\+ / contained contains=i3ConfigBindKeyword,i3ConfigBindArgument,i3ConfigBindCombo
-syn match i3ConfigBind /^\s*bind\(sym\|code\)\s\+.*[^{]$/ contains=i3ConfigBindComboLine,i3ConfigNumber,i3ConfigVariable,i3ConfigAction,i3ConfigOption,i3ConfigGapStyleKeyword,i3ConfigOperator,i3ConfigString,i3ConfigUnit,i3ConfigUnitOr,i3ConfigConditional,i3ConfigBoolean,i3ConfigExec
+syn region i3ConfigBind start=/^\s*bind\(sym\|code\) / skip=/\\$/ end=/$/ contains=i3ConfigBindComboLine,i3ConfigCriteria,i3ConfigAction,i3ConfigSeparator,i3ConfigActionKeyword,i3ConfigOption,i3ConfigString,i3ConfigNumber,i3ConfigVariable,i3ConfigBoolean keepend
-" Floating modifier
-syn keyword i3ConfigFloatingModifierKeyword floating_modifier contained
-syn match i3ConfigFloatingModifier /^floating_modifier [$a-zA-Z0-9+]\+$/ contains=i3ConfigVariable,i3ConfigBindModkey,i3ConfigFloatingModifierKeyword
+" 4.6 Binding modes
+syn region i3ConfigKeyword start=/^mode\( --pango_markup\)\? \([^'" {]\+\|'[^']\+'\|".\+"\)\s\+{$/ end=/^\s*}$/ contains=i3ConfigShParam,i3ConfigString,i3ConfigBind,i3ConfigComment,i3ConfigNumber,i3ConfigParen,i3ConfigVariable fold keepend extend
-" Floating window size limitation
+" 4.7 Floating modifier
+syn match i3ConfigKeyword /^floating_modifier [$a-zA-Z0-9+]\+$/ contains=i3ConfigVariable,i3ConfigBindModkey
+
+" 4.8 Floating window size
syn keyword i3ConfigSizeSpecial x contained
syn match i3ConfigSize / -\?\d\+ x -\?\d\+/ contained contains=i3ConfigSizeSpecial,i3ConfigNumber
-syn keyword i3ConfigFloatingSizeKeyword floating_minimum_size floating_maximum_size contained
-syn match i3ConfigFloatingSize /^floating_\(maximum\|minimum\)_size -\?\d\+ x -\?\d\+/ contains=i3ConfigFloatingSizeKeyword,i3ConfigSize
+syn match i3ConfigKeyword /^floating_\(maximum\|minimum\)_size .*$/ contains=i3ConfigSize
-" Orientation
-syn keyword i3ConfigOrientationKeyword vertical horizontal auto contained
-syn match i3ConfigOrientation /^default_orientation \(vertical\|horizontal\|auto\)$/ contains=i3ConfigOrientationKeyword
+" 4.9 Orientation
+syn keyword i3ConfigOrientationOpts vertical horizontal auto contained
+syn match i3ConfigKeyword /^default_orientation \w*$/ contains=i3ConfigOrientationOpts
-" Layout
-syn keyword i3ConfigLayoutKeyword default stacking tabbed contained
-syn match i3ConfigLayout /^workspace_layout \(default\|stacking\|tabbed\)$/ contains=i3ConfigLayoutKeyword
+" 4.10 Layout mode
+syn keyword i3ConfigWorkspaceLayoutOpts default stacking tabbed contained
+syn match i3ConfigKeyword /^workspace_layout \w*$/ contains=i3ConfigWorkspaceLayoutOpts
-" Border style
-syn keyword i3ConfigBorderStyleKeyword none normal pixel contained
-syn match i3ConfigBorderStyle /^\(new_window\|new_float\|default_border\|default_floating_border\)\s\+\(none\|\(normal\|pixel\)\(\s\+\d\+\)\?\(\s\+\$\w\+\(\(-\w\+\)\+\)\?\(\s\|+\)\?\)\?\)$/ contains=i3ConfigBorderStyleKeyword,i3ConfigNumber,i3ConfigVariable
+" 4.11 Title alignment
+syn keyword i3ConfigTitleAlignOpts left center right contained
+syn match i3ConfigKeyword /^title_align .*$/ contains=i3ConfigTitleAlignOpts
-" Hide borders and edges
-syn keyword i3ConfigEdgeKeyword none vertical horizontal both smart smart_no_gaps contained
-syn match i3ConfigEdge /^hide_edge_borders\s\+\(none\|vertical\|horizontal\|both\|smart\|smart_no_gaps\)\s\?$/ contains=i3ConfigEdgeKeyword
+" 4.12 Border style
+syn keyword i3ConfigBorderOpts none normal pixel contained
+syn match i3ConfigKeyword /^default\(_floating\)\?_border .*$/ contains=i3ConfigBorderOpts,i3ConfigNumber,i3ConfigVariable
+" 4.13 Hide edge borders
+syn keyword i3ConfigEdgeOpts none vertical horizontal both smart smart_no_gaps contained
+syn match i3ConfigKeyword /^hide_edge_borders \w\+$/ contains=i3ConfigEdgeOpts
-" Arbitrary commands for specific windows (for_window)
-syn keyword i3ConfigCommandKeyword for_window contained
-syn match i3ConfigConditionalText /\w\+\(-\w\+\)*/ contained
-syn match i3ConfigEqualsOperator /=/ contained
-syn region i3ConfigConditional start=/\[/ end=/\]/ contained contains=i3ConfigString,i3ConfigEqualsOperator,i3ConfigConditionalText
-syn match i3ConfigArbitraryCommand /^for_window\s\+.*$/ contains=i3ConfigConditional,i3ConfigCommandKeyword,i3ConfigAction,i3ConfigOption,i3ConfigSize,i3ConfigNumber,i3ConfigString,i3ConfigOperator,i3ConfigBoolean,i3ConfigVariable
+" 4.14 Smart Borders
+syn keyword i3ConfigSmartBorderOpts no_gaps contained
+syn match i3ConfigKeyword /^smart_borders \(on\|off\|no_gaps\)$/ contains=i3ConfigSmartBorderOpts,i3ConfigBoolean
-" Disable focus open opening
-syn keyword i3ConfigNoFocusKeyword no_focus contained
-syn match i3ConfigDisableFocus /^no_focus\s\+.*$/ contains=i3ConfigConditional,i3ConfigNoFocusKeyword
+" 4.15 Arbitrary commands
+syn keyword i3ConfigForWindowKeyword for_window contained
+syn region i3ConfigForWindow start=/^for_window / end=/$/ contains=i3ConfigForWindowKeyword,i3ConfigCriteria keepend
-" Move client to specific workspace automatically
-syn keyword i3ConfigAssignKeyword assign contained
-syn match i3ConfigAssignSpecial /→/ contained
-syn match i3ConfigAssign /^assign\s\+.*$/ contains=i3ConfigAssignKeyword,i3ConfigAssignSpecial,i3ConfigConditional,i3ConfigVariable,i3ConfigString,i3ConfigNumber
+" 4.16 No opening focus
+syn match i3ConfigKeyword /^no_focus .*$/ contains=i3ConfigCondition
+
+" 4.17 Variables
+syn match i3ConfigVariable /\$[A-Z0-9a-z_:|[\]-]\+/
+syn keyword i3ConfigSetKeyword set contained
+syn match i3ConfigSet /^set \$.*$/ contains=i3ConfigVariable,i3ConfigSetKeyword,i3ConfigColor,i3ConfigString,i3ConfigNoStartupId,i3ConfigNumber,i3ConfigShCommand,i3ConfigShDelim,i3ConfigShParam,i3ConfigShOper
-" X resources
+" 4.18 X resources
syn keyword i3ConfigResourceKeyword set_from_resource contained
-syn match i3ConfigResource /^set_from_resource\s\+.*$/ contains=i3ConfigResourceKeyword,i3ConfigConditional,i3ConfigColor,i3ConfigVariable,i3ConfigString,i3ConfigNumber
+syn match i3ConfigResource /^set_from_resource\s\+.*$/ contains=i3ConfigResourceKeyword,i3ConfigCondition,i3ConfigColor,i3ConfigVariable,i3ConfigString,i3ConfigNumber
+
+" 4.19 Assign clients to workspaces
+syn keyword i3ConfigAssignKeyword assign contained
+syn match i3ConfigAssignSpecial /→/ contained
+syn match i3ConfigAssign /^assign .*$/ contains=i3ConfigAssignKeyword,i3ConfigAssignSpecial,i3ConfigCondition,i3ConfigVariable,i3ConfigString,i3ConfigNumber
-" Executing shell commands
+" 4.20 Executing shell commands
syn keyword i3ConfigExecKeyword exec contained
syn keyword i3ConfigExecAlwaysKeyword exec_always contained
-syn match i3ConfigShCmdDelim /\$/ contained
+syn match i3ConfigShCmdDelim /\$(/ contained
syn region i3ConfigShCommand start=/\$(/ end=/)/ contained contains=i3ConfigShCmdDelim,i3ConfigShCommand,i3ConfigShDelim,i3ConfigShOper,i3ConfigShParam,i3ConfigString,i3ConfigNumber,i3ConfigVariable keepend extend
syn match i3ConfigShDelim /[[\]{}();`]\+/ contained
syn match i3ConfigShOper /[<>&|+=~^*!.?]\+/ contained
syn match i3ConfigShParam /\<-[a-zA-Z0-9_-]\+\>/ contained containedin=i3ConfigVar
-syn region i3ConfigExec start=/exec\(_always\)\?\( --no-startup-id\)\? [^{]/ skip=/\\$/ end=/\([,;]\|$\)/ contains=i3ConfigExecKeyword,i3ConfigExecAlwaysKeyword,i3ConfigShCommand,i3ConfigShDelim,i3ConfigShOper,i3ConfigShParam,i3ConfigNumber,i3ConfigString,i3ConfigVariable,i3ConfigOperator keepend extend
+syn region i3ConfigExec start=/^\s*exec\(_always\)\?\( --no-startup-id\)\? [^{]/ skip=/\\$/ end=/$/ contains=i3ConfigExecKeyword,i3ConfigExecAlwaysKeyword,i3ConfigShCommand,i3ConfigShDelim,i3ConfigShOper,i3ConfigShParam,i3ConfigNumber,i3ConfigString,i3ConfigVariable,i3ConfigExecAction keepend
-" Automatically putting workspaces on specific screens
+" 4.21 Workspaces per output
syn keyword i3ConfigWorkspaceKeyword workspace contained
-syn keyword i3ConfigOutput output contained
-syn match i3ConfigWorkspace /^\s*workspace\s\+.*$/ contains=i3ConfigWorkspaceKeyword,i3ConfigNumber,i3ConfigString,i3ConfigOutput,i3ConfigVariable,i3ConfigBoolean
+syn keyword i3ConfigWorkspaceOutput output contained
+syn keyword i3ConfigWorkspaceDir prev next back_and_forth contained
+syn region i3ConfigWorkspaceLine start=/^workspace / skip=/\\$/ end=/$/ contains=i3ConfigWorkspaceKeyword,i3ConfigNumber,i3ConfigString,i3ConfigGaps,i3ConfigWorkspaceOutput,i3ConfigVariable,i3ConfigBoolean,i3ConfigSeparator keepend
-" Changing colors
-syn keyword i3ConfigClientColorKeyword client focused focused_inactive unfocused urgent placeholder background contained
-syn match i3ConfigClientColor /^\s*client.\w\+\s\+.*$/ contains=i3ConfigClientColorKeyword,i3ConfigColor,i3ConfigVariable
+" 4.22 Changing colors
+syn match i3ConfigDotOperator /\./ contained
+syn keyword i3ConfigClientOpts focused focused_inactive unfocused urgent placeholder background contained
+syn match i3ConfigKeyword /^client\..*$/ contains=i3ConfigDotOperator,i3ConfigClientOpts,i3ConfigColor,i3ConfigVariable
-syn keyword i3ConfigTitleAlignKeyword left center right contained
-syn match i3ConfigTitleAlign /^title_align .*$/ contains=i3ConfigTitleAlignKeyword
+" 4.23 Interprocess communication
+syn match i3ConfigIpcKeyword /ipc-socket/ contained
+syn match i3ConfigIpc /^ipc-socket .*$/ contains=i3ConfigIpcKeyword
-" Interprocess communication
-syn match i3ConfigInterprocessKeyword /ipc-socket/ contained
-syn match i3ConfigInterprocess /^ipc-socket .*$/ contains=i3ConfigInterprocessKeyword
+" 4.24 Focus follows mouse
+syn keyword i3ConfigFocusFollowsMouseOpts always contained
+syn match i3ConfigFocusFollowsMouse /^focus_follows_mouse \(yes\|no\|always\)$/ contains=i3ConfigBoolean,i3ConfigFocusFollowsMouseOpts
-" Mouse warping
-syn keyword i3ConfigMouseWarpingKeyword mouse_warping contained
-syn keyword i3ConfigMouseWarpingType output container none contained
-syn match i3ConfigMouseWarping /^mouse_warping \(output\|container\|none\)$/ contains=i3ConfigMouseWarpingKeyword,i3ConfigMouseWarpingType
+" 4.25 Mouse warping
+syn keyword i3ConfigMouseWarpingOpts output container none contained
+syn match i3ConfigMouseWarping /^mouse_warping \w*$/ contains=i3ConfigMouseWarpingOpts
-" Focus follows mouse
-syn keyword i3ConfigFocusFollowsMouseKeyword focus_follows_mouse contained
-syn keyword i3ConfigFocusFollowsMouseType always contained
-syn match i3ConfigFocusFollowsMouse /^focus_follows_mouse \(yes\|no\|always\)$/ contains=i3ConfigFocusFollowsMouseKeyword,i3ConfigBoolean,i3ConfigFocusFollowsMouseType
+" 4.26 Popups while fullscreen
+syn keyword i3ConfigPopupFullscreenOpts smart ignore leave_fullscreen contained
+syn match i3ConfigPopupFullscreen /^popup_during_fullscreen \w*$/ contains=i3ConfigPopupFullscreenOpts
-" Focus wrapping
-syn keyword i3ConfigFocusWrappingKeyword force_focus_wrapping focus_wrapping contained
-syn keyword i3ConfigFocusWrappingType force workspace contained
-syn match i3ConfigFocusWrapping /^focus_wrapping \(yes\|no\|force\|workspace\)$/ contains=i3ConfigBoolean,i3ConfigFocusWrappingKeyword,i3ConfigFocusWrappingType
+" 4.27 Focus wrapping
+syn keyword i3ConfigFocusWrappingOpts force workspace contained
+syn match i3ConfigFocusWrapping /^focus_wrapping \(yes\|no\|force\|workspace\)$/ contains=i3ConfigBoolean,i3ConfigFocusWrappingOpts
-" Popups during fullscreen mode
-syn keyword i3ConfigPopupOnFullscreenKeyword popup_during_fullscreen contained
-syn keyword i3ConfigPopupOnFullscreenType smart ignore leave_fullscreen contained
-syn match i3ConfigPopupOnFullscreen /^popup_during_fullscreen \w\+$/ contains=i3ConfigPopupOnFullscreenKeyword,i3ConfigPopupOnFullscreenType
+" 4.28 Forcing Xinerama
+syn match i3ConfigForceXinerama /^force_xinerama \(yes\|no\)$/ contains=i3ConfigBoolean
-" Forcing Xinerama
-syn keyword i3ConfigForceXineramaKeyword force_xinerama contained
-syn match i3ConfigForceXinerama /^force_xinerama \(yes\|no\)$/ contains=i3ConfigBoolean,i3ConfigForceXineramaKeyword
+" 4.29 Automatic workspace back-and-forth
+syn match i3ConfigAutomaticSwitch /^workspace_auto_back_and_forth \(yes\|no\)$/ contains=i3ConfigBoolean
-" Automatic back-and-forth when switching to the current workspace
-syn keyword i3ConfigAutomaticSwitchKeyword workspace_auto_back_and_forth contained
-syn match i3ConfigAutomaticSwitch /^workspace_auto_back_and_forth \(yes\|no\)$/ contains=i3ConfigBoolean,i3ConfigAutomaticSwitchKeyword
-
-" Delay urgency hint
+" 4.30 Delay urgency hint
syn keyword i3ConfigTimeUnit ms contained
-syn keyword i3ConfigDelayUrgencyKeyword force_display_urgency_hint contained
-syn match i3ConfigDelayUrgency /^force_display_urgency_hint \d\+ ms$/ contains=i3ConfigBoolean,i3ConfigDelayUrgencyKeyword,i3ConfigNumber,i3ConfigTimeUnit
-
-" Focus on window activation
-syn keyword i3ConfigFocusOnActivationKeyword focus_on_window_activation contained
-syn keyword i3ConfigFocusOnActivationType smart urgent focus none contained
-syn match i3ConfigFocusOnActivation /^focus_on_window_activation \(smart\|urgent\|focus\|none\)$/ contains=i3ConfigFocusOnActivationKeyword,i3ConfigFocusOnActivationType
-
-" Show window marks in their window title
-syn keyword i3ConfigShowMarksKeyword show_marks contained
-syn match i3ConfigShowMarks /^show_marks \(yes\|no\)$/ contains=i3ConfigBoolean,i3ConfigShowMarksKeyword
-
-" Mode block
-syn match i3ConfigModeKeyword /^mode/ contained
-syn region i3ConfigModeBlock start=/^mode\( --pango_markup\)\? \([^'" {]\+\|'[^']\+'\|".\+"\)\s\+{$/ end=/^\s*}$/ contains=i3ConfigModeKeyword,i3ConfigString,i3ConfigBind,i3ConfigComment,i3ConfigNumber,i3ConfigParen,i3ConfigVariable fold keepend extend
+syn match i3ConfigDelayUrgency /^force_display_urgency_hint \d\+ ms$/ contains=i3ConfigBoolean,i3ConfigNumber,i3ConfigTimeUnit
+
+" 4.31 Focus on window activation
+syn keyword i3ConfigFocusOnActivationOpts smart urgent focus none contained
+syn match i3ConfigFocusOnActivation /^focus_on_window_activation .*$/ contains=i3ConfigFocusOnActivationKeyword
+
+" 4.32 Show marks in title
+syn match i3ConfigShowMarks /^show_marks \(yes\|no\)$/ contains=i3ConfigBoolean
+
+" 4.34 Tiling drag
+syn keyword i3ConfigTilingDragOpts modifier titlebar contained
+syn match i3ConfigTilingDrag /^tiling_drag\( off\|\( modifier\| titlebar\)\{1,2\}\)$/ contains=i3ConfigTilingOpts,i3ConfigBoolean
+
+" 4.35 Gaps
+syn keyword i3ConfigGapsOpts inner outer horizontal vertical left right top bottom current all set plus minus toggle contained
+syn region i3ConfigGaps start=/gaps/ skip=/\\$/ end=/\([,;]\|$\)/ contained contains=i3ConfigGapsOpts,i3ConfigNumber,i3ConfigVariable,i3ConfigSeparator keepend
+syn match i3ConfigGapStyleLine /^gaps .*$/ contains=i3ConfigGaps
+syn keyword i3ConfigSmartGapOpts inverse_outer contained
+syn match i3ConfigSmartGap /^smart_gaps \(on\|off\|inverse_outer\)$/ contains=i3ConfigSmartGapOpts,i3ConfigBoolean
+
+" 5 Configuring bar
+syn match i3ConfigBarModifier /^\s\+modifier [^ ]\+$/ contained contains=i3ConfigBindModifier,i3ConfigVariable,i3ConfigBindModkey
+syn keyword i3ConfigBarOpts bar i3bar_command status_command mode hidden_state id position output tray_output tray_padding font separator_symbol workspace_buttons workspace_min_width strip_workspace_numbers strip_workspace_name binding_mode_indicator padding contained
+syn region i3ConfigBarBlock start=/^bar {$/ end=/^}$/ contains=i3ConfigBarOpts,i3ConfigBarModifier,i3ConfigBind,i3ConfigString,i3ConfigComment,i3ConfigFont,i3ConfigBoolean,i3ConfigNumber,i3ConfigParen,i3ConfigColor,i3ConfigVariable,i3ConfigColorsBlock fold keepend extend
+
+" 5.16 Color block
+syn match i3ConfigColorsOpts /\(focused_\)\?\(background\|statusline\|separator\)\|\(focused\|active\|inactive\|urgent\)_workspace\|binding_mode/ contained
+syn region i3ConfigColorsBlock start=/^\s\+colors {$/ end=/^\s\+}$/ contained contains=i3ConfigColorsOpts,i3ConfigColor,i3ConfigVariable,i3ConfigComment,i3ConfigParen fold keepend extend
+
+" 6.0 Criteria-based commands
+syn match i3ConfigConditionProp /\w\+\(-\w\+\)*/ contained
+syn match i3ConfigConditionText /[^[ ]\+=/ contained contains=i3ConfigConditionProp,i3ConfigShOper
+syn keyword i3ConfigConditionFocused __focused__ contained
+syn region i3ConfigCondition start=/\[/ end=/\]/ contained contains=i3ConfigConditionText,i3ConfigShDelim,i3ConfigNumber,i3ConfigString,i3ConfigConditionFocused keepend extend
+syn region i3ConfigCriteria start=/\[/ skip=/\\$/ end=/\(;\|$\)/ contained contains=i3ConfigCondition,i3ConfigAction,i3ConfigActionKeyword,i3ConfigOption,i3ConfigBoolean,i3ConfigNumber,i3ConfigVariable,i3ConfigSeparator keepend
+
+" 6.1 Actions through shell
+syn match i3ConfigExecActionKeyword /i3-msg/ contained
+syn region i3ConfigExecAction start=/[a-z3-]\+msg '/ skip=/\\$\| '/ end=/'/ contained contains=i3ConfigExecActionKeyword,i3ConfigShCommand,i3ConfigNumber,i3ConfigShOper,i3ConfigCriteria,i3ConfigAction,i3ConfigActionKeyword,i3ConfigOption,i3ConfigVariable keepend extend
+syn region i3ConfigExecAction start=/[a-z3-]\+msg "/ skip=/\\$\| "/ end=/"/ contained contains=i3ConfigExecActionKeyword,i3ConfigShCommand,i3ConfigNumber,i3ConfigShOper,i3ConfigCriteria,i3ConfigAction,i3ConfigActionKeyword,i3ConfigOption,i3ConfigVariable keepend extend
+syn region i3ConfigExecAction start=/[a-z3-]\+msg\( ['"-]\)\@!/ skip=/\\$/ end=/\([&|;})'"]\|$\)/ contained contains=i3ConfigExecActionKeyword,i3ConfigShCommand,i3ConfigNumber,i3ConfigShOper,i3ConfigCriteria,i3ConfigAction,i3ConfigActionKeyword,i3ConfigOption,i3ConfigVariable keepend
+" 6.1 Executing applications (4.20)
+syn region i3ConfigAction start=/exec/ skip=/\\$/ end=/\([,;]\|$\)/ contained contains=i3ConfigExecKeyword,i3ConfigShCommand,i3ConfigShDelim,i3ConfigShOper,i3ConfigShParam,i3ConfigNumber,i3ConfigString,i3ConfigVariable,i3ConfigSeparator keepend
+
+" 6.3 Manipulating layout
+syn keyword i3ConfigLayoutKeyword layout contained
+syn keyword i3ConfigLayoutOpts default tabbed stacking splitv splith toggle split all contained
+syn region i3ConfigAction start=/layout/ skip=/\\$/ end=/\([,;]\|$\)/ contained contains=i3ConfigLayoutKeyword,i3ConfigLayoutOpts,i3ConfigSeparator keepend
+
+" 6.4 Focusing containers
+syn keyword i3ConfigFocusKeyword focus contained
+syn keyword i3ConfigFocusOpts left right up down parent child next prev sibling floating tiling mode_toggle contained
+syn keyword i3ConfigFocusOutputOpts left right down up current primary nonprimary next prev contained
+syn region i3ConfigFocusOutput start=/ output / skip=/\\$/ end=/\([,;]\|$\)/ contained contains=i3ConfigMoveType,i3ConfigWorkspaceOutput,i3ConfigFocusOutputOpts,i3ConfigString,i3ConfigNumber,i3ConfigSeparator keepend
+syn match i3ConfigFocusOutputLine /^focus output .*$/ contains=i3ConfigFocusKeyword,i3ConfigFocusOutput
+syn region i3ConfigAction start=/focus/ skip=/\\$/ end=/\([,;]\|$\)/ contained contains=i3ConfigFocusKeyword,i3ConfigFocusOpts,i3ConfigFocusOutput,i3ConfigString,i3ConfigSeparator keepend
+
+" 6.8 Focusing workspaces (4.21)
+syn region i3ConfigAction start=/workspace / skip=/\\$/ end=/\([,;]\|$\)/ contained contains=i3ConfigWorkspaceKeyword,i3ConfigWorkspaceDir,i3ConfigNumber,i3ConfigString,i3ConfigGaps,i3ConfigWorkspaceOutput,i3ConfigVariable,i3ConfigBoolean,i3ConfigSeparator keepend
+
+" 6.9-6.11 Moving containers
+syn keyword i3ConfigMoveKeyword move contained
+syn keyword i3ConfigMoveDir left right down up position absolute center to contained
+syn keyword i3ConfigMoveType window container workspace output mark mouse scratchpad contained
+syn match i3ConfigUnit / px\| ppt/ contained
+syn region i3ConfigAction start=/move/ skip=/\\$/ end=/\([,;]\|$\)/ contained contains=i3ConfigMoveKeyword,i3ConfigMoveDir,i3ConfigMoveType,i3ConfigWorkspaceDir,i3ConfigUnit,i3ConfigNumber,i3ConfigVariable,i3ConfigSeparator keepend
+
+" 6.12 Resizing containers/windows
+syn keyword i3ConfigResizeKeyword resize contained
+syn keyword i3ConfigResizeOpts grow shrink up down left right set width height or contained
+syn region i3ConfigAction start=/resize/ skip=/\\$/ end=/\([,;]\|$\)/ contained contains=i3ConfigResizeKeyword,i3ConfigResizeOpts,i3ConfigNumber,i3ConfigUnit,i3ConfigSeparator keepend
+
+" 6.14 VIM-like marks
+syn keyword i3ConfigMarkKeyword mark contained
+syn match i3ConfigMark /mark\( --\(add\|replace\)\( --toggle\)\?\)\?/ contained contains=i3ConfigMarkKeyword
+syn region i3ConfigAction start=/\<mark/ skip=/\\$/ end=/\([,;]\|$\)/ contained contains=i3ConfigMark,i3ConfigNumber,i3ConfigString,i3ConfigSeparator keepend
+
+" 6.24 Changing gaps (4.35)
+syn region i3ConfigAction start=/gaps/ skip=/\\$/ end=/\([,;]\|$\)/ contained contains=i3ConfigGaps keepend
-" Color block
-syn keyword i3ConfigColorsKeyword colors contained
-syn match i3ConfigColorsCategory /\(focused_\)\?\(background\|statusline\|separator\)\|\(focused\|active\|inactive\|urgent\)_workspace\|binding_mode/ contained
-syn region i3ConfigColorsBlock start=/^\s\+colors {$/ end=/^\s\+}$/ contained contains=i3ConfigColorsKeyword,i3ConfigColorsCategory,i3ConfigColor,i3ConfigVariable,i3ConfigComment,i3ConfigParen fold keepend extend
-
-" Bar block
-syn keyword i3ConfigBarBlockKeyword bar i3bar_command status_command mode hidden_state id position output tray_output tray_padding font separator_symbol workspace_buttons workspace_min_width strip_workspace_numbers strip_workspace_name binding_mode_indicator padding contained
-syn keyword i3ConfigBarModifierKeyword modifier contained
-syn match i3ConfigBarModifierLine /^\s\+modifier [^ ]\+$/ contained contains=i3ConfigBarModifierKeyword,i3ConfigBindModifier,i3ConfigVariable,i3ConfigBindModkey
-syn region i3ConfigBarBlock start=/^bar {$/ end=/^}$/ contains=i3ConfigBarBlockKeyword,i3ConfigBarModifierLine,i3ConfigBind,i3ConfigString,i3ConfigComment,i3ConfigFont,i3ConfigBoolean,i3ConfigNumber,i3ConfigOperator,i3ConfigParen,i3ConfigColor,i3ConfigVariable,i3ConfigColorsBlock fold keepend extend
+" Commands useable in keybinds
+syn keyword i3ConfigActionKeyword mode append_layout kill open fullscreen sticky split floating swap rename unmark show_marks title_window_icon title_format border restart reload exit scratchpad nop bar contained
+syn keyword i3ConfigOption enable disable toggle key restore current horizontal vertical auto none normal pixel show container with id con_id contained
" Define the highlighting.
-hi def link i3ConfigKeyword Keyword
-hi def link i3ConfigCommand Statement
hi def link i3ConfigError Error
hi def link i3ConfigTodo Todo
-hi def link i3ConfigComment Comment
+hi def link i3ConfigKeyword Keyword
+hi def link i3ConfigCommand Statement
hi def link i3ConfigOperator Operator
+hi def link i3ConfigSeparator i3ConfigOperator
hi def link i3ConfigParen Delimiter
-hi def link i3ConfigFontKeyword i3ConfigKeyword
-hi def link i3ConfigFontNamespace i3ConfigOption
-hi def link i3ConfigFontContent String
-hi def link i3ConfigFontSize Number
-hi def link i3ConfigString String
-hi def link i3ConfigNumber Number
hi def link i3ConfigBoolean Boolean
+hi def link i3ConfigString String
hi def link i3ConfigColor Constant
-hi def link i3ConfigVariable Variable
-hi def link i3ConfigSetKeyword i3ConfigKeyword
+hi def link i3ConfigNumber Number
hi def link i3ConfigIncludeKeyword i3ConfigKeyword
-hi def link i3ConfigCommandSubstitutionDelimiter Delimiter
-hi def link i3ConfigIncludePath String
-hi def link i3ConfigGapStyleKeyword i3ConfigOption
-hi def link i3ConfigGapStyle i3ConfigCommand
-hi def link i3ConfigSmartGapKeyword i3ConfigOption
-hi def link i3ConfigSmartGap i3ConfigKeyword
-hi def link i3ConfigSmartBorderKeyword i3ConfigOption
-hi def link i3ConfigSmartBorder i3ConfigKeyword
-hi def link i3ConfigAction i3ConfigCommand
-hi def link i3ConfigOption Type
-hi def link i3ConfigUnit i3ConfigNumber
-hi def link i3ConfigUnitOr i3ConfigOperator
+hi def link i3ConfigInclude i3ConfigString
+hi def link i3ConfigComment Comment
+hi def link i3ConfigFontKeyword i3ConfigKeyword
+hi def link i3ConfigColonOperator i3ConfigOperator
+hi def link i3ConfigFontNamespace i3ConfigOption
+hi def link i3ConfigFontSize i3ConfigNumber
+hi def link i3ConfigFont i3ConfigString
hi def link i3ConfigBindKeyword i3ConfigKeyword
+hi def link i3ConfigBindArgument i3ConfigShParam
+hi def link i3ConfigBindModifier i3ConfigOperator
hi def link i3ConfigBindModkey Special
hi def link i3ConfigBindCombo SpecialChar
-hi def link i3ConfigBindModifier i3ConfigOperator
-hi def link i3ConfigBindArgument i3ConfigShParam
-hi def link i3ConfigFloatingModifierKeyword i3ConfigKeyword
hi def link i3ConfigSizeSpecial i3ConfigOperator
-hi def link i3ConfigFloatingSizeKeyword i3ConfigKeyword
-hi def link i3ConfigOrientationKeyword i3ConfigOption
-hi def link i3ConfigOrientation i3ConfigKeyword
-hi def link i3ConfigLayoutKeyword i3ConfigOption
-hi def link i3ConfigLayout i3ConfigKeyword
-hi def link i3ConfigBorderStyleKeyword i3ConfigOption
-hi def link i3ConfigBorderStyle i3ConfigKeyword
-hi def link i3ConfigEdgeKeyword i3ConfigOption
-hi def link i3ConfigEdge i3ConfigKeyword
-hi def link i3ConfigCommandKeyword i3ConfigKeyword
-hi def link i3ConfigEqualsOperator i3ConfigOperator
-hi def link i3ConfigConditionalText Conditional
-hi def link i3ConfigConditional Delimiter
-hi def link i3ConfigNoFocusKeyword i3ConfigKeyword
+hi def link i3ConfigOrientationOpts i3ConfigOption
+hi def link i3ConfigWorkspaceLayoutOpts i3ConfigOption
+hi def link i3ConfigTitleAlignOpts i3ConfigOption
+hi def link i3ConfigBorderOpts i3ConfigOption
+hi def link i3ConfigEdgeOpts i3ConfigOption
+hi def link i3ConfigSmartBorderOpts i3ConfigOption
+hi def link i3ConfigForWindowKeyword i3ConfigKeyword
+hi def link i3ConfigVariable Variable
+hi def link i3ConfigSetKeyword i3ConfigKeyword
+hi def link i3ConfigResourceKeyword i3ConfigKeyword
+hi def link i3ConfigResource i3ConfigString
hi def link i3ConfigAssignKeyword i3ConfigKeyword
hi def link i3ConfigAssignSpecial i3ConfigOption
-hi def link i3ConfigResourceKeyword i3ConfigKeyword
+hi def link i3ConfigExecKeyword i3ConfigCommand
+hi def link i3ConfigExecAlwaysKeyword i3ConfigKeyword
hi def link i3ConfigShParam PreProc
hi def link i3ConfigShDelim Delimiter
hi def link i3ConfigShOper Operator
hi def link i3ConfigShCmdDelim i3ConfigShDelim
hi def link i3ConfigShCommand Normal
-hi def link i3ConfigExecKeyword i3ConfigCommand
-hi def link i3ConfigExecAlwaysKeyword i3ConfigKeyword
hi def link i3ConfigWorkspaceKeyword i3ConfigCommand
-hi def link i3ConfigOutput i3ConfigOption
-hi def link i3ConfigClientColorKeyword i3ConfigKeyword
-hi def link i3ConfigClientColor Operator
-hi def link i3ConfigTitleAlignKeyword i3ConfigOption
-hi def link i3ConfigTitleAlign i3ConfigKeyword
-hi def link i3ConfigInterprocessKeyword i3ConfigKeyword
-hi def link i3ConfigMouseWarpingKeyword i3ConfigKeyword
-hi def link i3ConfigMouseWarpingType i3ConfigOption
-hi def link i3ConfigFocusFollowsMouseKeyword i3ConfigKeyword
-hi def link i3ConfigFocusFollowsMouseType i3ConfigOption
-hi def link i3ConfigFocusWrappingKeyword i3ConfigKeyword
-hi def link i3ConfigFocusWrappingType i3ConfigOption
-hi def link i3ConfigPopupOnFullscreenKeyword i3ConfigKeyword
-hi def link i3ConfigPopupOnFullscreenType i3ConfigOption
-hi def link i3ConfigForceXineramaKeyword i3ConfigKeyword
-hi def link i3ConfigAutomaticSwitchKeyword i3ConfigKeyword
+hi def link i3ConfigWorkspaceOutput i3ConfigOption
+hi def link i3ConfigWorkspaceDir i3ConfigOption
+hi def link i3ConfigDotOperator i3ConfigOperator
+hi def link i3ConfigClientOpts i3ConfigOption
+hi def link i3ConfigIpcKeyword i3ConfigKeyword
+hi def link i3ConfigIpc i3ConfigString
+hi def link i3ConfigFocusFollowsMouseOpts i3ConfigOption
+hi def link i3ConfigFocusFollowsMouse i3ConfigKeyword
+hi def link i3ConfigMouseWarpingOpts i3ConfigOption
+hi def link i3ConfigMouseWarping i3ConfigKeyword
+hi def link i3ConfigPopupFullscreenOpts i3ConfigOption
+hi def link i3ConfigPopupFullscreen i3ConfigKeyword
+hi def link i3ConfigFocusWrappingOpts i3ConfigOption
+hi def link i3ConfigFocusWrapping i3ConfigKeyword
+hi def link i3ConfigForceXinerama i3ConfigKeyword
+hi def link i3ConfigAutomaticSwitch i3ConfigKeyword
hi def link i3ConfigTimeUnit i3ConfigNumber
-hi def link i3ConfigDelayUrgencyKeyword i3ConfigKeyword
-hi def link i3ConfigFocusOnActivationKeyword i3ConfigKeyword
-hi def link i3ConfigFocusOnActivationType i3ConfigOption
-hi def link i3ConfigShowMarksKeyword i3ConfigKeyword
-hi def link i3ConfigModeKeyword i3ConfigKeyword
-hi def link i3ConfigColorsKeyword i3ConfigKeyword
-hi def link i3ConfigColorsCategory Type
-hi def link i3ConfigBarModifierKeyword i3ConfigKeyword
-hi def link i3ConfigBarBlockKeyword i3ConfigKeyword
-
-let b:current_syntax = "i3config"
+hi def link i3ConfigDelayUrgency i3ConfigKeyword
+hi def link i3ConfigFocusOnActivationOpts i3ConfigOption
+hi def link i3ConfigFocusOnActivation i3ConfigKeyword
+hi def link i3ConfigShowMarks i3ConfigCommand
+hi def link i3ConfigTilingDragOpts i3ConfigOption
+hi def link i3ConfigTilingDrag i3ConfigKeyword
+hi def link i3ConfigGapsOpts i3ConfigOption
+hi def link i3ConfigGaps i3ConfigCommand
+hi def link i3ConfigSmartGapOpts i3ConfigOption
+hi def link i3ConfigSmartGap i3ConfigKeyword
+hi def link i3ConfigBarModifier i3ConfigKeyword
+hi def link i3ConfigBarOpts i3ConfigKeyword
+hi def link i3ConfigColorsOpts i3ConfigOption
+hi def link i3ConfigColors i3ConfigKeyword
+hi def link i3ConfigConditionProp i3ConfigShParam
+hi def link i3ConfigConditionFocused Constant
+hi def link i3ConfigExecActionKeyword i3ConfigShCommand
+hi def link i3ConfigExecAction i3ConfigString
+hi def link i3ConfigLayoutKeyword i3ConfigCommand
+hi def link i3ConfigLayoutOpts i3ConfigOption
+hi def link i3ConfigFocusKeyword i3ConfigCommand
+hi def link i3ConfigFocusOpts i3ConfigOption
+hi def link i3ConfigFocusOutputOpts i3ConfigOption
+hi def link i3ConfigMoveKeyword i3ConfigCommand
+hi def link i3ConfigMoveDir i3ConfigOption
+hi def link i3ConfigMoveType i3ConfigOption
+hi def link i3ConfigUnit i3ConfigNumber
+hi def link i3ConfigResizeKeyword i3ConfigCommand
+hi def link i3ConfigResizeOpts i3ConfigOption
+hi def link i3ConfigMarkKeyword i3ConfigCommand
+hi def link i3ConfigMark i3ConfigShParam
+hi def link i3ConfigActionKeyword i3ConfigCommand
+hi def link i3ConfigOption Type
+
+let b:current_syntax = "i3config" \ No newline at end of file
diff --git a/runtime/syntax/rust.vim b/runtime/syntax/rust.vim
index 57343301e0..55d3f14dc2 100644
--- a/runtime/syntax/rust.vim
+++ b/runtime/syntax/rust.vim
@@ -3,44 +3,57 @@
" Maintainer: Patrick Walton <pcwalton@mozilla.com>
" Maintainer: Ben Blum <bblum@cs.cmu.edu>
" 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
if version < 600
- syntax clear
+ syntax clear
elseif exists("b:current_syntax")
- finish
+ finish
endif
" Syntax definitions {{{1
" Basic keywords {{{2
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 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 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 rustPanic "\<panic\(\w\)*!" contained
+syn match rustAsync "\<async\%(\s\|\n\)\@="
syn keyword rustKeyword break
-syn keyword rustKeyword box nextgroup=rustBoxPlacement skipwhite skipempty
+syn keyword rustKeyword box
syn keyword rustKeyword continue
+syn keyword rustKeyword crate
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 impl let
+syn keyword rustKeyword macro
syn keyword rustKeyword pub nextgroup=rustPubScope skipwhite skipempty
syn keyword rustKeyword return
+syn keyword rustKeyword yield
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
" 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 match rustDefault /\<default\ze\_s\+\(impl\|fn\|type\|const\)\>/
+syn keyword rustAwait await
+syn match rustKeyword /\<try\>!\@!/ display
syn keyword rustPubScopeCrate crate 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 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 rustFuncName "\%(r#\)\=\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained
+
+syn region rustMacroRepeat matchgroup=rustMacroRepeatDelimiters start="$(" end="),\=[*+]" contains=TOP
syn match rustMacroVariable "$\w\+"
+syn match rustRawIdent "\<r#\h\w*" contains=NONE
" 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
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 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 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 rustString matchgroup=rustStringDelimiter start=+b"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeError,rustStringContinuation
+syn region rustString matchgroup=rustStringDelimiter start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeUnicode,rustEscapeError,rustStringContinuation,@Spell
+syn region rustString matchgroup=rustStringDelimiter start='b\?r\z(#*\)"' end='"\z1' contains=@Spell
+
+" 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
" 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
+" 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
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\)\)\="
@@ -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\)"
" 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 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 rustLabel display "\%(\<\%(break\|continue\)\s*\)\@<=\'\%([^[: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 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 rustCommentBlockDoc matchgroup=rustCommentBlockDoc start="/\*\%(!\|\*[*/]\@!\)" end="\*/" contains=rustTodo,rustCommentBlockDocNest,rustCommentBlockDocRustCode,@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
@@ -203,13 +229,67 @@ syn region rustCommentBlockDocNestError matchgroup=rustCommentBlockDocError star
" 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
+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
" Trivial folding rules to begin with.
" FIXME: use the AST to make really good folding
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 rust’s src/librustdoc/html/markdown.rs, so that
+ " we only highlight as Rust what it would perceive as Rust (almost; it’s
+ " possible to trick it if you try hard, and indented code blocks aren’t
+ " 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 don’t care. Balance of probability, and all that.
+ syn match rustCommentBlockDocStar /^\s*\*\s\?/ contained
+ syn match rustCommentLineDocLeader "^\s*//\%(//\@!\|!\)" contained
+endif
+
" Default highlighting {{{1
hi def link rustDecNumber rustNumber
hi def link rustHexNumber rustNumber
@@ -219,7 +299,6 @@ 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
@@ -228,6 +307,7 @@ hi def link rustEscapeUnicode rustEscape
hi def link rustEscapeError Error
hi def link rustStringContinuation Special
hi def link rustString String
+hi def link rustStringDelimiter String
hi def link rustCharacterInvalid Error
hi def link rustCharacterInvalidUnicode rustCharacterInvalid
hi def link rustCharacter Character
@@ -241,12 +321,15 @@ hi def link rustFloat Float
hi def link rustArrowCharacter rustOperator
hi def link rustOperator Operator
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 rustStructure Keyword " More precise is Structure
hi def link rustUnion rustStructure
+hi def link rustExistential rustKeyword
hi def link rustPubScopeDelim Delimiter
hi def link rustPubScopeCrate rustKeyword
hi def link rustSuper rustKeyword
+hi def link rustUnsafeKeyword Exception
hi def link rustReservedKeyword Error
hi def link rustRepeat Conditional
hi def link rustConditional Conditional
@@ -260,10 +343,13 @@ hi def link rustFuncCall Function
hi def link rustShebang Comment
hi def link rustCommentLine Comment
hi def link rustCommentLineDoc SpecialComment
+hi def link rustCommentLineDocLeader rustCommentLineDoc
hi def link rustCommentLineDocError Error
hi def link rustCommentBlock rustCommentLine
hi def link rustCommentBlockDoc rustCommentLineDoc
+hi def link rustCommentBlockDocStar rustCommentBlockDoc
hi def link rustCommentBlockDocError Error
+hi def link rustCommentDocCodeFence rustCommentLineDoc
hi def link rustAssert PreCondit
hi def link rustPanic PreCondit
hi def link rustMacro Macro
@@ -276,11 +362,15 @@ 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
+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:
" hi rustAttribute ctermfg=cyan
@@ -293,3 +383,5 @@ syn sync minlines=200
syn sync maxlines=500
let b:current_syntax = "rust"
+
+" vim: set et sw=4 sts=4 ts=8:
diff --git a/runtime/syntax/swayconfig.vim b/runtime/syntax/swayconfig.vim
index 6b36210252..290e8cc1ac 100644
--- a/runtime/syntax/swayconfig.vim
+++ b/runtime/syntax/swayconfig.vim
@@ -1,10 +1,10 @@
" Vim syntax file
" Language: sway window manager config
-" Original Author: James Eapen <james.eapen@vai.org>
+" Original Author: Josef Litos
" Maintainer: James Eapen <james.eapen@vai.org>
-" Version: 0.2.1
-" Reference version (jamespeapen/swayconfig.vim): 0.12.1
-" Last Change: 2023 Mar 20
+" Version: 0.2.2
+" Reference version (JosefLitos/i3config.vim): 1.8.1
+" Last Change: 2023-09-12
" References:
" http://i3wm.org/docs/userguide.html#configuring
@@ -19,98 +19,110 @@ endif
runtime! syntax/i3config.vim
-scriptencoding utf-8
+" i3 extensions
+syn match i3ConfigSet /^\s*set \$\w\+ .*$/ contains=i3ConfigVariable,i3ConfigSetKeyword,i3ConfigColor,i3ConfigString,i3ConfigNoStartupId,i3ConfigNumber,swayConfigOutputCommand,i3ConfigShCommand,i3ConfigShDelim,i3ConfigShParam,i3ConfigShOper
-" Error
-"syn match swayConfigError /.*/
+syn keyword i3ConfigActionKeyword opacity contained
-" binding
syn keyword swayConfigBindKeyword bindswitch bindgesture contained
-syn match swayConfigBind /^\s*\(bindswitch\)\s\+.*$/ contains=i3ConfigVariable,i3ConfigBindKeyword,swayConfigBindKeyword,i3ConfigVariableAndModifier,i3ConfigNumber,i3ConfigUnit,i3ConfigUnitOr,i3ConfigBindArgument,i3ConfigModifier,i3ConfigAction,i3ConfigString,i3ConfigGapStyleKeyword,i3ConfigBorderStyleKeyword
-
-" bindgestures
-syn keyword swayConfigBindGestureCommand swipe pinch hold contained
-syn keyword swayConfigBindGestureDirection up down left right next prev contained
-syn keyword swayConfigBindGesturePinchDirection inward outward clockwise counterclockwise contained
-syn match swayConfigBindGestureHold /^\s*\(bindgesture\)\s\+hold\(:[1-5]\)\?\s\+.*$/ contains=swayConfigBindKeyword,swayConfigBindGestureCommand,swayConfigBindGestureDirection,i3ConfigWorkspaceKeyword,i3ConfigAction
-syn match swayConfigBindGestureSwipe /^\s*\(bindgesture\)\s\+swipe\(:[3-5]\)\?:\(up\|down\|left\|right\)\s\+.*$/ contains=swayConfigBindKeyword,swayConfigBindGestureCommand,swayConfigBindGestureDirection,i3ConfigWorkspaceKeyword,i3ConfigAction
-syn match swayConfigBindGesturePinch /^\s*\(bindgesture\)\s\+pinch\(:[2-5]\)\?:\(up\|down\|left\|right\|inward\|outward\|clockwise\|counterclockwise\)\(+\(up\|down\|left\|right\|inward\|outward\|clockwise\|counterclockwise\)\)\?.*$/ contains=swayConfigBindKeyword,swayConfigBindGestureCommand,swayConfigBindGestureDirection,swayConfigBindGesturePinchDirection,i3ConfigWorkspaceKeyword,i3ConfigAction
-
-" floating
-syn keyword swayConfigFloatingKeyword floating contained
-syn match swayConfigFloating /^\s*floating\s\+\(enable\|disable\|toggle\)\s*$/ contains=swayConfigFloatingKeyword
-
-syn clear i3ConfigFloatingModifier
-syn keyword swayConfigFloatingModifier floating_modifier contained
-syn match swayConfigFloatingMouseAction /^\s\?.*floating_modifier\s\S\+\s\?\(normal\|inverted\|none\)\?$/ contains=swayConfigFloatingModifier,i3ConfigVariable
-
-" Gaps
-syn clear i3ConfigSmartBorderKeyword
-syn clear i3ConfigSmartBorder
-syn keyword swayConfigSmartBorderKeyword on no_gaps off contained
-syn match swayConfigSmartBorder /^\s*smart_borders\s\+\(on\|no_gaps\|off\)\s\?$/ contains=swayConfigSmartBorderKeyword
-
-" Changing colors
-syn keyword swayConfigClientColorKeyword focused_tab_title contained
-syn match swayConfigClientColor /^\s*client.\w\+\s\+.*$/ contains=i3ConfigClientColorKeyword,i3ConfigColor,i3ConfigVariable,i3ConfigClientColorKeyword,swayConfigClientColorKeyword
-
-" Input config
-syn keyword swayConfigInputKeyword input contained
-syn match swayConfigInput /^\s*input\s\+.*$/ contains=swayConfigInputKeyword
+syn match i3ConfigBindArgument /--\(locked\|to-code\|no-repeat\|input-device=[:0-9a-zA-Z_/-]\+\|no-warn\)/ contained
+syn region i3ConfigBind start=/^\s*bind\(switch\|gesture\) / skip=/\\$/ end=/$/ contains=swayConfigBindKeyword,swayConfigBindswitch,swayConfigBindswitchArgument,swayConfigBindgesture,swayConfigBindgestureArgument,i3ConfigCriteria,i3ConfigAction,i3ConfigSeparator,i3ConfigActionKeyword,i3ConfigOption,i3ConfigString,i3ConfigNumber,i3ConfigVariable,i3ConfigBoolean keepend
+
+syn match swayConfigBindBlockHeader /^\s*bind\(sym\|code\) .*{$/ contained contains=i3ConfigBindKeyword,i3ConfigBindArgument,i3ConfigParen
+syn match swayConfigBindBlockCombo /^\s\+\(--[a-z-]\+ \)*[$a-zA-Z0-9_+]\+ [a-z[]\@=/ contained contains=i3ConfigBindArgument,i3ConfigBindCombo
+syn region i3ConfigBind start=/^\s*bind\(sym\|code\) .*{$/ end=/^\s*}$/ contains=swayConfigBindBlockHeader,swayConfigBindBlockCombo,i3ConfigCriteria,i3ConfigAction,i3ConfigSeparator,i3ConfigActionKeyword,i3ConfigOption,i3ConfigString,i3ConfigNumber,i3ConfigVariable,i3ConfigBoolean,i3ConfigComment,i3ConfigParen fold keepend extend
+
+syn keyword i3ConfigClientOpts focused_tab_title contained
+
+syn region swayConfigExecBlock start=/exec\(_always\)\? {/ end=/^}$/ contains=i3ConfigExecKeyword,i3ConfigExecAlwaysKeyword,i3ConfigShCommand,i3ConfigShDelim,i3ConfigShOper,i3ConfigShParam,i3ConfigNumber,i3ConfigString,i3ConfigVariable,i3ConfigComment fold keepend extend
+
+syn keyword swayConfigFloatingModifierOpts normal inverse contained
+syn match i3ConfigKeyword /^floating_modifier [$a-zA-Z0-9+]\+ \(normal\|inverse\)$/ contains=i3ConfigVariable,i3ConfigBindModkey,swayConfigFloatingModifierOpts
+
+syn match i3ConfigEdge /^hide_edge_borders\( --i3\)\? \(none\|vertical\|horizontal\|both\|smart\|smart_no_gaps\)\s\?$/ contains=i3ConfigEdgeKeyword,i3ConfigShParam
+
+syn keyword i3ConfigBarBlockKeyword swaybar_command gaps height pango_markup status_edge_padding status_padding wrap_scroll tray_bindcode tray_bindsym icon_theme contained
+
+syn keyword i3ConfigExecActionKeyword swaymsg contained
-" Seat config
+" Sway-only options
+" Xwayland
+syn keyword swayConfigXOpt enable disable force contained
+syn match i3ConfigKeyword /^xwayland .*$/ contains=swayConfigXOpt
+
+" Bindswitch
+syn match swayConfigBindswitchArgument /--\(locked\|no-warn\|reload\)/ contained
+syn keyword swayConfigBindswitchType lid tablet contained
+syn keyword swayConfigBindswitchState toggle contained
+syn match swayConfigBindswitch /\(lid\|tablet\):\(on\|off\|toggle\) / contained contains=swayConfigBindswitchType,i3ConfigColonOperator,swayConfigBindswitchState,i3ConfigBoolean
+syn region i3ConfigBind start=/^\s*bindswitch\s\+.*{$/ end=/^\s*}$/ contains=swayConfigBindKeyword,swayConfigBindswitch,swayConfigBindswitchArgument,i3ConfigNumber,i3ConfigVariable,i3ConfigAction,i3ConfigActionKeyword,i3ConfigOption,i3ConfigSeparator,i3ConfigString,i3ConfigCriteria,swayConfigOutputCommand,i3ConfigBoolean,i3ConfigComment,i3ConfigParen fold keepend extend
+
+" Bindgesture
+syn match swayConfigBindgestureArgument /--\(exact\|input-device=[:0-9a-zA-Z_/-]\+\|no-warn\)/ contained
+syn keyword swayConfigBindgestureType hold swipe pinch contained
+syn keyword swayConfigBindgestureDir up down left right inward outward clockwise counterclockwise contained
+syn match swayConfigBindgesture /\(hold\(:[1-5]\)\?\|swipe\(:[3-5]\)\?\(:up\|:down\|:left\|:right\)\?\|pinch\(:[2-5]\)\?:\(+\?\(inward\|outward\|clockwise\|counterclockwise\|up\|down\|left\|right\)\)\+\) / contained contains=i3ConfigNumber,swayConfigBindgestureType,i3ConfigColonOperator,swayConfigBindgestureDir,i3ConfigBindModifier
+syn region i3ConfigBind start=/^\s*bindgesture\s\+.*{$/ end=/^\s*}$/ contains=swayConfigBindKeyword,swayConfigBindgesture,swayConfigBindgestureArgument,i3ConfigCriteria,i3ConfigAction,i3ConfigSeparator,i3ConfigActionKeyword,i3ConfigOption,i3ConfigString,i3ConfigNumber,i3ConfigVariable,i3ConfigBoolean,i3ConfigParen fold keepend extend
+
+" Titlebar commands
+syn match i3ConfigKeyword /^titlebar_border_thickness \(\d\+\|\$\S\+\)$/ contains=i3ConfigNumber,i3ConfigVariable
+syn match i3ConfigKeyword /^titlebar_padding \(\d\+\|\$\S\+\)\( \d\+\)\?$/ contains=i3ConfigNumber,i3ConfigVariable
+
+syn match swayConfigDeviceOps /[*,:;]/ contained
+
+" Output monitors
+syn keyword swayConfigOutputKeyword output contained
+syn keyword swayConfigOutputOpts mode resolution res modeline position pos scale scale_filter subpixel background bg transform disable enable power dpms max_render_time adaptive_sync render_bit_depth contained
+syn keyword swayConfigOutputOptVals linear nearest smart rgb bgr vrgb vbgr none normal flipped fill stretch fit center tile solid_color clockwise anticlockwise toggle contained
+syn match swayConfigOutputFPS /@[0-9.]\+Hz/ contained
+syn match swayConfigOutputMode / [0-9]\+x[0-9]\+\(@[0-9.]\+Hz\)\?/ contained contains=swayConfigOutputFPS,i3ConfigNumber
+syn region i3ConfigAction start=/output/ skip=/\\$/ end=/\([,;]\|$\)/ contained contains=swayConfigOutputKeyword,swayConfigOutputMode,swayConfigOutputOpts,swayConfigOutputOptVals,i3ConfigVariable,i3ConfigNumber,i3ConfigString,i3ConfigColor,i3ConfigBoolean,swayConfigDeviceOps keepend
+syn region swayConfigOutput start=/^output/ skip=/\\$/ end=/$/ contains=swayConfigOutputKeyword,swayConfigOutputMode,swayConfigOutputOpts,swayConfigOutputOptVals,i3ConfigVariable,i3ConfigNumber,i3ConfigString,i3ConfigColor,i3ConfigBoolean,swayConfigDeviceOps keepend
+syn region swayConfigOutput start=/^output .* {$/ end=/}$/ contains=swayConfigOutputKeyword,swayConfigOutputMode,swayConfigOutputOpts,swayConfigOutputOptVals,i3ConfigVariable,i3ConfigNumber,i3ConfigString,i3ConfigColor,i3ConfigBoolean,swayConfigDeviceOps,i3ConfigParen keepend extend
+
+" Input devices
+syn keyword swayConfigInputKeyword input contained
+syn keyword swayConfigInputOpts xkb_layout xkb_variant xkb_rules xkb_switch_layout xkb_numlock xkb_file xkb_capslock xkb_model repeat_delay repeat_rate map_to_output map_to_region map_from_region tool_mode accel_profile dwt dwtp drag_lock drag click_method middle_emulation tap events calibration_matrix natural_scroll left_handed pointer_accel scroll_button scroll_factor scroll_method tap_button_map contained
+syn keyword swayConfigInputOptVals absolute relative adaptive flat none button_areas clickfinger toggle two_finger edge on_button_down lrm lmr contained
+syn match swayConfigColonPairVal /:[0-9a-z_-]\+/ contained contains=i3ConfigColonOperator
+syn match swayConfigColonPair /[a-z]\+:[0-9a-z_-]\+/ contained contains=swayConfigColonPairVal
+syn match swayConfigInputXkbOpts /xkb_options \([a-z]\+:[0-9a-z_-]\+,\?\)\+/ contained contains=swayConfigColonPair,swayConfigDeviceOps
+syn region i3ConfigAction start=/input/ skip=/\\$/ end=/\([,;]\|$\)/ contained contains=swayConfigInputKeyword,swayConfigColonPair,swayConfigInputXkbOpts,swayConfigInputOpts,swayConfigInputOptVals,i3ConfigVariable,i3ConfigNumber,i3ConfigString,i3ConfigBoolean,swayConfigDeviceOps keepend
+syn region i3ConfigInput start=/^input/ skip=/\\$/ end=/$/ contains=swayConfigInputKeyword,swayConfigColonPair,swayConfigInputXkbOpts,swayConfigInputOpts,swayConfigInputOptVals,i3ConfigVariable,i3ConfigNumber,i3ConfigString,i3ConfigBoolean,swayConfigDeviceOps keepend
+syn region i3ConfigInput start=/^input .* {/ end=/}$/ contains=swayConfigInputKeyword,swayConfigColonPair,swayConfigInputXkbOpts,swayConfigInputOpts,swayConfigInputOptVals,i3ConfigVariable,i3ConfigNumber,i3ConfigString,i3ConfigBoolean,swayConfigDeviceOps,i3ConfigParen keepend extend
+
+" Seat
syn keyword swayConfigSeatKeyword seat contained
-syn match swayConfigSeat /^\s*seat\s\+.*$/ contains=swayConfigSeatKeyword
-
-" set display outputs
-syn match swayConfigOutput /^\s*output\s\+.*$/ contains=i3ConfigOutput
-
-" set display focus
-syn keyword swayConfigFocusKeyword focus contained
-syn keyword swayConfigFocusType output contained
-syn match swayConfigFocus /^\s*focus\soutput\s.*$/ contains=swayConfigFocusKeyword,swayConfigFocusType
-
-" mouse warping
-syn keyword swayConfigMouseWarpingType container contained
-syn match swayConfigMouseWarping /^\s*mouse_warping\s\+\(output\|container\|none\)\s\?$/ contains=i3ConfigMouseWarpingKeyword,i3ConfigMouseWarpingType,swayConfigMouseWarpingType
-
-" focus follows mouse
-syn clear i3ConfigFocusFollowsMouseType
-syn clear i3ConfigFocusFollowsMouse
-
-syn keyword swayConfigFocusFollowsMouseType yes no always contained
-syn match swayConfigFocusFollowsMouse /^\s*focus_follows_mouse\s\+\(yes\|no\|always\)\s\?$/ contains=i3ConfigFocusFollowsMouseKeyword,swayConfigFocusFollowsMouseType
-
-
-" xwayland
-syn keyword swayConfigXwaylandKeyword xwayland contained
-syn match swayConfigXwaylandModifier /^\s*xwayland\s\+\(enable\|disable\|force\)\s\?$/ contains=swayConfigXwaylandKeyword
-
-" Group mode/bar
-syn clear i3ConfigBlock
-syn region swayConfigBlock start=+.*s\?{$+ end=+^}$+ contains=i3ConfigBlockKeyword,i3ConfigString,i3ConfigBind,i3ConfigInitializeKeyword,i3ConfigComment,i3ConfigFont,i3ConfigFocusWrappingType,i3ConfigColor,i3ConfigVariable,swayConfigInputKeyword,swayConfigSeatKeyword,i3ConfigOutput transparent keepend extend
-
-"hi def link swayConfigError Error
-hi def link i3ConfigFloating Error
-hi def link swayConfigFloating Type
-hi def link swayConfigFloatingMouseAction Type
-hi def link swayConfigFocusKeyword Type
-hi def link swayConfigSmartBorderKeyword Type
-hi def link swayConfigInputKeyword Type
-hi def link swayConfigSeatKeyword Type
-hi def link swayConfigMouseWarpingType Type
-hi def link swayConfigFocusFollowsMouseType Type
-hi def link swayConfigBindGestureCommand Identifier
-hi def link swayConfigBindGestureDirection Constant
-hi def link swayConfigBindGesturePinchDirection Constant
-hi def link swayConfigBindKeyword Identifier
-hi def link swayConfigClientColorKeyword Identifier
-hi def link swayConfigFloatingKeyword Identifier
-hi def link swayConfigFloatingModifier Identifier
-hi def link swayConfigFocusType Identifier
-hi def link swayConfigSmartBorder Identifier
-hi def link swayConfigXwaylandKeyword Identifier
-hi def link swayConfigXwaylandModifier Type
-hi def link swayConfigBindGesture PreProc
+syn keyword swayConfigSeatOpts attach cursor fallback hide_cursor idle_inhibit idle_wake keyboard_grouping shortcuts_inhibitor pointer_constraint xcursor_theme contained
+syn match swayConfigSeatOptVals /when-typing/ contained
+syn keyword swayConfigSeatOptVals move set press release none smart activate deactivate toggle escape enable disable contained
+syn region i3ConfigAction start=/seat/ skip=/\\$/ end=/\([,;]\|$\)/ contained contains=swayConfigSeatKeyword,i3ConfigString,i3ConfigNumber,i3ConfigBoolean,swayConfigSeatOptVals,swayConfigSeatOpts,swayConfigDeviceOps keepend
+syn region swayConfigSeat start=/seat/ skip=/\\$/ end=/$/ contains=swayConfigSeatKeyword,i3ConfigString,i3ConfigNumber,i3ConfigBoolean,swayConfigSeatOptVals,swayConfigSeatOpts,swayConfigDeviceOps keepend
+syn region swayConfigSeat start=/seat .* {$/ end=/}$/ contains=swayConfigSeatKeyword,i3ConfigString,i3ConfigNumber,i3ConfigBoolean,swayConfigSeatOptVals,swayConfigSeatOpts,swayConfigDeviceOps,i3ConfigParen keepend extend
+
+" Define the highlighting.
+hi def link swayConfigFloatingModifierOpts i3ConfigOption
+hi def link swayConfigBindKeyword i3ConfigBindKeyword
+hi def link swayConfigXOpt i3ConfigOption
+hi def link swayConfigBindswitchArgument i3ConfigBindArgument
+hi def link swayConfigBindswitchType i3ConfigMoveType
+hi def link swayConfigBindswitchState i3ConfigMoveDir
+hi def link swayConfigBindgestureArgument i3ConfigBindArgument
+hi def link swayConfigBindgestureType i3ConfigMoveType
+hi def link swayConfigBindgestureDir i3ConfigMoveDir
+hi def link swayConfigDeviceOps i3ConfigOperator
+hi def link swayConfigOutputKeyword i3ConfigCommand
+hi def link swayConfigOutputOptVals i3ConfigOption
+hi def link swayConfigOutputOpts i3ConfigOption
+hi def link swayConfigOutputFPS Constant
+hi def link swayConfigInputKeyword i3ConfigCommand
+hi def link swayConfigInputOptVals i3ConfigShParam
+hi def link swayConfigInputOpts i3ConfigOption
+hi def link swayConfigInputXkbOpts i3ConfigOption
+hi def link swayConfigColonPairVal i3ConfigString
+hi def link swayConfigColonPair i3ConfigShParam
+hi def link swayConfigSeatKeyword i3ConfigCommand
+hi def link swayConfigSeatOptVals i3ConfigOption
+hi def link swayConfigSeatOpts i3ConfigOption
let b:current_syntax = "swayconfig"
diff --git a/scripts/gen_help_html.lua b/scripts/gen_help_html.lua
index 5e06830336..c8e004e2ab 100644
--- a/scripts/gen_help_html.lua
+++ b/scripts/gen_help_html.lua
@@ -574,14 +574,15 @@ local function visit_node(root, level, lang_tree, headings, opt, stats)
return ''
end
local el = in_heading and 'span' or 'code'
- local s = ('%s<%s id="%s" class="%s">%s</%s>'):format(ws(), el, url_encode(tagname), cssclass, trimmed, el)
+ local encoded_tagname = url_encode(tagname)
+ local s = ('%s<%s id="%s" class="%s"><a href="#%s">%s</a></%s>'):format(ws(), el, encoded_tagname, cssclass, encoded_tagname, trimmed, el)
if opt.old then
s = fix_tab_after_conceal(s, node_text(root:next_sibling()))
end
if in_heading and prev ~= 'tag' then
-- Don't set "id", let the heading use the tag as its "id" (used by search engines).
- s = ('%s<%s class="%s">%s</%s>'):format(ws(), el, cssclass, trimmed, el)
+ s = ('%s<%s class="%s"><a href="#%s">%s</a></%s>'):format(ws(), el, cssclass, encoded_tagname, trimmed, el)
-- Start the <span> container for tags in a heading.
-- This makes "justify-content:space-between" right-align the tags.
-- <h2>foo bar<span>tag1 tag2</span></h2>
@@ -963,6 +964,7 @@ local function gen_css(fname)
margin-bottom: 0;
}
+ /* TODO: should this rule be deleted? help tags are rendered as <code> or <span>, not <a> */
a.help-tag, a.help-tag:focus, a.help-tag:hover {
color: inherit;
text-decoration: none;
@@ -977,6 +979,14 @@ local function gen_css(fname)
margin-right: 0;
float: right;
}
+ .help-tag a,
+ .help-tag-right a {
+ color: inherit;
+ }
+ .help-tag a:not(:hover),
+ .help-tag-right a:not(:hover) {
+ text-decoration: none;
+ }
h1 .help-tag, h2 .help-tag, h3 .help-tag {
font-size: smaller;
}
diff --git a/scripts/gen_vimdoc.py b/scripts/gen_vimdoc.py
index dfad1f000c..d485e68e2f 100755
--- a/scripts/gen_vimdoc.py
+++ b/scripts/gen_vimdoc.py
@@ -440,7 +440,7 @@ def is_blank(text):
return '' == clean_lines(text)
-def get_text(n, preformatted=False):
+def get_text(n):
"""Recursively concatenates all text in a node tree."""
text = ''
if n.nodeType == n.TEXT_NODE:
@@ -449,11 +449,13 @@ def get_text(n, preformatted=False):
for node in n.childNodes:
text += get_text(node)
return '`{}`'.format(text)
+ if n.nodeName == 'sp': # space, used in "programlisting" nodes
+ return ' '
for node in n.childNodes:
if node.nodeType == node.TEXT_NODE:
text += node.data
elif node.nodeType == node.ELEMENT_NODE:
- text += get_text(node, preformatted)
+ text += get_text(node)
return text
@@ -571,7 +573,7 @@ def render_node(n, text, prefix='', indent='', width=text_width - indentation,
# text += (int(not space_preceding) * ' ')
if n.nodeName == 'preformatted':
- o = get_text(n, preformatted=True)
+ o = get_text(n)
ensure_nl = '' if o[-1] == '\n' else '\n'
if o[0:4] == 'lua\n':
text += '>lua{}{}\n<'.format(ensure_nl, o[3:-1])
@@ -581,7 +583,15 @@ def render_node(n, text, prefix='', indent='', width=text_width - indentation,
text += o[4:-1]
else:
text += '>{}{}\n<'.format(ensure_nl, o)
+ elif n.nodeName == 'programlisting': # codeblock (```)
+ o = get_text(n)
+ filename = n.attributes['filename'].value
+ if filename:
+ text += '>{}'.format(filename.lstrip('.'))
+ else:
+ text += '>'
+ text += '\n\n{}\n<'.format(textwrap.indent(o, ' ' * 4))
elif is_inline(n):
text = doc_wrap(get_text(n), prefix=prefix, indent=indent, width=width)
elif n.nodeName == 'verbatim':
@@ -786,6 +796,18 @@ def fmt_node_as_vimhelp(parent: Element, width=text_width - indentation, indent=
for child in parent.childNodes:
para, _ = para_as_map(child, indent, width, fmt_vimhelp)
+ # 'programlisting' blocks are Markdown code blocks. Do not include
+ # these as a separate paragraph, but append to the last non-empty line
+ # in the text
+ if (
+ len(child.childNodes) == 1
+ and child.childNodes[0].nodeName == 'programlisting'
+ ):
+ while rendered_blocks and rendered_blocks[-1] == '':
+ rendered_blocks.pop()
+ rendered_blocks[-1] += ' ' + para['text']
+ continue
+
# Generate text from the gathered items.
chunks = [para['text']]
if len(para['note']) > 0: