xref: /vim-8.2.3635/runtime/indent/mp.vim (revision dc083288)
1071d4279SBram Moolenaar" MetaPost indent file
2071d4279SBram Moolenaar" Language:           MetaPost
32ec618c9SBram Moolenaar" Maintainer:         Nicola Vitacolonna <[email protected]>
42ec618c9SBram Moolenaar" Former Maintainers: Eugene Minkovskii <[email protected]>
5*dc083288SBram Moolenaar" Last Change:        2016 Oct 2, 4:13pm
62ec618c9SBram Moolenaar" Version: 0.2
7071d4279SBram Moolenaar
8071d4279SBram Moolenaarif exists("b:did_indent")
9071d4279SBram Moolenaar  finish
10071d4279SBram Moolenaarendif
11071d4279SBram Moolenaarlet b:did_indent = 1
12071d4279SBram Moolenaar
13071d4279SBram Moolenaarsetlocal indentexpr=GetMetaPostIndent()
142ec618c9SBram Moolenaarsetlocal indentkeys+==end,=else,=fi,=fill,0),0]
152ec618c9SBram Moolenaar
162ec618c9SBram Moolenaarlet b:undo_indent = "setl indentkeys< indentexpr<"
17071d4279SBram Moolenaar
18071d4279SBram Moolenaar" Only define the function once.
19071d4279SBram Moolenaarif exists("*GetMetaPostIndent")
20071d4279SBram Moolenaar  finish
21071d4279SBram Moolenaarendif
228e52a593SBram Moolenaarlet s:keepcpo= &cpo
238e52a593SBram Moolenaarset cpo&vim
24071d4279SBram Moolenaar
252ec618c9SBram Moolenaarfunction GetMetaPostIndent()
262ec618c9SBram Moolenaar  let ignorecase_save = &ignorecase
272ec618c9SBram Moolenaar  try
282ec618c9SBram Moolenaar    let &ignorecase = 0
292ec618c9SBram Moolenaar    return GetMetaPostIndentIntern()
302ec618c9SBram Moolenaar  finally
312ec618c9SBram Moolenaar    let &ignorecase = ignorecase_save
322ec618c9SBram Moolenaar  endtry
332ec618c9SBram Moolenaarendfunc
34071d4279SBram Moolenaar
352ec618c9SBram Moolenaar" Regexps {{{
362ec618c9SBram Moolenaar" Note: the next three variables are made global so that a user may add
372ec618c9SBram Moolenaar" further keywords.
38071d4279SBram Moolenaar"
392ec618c9SBram Moolenaar" Example:
402ec618c9SBram Moolenaar"
412ec618c9SBram Moolenaar"    Put these in ~/.vim/after/indent/mp.vim
422ec618c9SBram Moolenaar"
432ec618c9SBram Moolenaar"    let g:mp_open_tag .= '\|\<begintest\>'
442ec618c9SBram Moolenaar"    let g:mp_close_tag .= '\|\<endtest\>'
452ec618c9SBram Moolenaar
462ec618c9SBram Moolenaar" Expressions starting indented blocks
472ec618c9SBram Moolenaarlet g:mp_open_tag = ''
482ec618c9SBram Moolenaar      \ . '\<if\>'
492ec618c9SBram Moolenaar      \ . '\|\<else\%[if]\>'
502ec618c9SBram Moolenaar      \ . '\|\<for\%(\|ever\|suffixes\)\>'
512ec618c9SBram Moolenaar      \ . '\|\<begingroup\>'
522ec618c9SBram Moolenaar      \ . '\|\<\%(\|var\|primary\|secondary\|tertiary\)def\>'
532ec618c9SBram Moolenaar      \ . '\|^\s*\<begin\%(fig\|graph\|glyph\|char\|logochar\)\>'
542ec618c9SBram Moolenaar      \ . '\|[([{]'
552ec618c9SBram Moolenaar
562ec618c9SBram Moolenaar" Expressions ending indented blocks
572ec618c9SBram Moolenaarlet g:mp_close_tag = ''
582ec618c9SBram Moolenaar      \ . '\<fi\>'
592ec618c9SBram Moolenaar      \ . '\|\<else\%[if]\>'
60*dc083288SBram Moolenaar      \ . '\|\<end\%(\|for\|group\|def\|fig\|char\|glyph\|graph\)\>'
612ec618c9SBram Moolenaar      \ . '\|[)\]}]'
622ec618c9SBram Moolenaar
632ec618c9SBram Moolenaar" Statements that may span multiple lines and are ended by a semicolon. To
642ec618c9SBram Moolenaar" keep this list short, statements that are unlikely to be very long or are
652ec618c9SBram Moolenaar" not very common (e.g., keywords like `interim` or `showtoken`) are not
662ec618c9SBram Moolenaar" included.
672ec618c9SBram Moolenaar"
682ec618c9SBram Moolenaar" The regex for assignments and equations (the last branch) is tricky, because
692ec618c9SBram Moolenaar" it must not match things like `for i :=`, `if a=b`, `def...=`, etc... It is
702ec618c9SBram Moolenaar" not perfect, but it works reasonably well.
712ec618c9SBram Moolenaarlet g:mp_statement = ''
722ec618c9SBram Moolenaar      \ . '\<\%(\|un\|cut\)draw\>'
732ec618c9SBram Moolenaar      \ . '\|\<\%(\|un\)fill\%[draw]\>'
742ec618c9SBram Moolenaar      \ . '\|\<draw\%(dbl\)\=arrow\>'
752ec618c9SBram Moolenaar      \ . '\|\<clip\>'
762ec618c9SBram Moolenaar      \ . '\|\<addto\>'
772ec618c9SBram Moolenaar      \ . '\|\<save\>'
782ec618c9SBram Moolenaar      \ . '\|\<setbounds\>'
792ec618c9SBram Moolenaar      \ . '\|\<message\>'
802ec618c9SBram Moolenaar      \ . '\|\<errmessage\>'
812ec618c9SBram Moolenaar      \ . '\|\<errhelp\>'
822ec618c9SBram Moolenaar      \ . '\|\<fontmapline\>'
832ec618c9SBram Moolenaar      \ . '\|\<pickup\>'
842ec618c9SBram Moolenaar      \ . '\|\<show\>'
852ec618c9SBram Moolenaar      \ . '\|\<special\>'
862ec618c9SBram Moolenaar      \ . '\|\<write\>'
872ec618c9SBram Moolenaar      \ . '\|\%(^\|;\)\%([^;=]*\%('.g:mp_open_tag.'\)\)\@!.\{-}:\=='
882ec618c9SBram Moolenaar
892ec618c9SBram Moolenaar" A line ends with zero or more spaces, possibly followed by a comment.
902ec618c9SBram Moolenaarlet s:eol = '\s*\%($\|%\)'
912ec618c9SBram Moolenaar" }}}
922ec618c9SBram Moolenaar
932ec618c9SBram Moolenaar" Auxiliary functions {{{
942ec618c9SBram Moolenaar" Returns 1 if (0-based) position immediately preceding `pos` in `line` is
952ec618c9SBram Moolenaar" inside a string or a comment; returns 0 otherwise.
962ec618c9SBram Moolenaar
972ec618c9SBram Moolenaar" This is the function that is called more often when indenting, so it is
982ec618c9SBram Moolenaar" critical that it is efficient. The method we use is significantly faster
992ec618c9SBram Moolenaar" than using syntax attributes, and more general (it does not require
1002ec618c9SBram Moolenaar" syntax_items). It is also faster than using a single regex matching an even
1012ec618c9SBram Moolenaar" number of quotes. It helps that MetaPost strings cannot span more than one
1022ec618c9SBram Moolenaar" line and cannot contain escaped quotes.
1032ec618c9SBram Moolenaarfunction! s:CommentOrString(line, pos)
1042ec618c9SBram Moolenaar  let in_string = 0
1052ec618c9SBram Moolenaar  let q = stridx(a:line, '"')
1062ec618c9SBram Moolenaar  let c = stridx(a:line, '%')
1072ec618c9SBram Moolenaar  while q >= 0 && q < a:pos
1082ec618c9SBram Moolenaar    if c >= 0 && c < q
1092ec618c9SBram Moolenaar      if in_string " Find next percent symbol
1102ec618c9SBram Moolenaar        let c = stridx(a:line, '%', q + 1)
1112ec618c9SBram Moolenaar      else " Inside comment
1122ec618c9SBram Moolenaar        return 1
1132ec618c9SBram Moolenaar      endif
1142ec618c9SBram Moolenaar    endif
1152ec618c9SBram Moolenaar    let in_string = 1 - in_string
1162ec618c9SBram Moolenaar    let q = stridx(a:line, '"', q + 1) " Find next quote
1172ec618c9SBram Moolenaar  endwhile
1182ec618c9SBram Moolenaar  return in_string || (c >= 0 && c <= a:pos)
1192ec618c9SBram Moolenaarendfunction
1202ec618c9SBram Moolenaar
121*dc083288SBram Moolenaar" Find the first non-comment non-blank line before the current line.
1222ec618c9SBram Moolenaarfunction! s:PrevNonBlankNonComment(lnum)
1232ec618c9SBram Moolenaar  let l:lnum = prevnonblank(a:lnum - 1)
124*dc083288SBram Moolenaar  while getline(l:lnum) =~# '^\s*%'
1252ec618c9SBram Moolenaar    let l:lnum = prevnonblank(l:lnum - 1)
1262ec618c9SBram Moolenaar  endwhile
1272ec618c9SBram Moolenaar  return l:lnum
1282ec618c9SBram Moolenaarendfunction
1292ec618c9SBram Moolenaar
1302ec618c9SBram Moolenaar" Returns true if the last tag appearing in the line is an open tag; returns
1312ec618c9SBram Moolenaar" false otherwise.
1322ec618c9SBram Moolenaarfunction! s:LastTagIsOpen(line)
1332ec618c9SBram Moolenaar  let o = s:LastValidMatchEnd(a:line, g:mp_open_tag, 0)
1342ec618c9SBram Moolenaar  if o == - 1 | return v:false | endif
1352ec618c9SBram Moolenaar  return s:LastValidMatchEnd(a:line, g:mp_close_tag, o) < 0
1362ec618c9SBram Moolenaarendfunction
1372ec618c9SBram Moolenaar
1382ec618c9SBram Moolenaar" A simple, efficient and quite effective heuristics is used to test whether
1392ec618c9SBram Moolenaar" a line should cause the next line to be indented: count the "opening tags"
1402ec618c9SBram Moolenaar" (if, for, def, ...) in the line, count the "closing tags" (endif, endfor,
1412ec618c9SBram Moolenaar" ...) in the line, and compute the difference. We call the result the
1422ec618c9SBram Moolenaar" "weight" of the line. If the weight is positive, then the next line should
1432ec618c9SBram Moolenaar" most likely be indented. Note that `else` and `elseif` are both opening and
1442ec618c9SBram Moolenaar" closing tags, so they "cancel out" in almost all cases, the only exception
1452ec618c9SBram Moolenaar" being a leading `else[if]`, which is counted as an opening tag, but not as
1462ec618c9SBram Moolenaar" a closing tag (so that, for instance, a line containing a single `else:`
1472ec618c9SBram Moolenaar" will have weight equal to one, not zero). We do not treat a trailing
1482ec618c9SBram Moolenaar" `else[if]` in any special way, because lines ending with an open tag are
1492ec618c9SBram Moolenaar" dealt with separately before this function is called (see
1502ec618c9SBram Moolenaar" GetMetaPostIndentIntern()).
1512ec618c9SBram Moolenaar"
1522ec618c9SBram Moolenaar" Example:
1532ec618c9SBram Moolenaar"
1542ec618c9SBram Moolenaar"     forsuffixes $=a,b: if x.$ = y.$ : draw else: fill fi
1552ec618c9SBram Moolenaar"       % This line will be indented because |{forsuffixes,if,else}| > |{else,fi}| (3 > 2)
1562ec618c9SBram Moolenaar"     endfor
1572ec618c9SBram Moolenaar
1582ec618c9SBram Moolenaarfunction! s:Weight(line)
1592ec618c9SBram Moolenaar  let [o, i] = [0, s:ValidMatchEnd(a:line, g:mp_open_tag, 0)]
1602ec618c9SBram Moolenaar  while i > 0
1612ec618c9SBram Moolenaar    let o += 1
1622ec618c9SBram Moolenaar    let i = s:ValidMatchEnd(a:line, g:mp_open_tag, i)
1632ec618c9SBram Moolenaar  endwhile
1642ec618c9SBram Moolenaar  let [c, i] = [0, matchend(a:line, '^\s*\<else\%[if]\>')] " Skip a leading else[if]
1652ec618c9SBram Moolenaar  let i = s:ValidMatchEnd(a:line, g:mp_close_tag, i)
1662ec618c9SBram Moolenaar  while i > 0
1672ec618c9SBram Moolenaar    let c += 1
1682ec618c9SBram Moolenaar    let i = s:ValidMatchEnd(a:line, g:mp_close_tag, i)
1692ec618c9SBram Moolenaar  endwhile
1702ec618c9SBram Moolenaar  return o - c
1712ec618c9SBram Moolenaarendfunction
1722ec618c9SBram Moolenaar
1732ec618c9SBram Moolenaar" Similar to matchend(), but skips strings and comments.
1742ec618c9SBram Moolenaar" line: a String
1752ec618c9SBram Moolenaarfunction! s:ValidMatchEnd(line, pat, start)
1762ec618c9SBram Moolenaar  let i = matchend(a:line, a:pat, a:start)
1772ec618c9SBram Moolenaar  while i > 0 && s:CommentOrString(a:line, i)
1782ec618c9SBram Moolenaar    let i = matchend(a:line, a:pat, i)
1792ec618c9SBram Moolenaar  endwhile
1802ec618c9SBram Moolenaar  return i
1812ec618c9SBram Moolenaarendfunction
1822ec618c9SBram Moolenaar
1832ec618c9SBram Moolenaar" Like s:ValidMatchEnd(), but returns the end position of the last (i.e.,
1842ec618c9SBram Moolenaar" rightmost) match.
1852ec618c9SBram Moolenaarfunction! s:LastValidMatchEnd(line, pat, start)
1862ec618c9SBram Moolenaar  let last_found = -1
1872ec618c9SBram Moolenaar  let i = matchend(a:line, a:pat, a:start)
1882ec618c9SBram Moolenaar  while i > 0
1892ec618c9SBram Moolenaar    if !s:CommentOrString(a:line, i)
1902ec618c9SBram Moolenaar      let last_found = i
1912ec618c9SBram Moolenaar    endif
1922ec618c9SBram Moolenaar    let i = matchend(a:line, a:pat, i)
1932ec618c9SBram Moolenaar  endwhile
1942ec618c9SBram Moolenaar  return last_found
1952ec618c9SBram Moolenaarendfunction
1962ec618c9SBram Moolenaar
1972ec618c9SBram Moolenaarfunction! s:DecreaseIndentOnClosingTag(curr_indent)
1982ec618c9SBram Moolenaar  let cur_text = getline(v:lnum)
1992ec618c9SBram Moolenaar  if cur_text =~# '^\s*\%('.g:mp_close_tag.'\)'
2002ec618c9SBram Moolenaar    return max([a:curr_indent - shiftwidth(), 0])
2012ec618c9SBram Moolenaar  endif
2022ec618c9SBram Moolenaar  return a:curr_indent
2032ec618c9SBram Moolenaarendfunction
2042ec618c9SBram Moolenaar" }}}
2052ec618c9SBram Moolenaar
2062ec618c9SBram Moolenaar" Main function {{{
2072ec618c9SBram Moolenaar"
2082ec618c9SBram Moolenaar" Note: Every rule of indentation in MetaPost is very subjective. We might get
2092ec618c9SBram Moolenaar" creative, but things get murky very soon (there are too many corner cases).
2102ec618c9SBram Moolenaar" So, we provide a means for the user to decide what to do when this script
2112ec618c9SBram Moolenaar" doesn't get it. We use a simple idea: use '%>', '%<' and '%=' to explicitly
2122ec618c9SBram Moolenaar" control indentation. The '<' and '>' symbols may be repeated many times
2132ec618c9SBram Moolenaar" (e.g., '%>>' will cause the next line to be indented twice).
2142ec618c9SBram Moolenaar"
2152ec618c9SBram Moolenaar" By using '%>...', '%<...' and '%=', the indentation the user wants is
2162ec618c9SBram Moolenaar" preserved by commands like gg=G, even if it does not follow the rules of
2172ec618c9SBram Moolenaar" this script.
2182ec618c9SBram Moolenaar"
2192ec618c9SBram Moolenaar" Example:
2202ec618c9SBram Moolenaar"
2212ec618c9SBram Moolenaar"    def foo =
222*dc083288SBram Moolenaar"        makepen(
223*dc083288SBram Moolenaar"            subpath(T-n,t) of r  %>
2242ec618c9SBram Moolenaar"                shifted .5down   %>
225*dc083288SBram Moolenaar"                    --subpath(t,T) of r shifted .5up -- cycle   %<<<
226*dc083288SBram Moolenaar"        )
2272ec618c9SBram Moolenaar"        withcolor black
2282ec618c9SBram Moolenaar"    enddef
2292ec618c9SBram Moolenaar"
2302ec618c9SBram Moolenaar" The default indentation of the previous example would be:
2312ec618c9SBram Moolenaar"
2322ec618c9SBram Moolenaar"    def foo =
233*dc083288SBram Moolenaar"        makepen(
234*dc083288SBram Moolenaar"            subpath(T-n,t) of r
2352ec618c9SBram Moolenaar"            shifted .5down
236*dc083288SBram Moolenaar"            --subpath(t,T) of r shifted .5up -- cycle
237*dc083288SBram Moolenaar"        )
2382ec618c9SBram Moolenaar"        withcolor black
2392ec618c9SBram Moolenaar"    enddef
2402ec618c9SBram Moolenaar"
2412ec618c9SBram Moolenaar" Personally, I prefer the latter, but anyway...
2422ec618c9SBram Moolenaarfunction! GetMetaPostIndentIntern()
243*dc083288SBram Moolenaar  " Do not touch indentation inside verbatimtex/btex.. etex blocks.
244*dc083288SBram Moolenaar  if synIDattr(synID(v:lnum, 1, 1), "name") =~# '^mpTeXinsert$\|^tex\|^Delimiter'
245*dc083288SBram Moolenaar    return -1
246*dc083288SBram Moolenaar  endif
2472ec618c9SBram Moolenaar
2482ec618c9SBram Moolenaar  " This is the reference line relative to which the current line is indented
2492ec618c9SBram Moolenaar  " (but see below).
2502ec618c9SBram Moolenaar  let lnum = s:PrevNonBlankNonComment(v:lnum)
2512ec618c9SBram Moolenaar
2522ec618c9SBram Moolenaar  " At the start of the file use zero indent.
2532ec618c9SBram Moolenaar  if lnum == 0
2542ec618c9SBram Moolenaar    return 0
2552ec618c9SBram Moolenaar  endif
2562ec618c9SBram Moolenaar
2572ec618c9SBram Moolenaar  let prev_text = getline(lnum)
2582ec618c9SBram Moolenaar
2592ec618c9SBram Moolenaar  " User-defined overrides take precedence over anything else.
2602ec618c9SBram Moolenaar  " See above for an example.
2612ec618c9SBram Moolenaar  let j = match(prev_text, '%[<>=]')
2622ec618c9SBram Moolenaar  if j > 0
2632ec618c9SBram Moolenaar    let i = strlen(matchstr(prev_text, '%>\+', j)) - 1
2642ec618c9SBram Moolenaar    if i > 0
2652ec618c9SBram Moolenaar      return indent(lnum) + i * shiftwidth()
2662ec618c9SBram Moolenaar    endif
2672ec618c9SBram Moolenaar
2682ec618c9SBram Moolenaar    let i = strlen(matchstr(prev_text, '%<\+', j)) - 1
2692ec618c9SBram Moolenaar    if i > 0
2702ec618c9SBram Moolenaar      return max([indent(lnum) - i * shiftwidth(), 0])
2712ec618c9SBram Moolenaar    endif
2722ec618c9SBram Moolenaar
2732ec618c9SBram Moolenaar    if match(prev_text, '%=', j)
2742ec618c9SBram Moolenaar      return indent(lnum)
2752ec618c9SBram Moolenaar    endif
2762ec618c9SBram Moolenaar  endif
2772ec618c9SBram Moolenaar
2782ec618c9SBram Moolenaar  " If the reference line ends with an open tag, indent.
2792ec618c9SBram Moolenaar  "
2802ec618c9SBram Moolenaar  " Example:
2812ec618c9SBram Moolenaar  "
2822ec618c9SBram Moolenaar  " if c:
2832ec618c9SBram Moolenaar  "     0
2842ec618c9SBram Moolenaar  " else:
2852ec618c9SBram Moolenaar  "     1
2862ec618c9SBram Moolenaar  " fi if c2: % Note that this line has weight equal to zero.
2872ec618c9SBram Moolenaar  "     ...   % This line will be indented
2882ec618c9SBram Moolenaar  if s:LastTagIsOpen(prev_text)
2892ec618c9SBram Moolenaar    return s:DecreaseIndentOnClosingTag(indent(lnum) + shiftwidth())
2902ec618c9SBram Moolenaar  endif
2912ec618c9SBram Moolenaar
2922ec618c9SBram Moolenaar  " Lines with a positive weight are unbalanced and should likely be indented.
2932ec618c9SBram Moolenaar  "
2942ec618c9SBram Moolenaar  " Example:
2952ec618c9SBram Moolenaar  "
2962ec618c9SBram Moolenaar  " def f = enddef for i = 1 upto 5: if x[i] > 0: 1 else: 2 fi
2972ec618c9SBram Moolenaar  "     ... % This line will be indented (because of the unterminated `for`)
2982ec618c9SBram Moolenaar  if s:Weight(prev_text) > 0
2992ec618c9SBram Moolenaar    return s:DecreaseIndentOnClosingTag(indent(lnum) + shiftwidth())
3002ec618c9SBram Moolenaar  endif
3012ec618c9SBram Moolenaar
3022ec618c9SBram Moolenaar  " Unterminated statements cause indentation to kick in.
3032ec618c9SBram Moolenaar  "
3042ec618c9SBram Moolenaar  " Example:
3052ec618c9SBram Moolenaar  "
3062ec618c9SBram Moolenaar  " draw unitsquare
3072ec618c9SBram Moolenaar  "     withcolor black; % This line is indented because of `draw`.
3082ec618c9SBram Moolenaar  " x := a + b + c
3092ec618c9SBram Moolenaar  "     + d + e;         % This line is indented because of `:=`.
3102ec618c9SBram Moolenaar  "
3112ec618c9SBram Moolenaar  let i = s:LastValidMatchEnd(prev_text, g:mp_statement, 0)
3122ec618c9SBram Moolenaar  if i >= 0 " Does the line contain a statement?
3132ec618c9SBram Moolenaar    if s:ValidMatchEnd(prev_text, ';', i) < 0 " Is the statement unterminated?
3142ec618c9SBram Moolenaar      return indent(lnum) + shiftwidth()
3152ec618c9SBram Moolenaar    else
3162ec618c9SBram Moolenaar      return s:DecreaseIndentOnClosingTag(indent(lnum))
3172ec618c9SBram Moolenaar    endif
3182ec618c9SBram Moolenaar  endif
3192ec618c9SBram Moolenaar
3202ec618c9SBram Moolenaar  " Deal with the special case of a statement spanning multiple lines. If the
3212ec618c9SBram Moolenaar  " current reference line L ends with a semicolon, search backwards for
3222ec618c9SBram Moolenaar  " another semicolon or a statement keyword. If the latter is found first,
3232ec618c9SBram Moolenaar  " its line is used as the reference line for indenting the current line
3242ec618c9SBram Moolenaar  " instead of L.
3252ec618c9SBram Moolenaar  "
3262ec618c9SBram Moolenaar  "  Example:
3272ec618c9SBram Moolenaar  "
3282ec618c9SBram Moolenaar  "  if cond:
3292ec618c9SBram Moolenaar  "    draw if a: z0 else: z1 fi
3302ec618c9SBram Moolenaar  "        shifted S
3312ec618c9SBram Moolenaar  "        scaled T;      % L
3322ec618c9SBram Moolenaar  "
3332ec618c9SBram Moolenaar  "    for i = 1 upto 3:  % <-- Current line: this gets the same indent as `draw ...`
3342ec618c9SBram Moolenaar  "
335*dc083288SBram Moolenaar  " NOTE: we get here only if L does not contain a statement (among those
336*dc083288SBram Moolenaar  " listed in g:mp_statement).
3372ec618c9SBram Moolenaar  if s:ValidMatchEnd(prev_text, ';'.s:eol, 0) >= 0 " L ends with a semicolon
3382ec618c9SBram Moolenaar    let stm_lnum = s:PrevNonBlankNonComment(lnum)
3392ec618c9SBram Moolenaar    while stm_lnum > 0
3402ec618c9SBram Moolenaar      let prev_text = getline(stm_lnum)
3412ec618c9SBram Moolenaar      let sc_pos = s:LastValidMatchEnd(prev_text, ';', 0)
3422ec618c9SBram Moolenaar      let stm_pos = s:ValidMatchEnd(prev_text, g:mp_statement, sc_pos)
3432ec618c9SBram Moolenaar      if stm_pos > sc_pos
3442ec618c9SBram Moolenaar        let lnum = stm_lnum
3452ec618c9SBram Moolenaar        break
3462ec618c9SBram Moolenaar      elseif sc_pos > stm_pos
3472ec618c9SBram Moolenaar        break
3482ec618c9SBram Moolenaar      endif
3492ec618c9SBram Moolenaar      let stm_lnum = s:PrevNonBlankNonComment(stm_lnum)
3502ec618c9SBram Moolenaar    endwhile
3512ec618c9SBram Moolenaar  endif
3522ec618c9SBram Moolenaar
3532ec618c9SBram Moolenaar  return s:DecreaseIndentOnClosingTag(indent(lnum))
3542ec618c9SBram Moolenaarendfunction
3552ec618c9SBram Moolenaar" }}}
356071d4279SBram Moolenaar
3578e52a593SBram Moolenaarlet &cpo = s:keepcpo
3588e52a593SBram Moolenaarunlet s:keepcpo
3598e52a593SBram Moolenaar
360071d4279SBram Moolenaar" vim:sw=2:fdm=marker
361