mirror of
https://github.com/neovim/neovim.git
synced 2026-01-02 17:36:56 +10:00
This reverts commits:
- 6b652a785033fd4164e049492a7327c1ed7c3e5f
- 2f689d5abde0ccddca9e20d8c93a0299bd054e32
- a025a46d4169587145fb54f04af349cd05cb6122
Several email addresses that are known to be valid caused bounces
due to an issue with my email setup. The previous commits incorrectly
marked these addresses as invalid. So revert the whole thing again.
62d8f3dab5
N/A patch:
vim-patch:2f689d5: runtime: mark more invalid email addresses
Co-authored-by: Christian Brabandt <cb@256bit.org>
261 lines
9.6 KiB
VimL
261 lines
9.6 KiB
VimL
" Vim indent file
|
|
" Language: Rust
|
|
" Author: Chris Morgan <me@chrismorgan.info>
|
|
" Last Change: 2023-09-11
|
|
" 2024 Jul 04 by Vim Project: use shiftwidth() instead of hard-coding shifted values #15138
|
|
" 2025 Dec 29 by Vim Project: clean up
|
|
" 2025 Dec 31 by Vim Project: correcly indent after nested array literal #19042
|
|
|
|
" For bugs, patches and license go to https://github.com/rust-lang/rust.vim
|
|
" Note: upstream seems umaintained: https://github.com/rust-lang/rust.vim/issues/502
|
|
|
|
" Only load this indent file when no other was loaded.
|
|
if exists("b:did_indent")
|
|
finish
|
|
endif
|
|
let b:did_indent = 1
|
|
|
|
setlocal cindent
|
|
setlocal cinoptions=L0,(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,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],0(,0)
|
|
|
|
setlocal indentexpr=GetRustIndent(v:lnum)
|
|
|
|
let b:undo_indent = "setlocal cindent< cinoptions< cinkeys< cinwords< lisp< autoindent< indentkeys< indentexpr<"
|
|
|
|
" Only define the function once.
|
|
if exists("*GetRustIndent")
|
|
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
|
|
endfunction
|
|
|
|
function! s:is_string_comment(lnum, col)
|
|
if has('syntax_items')
|
|
for id in synstack(a:lnum, a:col)
|
|
let synname = synIDattr(id, "name")
|
|
if synname ==# "rustString" || synname =~# "^rustComment"
|
|
return 1
|
|
endif
|
|
endfor
|
|
else
|
|
" without syntax, let's not even try
|
|
return 0
|
|
endif
|
|
endfunction
|
|
|
|
function GetRustIndent(lnum)
|
|
" Starting assumption: cindent (called at the end) will do it right
|
|
" normally. We just want to fix up a few cases.
|
|
|
|
let line = getline(a:lnum)
|
|
|
|
if has('syntax_items')
|
|
let synname = synIDattr(synID(a:lnum, 1, 1), "name")
|
|
if synname ==# "rustString"
|
|
" If the start of the line is in a string, don't change the indent
|
|
return -1
|
|
elseif synname =~? '\(Comment\|Todo\)'
|
|
\ && line !~# '^\s*/\*' " not /* opening line
|
|
if synname =~? "CommentML" " multi-line
|
|
if line !~# '^\s*\*' && getline(a:lnum - 1) =~# '^\s*/\*'
|
|
" This is (hopefully) the line after a /*, and it has no
|
|
" leader, so the correct indentation is that of the
|
|
" previous line.
|
|
return GetRustIndent(a:lnum - 1)
|
|
endif
|
|
endif
|
|
" If it's in a comment, let cindent take care of it now. This is
|
|
" for cases like "/*" where the next line should start " * ", not
|
|
" "* " as the code below would otherwise cause for module scope
|
|
" Fun fact: " /*\n*\n*/" takes two calls to get right!
|
|
return cindent(a:lnum)
|
|
endif
|
|
endif
|
|
|
|
" cindent gets second and subsequent match patterns/struct members wrong,
|
|
" as it treats the comma as indicating an unfinished statement::
|
|
"
|
|
" match a {
|
|
" b => c,
|
|
" d => e,
|
|
" f => g,
|
|
" };
|
|
|
|
" Search backwards for the previous non-empty line.
|
|
let prevlinenum = prevnonblank(a:lnum - 1)
|
|
let prevline = s:get_line_trimmed(prevlinenum)
|
|
while prevlinenum > 1 && prevline !~# '[^[:blank:]]'
|
|
let prevlinenum = prevnonblank(prevlinenum - 1)
|
|
let prevline = s:get_line_trimmed(prevlinenum)
|
|
endwhile
|
|
|
|
" 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) + shiftwidth()
|
|
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
|
|
|
|
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) + shiftwidth()
|
|
endif
|
|
endif
|
|
|
|
" Prevent cindent from becoming confused when pairing square brackets, as
|
|
" in
|
|
"
|
|
" let arr = [[u8; 4]; 2] = [
|
|
" [0; 4],
|
|
" [1, 3, 5, 9],
|
|
" ];
|
|
" | ← indentation placed here
|
|
"
|
|
" for which it calculates too much indentation in the line following the
|
|
" close of the array.
|
|
if prevline =~# '^\s*\]' && l:last_prevline_character ==# ';'
|
|
\ && line !~# '^\s*}'
|
|
return indent(prevlinenum)
|
|
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
|
|
|
|
" 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:
|