10c4a2e7f3b1b20d12d37f734cd8b57467576c23
[nit.git] / misc / vim / indent / nit.vim
1 " Vim indent file
2 " Language:     Nit
3 " Maintainer:   Jean Privat <jean@pryen.org>
4
5 " This file is part of NIT ( http://www.nitlanguage.org ).
6 "
7 " Copyright 2009 Jean Privat <jean@pryen.org>
8 "
9 " Licensed under the Apache License, Version 2.0 (the "License");
10 " you may not use this file except in compliance with the License.
11 " You may obtain a copy of the License at
12 "
13 "     http://www.apache.org/licenses/LICENSE-2.0
14 "
15 " Unless required by applicable law or agreed to in writing, software
16 " distributed under the License is distributed on an "AS IS" BASIS,
17 " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 " See the License for the specific language governing permissions and
19 " limitations under the License.
20
21 " Only load this indent file when no other was loaded.
22 if exists("b:did_indent")
23         finish
24 endif
25 let b:did_indent = 1
26
27 setlocal indentexpr=GetNITIndent()
28 setlocal nolisp
29 setlocal nosmartindent
30 setlocal nocindent
31 setlocal autoindent
32 setlocal comments=:#
33 setlocal indentkeys+==end,=else,=do,=var,0!,=then,=loop,=special,=class,=interface,=universal
34
35 " Only define the function once.
36 if exists("*GetNITIndent")
37         finish
38 endif
39
40 " Indent after
41 let s:relative_indent = '\<\(do\|loop\|then\|else\|if\)\s*\(#\|$\)\|^\s*\(\<\(redef\|private\)\>\s*\)\?\(\<abstract\>\s*\)\?\<\(class\|interface\|universal\|special\)\>'
42 " Unindent on them
43 let s:outdent = '^\s*\(else\|then\|end\)\>'
44 " At 0
45 let s:no_indent = '^\s*\(class\|import\|special\)\>'
46
47 let s:syng_strcom = '\<NIT\(String\|StringDelimiter\|Escape\|Comment\|Documentation\)\>'
48
49 " Check if the character at lnum:col is inside a string, comment, or is ascii.
50 function s:IsInStringOrComment(lnum, col)
51           return synIDattr(synID(a:lnum, a:col, 0), 'name') =~ s:syng_strcom
52 endfunction
53
54 function s:Match(lnum, regex)
55         let col = match(getline(a:lnum), a:regex) + 1
56         return col > 0 && !s:IsInStringOrComment(a:lnum, col) ? col : 0
57 endfunction
58
59 function GetNITIndent()
60         " Find a non-blank line above the current line.
61         let plnum = prevnonblank(v:lnum - 1)
62
63         " At the start of the file use zero indent.
64         if plnum == 0
65                 return 0
66         endif
67
68         let cline = getline(v:lnum) " The line to indent
69         let prevline=getline(plnum) " The previous nonempty line
70         let ind = indent(plnum) " The previous nonempty indent level
71
72         " Add a 'shiftwidth' after lines that start with an indent word
73         if s:Match(plnum, s:relative_indent)
74         "if prevline =~ s:relative_indent
75                 let ind = ind + &sw
76         endif
77
78         " Subtract a 'shiftwidth', for lines that start with an outdent word
79         "if cline =~ s:outdent
80         if s:Match(v:lnum, s:outdent)
81                 let ind = ind - &sw
82         endif
83
84         " Unindent line after a closure declaration
85         if prevline =~ '^\s*\(break\)\=\s*!'
86                 let col = match(prevline, "!")
87                 let ctx = synIDattr(synID(plnum, col, 0), 'name')
88                 echo "prev is " ctx
89                 if ctx !~ "NITStmtBlock"
90                         " closure declaration
91                         let ind = ind - &sw
92                 end
93         endif
94
95         " Indent line of a closure declaration
96         " Unindent line of a closure definition
97         if cline =~ '^\s*\(break\)\=\s*!'
98                 let col = match(cline, "!")
99                 let ctx = synIDattr(synID(v:lnum, col, 0), 'name')
100                 if ctx =~ "NITStmtBlock"
101                         " closure definition
102                         let ind = ind - &sw
103                 else
104                         " closure declaration
105                         let ind = ind + &sw
106                 end
107         endif
108
109         " The following should always be at the start of a line, no indenting
110         "if cline =~ s:no_indent
111         if s:Match(v:lnum, s:no_indent)
112                 let ind = 0
113         endif
114
115         return ind
116 endfunction