diff options
Diffstat (limited to 'indent/julia.vim')
-rw-r--r-- | indent/julia.vim | 225 |
1 files changed, 209 insertions, 16 deletions
diff --git a/indent/julia.vim b/indent/julia.vim index 7fafe89c..4833d7e5 100644 --- a/indent/julia.vim +++ b/indent/julia.vim @@ -3,13 +3,13 @@ if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'julia') == -1 " Vim indent file " Language: Julia " Maintainer: Carlo Baldassi <carlobaldassi@gmail.com> -" Last Change: 2011 dec 11 -" Notes: based on Bram Moneaar's indent file for vim +" Last Change: 2016 jun 16 +" Notes: originally based on Bram Molenaar's indent file for vim setlocal autoindent setlocal indentexpr=GetJuliaIndent() -setlocal indentkeys+==end,=else,=catch,=finally +setlocal indentkeys+==end,=else,=catch,=finally,),],} setlocal indentkeys-=0# setlocal indentkeys-=: setlocal indentkeys-=0{ @@ -21,12 +21,16 @@ if exists("*GetJuliaIndent") finish endif -let s:skipPatterns = '\<julia\%(Comment\)\>' +let s:skipPatterns = '\<julia\%(Comprehension\%(For\|If\)\|RangeEnd\|CommentL\|\%([bsv]\|ip\|big\|MIME\|Shell\|Printf\|Doc\)\=String\|RegEx\|SymbolS\?\)\>' -function JuliaMatch(lnum, str, regex, st) +function JuliaMatch(lnum, str, regex, st, ...) let s = a:st + let e = a:0 > 0 ? a:1 : -1 while 1 let f = match(a:str, a:regex, s) + if e >= 0 && f >= e + return -1 + endif if f >= 0 let attr = synIDattr(synID(a:lnum,f+1,1),"name") if attr =~ s:skipPatterns @@ -39,15 +43,16 @@ function JuliaMatch(lnum, str, regex, st) return f endfunction -function GetJuliaNestingStruct(lnum) +function GetJuliaNestingStruct(lnum, ...) " Auxiliary function to inspect the block structure of a line let line = getline(a:lnum) - let s = 0 + let s = a:0 > 0 ? a:1 : 0 + let e = a:0 > 1 ? a:2 : -1 let blocks_stack = [] let num_closed_blocks = 0 while 1 - let fb = JuliaMatch(a:lnum, line, '@\@<!\<\%(if\|else\%(if\)\=\|while\|for\|try\|catch\|finally\|function\|macro\|begin\|type\|immutable\|let\|\%(bare\)\?module\|quote\|do\)\>', s) - let fe = JuliaMatch(a:lnum, line, '@\@<!\<end\>', s) + 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\|\%(\%(abstract\|primitive\)\s\+\)\@<!type\|immutable\|let\|\%(bare\)\?module\|quote\|do\)\>', s, e) + let fe = JuliaMatch(a:lnum, line, '@\@<!\<end\>', s, e) if fb < 0 && fe < 0 " No blocks found @@ -128,9 +133,13 @@ function GetJuliaNestingStruct(lnum) continue endif - let i = JuliaMatch(a:lnum, line, '@\@<!\<\%(while\|for\|function\|macro\|begin\|type\|immutable\|let\|quote\|do\)\>', s) + let i = JuliaMatch(a:lnum, line, '@\@<!\<\%(while\|for\|\%(staged\)\?function\|macro\|begin\|\%(mutable\s\+\)\?struct\|\%(\%(abstract\|primitive\)\s\+\)\?type\|immutable\|let\|quote\|do\)\>', s) if i >= 0 && i == fb - let s = i+1 + if match(line, '\<\%(mutable\|abstract\|primitive\)', i) != -1 + let s = i+11 + else + let s = i+1 + endif call add(blocks_stack, 'other') continue endif @@ -158,6 +167,128 @@ function GetJuliaNestingStruct(lnum) return [num_open_blocks, num_closed_blocks] endfunction +function GetJuliaNestingBrackets(lnum, c) + " Auxiliary function to inspect the brackets structure of a line + let line = getline(a:lnum)[0 : (a:c - 1)] + let s = 0 + let brackets_stack = [] + let last_closed_bracket = -1 + while 1 + let fb = JuliaMatch(a:lnum, line, '[([{]', s) + let fe = JuliaMatch(a:lnum, line, '[])}]', s) + + if fb < 0 && fe < 0 + " No brackets found + break + end + + if fb >= 0 && (fb < fe || fe < 0) + " The first occurrence is an opening bracket + + let i = JuliaMatch(a:lnum, line, '(', s) + if i >= 0 && i == fb + let s = i+1 + call add(brackets_stack, ['par',i]) + continue + endif + + let i = JuliaMatch(a:lnum, line, '\[', s) + if i >= 0 && i == fb + let s = i+1 + call add(brackets_stack, ['sqbra',i]) + continue + endif + + let i = JuliaMatch(a:lnum, line, '{', s) + if i >= 0 && i == fb + let s = i+1 + call add(brackets_stack, ['curbra',i]) + continue + endif + + " Note: it should be impossible to get here + break + + else + " The first occurrence is a closing bracket + + let i = JuliaMatch(a:lnum, line, ')', s) + if i >= 0 && i == fe + let s = i+1 + if len(brackets_stack) > 0 && brackets_stack[-1][0] == 'par' + call remove(brackets_stack, -1) + else + let last_closed_bracket = i + 1 + endif + continue + endif + + let i = JuliaMatch(a:lnum, line, ']', s) + if i >= 0 && i == fe + let s = i+1 + if len(brackets_stack) > 0 && brackets_stack[-1][0] == 'sqbra' + call remove(brackets_stack, -1) + else + let last_closed_bracket = i + 1 + endif + continue + endif + + let i = JuliaMatch(a:lnum, line, '}', s) + if i >= 0 && i == fe + let s = i+1 + if len(brackets_stack) > 0 && brackets_stack[-1][0] == 'curbra' + call remove(brackets_stack, -1) + else + let last_closed_bracket = i + 1 + endif + continue + endif + + " Note: it should be impossible to get here + break + + endif + + " Note: it should be impossible to get here + break + endwhile + let first_open_bracket = -1 + let last_open_bracket = -1 + if len(brackets_stack) > 0 + let first_open_bracket = brackets_stack[0][1] + let last_open_bracket = brackets_stack[-1][1] + endif + return [first_open_bracket, last_open_bracket, last_closed_bracket] +endfunction + +let s:bracketBlocks = '\<julia\%(\%(\%(Printf\)\?Par\|SqBra\|CurBra\)Block\|ParBlockInRange\|StringVars\%(Par\|SqBra\|CurBra\)\|Dollar\%(Par\|SqBra\)\|QuotedParBlockS\?\)\>' + +function IsInBrackets(lnum, c) + let stack = map(synstack(a:lnum, a:c), 'synIDattr(v:val, "name")') + call filter(stack, 'v:val =~# s:bracketBlocks') + return len(stack) > 0 +endfunction + +" Auxiliary function to find a line which does not start in the middle of a +" multiline bracketed expression, to be used as reference for block +" indentation. +function LastBlockIndent(lnum) + let lnum = a:lnum + let ind = 0 + while lnum > 0 + let ind = indent(lnum) + if ind == 0 + return [lnum, 0] + endif + if !IsInBrackets(lnum, 1) + break + endif + let lnum = prevnonblank(lnum - 1) + endwhile + return [max([lnum,1]), ind] +endfunction + function GetJuliaIndent() let s:save_ignorecase = &ignorecase set noignorecase @@ -172,19 +303,81 @@ function GetJuliaIndent() return 0 endif - let ind = indent(lnum) + let ind = -1 + let st = -1 + let lim = -1 + + " Multiline bracketed expressions take precedence + let c = len(getline(lnum)) + 1 + while IsInBrackets(lnum, c) + let [first_open_bracket, last_open_bracket, last_closed_bracket] = GetJuliaNestingBrackets(lnum, c) + + " First scenario: the previous line has a hanging open bracket: + " set the indentation to match the opening bracket (plus an extra space) + if last_open_bracket != -1 + let st = last_open_bracket + let ind = virtcol([lnum, st + 1]) + + " Second scenario: some multiline bracketed expression was closed in the + " previous line. But since we know we are still in a bracketed expression, + " we need to find the line where the bracket was open + elseif last_closed_bracket != -1 " && exists("loaded_matchit") + " we use the % command to skip back (this is buggy without matchit, and + " is potentially a disaster if % got remapped) + call cursor(lnum, last_closed_bracket) + normal % + if line(".") == lnum + " something wrong here, give up + let ind = indent(lnum) + else + let lnum = line(".") + let c = col(".") - 1 + if c == 0 + " uhm, give up + let ind = 0 + else + " we skipped a bracket set, keep searching for an opening bracket + let lim = c + continue + endif + endif + + " Third scenario: nothing special, or matchit not available: keep the indentation + else + let ind = indent(lnum) + endif + + " In case the current line starts with a closing bracket, we align it with + " the opening one. + if JuliaMatch(v:lnum, getline(v:lnum), '[])}]', indent(v:lnum)) == indent(v:lnum) && ind > 0 + return ind - 1 + endif + + break + endwhile + + if ind == -1 + " We are not in a multiline bracketed expression. Thus we look for a + " previous line to use as a reference + let [lnum,ind] = LastBlockIndent(lnum) + let c = len(getline(lnum)) + 1 + if IsInBrackets(lnum, c) + let [first_open_bracket, last_open_bracket, last_closed_bracket] = GetJuliaNestingBrackets(lnum, c) + let lim = first_open_bracket + endif + end - " Analyse previous line - let [num_open_blocks, num_closed_blocks] = GetJuliaNestingStruct(lnum) + " Analyse the reference line + let [num_open_blocks, num_closed_blocks] = GetJuliaNestingStruct(lnum, st, lim) " Increase indentation for each newly opened block - " in the previous line + " in the reference line while num_open_blocks > 0 let ind += &sw let num_open_blocks -= 1 endwhile - " Analyse current line + " Analyse the current line let [num_open_blocks, num_closed_blocks] = GetJuliaNestingStruct(v:lnum) " Decrease indentation for each closed block |