summaryrefslogtreecommitdiff
path: root/runtime/indent/mp.vim
blob: a118eb8b60922f24d2962f80d15e6d8780fa8869 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
" MetaPost indent file
" Language:	MetaPost
" Maintainer:	Eugene Minkovskii <emin@mccme.ru>
" Last Change:	2012 May 18
" Version: 0.1
" ==========================================================================

" Identation Rules: {{{1
" First of all, MetaPost language don't expect any identation rules.
" This screept need for you only if you (not MetaPost) need to do
" exactly code. If you don't need to use indentation, see
" :help filetype-indent-off
"
" Note: Every rules of identation in MetaPost or TeX languages (and in some
" other of course) is very subjective. I can release only my vision of this
" promlem.
"
" ..........................................................................
" Example of correct (by me) identation {{{2
" shiftwidth=4
" ==========================================================================
" for i=0 upto 99:
"     z[i] = (0,1u) rotated (i*360/100);
" endfor
" draw z0 -- z10 -- z20
"         withpen ...     % <- 2sw because breaked line
"         withcolor ...;  % <- same as previous
" draw z0 for i=1 upto 99:
"             -- z[i]             % <- 1sw from left end of 'for' satement
"         endfor withpen ...      % <- 0sw from left end of 'for' satement
"                 withcolor ...;  % <- 2sw because breaked line
" draw if One:     % <- This is internal if (like 'for' above)
"          one
"      elsif Other:
"          other
"      fi withpen ...;
" if one:          % <- This is external if
"     draw one;
" elseif other:
"     draw other;
" fi
" draw z0; draw z1;
" }}}
" }}}

" Only load this indent file when no other was loaded.
if exists("b:did_indent")
  finish
endif
let b:did_indent = 1

setlocal indentexpr=GetMetaPostIndent()
setlocal indentkeys+=;,<:>,=if,=for,=def,=end,=else,=fi

" Only define the function once.
if exists("*GetMetaPostIndent")
  finish
endif
let s:keepcpo= &cpo
set cpo&vim

" Auxiliary Definitions: {{{1
function! MetaNextNonblankNoncomment(pos)
  " Like nextnonblank() but ignore comment lines
  let tmp = nextnonblank(a:pos)
  while tmp && getline(tmp) =~ '^\s*%'
    let tmp = nextnonblank(tmp+1)
  endwhile
  return tmp
endfunction

function! MetaPrevNonblankNoncomment(pos)
  " Like prevnonblank() but ignore comment lines
  let tmp = prevnonblank(a:pos)
  while tmp && getline(tmp) =~ '^\s*%'
    let tmp = prevnonblank(tmp-1)
  endwhile
  return tmp
endfunction

function! MetaSearchNoncomment(pattern, ...)
  " Like search() but ignore commented areas
  if a:0
    let flags = a:1
  elseif &wrapscan
    let flags = "w"
  else
    let flags = "W"
  endif
  let cl  = line(".")
  let cc  = col(".")
  let tmp = search(a:pattern, flags)
  while tmp && synIDattr(synID(line("."), col("."), 1), "name") =~
        \ 'm[fp]\(Comment\|TeXinsert\|String\)'
    let tmp = search(a:pattern, flags)
  endwhile
  if !tmp
    call cursor(cl,cc)
  endif
  return tmp
endfunction
" }}}

function! GetMetaPostIndent()
  " not indent in comment ???
  if synIDattr(synID(line("."), col("."), 1), "name") =~
        \ 'm[fp]\(Comment\|TeXinsert\|String\)'
    return -1
  endif
  " Some RegExps: {{{1
  " end_of_item: all of end by ';'
  "            + all of end by :endfor, :enddef, :endfig, :endgroup, :fi
  "            + all of start by :beginfig(num), :begingroup
  "            + all of start by :for, :if, :else, :elseif and end by ':'
  "            + all of start by :def, :vardef             and end by '='
  let end_of_item = '\('                              .
        \ ';\|'                                       .
        \ '\<\(end\(for\|def\|fig\|group\)\|fi\)\>\|' .
        \ '\<begin\(group\>\|fig\s*(\s*\d\+\s*)\)\|'  .
        \ '\<\(for\|if\|else\(if\)\=\)\>.\+:\|'       .
        \ '\<\(var\)\=def\>.\+='                      . '\)'
  " }}}
  " Save: current position {{{1
  let cl = line   (".")
  let cc = col    (".")
  let cs = getline(".")
  " if it is :beginfig or :endfig use zero indent
  if  cs =~ '^\s*\(begin\|end\)fig\>'
    return 0
  endif
  " }}}
  " Initialise: ind variable {{{1
  " search previous item not in current line
  let p_semicol_l = MetaSearchNoncomment(end_of_item,"bW")
  while p_semicol_l == cl
    let p_semicol_l = MetaSearchNoncomment(end_of_item,"bW")
  endwhile
  " if this is first item in program use zero indent
  if !p_semicol_l
    return 0
  endif
  " if this is multiline item, remember first indent
  if MetaNextNonblankNoncomment(p_semicol_l+1) < cl
    let ind = indent(MetaNextNonblankNoncomment(p_semicol_l+1))
  " else --- search pre-previous item for search first line in previous item
  else
    " search pre-previous item not in current line
    let pp_semicol_l = MetaSearchNoncomment(end_of_item,"bW")
    while pp_semicol_l == p_semicol_l
      let pp_semicol_l = MetaSearchNoncomment(end_of_item,"bW")
    endwhile
    " if we find pre-previous item, remember indent of previous item
    " else --- remember zero
    if pp_semicol_l
      let ind = indent(MetaNextNonblankNoncomment(line(".")+1))
    else
      let ind = 0
    endif
  endif
  " }}}
  " Increase Indent: {{{1
  " if it is an internal/external :for or :if statements {{{2
  let pnn_s = getline(MetaPrevNonblankNoncomment(cl-1))
  if  pnn_s =~ '\<\(for\|if\)\>.\+:\s*\($\|%\)'
    let ind = match(pnn_s, '\<\(for\|if\)\>.\+:\s*\($\|%\)') + &sw
  " }}}
  " if it is a :def, :vardef, :beginfig, :begingroup, :else, :elseif {{{2
  elseif pnn_s =~ '^\s*\('                       .
        \ '\(var\)\=def\|'                       .
        \ 'begin\(group\|fig\s*(\s*\d\+\s*)\)\|' .
        \ 'else\(if\)\='                         . '\)\>'
    let ind = ind + &sw
  " }}}
  " if it is a broken line {{{2
  elseif pnn_s !~ end_of_item.'\s*\($\|%\)'
    let ind = ind + (2 * &sw)
  endif
  " }}}
  " }}}
  " Decrease Indent: {{{1
  " if this is :endfor or :enddef statements {{{2
  " this is correct because :def cannot be inside :for
  if  cs  =~ '\<end\(for\|def\)\=\>'
    call MetaSearchNoncomment('\<for\>.\+:\s*\($\|%\)' . '\|' .
                            \ '^\s*\(var\)\=def\>',"bW")
    if col(".") > 1
      let ind = col(".") - 1
    else
      let ind = indent(".")
    endif
  " }}}
  " if this is :fi, :else, :elseif statements {{{2
  elseif cs =~ '\<\(else\(if\)\=\|fi\)\>'
    call MetaSearchNoncomment('\<if\>.\+:\s*\($\|%\)',"bW")
    let ind = col(".") - 1
  " }}}
  " if this is :endgroup statement {{{2
  elseif cs =~ '^\s*endgroup\>'
    let ind = ind - &sw
  endif
  " }}}
  " }}}

  return ind
endfunction
"

let &cpo = s:keepcpo
unlet s:keepcpo

" vim:sw=2:fdm=marker