1" MetaPost indent file
2" Language:	MetaPost
3" Maintainer:	Eugene Minkovskii <emin@mccme.ru>
4" Last Change:	2003 Nov 21
5" Version: 0.1
6" ==========================================================================
7
8" Identation Rules: {{{1
9" First of all, MetaPost language don't expect any identation rules.
10" This screept need for you only if you (not MetaPost) need to do
11" exactly code. If you don't need to use indentation, see
12" :help filetype-indent-off
13"
14" Note: Every rules of identation in MetaPost or TeX languages (and in some
15" other of course) is very subjective. I can release only my vision of this
16" promlem.
17"
18" ..........................................................................
19" Example of correct (by me) identation {{{2
20" shiftwidth=4
21" ==========================================================================
22" for i=0 upto 99:
23"     z[i] = (0,1u) rotated (i*360/100);
24" endfor
25" draw z0 -- z10 -- z20
26"         withpen ...     % <- 2sw because breaked line
27"         withcolor ...;  % <- same as previous
28" draw z0 for i=1 upto 99:
29"             -- z[i]             % <- 1sw from left end of 'for' satement
30"         endfor withpen ...      % <- 0sw from left end of 'for' satement
31"                 withcolor ...;  % <- 2sw because breaked line
32" draw if One:     % <- This is internal if (like 'for' above)
33"          one
34"      elsif Other:
35"          other
36"      fi withpen ...;
37" if one:          % <- This is external if
38"     draw one;
39" elseif other:
40"     draw other;
41" fi
42" draw z0; draw z1;
43" }}}
44" }}}
45
46" Only load this indent file when no other was loaded.
47if exists("b:did_indent")
48  finish
49endif
50let b:did_indent = 1
51
52setlocal indentexpr=GetMetaPostIndent()
53setlocal indentkeys+=;,<:>,=if,=for,=def,=end,=else,=fi
54
55" Only define the function once.
56if exists("*GetMetaPostIndent")
57  finish
58endif
59
60" Auxiliary Definitions: {{{1
61function! MetaNextNonblankNoncomment(pos)
62  " Like nextnonblank() but ignore comment lines
63  let tmp = nextnonblank(a:pos)
64  while tmp && getline(tmp) =~ '^\s*%'
65    let tmp = nextnonblank(tmp+1)
66  endwhile
67  return tmp
68endfunction
69
70function! MetaPrevNonblankNoncomment(pos)
71  " Like prevnonblank() but ignore comment lines
72  let tmp = prevnonblank(a:pos)
73  while tmp && getline(tmp) =~ '^\s*%'
74    let tmp = prevnonblank(tmp-1)
75  endwhile
76  return tmp
77endfunction
78
79function! MetaSearchNoncomment(pattern, ...)
80  " Like search() but ignore commented areas
81  if a:0
82    let flags = a:1
83  elseif &wrapscan
84    let flags = "w"
85  else
86    let flags = "W"
87  endif
88  let cl  = line(".")
89  let cc  = col(".")
90  let tmp = search(a:pattern, flags)
91  while tmp && synIDattr(synID(line("."), col("."), 1), "name") =~
92        \ 'm[fp]\(Comment\|TeXinsert\|String\)'
93    let tmp = search(a:pattern, flags)
94  endwhile
95  if !tmp
96    call cursor(cl,cc)
97  endif
98  return tmp
99endfunction
100" }}}
101
102function! GetMetaPostIndent()
103  " not indent in comment ???
104  if synIDattr(synID(line("."), col("."), 1), "name") =~
105        \ 'm[fp]\(Comment\|TeXinsert\|String\)'
106    return -1
107  endif
108  " Some RegExps: {{{1
109  " end_of_item: all of end by ';'
110  "            + all of end by :endfor, :enddef, :endfig, :endgroup, :fi
111  "            + all of start by :beginfig(num), :begingroup
112  "            + all of start by :for, :if, :else, :elseif and end by ':'
113  "            + all of start by :def, :vardef             and end by '='
114  let end_of_item = '\('                              .
115        \ ';\|'                                       .
116        \ '\<\(end\(for\|def\|fig\|group\)\|fi\)\>\|' .
117        \ '\<begin\(group\>\|fig\s*(\s*\d\+\s*)\)\|'  .
118        \ '\<\(for\|if\|else\(if\)\=\)\>.\+:\|'       .
119        \ '\<\(var\)\=def\>.\+='                      . '\)'
120  " }}}
121  " Save: current position {{{1
122  let cl = line   (".")
123  let cc = col    (".")
124  let cs = getline(".")
125  " if it is :beginfig or :endfig use zero indent
126  if  cs =~ '^\s*\(begin\|end\)fig\>'
127    return 0
128  endif
129  " }}}
130  " Initialise: ind variable {{{1
131  " search previous item not in current line
132  let p_semicol_l = MetaSearchNoncomment(end_of_item,"bW")
133  while p_semicol_l == cl
134    let p_semicol_l = MetaSearchNoncomment(end_of_item,"bW")
135  endwhile
136  " if this is first item in program use zero indent
137  if !p_semicol_l
138    return 0
139  endif
140  " if this is multiline item, remember first indent
141  if MetaNextNonblankNoncomment(p_semicol_l+1) < cl
142    let ind = indent(MetaNextNonblankNoncomment(p_semicol_l+1))
143  " else --- search pre-previous item for search first line in previous item
144  else
145    " search pre-previous item not in current line
146    let pp_semicol_l = MetaSearchNoncomment(end_of_item,"bW")
147    while pp_semicol_l == p_semicol_l
148      let pp_semicol_l = MetaSearchNoncomment(end_of_item,"bW")
149    endwhile
150    " if we find pre-previous item, remember indent of previous item
151    " else --- remember zero
152    if pp_semicol_l
153      let ind = indent(MetaNextNonblankNoncomment(line(".")+1))
154    else
155      let ind = 0
156    endif
157  endif
158  " }}}
159  " Increase Indent: {{{1
160  " if it is an internal/external :for or :if statements {{{2
161  let pnn_s = getline(MetaPrevNonblankNoncomment(cl-1))
162  if  pnn_s =~ '\<\(for\|if\)\>.\+:\s*\($\|%\)'
163    let ind = match(pnn_s, '\<\(for\|if\)\>.\+:\s*\($\|%\)') + &sw
164  " }}}
165  " if it is a :def, :vardef, :beginfig, :begingroup, :else, :elseif {{{2
166  elseif pnn_s =~ '^\s*\('                       .
167        \ '\(var\)\=def\|'                       .
168        \ 'begin\(group\|fig\s*(\s*\d\+\s*)\)\|' .
169        \ 'else\(if\)\='                         . '\)\>'
170    let ind = ind + &sw
171  " }}}
172  " if it is a broken line {{{2
173  elseif pnn_s !~ end_of_item.'\s*\($\|%\)'
174    let ind = ind + (2 * &sw)
175  endif
176  " }}}
177  " }}}
178  " Decrease Indent: {{{1
179  " if this is :endfor or :enddef statements {{{2
180  " this is correct because :def cannot be inside :for
181  if  cs  =~ '\<end\(for\|def\)\=\>'
182    call MetaSearchNoncomment('\<for\>.\+:\s*\($\|%\)' . '\|' .
183                            \ '^\s*\(var\)\=def\>',"bW")
184    if col(".") > 1
185      let ind = col(".") - 1
186    else
187      let ind = indent(".")
188    endif
189  " }}}
190  " if this is :fi, :else, :elseif statements {{{2
191  elseif cs =~ '\<\(else\(if\)\=\|fi\)\>'
192    call MetaSearchNoncomment('\<if\>.\+:\s*\($\|%\)',"bW")
193    let ind = col(".") - 1
194  " }}}
195  " if this is :endgroup statement {{{2
196  elseif cs =~ '^\s*endgroup\>'
197    let ind = ind - &sw
198  endif
199  " }}}
200  " }}}
201
202  return ind
203endfunction
204"
205
206" vim:sw=2:fdm=marker
207