diff options
| author | Adam Stankiewicz <sheerun@sher.pl> | 2013-09-26 12:44:31 +0200 | 
|---|---|---|
| committer | Adam Stankiewicz <sheerun@sher.pl> | 2013-09-26 12:44:31 +0200 | 
| commit | 90d87abd3051c5acf15bc352c9f51f18e23b7095 (patch) | |
| tree | bf13d90559fdbfeeb7cf79cb0c2e04edfeed7443 /indent | |
| parent | d6710f1b578ee233e92d1810fdb3e5c9fba651f7 (diff) | |
| download | vim-polyglot-90d87abd3051c5acf15bc352c9f51f18e23b7095.tar.gz vim-polyglot-90d87abd3051c5acf15bc352c9f51f18e23b7095.zip | |
Add Rust lang support
Diffstat (limited to 'indent')
| -rw-r--r-- | indent/rust.vim | 147 | 
1 files changed, 147 insertions, 0 deletions
| diff --git a/indent/rust.vim b/indent/rust.vim new file mode 100644 index 00000000..ae3ca403 --- /dev/null +++ b/indent/rust.vim @@ -0,0 +1,147 @@ +" Vim indent file +" Language:         Rust +" Author:           Chris Morgan <me@chrismorgan.info> +" Last Change:      2013 Jul 10 + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") +  finish +endif +let b:did_indent = 1 + +setlocal cindent +setlocal cinoptions=L0,(0,Ws,JN,j1 +setlocal cinkeys=0{,0},!^F,o,O,0[,0] +" Don't think cinwords will actually do anything at all... never mind +setlocal cinwords=do,for,if,else,while,loop,impl,mod,unsafe,trait,struct,enum,fn,extern + +" Some preliminary settings +setlocal nolisp		" Make sure lisp indenting doesn't supersede us +setlocal autoindent	" indentexpr isn't much help otherwise +" Also do indentkeys, otherwise # gets shoved to column 0 :-/ +setlocal indentkeys=0{,0},!^F,o,O,0[,0] + +setlocal indentexpr=GetRustIndent(v:lnum) + +" Only define the function once. +if exists("*GetRustIndent") +  finish +endif + +" 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 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 prevline = s:get_line_trimmed(prevnonblank(a:lnum - 1)) +	if prevline[len(prevline) - 1] == "," +				\ && s:get_line_trimmed(a:lnum) !~ "^\\s*[\\[\\]{}]" +		" Oh ho! The previous line ended in a comma! I bet cindent will try to +		" take this too far... For now, let's use the previous line's indent +		return GetRustIndent(a:lnum - 1) +	endif + +	" cindent 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') == 0 +		if searchpair('\[', '', '\]', 'nbW') == 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 + +	" Fall back on cindent, which does it mostly right +	return cindent(a:lnum) +endfunction | 
