Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 1 | vim9script |
| 2 | |
| 3 | # MetaPost indent file |
| 4 | # Language: MetaPost |
| 5 | # Maintainer: Nicola Vitacolonna <nvitacolonna@gmail.com> |
| 6 | # Former Maintainers: Eugene Minkovskii <emin@mccme.ru> |
| 7 | # Latest Revision: 2022 Aug 12 |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 8 | |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 9 | if exists("b:did_indent") |
| 10 | finish |
| 11 | endif |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 12 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 13 | b:did_indent = 1 |
| 14 | |
| 15 | setlocal indentexpr=g:MetaPostIndent() |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 16 | setlocal indentkeys+==end,=else,=fi,=fill,0),0] |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 17 | setlocal nolisp |
| 18 | setlocal nosmartindent |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 19 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 20 | b:undo_indent = "setl indentexpr< indentkeys< lisp< smartindent<" |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 21 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 22 | # Regexps {{{ |
| 23 | # Expressions starting indented blocks |
| 24 | const MP_OPEN_TAG = [ |
| 25 | '\<if\>', |
| 26 | '\<else\%[if]\>', |
| 27 | '\<for\%(\|ever\|suffixes\)\>', |
| 28 | '\<begingroup\>', |
| 29 | '\<\%(\|var\|primary\|secondary\|tertiary\)def\>', |
| 30 | '^\s*\<begin\%(fig\|graph\|glyph\|char\|logochar\)\>', |
| 31 | '[([{]', |
| 32 | ]->extend(get(g:, "mp_open_tag", []))->join('\|') |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 33 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 34 | # Expressions ending indented blocks |
| 35 | const MP_CLOSE_TAG = [ |
| 36 | '\<fi\>', |
| 37 | '\<else\%[if]\>', |
| 38 | '\<end\%(\|for\|group\|def\|fig\|char\|glyph\|graph\)\>', |
| 39 | '[)\]}]' |
| 40 | ]->extend(get(g:, "mp_close_tag", []))->join('\|') |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 41 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 42 | # Statements that may span multiple lines and are ended by a semicolon. To |
| 43 | # keep this list short, statements that are unlikely to be very long or are |
| 44 | # not very common (e.g., keywords like `interim` or `showtoken`) are not |
| 45 | # included. |
| 46 | # |
| 47 | # The regex for assignments and equations (the last branch) is tricky, because |
| 48 | # it must not match things like `for i :=`, `if a=b`, `def...=`, etc... It is |
| 49 | # not perfect, but it works reasonably well. |
| 50 | const MP_STATEMENT = [ |
| 51 | '\<\%(\|un\|cut\)draw\%(dot\)\=\>', |
| 52 | '\<\%(\|un\)fill\%[draw]\>', |
| 53 | '\<draw\%(dbl\)\=arrow\>', |
| 54 | '\<clip\>', |
| 55 | '\<addto\>', |
| 56 | '\<save\>', |
| 57 | '\<setbounds\>', |
| 58 | '\<message\>', |
| 59 | '\<errmessage\>', |
| 60 | '\<errhelp\>', |
| 61 | '\<fontmapline\>', |
| 62 | '\<pickup\>', |
| 63 | '\<show\>', |
| 64 | '\<special\>', |
| 65 | '\<write\>', |
| 66 | '\%(^\|;\)\%([^;=]*\%(' .. MP_OPEN_TAG .. '\)\)\@!.\{-}:\==', |
| 67 | ]->join('\|') |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 68 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 69 | # A line ends with zero or more spaces, possibly followed by a comment. |
| 70 | const EOL = '\s*\%($\|%\)' |
| 71 | # }}} |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 72 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 73 | # Auxiliary functions {{{ |
| 74 | # Returns true if (0-based) position immediately preceding `pos` in `line` is |
| 75 | # inside a string or a comment; returns false otherwise. |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 76 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 77 | # This is the function that is called more often when indenting, so it is |
| 78 | # critical that it is efficient. The method we use is significantly faster |
| 79 | # than using syntax attributes, and more general (it does not require |
| 80 | # syntax_items). It is also faster than using a single regex matching an even |
| 81 | # number of quotes. It helps that MetaPost strings cannot span more than one |
| 82 | # line and cannot contain escaped quotes. |
| 83 | def IsCommentOrString(line: string, pos: number): bool |
| 84 | var in_string = 0 |
| 85 | var q = stridx(line, '"') |
| 86 | var c = stridx(line, '%') |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 87 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 88 | while q >= 0 && q < pos |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 89 | if c >= 0 && c < q |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 90 | if in_string # Find next percent symbol |
| 91 | c = stridx(line, '%', q + 1) |
| 92 | else # Inside comment |
| 93 | return true |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 94 | endif |
| 95 | endif |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 96 | in_string = 1 - in_string |
| 97 | q = stridx(line, '"', q + 1) # Find next quote |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 98 | endwhile |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 99 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 100 | return in_string || (c >= 0 && c <= pos) |
| 101 | enddef |
| 102 | |
| 103 | # Find the first non-comment non-blank line before the given line. |
| 104 | def PrevNonBlankNonComment(lnum: number): number |
| 105 | var nr = prevnonblank(lnum - 1) |
| 106 | while getline(nr) =~# '^\s*%' |
| 107 | nr = prevnonblank(nr - 1) |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 108 | endwhile |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 109 | return nr |
| 110 | enddef |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 111 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 112 | # Returns true if the last tag appearing in the line is an open tag; returns |
| 113 | # false otherwise. |
| 114 | def LastTagIsOpen(line: string): bool |
| 115 | var o = LastValidMatchEnd(line, MP_OPEN_TAG, 0) |
| 116 | if o == - 1 |
| 117 | return false |
| 118 | endif |
| 119 | return LastValidMatchEnd(line, MP_CLOSE_TAG, o) < 0 |
| 120 | enddef |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 121 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 122 | # A simple, efficient and quite effective heuristics is used to test whether |
| 123 | # a line should cause the next line to be indented: count the "opening tags" |
| 124 | # (if, for, def, ...) in the line, count the "closing tags" (endif, endfor, |
| 125 | # ...) in the line, and compute the difference. We call the result the |
| 126 | # "weight" of the line. If the weight is positive, then the next line should |
| 127 | # most likely be indented. Note that `else` and `elseif` are both opening and |
| 128 | # closing tags, so they "cancel out" in almost all cases, the only exception |
| 129 | # being a leading `else[if]`, which is counted as an opening tag, but not as |
| 130 | # a closing tag (so that, for instance, a line containing a single `else:` |
| 131 | # will have weight equal to one, not zero). We do not treat a trailing |
| 132 | # `else[if]` in any special way, because lines ending with an open tag are |
| 133 | # dealt with separately before this function is called (see MetaPostIndent()). |
| 134 | # |
| 135 | # Example: |
| 136 | # |
| 137 | # forsuffixes $=a,b: if x.$ = y.$ : draw else: fill fi |
| 138 | # % This line will be indented because |{forsuffixes,if,else}| > |{else,fi}| (3 > 2) |
| 139 | # endfor |
| 140 | def Weight(line: string): number |
| 141 | var o = 0 |
| 142 | var i = ValidMatchEnd(line, MP_OPEN_TAG, 0) |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 143 | while i > 0 |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 144 | o += 1 |
| 145 | i = ValidMatchEnd(line, MP_OPEN_TAG, i) |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 146 | endwhile |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 147 | var c = 0 |
| 148 | i = matchend(line, '^\s*\<else\%[if]\>') # Skip a leading else[if] |
| 149 | i = ValidMatchEnd(line, MP_CLOSE_TAG, i) |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 150 | while i > 0 |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 151 | c += 1 |
| 152 | i = ValidMatchEnd(line, MP_CLOSE_TAG, i) |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 153 | endwhile |
| 154 | return o - c |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 155 | enddef |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 156 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 157 | # Similar to matchend(), but skips strings and comments. |
| 158 | # line: a String |
| 159 | def ValidMatchEnd(line: string, pat: string, start: number): number |
| 160 | var i = matchend(line, pat, start) |
| 161 | while i > 0 && IsCommentOrString(line, i) |
| 162 | i = matchend(line, pat, i) |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 163 | endwhile |
| 164 | return i |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 165 | enddef |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 166 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 167 | # Like s:ValidMatchEnd(), but returns the end position of the last (i.e., |
| 168 | # rightmost) match. |
| 169 | def LastValidMatchEnd(line: string, pat: string, start: number): number |
| 170 | var last_found = -1 |
| 171 | var i = matchend(line, pat, start) |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 172 | while i > 0 |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 173 | if !IsCommentOrString(line, i) |
| 174 | last_found = i |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 175 | endif |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 176 | i = matchend(line, pat, i) |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 177 | endwhile |
| 178 | return last_found |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 179 | enddef |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 180 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 181 | def DecreaseIndentOnClosingTag(curr_indent: number): number |
| 182 | var cur_text = getline(v:lnum) |
| 183 | if cur_text =~# '^\s*\%(' .. MP_CLOSE_TAG .. '\)' |
| 184 | return max([curr_indent - shiftwidth(), 0]) |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 185 | endif |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 186 | return curr_indent |
| 187 | enddef |
| 188 | # }}} |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 189 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 190 | # Main function {{{ |
| 191 | def g:MetaPostIndent(): number |
| 192 | # Do not touch indentation inside verbatimtex/btex.. etex blocks. |
Bram Moolenaar | dc08328 | 2016-10-11 08:57:33 +0200 | [diff] [blame] | 193 | if synIDattr(synID(v:lnum, 1, 1), "name") =~# '^mpTeXinsert$\|^tex\|^Delimiter' |
| 194 | return -1 |
| 195 | endif |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 196 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 197 | # At the start of a MetaPost block inside ConTeXt, do not touch indentation |
| 198 | if synIDattr(synID(prevnonblank(v:lnum - 1), 1, 1), "name") == "contextBlockDelim" |
| 199 | return -1 |
| 200 | endif |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 201 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 202 | var lnum = PrevNonBlankNonComment(v:lnum) |
| 203 | |
| 204 | # At the start of the file use zero indent. |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 205 | if lnum == 0 |
| 206 | return 0 |
| 207 | endif |
| 208 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 209 | var prev_text = getline(lnum) |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 210 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 211 | # Every rule of indentation in MetaPost is very subjective. We might get |
| 212 | # creative, but things get murky very soon (there are too many corner |
| 213 | # cases). So, we provide a means for the user to decide what to do when this |
| 214 | # script doesn't get it. We use a simple idea: use '%>', '%<', '%=', and |
| 215 | # '%!', to explicitly control indentation. The '<' and '>' symbols may be |
| 216 | # repeated many times (e.g., '%>>' will cause the next line to be indented |
| 217 | # twice). |
| 218 | # |
| 219 | # User-defined overrides take precedence over anything else. |
| 220 | var j = match(prev_text, '%[<>=!]') |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 221 | if j > 0 |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 222 | var i = strlen(matchstr(prev_text, '%>\+', j)) - 1 |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 223 | if i > 0 |
| 224 | return indent(lnum) + i * shiftwidth() |
| 225 | endif |
| 226 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 227 | i = strlen(matchstr(prev_text, '%<\+', j)) - 1 |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 228 | if i > 0 |
| 229 | return max([indent(lnum) - i * shiftwidth(), 0]) |
| 230 | endif |
| 231 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 232 | if match(prev_text, '%=', j) > -1 |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 233 | return indent(lnum) |
| 234 | endif |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 235 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 236 | if match(prev_text, '%!', j) > -1 |
| 237 | return -1 |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 238 | endif |
| 239 | endif |
| 240 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 241 | # If the reference line ends with an open tag, indent. |
| 242 | # |
| 243 | # Example: |
| 244 | # |
| 245 | # if c: |
| 246 | # 0 |
| 247 | # else: |
| 248 | # 1 |
| 249 | # fi if c2: % Note that this line has weight equal to zero. |
| 250 | # ... % This line will be indented |
| 251 | if LastTagIsOpen(prev_text) |
| 252 | return DecreaseIndentOnClosingTag(indent(lnum) + shiftwidth()) |
| 253 | endif |
| 254 | |
| 255 | # Lines with a positive weight are unbalanced and should likely be indented. |
| 256 | # |
| 257 | # Example: |
| 258 | # |
| 259 | # def f = enddef for i = 1 upto 5: if x[i] > 0: 1 else: 2 fi |
| 260 | # ... % This line will be indented (because of the unterminated `for`) |
| 261 | if Weight(prev_text) > 0 |
| 262 | return DecreaseIndentOnClosingTag(indent(lnum) + shiftwidth()) |
| 263 | endif |
| 264 | |
| 265 | # Unterminated statements cause indentation to kick in. |
| 266 | # |
| 267 | # Example: |
| 268 | # |
| 269 | # draw unitsquare |
| 270 | # withcolor black; % This line is indented because of `draw`. |
| 271 | # x := a + b + c |
| 272 | # + d + e; % This line is indented because of `:=`. |
| 273 | # |
| 274 | var i = LastValidMatchEnd(prev_text, MP_STATEMENT, 0) |
| 275 | if i >= 0 # Does the line contain a statement? |
| 276 | if ValidMatchEnd(prev_text, ';', i) < 0 # Is the statement unterminated? |
| 277 | return indent(lnum) + shiftwidth() |
| 278 | else |
| 279 | return DecreaseIndentOnClosingTag(indent(lnum)) |
| 280 | endif |
| 281 | endif |
| 282 | |
| 283 | # Deal with the special case of a statement spanning multiple lines. If the |
| 284 | # current reference line L ends with a semicolon, search backwards for |
| 285 | # another semicolon or a statement keyword. If the latter is found first, |
| 286 | # its line is used as the reference line for indenting the current line |
| 287 | # instead of L. |
| 288 | # |
| 289 | # Example: |
| 290 | # |
| 291 | # if cond: |
| 292 | # draw if a: z0 else: z1 fi |
| 293 | # shifted S |
| 294 | # scaled T; % L |
| 295 | # |
| 296 | # for i = 1 upto 3: % <-- Current line: this gets the same indent as `draw ...` |
| 297 | # |
| 298 | # NOTE: we get here only if L does not contain a statement (among those |
| 299 | # listed in g:MP_STATEMENT). |
| 300 | if ValidMatchEnd(prev_text, ';' .. EOL, 0) >= 0 # L ends with a semicolon |
| 301 | var stm_lnum = PrevNonBlankNonComment(lnum) |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 302 | while stm_lnum > 0 |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 303 | prev_text = getline(stm_lnum) |
| 304 | var sc_pos = LastValidMatchEnd(prev_text, ';', 0) |
| 305 | var stm_pos = ValidMatchEnd(prev_text, MP_STATEMENT, sc_pos) |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 306 | if stm_pos > sc_pos |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 307 | lnum = stm_lnum |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 308 | break |
| 309 | elseif sc_pos > stm_pos |
| 310 | break |
| 311 | endif |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 312 | stm_lnum = PrevNonBlankNonComment(stm_lnum) |
Bram Moolenaar | 2ec618c | 2016-10-01 14:47:05 +0200 | [diff] [blame] | 313 | endwhile |
| 314 | endif |
| 315 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 316 | return DecreaseIndentOnClosingTag(indent(lnum)) |
| 317 | enddef |
| 318 | # }}} |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 319 | |
Bram Moolenaar | 7dd5432 | 2022-08-26 18:01:12 +0100 | [diff] [blame] | 320 | # vim: sw=2 fdm=marker |