Skip to content

Better Vim support #7665

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/etc/vim/ftplugin/rust.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
" Vim syntax file
" Language: Rust
" Maintainer: Chris Morgan <me@chrismorgan.info>
" Last Change: 2013 Jul 6

if exists("b:did_ftplugin")
finish
endif
let b:did_ftplugin = 1

setlocal comments=s1:/*,mb:*,ex:*/,:///,://!,://
setlocal commentstring=//%s
setlocal formatoptions-=t formatoptions+=croqnlj

" This includeexpr isn't perfect, but it's a good start
setlocal includeexpr=substitute(v:fname,'::','/','g')

" NOT adding .rc as it's being phased out (0.7)
setlocal suffixesadd=.rs

if exists("g:ftplugin_rust_source_path")
let &l:path=g:ftplugin_rust_source_path . ',' . &l:path
endif

let b:undo_ftplugin = "setlocal formatoptions< comments< commentstring< includeexpr< suffixesadd<"
132 changes: 129 additions & 3 deletions src/etc/vim/indent/rust.vim
Original file line number Diff line number Diff line change
@@ -1,11 +1,137 @@
" 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
finish
endif

let b:did_indent = 1

setlocal cindent
setlocal cinoptions=L0,(0,Ws,JN
setlocal cinkeys=0{,0},!^F,o,O
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.

if has('syntax_items')
if synIDattr(synID(a:lnum, 1, 1), "name") == "rustString"
" If the start of the line is in a string, don't change the indent
return -1
elseif synIDattr(synID(a:lnum, 1, 1), "name") =~ "\\(Comment\\|Todo\\)"
\ && getline(a:lnum) !~ "^\\s*/\\*"
" 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)

let line = getline(a:lnum)
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
30 changes: 19 additions & 11 deletions src/etc/vim/syntax/rust.vim
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
" Language: Rust
" Maintainer: Patrick Walton <pcwalton@mozilla.com>
" Maintainer: Ben Blum <bblum@cs.cmu.edu>
" Last Change: 2013 Jun 14
" Maintainer: Chris Morgan <me@chrismorgan.info>
" Last Change: 2013 Jul 10

if version < 600
syntax clear
Expand All @@ -13,8 +14,8 @@ endif
syn keyword rustConditional match if else
syn keyword rustOperator as

syn match rustAssert "\<assert\(\w\)*!"
syn match rustFail "\<fail\(\w\)*!"
syn match rustAssert "\<assert\(\w\)*!" contained
syn match rustFail "\<fail\(\w\)*!" contained
syn keyword rustKeyword break copy do extern
syn keyword rustKeyword for if impl let log
syn keyword rustKeyword copy do extern
Expand Down Expand Up @@ -90,7 +91,7 @@ syn match rustFormat display "%%" contained
syn region rustString start=+L\="+ skip=+\\\\\|\\"+ end=+"+ contains=rustTodo,rustFormat

syn region rustAttribute start="#\[" end="\]" contains=rustString,rustDeriving
syn region rustDeriving start="deriving(" end=")" contains=rustTrait
syn region rustDeriving start="deriving(" end=")" contained contains=rustTrait

" Number literals
syn match rustNumber display "\<[0-9][0-9_]*\>"
Expand All @@ -116,13 +117,18 @@ syn match rustFloat display "\<[0-9][0-9_]*\.[0-9_]\+\%([eE][+-]\=[0-9
syn match rustLifetime display "\'\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*"
syn match rustCharacter "'\([^'\\]\|\\\(['nrt\\\"]\|x\x\{2}\|u\x\{4}\|U\x\{8}\)\)'"

syn region rustCommentDoc start="/\*[\*!]" end="\*/"
syn region rustCommentDoc start="//[/!]" skip="\\$" end="$" keepend
syn match rustComment "/\*\*/"
syn region rustComment start="/\*\([^\*!]\|$\)" end="\*/" contains=rustTodo
syn region rustComment start="//\([^/!]\|$\)" skip="\\$" end="$" contains=rustTodo keepend
syn region rustComment start="/\*" end="\*/" contains=rustTodo
syn region rustComment start="//" skip="\\$" end="$" contains=rustTodo keepend
syn region rustCommentDoc start="/\*\%(!\|\*/\@!\)" end="\*/" contains=rustTodo
syn region rustCommentDoc start="//[/!]" skip="\\$" end="$" contains=rustTodo keepend

syn keyword rustTodo contained TODO FIXME XXX NB
syn keyword rustTodo contained TODO FIXME XXX NB NOTE

" Trivial folding rules to begin with.
" TODO: use the AST to make really good folding
syn region rustFoldBraces start="{" end="}" transparent fold
" If you wish to enable this, setlocal foldmethod=syntax
" It's not enabled by default as it would drive some people mad.

hi def link rustHexNumber rustNumber
hi def link rustBinNumber rustNumber
Expand All @@ -142,10 +148,13 @@ hi def link rustKeyword Keyword
hi def link rustConditional Conditional
hi def link rustIdentifier Identifier
hi def link rustModPath Include
hi def link rustModPathSep Delimiter
hi def link rustFuncName Function
hi def link rustFuncCall Function
hi def link rustCommentDoc SpecialComment
hi def link rustComment Comment
hi def link rustAssert PreCondit
hi def link rustFail PreCondit
hi def link rustMacro Macro
hi def link rustType Type
hi def link rustTodo Todo
Expand All @@ -160,7 +169,6 @@ hi def link rustLifetime Special
" hi rustAssert ctermfg=yellow
" hi rustFail ctermfg=red
" hi rustMacro ctermfg=magenta
" hi rustModPathSep ctermfg=grey

syn sync minlines=200
syn sync maxlines=500
Expand Down