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