Mercurial > vim
comparison runtime/indent/julia.vim @ 25619:29ec2c198c8d
Update runtime files
Commit: https://github.com/vim/vim/commit/6aa57295cfbe8f21c15f0671e45fd53cf990d404
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Aug 14 21:25:52 2021 +0200
Update runtime files
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sat, 14 Aug 2021 21:30:04 +0200 |
parents | |
children | 1e9e9d89f0ee |
comparison
equal
deleted
inserted
replaced
25618:b5765575dc5a | 25619:29ec2c198c8d |
---|---|
1 " Vim indent file | |
2 " Language: Julia | |
3 " Maintainer: Carlo Baldassi <carlobaldassi@gmail.com> | |
4 " Homepage: https://github.com/JuliaEditorSupport/julia-vim | |
5 " Last Change: 2016 jun 16 | |
6 " Notes: originally based on Bram Molenaar's indent file for vim | |
7 | |
8 setlocal autoindent | |
9 | |
10 setlocal indentexpr=GetJuliaIndent() | |
11 setlocal indentkeys+==end,=else,=catch,=finally,),],} | |
12 setlocal indentkeys-=0# | |
13 setlocal indentkeys-=: | |
14 setlocal indentkeys-=0{ | |
15 setlocal indentkeys-=0} | |
16 setlocal nosmartindent | |
17 | |
18 " Only define the function once. | |
19 if exists("*GetJuliaIndent") | |
20 finish | |
21 endif | |
22 | |
23 let s:skipPatternsBasic = '\<julia\%(Comment\%([LM]\|Delim\)\)\>' | |
24 let s:skipPatterns = '\<julia\%(Comprehension\%(For\|If\)\|RangeKeyword\|Comment\%([LM]\|Delim\)\|\%([bs]\|Shell\|Printf\|Doc\)\?String\|StringPrefixed\|DocStringM\(Raw\)\?\|RegEx\|SymbolS\?\|Macro\|Dotted\)\>' | |
25 | |
26 function JuliaMatch(lnum, str, regex, st, ...) | |
27 let s = a:st | |
28 let e = a:0 > 0 ? a:1 : -1 | |
29 let basic_skip = a:0 > 1 ? a:2 : 'all' | |
30 let skip = basic_skip ==# 'basic' ? s:skipPatternsBasic : s:skipPatterns | |
31 while 1 | |
32 let f = match(a:str, '\C' . a:regex, s) | |
33 if e >= 0 && f >= e | |
34 return -1 | |
35 endif | |
36 if f >= 0 | |
37 let attr = synIDattr(synID(a:lnum,f+1,1),"name") | |
38 let attrT = synIDattr(synID(a:lnum,f+1,0),"name") | |
39 if attr =~# skip || attrT =~# skip | |
40 let s = f+1 | |
41 continue | |
42 endif | |
43 endif | |
44 break | |
45 endwhile | |
46 return f | |
47 endfunction | |
48 | |
49 function GetJuliaNestingStruct(lnum, ...) | |
50 " Auxiliary function to inspect the block structure of a line | |
51 let line = getline(a:lnum) | |
52 let s = a:0 > 0 ? a:1 : 0 | |
53 let e = a:0 > 1 ? a:2 : -1 | |
54 let blocks_stack = [] | |
55 let num_closed_blocks = 0 | |
56 while 1 | |
57 let fb = JuliaMatch(a:lnum, line, '\<\%(if\|else\%(if\)\?\|while\|for\|try\|catch\|finally\|\%(staged\)\?function\|macro\|begin\|mutable\s\+struct\|\%(mutable\s\+\)\@<!struct\|\%(abstract\|primitive\)\s\+type\|let\|\%(bare\)\?module\|quote\|do\)\>', s, e) | |
58 let fe = JuliaMatch(a:lnum, line, '\<end\>', s, e) | |
59 | |
60 if fb < 0 && fe < 0 | |
61 " No blocks found | |
62 break | |
63 end | |
64 | |
65 if fb >= 0 && (fb < fe || fe < 0) | |
66 " The first occurrence is an opening block keyword | |
67 " Note: some keywords (elseif,else,catch,finally) are both | |
68 " closing blocks and opening new ones | |
69 | |
70 let i = JuliaMatch(a:lnum, line, '\<if\>', s) | |
71 if i >= 0 && i == fb | |
72 let s = i+1 | |
73 call add(blocks_stack, 'if') | |
74 continue | |
75 endif | |
76 let i = JuliaMatch(a:lnum, line, '\<elseif\>', s) | |
77 if i >= 0 && i == fb | |
78 let s = i+1 | |
79 if len(blocks_stack) > 0 && blocks_stack[-1] == 'if' | |
80 let blocks_stack[-1] = 'elseif' | |
81 elseif (len(blocks_stack) > 0 && blocks_stack[-1] != 'elseif') || len(blocks_stack) == 0 | |
82 call add(blocks_stack, 'elseif') | |
83 let num_closed_blocks += 1 | |
84 endif | |
85 continue | |
86 endif | |
87 let i = JuliaMatch(a:lnum, line, '\<else\>', s) | |
88 if i >= 0 && i == fb | |
89 let s = i+1 | |
90 if len(blocks_stack) > 0 && blocks_stack[-1] =~# '\<\%(else\)\=if\>' | |
91 let blocks_stack[-1] = 'else' | |
92 else | |
93 call add(blocks_stack, 'else') | |
94 let num_closed_blocks += 1 | |
95 endif | |
96 continue | |
97 endif | |
98 | |
99 let i = JuliaMatch(a:lnum, line, '\<try\>', s) | |
100 if i >= 0 && i == fb | |
101 let s = i+1 | |
102 call add(blocks_stack, 'try') | |
103 continue | |
104 endif | |
105 let i = JuliaMatch(a:lnum, line, '\<catch\>', s) | |
106 if i >= 0 && i == fb | |
107 let s = i+1 | |
108 if len(blocks_stack) > 0 && blocks_stack[-1] == 'try' | |
109 let blocks_stack[-1] = 'catch' | |
110 else | |
111 call add(blocks_stack, 'catch') | |
112 let num_closed_blocks += 1 | |
113 endif | |
114 continue | |
115 endif | |
116 let i = JuliaMatch(a:lnum, line, '\<finally\>', s) | |
117 if i >= 0 && i == fb | |
118 let s = i+1 | |
119 if len(blocks_stack) > 0 && (blocks_stack[-1] == 'try' || blocks_stack[-1] == 'catch') | |
120 let blocks_stack[-1] = 'finally' | |
121 else | |
122 call add(blocks_stack, 'finally') | |
123 let num_closed_blocks += 1 | |
124 endif | |
125 continue | |
126 endif | |
127 | |
128 let i = JuliaMatch(a:lnum, line, '\<\%(bare\)\?module\>', s) | |
129 if i >= 0 && i == fb | |
130 let s = i+1 | |
131 if i == 0 | |
132 call add(blocks_stack, 'col1module') | |
133 else | |
134 call add(blocks_stack, 'other') | |
135 endif | |
136 continue | |
137 endif | |
138 | |
139 let i = JuliaMatch(a:lnum, line, '\<\%(while\|for\|function\|macro\|begin\|\%(mutable\s\+\)\?struct\|\%(abstract\|primitive\)\s\+type\|let\|quote\|do\)\>', s) | |
140 if i >= 0 && i == fb | |
141 if match(line, '\C\<\%(mutable\|abstract\|primitive\)', i) != -1 | |
142 let s = i+11 | |
143 else | |
144 let s = i+1 | |
145 endif | |
146 call add(blocks_stack, 'other') | |
147 continue | |
148 endif | |
149 | |
150 " Note: it should be impossible to get here | |
151 break | |
152 | |
153 else | |
154 " The first occurrence is an 'end' | |
155 | |
156 let s = fe+1 | |
157 if len(blocks_stack) == 0 | |
158 let num_closed_blocks += 1 | |
159 else | |
160 call remove(blocks_stack, -1) | |
161 endif | |
162 continue | |
163 | |
164 endif | |
165 | |
166 " Note: it should be impossible to get here | |
167 break | |
168 endwhile | |
169 let num_open_blocks = len(blocks_stack) - count(blocks_stack, 'col1module') | |
170 return [num_open_blocks, num_closed_blocks] | |
171 endfunction | |
172 | |
173 function GetJuliaNestingBrackets(lnum, c) | |
174 " Auxiliary function to inspect the brackets structure of a line | |
175 let line = getline(a:lnum)[0 : (a:c - 1)] | |
176 let s = 0 | |
177 let brackets_stack = [] | |
178 let last_closed_bracket = -1 | |
179 while 1 | |
180 let fb = JuliaMatch(a:lnum, line, '[([{]', s) | |
181 let fe = JuliaMatch(a:lnum, line, '[])}]', s) | |
182 | |
183 if fb < 0 && fe < 0 | |
184 " No brackets found | |
185 break | |
186 end | |
187 | |
188 if fb >= 0 && (fb < fe || fe < 0) | |
189 " The first occurrence is an opening bracket | |
190 | |
191 let i = JuliaMatch(a:lnum, line, '(', s) | |
192 if i >= 0 && i == fb | |
193 let s = i+1 | |
194 call add(brackets_stack, ['par',i]) | |
195 continue | |
196 endif | |
197 | |
198 let i = JuliaMatch(a:lnum, line, '\[', s) | |
199 if i >= 0 && i == fb | |
200 let s = i+1 | |
201 call add(brackets_stack, ['sqbra',i]) | |
202 continue | |
203 endif | |
204 | |
205 let i = JuliaMatch(a:lnum, line, '{', s) | |
206 if i >= 0 && i == fb | |
207 let s = i+1 | |
208 call add(brackets_stack, ['curbra',i]) | |
209 continue | |
210 endif | |
211 | |
212 " Note: it should be impossible to get here | |
213 break | |
214 | |
215 else | |
216 " The first occurrence is a closing bracket | |
217 | |
218 let i = JuliaMatch(a:lnum, line, ')', s) | |
219 if i >= 0 && i == fe | |
220 let s = i+1 | |
221 if len(brackets_stack) > 0 && brackets_stack[-1][0] == 'par' | |
222 call remove(brackets_stack, -1) | |
223 else | |
224 let last_closed_bracket = i + 1 | |
225 endif | |
226 continue | |
227 endif | |
228 | |
229 let i = JuliaMatch(a:lnum, line, ']', s) | |
230 if i >= 0 && i == fe | |
231 let s = i+1 | |
232 if len(brackets_stack) > 0 && brackets_stack[-1][0] == 'sqbra' | |
233 call remove(brackets_stack, -1) | |
234 else | |
235 let last_closed_bracket = i + 1 | |
236 endif | |
237 continue | |
238 endif | |
239 | |
240 let i = JuliaMatch(a:lnum, line, '}', s) | |
241 if i >= 0 && i == fe | |
242 let s = i+1 | |
243 if len(brackets_stack) > 0 && brackets_stack[-1][0] == 'curbra' | |
244 call remove(brackets_stack, -1) | |
245 else | |
246 let last_closed_bracket = i + 1 | |
247 endif | |
248 continue | |
249 endif | |
250 | |
251 " Note: it should be impossible to get here | |
252 break | |
253 | |
254 endif | |
255 | |
256 " Note: it should be impossible to get here | |
257 break | |
258 endwhile | |
259 let first_open_bracket = -1 | |
260 let last_open_bracket = -1 | |
261 let infuncargs = 0 | |
262 if len(brackets_stack) > 0 | |
263 let first_open_bracket = brackets_stack[0][1] | |
264 let last_open_bracket = brackets_stack[-1][1] | |
265 if brackets_stack[-1][0] == 'par' && IsFunctionArgPar(a:lnum, last_open_bracket+1) | |
266 let infuncargs = 1 | |
267 endif | |
268 endif | |
269 return [first_open_bracket, last_open_bracket, last_closed_bracket, infuncargs] | |
270 endfunction | |
271 | |
272 let s:bracketBlocks = '\<julia\%(\%(\%(Printf\)\?Par\|SqBra\%(Idx\)\?\|CurBra\)Block\|ParBlockInRange\|StringVars\%(Par\|SqBra\|CurBra\)\|Dollar\%(Par\|SqBra\)\|QuotedParBlockS\?\)\>' | |
273 | |
274 function IsInBrackets(lnum, c) | |
275 let stack = map(synstack(a:lnum, a:c), 'synIDattr(v:val, "name")') | |
276 call filter(stack, 'v:val =~# s:bracketBlocks') | |
277 return len(stack) > 0 | |
278 endfunction | |
279 | |
280 function IsInDocString(lnum) | |
281 let stack = map(synstack(a:lnum, 1), 'synIDattr(v:val, "name")') | |
282 call filter(stack, 'v:val =~# "\\<juliaDocString\\(Delim\\|M\\\(Raw\\)\\?\\)\\?\\>"') | |
283 return len(stack) > 0 | |
284 endfunction | |
285 | |
286 function IsInContinuationImportLine(lnum) | |
287 let stack = map(synstack(a:lnum, 1), 'synIDattr(v:val, "name")') | |
288 call filter(stack, 'v:val =~# "\\<juliaImportLine\\>"') | |
289 if len(stack) == 0 | |
290 return 0 | |
291 endif | |
292 return JuliaMatch(a:lnum, getline(a:lnum), '\<\%(import\|using\|export\)\>', indent(a:lnum)) == -1 | |
293 endfunction | |
294 | |
295 function IsFunctionArgPar(lnum, c) | |
296 if a:c == 0 | |
297 return 0 | |
298 endif | |
299 let stack = map(synstack(a:lnum, a:c-1), 'synIDattr(v:val, "name")') | |
300 return len(stack) >= 2 && stack[-2] ==# 'juliaFunctionDef' | |
301 endfunction | |
302 | |
303 function JumpToMatch(lnum, last_closed_bracket) | |
304 " we use the % command to skip back (tries to ues matchit if possible, | |
305 " otherwise resorts to vim's default, which is buggy but better than | |
306 " nothing) | |
307 call cursor(a:lnum, a:last_closed_bracket) | |
308 let percmap = maparg("%", "n") | |
309 if exists("g:loaded_matchit") && percmap =~# 'Match\%(it\|_wrapper\)' | |
310 normal % | |
311 else | |
312 normal! % | |
313 end | |
314 endfunction | |
315 | |
316 " Auxiliary function to find a line which does not start in the middle of a | |
317 " multiline bracketed expression, to be used as reference for block | |
318 " indentation. | |
319 function LastBlockIndent(lnum) | |
320 let lnum = a:lnum | |
321 let ind = 0 | |
322 while lnum > 0 | |
323 let ind = indent(lnum) | |
324 if ind == 0 | |
325 return [lnum, 0] | |
326 endif | |
327 if !IsInBrackets(lnum, 1) | |
328 break | |
329 endif | |
330 let lnum = prevnonblank(lnum - 1) | |
331 endwhile | |
332 return [max([lnum,1]), ind] | |
333 endfunction | |
334 | |
335 function GetJuliaIndent() | |
336 " Do not alter doctrings indentation | |
337 if IsInDocString(v:lnum) | |
338 return -1 | |
339 endif | |
340 | |
341 " Find a non-blank line above the current line. | |
342 let lnum = prevnonblank(v:lnum - 1) | |
343 | |
344 " At the start of the file use zero indent. | |
345 if lnum == 0 | |
346 return 0 | |
347 endif | |
348 | |
349 let ind = -1 | |
350 let st = -1 | |
351 let lim = -1 | |
352 | |
353 " Multiline bracketed expressions take precedence | |
354 let align_brackets = get(g:, "julia_indent_align_brackets", 1) | |
355 let align_funcargs = get(g:, "julia_indent_align_funcargs", 0) | |
356 let c = len(getline(lnum)) + 1 | |
357 while IsInBrackets(lnum, c) | |
358 let [first_open_bracket, last_open_bracket, last_closed_bracket, infuncargs] = GetJuliaNestingBrackets(lnum, c) | |
359 | |
360 " First scenario: the previous line has a hanging open bracket: | |
361 " set the indentation to match the opening bracket (plus an extra space) | |
362 " unless we're in a function arguments list or alignment is disabled, in | |
363 " which case we just add an extra indent | |
364 if last_open_bracket != -1 | |
365 if (!infuncargs && align_brackets) || (infuncargs && align_funcargs) | |
366 let st = last_open_bracket | |
367 let ind = virtcol([lnum, st + 1]) | |
368 else | |
369 let ind = indent(lnum) + shiftwidth() | |
370 endif | |
371 | |
372 " Second scenario: some multiline bracketed expression was closed in the | |
373 " previous line. But since we know we are still in a bracketed expression, | |
374 " we need to find the line where the bracket was opened | |
375 elseif last_closed_bracket != -1 | |
376 call JumpToMatch(lnum, last_closed_bracket) | |
377 if line(".") == lnum | |
378 " something wrong here, give up | |
379 let ind = indent(lnum) | |
380 else | |
381 let lnum = line(".") | |
382 let c = col(".") - 1 | |
383 if c == 0 | |
384 " uhm, give up | |
385 let ind = 0 | |
386 else | |
387 " we skipped a bracket set, keep searching for an opening bracket | |
388 let lim = c | |
389 continue | |
390 endif | |
391 endif | |
392 | |
393 " Third scenario: nothing special: keep the indentation | |
394 else | |
395 let ind = indent(lnum) | |
396 endif | |
397 | |
398 " Does the current line start with a closing bracket? Then depending on | |
399 " the situation we align it with the opening one, or we let the rest of | |
400 " the code figure it out (the case in which we're closing a function | |
401 " argument list is special-cased) | |
402 if JuliaMatch(v:lnum, getline(v:lnum), '[])}]', indent(v:lnum)) == indent(v:lnum) && ind > 0 | |
403 if !align_brackets && !align_funcargs | |
404 call JumpToMatch(v:lnum, indent(v:lnum)) | |
405 return indent(line(".")) | |
406 elseif (align_brackets && getline(v:lnum)[indent(v:lnum)] != ')') || align_funcargs | |
407 return ind - 1 | |
408 else " must be a ')' and align_brackets==1 and align_funcargs==0 | |
409 call JumpToMatch(v:lnum, indent(v:lnum)) | |
410 if IsFunctionArgPar(line("."), col(".")) | |
411 let ind = -1 | |
412 else | |
413 return ind - 1 | |
414 endif | |
415 endif | |
416 endif | |
417 | |
418 break | |
419 endwhile | |
420 | |
421 if ind == -1 | |
422 " We are not in a multiline bracketed expression. Thus we look for a | |
423 " previous line to use as a reference | |
424 let [lnum,ind] = LastBlockIndent(lnum) | |
425 let c = len(getline(lnum)) + 1 | |
426 if IsInBrackets(lnum, c) | |
427 let [first_open_bracket, last_open_bracket, last_closed_bracket, infuncargs] = GetJuliaNestingBrackets(lnum, c) | |
428 let lim = first_open_bracket | |
429 endif | |
430 end | |
431 | |
432 " Analyse the reference line | |
433 let [num_open_blocks, num_closed_blocks] = GetJuliaNestingStruct(lnum, st, lim) | |
434 " Increase indentation for each newly opened block in the reference line | |
435 let ind += shiftwidth() * num_open_blocks | |
436 | |
437 " Analyse the current line | |
438 let [num_open_blocks, num_closed_blocks] = GetJuliaNestingStruct(v:lnum) | |
439 " Decrease indentation for each closed block in the current line | |
440 let ind -= shiftwidth() * num_closed_blocks | |
441 | |
442 " Additional special case: multiline import/using/export statements | |
443 | |
444 let prevline = getline(lnum) | |
445 " Are we in a multiline import/using/export statement, right below the | |
446 " opening line? | |
447 if IsInContinuationImportLine(v:lnum) && !IsInContinuationImportLine(lnum) | |
448 if get(g:, 'julia_indent_align_import', 1) | |
449 " if the opening line has a colon followed by non-comments, use it as | |
450 " reference point | |
451 let cind = JuliaMatch(lnum, prevline, ':', indent(lnum), lim) | |
452 if cind >= 0 | |
453 let nonwhiteind = JuliaMatch(lnum, prevline, '\S', cind+1, -1, 'basic') | |
454 if nonwhiteind >= 0 | |
455 " return match(prevline, '\S', cind+1) " a bit overkill... | |
456 return cind + 2 | |
457 endif | |
458 else | |
459 " if the opening line is not a naked import/using/export statement, use | |
460 " it as reference | |
461 let iind = JuliaMatch(lnum, prevline, '\<import\|using\|export\>', indent(lnum), lim) | |
462 if iind >= 0 | |
463 " assuming whitespace after using... so no `using(XYZ)` please! | |
464 let nonwhiteind = JuliaMatch(lnum, prevline, '\S', iind+6, -1, 'basic') | |
465 if nonwhiteind >= 0 | |
466 return match(prevline, '\S', iind+6) | |
467 endif | |
468 endif | |
469 endif | |
470 endif | |
471 let ind += shiftwidth() | |
472 | |
473 " Or did we just close a multiline import/using/export statement? | |
474 elseif !IsInContinuationImportLine(v:lnum) && IsInContinuationImportLine(lnum) | |
475 " find the starting line of the statement | |
476 let ilnum = 0 | |
477 for iln in range(lnum-1, 1, -1) | |
478 if !IsInContinuationImportLine(iln) | |
479 let ilnum = iln | |
480 break | |
481 endif | |
482 endfor | |
483 if ilnum == 0 | |
484 " something went horribly wrong, give up | |
485 let ind = indent(lnum) | |
486 endif | |
487 let ind = indent(ilnum) | |
488 endif | |
489 | |
490 return ind | |
491 endfunction |