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/rust.vim | |
parent | d6710f1b578ee233e92d1810fdb3e5c9fba651f7 (diff) | |
download | vim-polyglot-90d87abd3051c5acf15bc352c9f51f18e23b7095.tar.gz vim-polyglot-90d87abd3051c5acf15bc352c9f51f18e23b7095.zip |
Add Rust lang support
Diffstat (limited to 'indent/rust.vim')
-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 |