1" Vim indent file
2" Language:	Java
3" Maintainer:	Toby Allsopp <toby.allsopp@peace.com> (resigned)
4" Last Change:	2005 Mar 28
5
6" Only load this indent file when no other was loaded.
7if exists("b:did_indent")
8  finish
9endif
10let b:did_indent = 1
11
12" Indent Java anonymous classes correctly.
13setlocal cindent cinoptions& cinoptions+=j1
14
15" The "extends" and "implements" lines start off with the wrong indent.
16setlocal indentkeys& indentkeys+=0=extends indentkeys+=0=implements
17
18" Set the function to do the work.
19setlocal indentexpr=GetJavaIndent()
20
21let b:undo_indent = "set cin< cino< indentkeys< indentexpr<"
22
23" Only define the function once.
24if exists("*GetJavaIndent")
25  finish
26endif
27
28function! SkipJavaBlanksAndComments(startline)
29  let lnum = a:startline
30  while lnum > 1
31    let lnum = prevnonblank(lnum)
32    if getline(lnum) =~ '\*/\s*$'
33      while getline(lnum) !~ '/\*' && lnum > 1
34        let lnum = lnum - 1
35      endwhile
36      if getline(lnum) =~ '^\s*/\*'
37        let lnum = lnum - 1
38      else
39        break
40      endif
41    elseif getline(lnum) =~ '^\s*//'
42      let lnum = lnum - 1
43    else
44      break
45    endif
46  endwhile
47  return lnum
48endfunction
49
50function GetJavaIndent()
51
52  " Java is just like C; use the built-in C indenting and then correct a few
53  " specific cases.
54  let theIndent = cindent(v:lnum)
55
56  " If we're in the middle of a comment then just trust cindent
57  if getline(v:lnum) =~ '^\s*\*'
58    return theIndent
59  endif
60
61  " find start of previous line, in case it was a continuation line
62  let lnum = SkipJavaBlanksAndComments(v:lnum - 1)
63  let prev = lnum
64  while prev > 1
65    let next_prev = SkipJavaBlanksAndComments(prev - 1)
66    if getline(next_prev) !~ ',\s*$'
67      break
68    endif
69    let prev = next_prev
70  endwhile
71
72  " Try to align "throws" lines for methods and "extends" and "implements" for
73  " classes.
74  if getline(v:lnum) =~ '^\s*\(extends\|implements\)\>'
75        \ && getline(lnum) !~ '^\s*\(extends\|implements\)\>'
76    let theIndent = theIndent + &sw
77  endif
78
79  " correct for continuation lines of "throws", "implements" and "extends"
80  let cont_kw = matchstr(getline(prev),
81        \ '^\s*\zs\(throws\|implements\|extends\)\>\ze.*,\s*$')
82  if strlen(cont_kw) > 0
83    let amount = strlen(cont_kw) + 1
84    if getline(lnum) !~ ',\s*$'
85      let theIndent = theIndent - (amount + &sw)
86      if theIndent < 0
87        let theIndent = 0
88      endif
89    elseif prev == lnum
90      let theIndent = theIndent + amount
91      if cont_kw ==# 'throws'
92        let theIndent = theIndent + &sw
93      endif
94    endif
95  elseif getline(prev) =~ '^\s*\(throws\|implements\|extends\)\>'
96        \ && (getline(prev) =~ '{\s*$'
97        \  || getline(v:lnum) =~ '^\s*{\s*$')
98    let theIndent = theIndent - &sw
99  endif
100
101  " When the line starts with a }, try aligning it with the matching {,
102  " skipping over "throws", "extends" and "implements" clauses.
103  if getline(v:lnum) =~ '^\s*}\s*\(//.*\|/\*.*\)\=$'
104    call cursor(v:lnum, 1)
105    silent normal %
106    let lnum = line('.')
107    if lnum < v:lnum
108      while lnum > 1
109        let next_lnum = SkipJavaBlanksAndComments(lnum - 1)
110        if getline(lnum) !~ '^\s*\(throws\|extends\|implements\)\>'
111              \ && getline(next_lnum) !~ ',\s*$'
112          break
113        endif
114        let lnum = prevnonblank(next_lnum)
115      endwhile
116      return indent(lnum)
117    endif
118  endif
119
120  " Below a line starting with "}" never indent more.  Needed for a method
121  " below a method with an indented "throws" clause.
122  let lnum = SkipJavaBlanksAndComments(v:lnum - 1)
123  if getline(lnum) =~ '^\s*}\s*\(//.*\|/\*.*\)\=$' && indent(lnum) < theIndent
124    let theIndent = indent(lnum)
125  endif
126
127  return theIndent
128endfunction
129
130" vi: sw=2 et
131