Bram Moolenaar | 9d87a37 | 2018-12-18 21:41:50 +0100 | [diff] [blame] | 1 | " Vim indent file |
| 2 | " Language: MATLAB |
| 3 | " Maintainer: Axel Forsman <axelsfor@gmail.com> |
| 4 | " Previous maintainer: Christophe Poucet <christophe.poucet@pandora.be> |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 5 | |
Bram Moolenaar | 9d87a37 | 2018-12-18 21:41:50 +0100 | [diff] [blame] | 6 | " Only load if no other indent file is loaded |
| 7 | if exists('b:did_indent') | finish | endif |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 8 | let b:did_indent = 1 |
| 9 | |
Bram Moolenaar | 9d87a37 | 2018-12-18 21:41:50 +0100 | [diff] [blame] | 10 | setlocal indentexpr=GetMatlabIndent() |
| 11 | setlocal indentkeys=!,o,O,e,0=end,0=elseif,0=case,0=otherwise,0=catch,0=function,0=elsei |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 12 | |
Bram Moolenaar | 9d87a37 | 2018-12-18 21:41:50 +0100 | [diff] [blame] | 13 | " The value of the Function indenting format in |
| 14 | " MATLAB Editor/Debugger Language Preferences. |
| 15 | " The possible values are 0 for Classic, 1 for Indent nested functions |
| 16 | " and 2 for Indent all functions (default). |
| 17 | let b:MATLAB_function_indent = get(g:, 'MATLAB_function_indent', 2) |
| 18 | " The previous value of b:changedtick |
| 19 | let b:MATLAB_lasttick = -1 |
| 20 | " The previously indented line |
| 21 | let b:MATLAB_lastline = -1 |
| 22 | " Whether the line above was a line continuation |
| 23 | let b:MATLAB_waslc = 0 |
| 24 | let b:MATLAB_bracketlevel = 0 |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 25 | |
Bram Moolenaar | 9d87a37 | 2018-12-18 21:41:50 +0100 | [diff] [blame] | 26 | " Only define the function once |
| 27 | if exists("*GetMatlabIndent") | finish | endif |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 28 | |
Bram Moolenaar | 9d87a37 | 2018-12-18 21:41:50 +0100 | [diff] [blame] | 29 | let s:keepcpo = &cpo |
| 30 | set cpo&vim |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 31 | |
Bram Moolenaar | 9d87a37 | 2018-12-18 21:41:50 +0100 | [diff] [blame] | 32 | let s:end = '\<end\>\%([^(]*)\)\@!' " Array indexing heuristic |
| 33 | let s:open_pat = 'for\|if\|parfor\|spmd\|switch\|try\|while\|classdef\|properties\|methods\|events\|enumeration' |
| 34 | let s:dedent_pat = '\C^\s*\zs\<\%(end\|else\|elseif\|catch\|\(case\|otherwise\|function\)\)\>' |
| 35 | let s:start_pat = '\C\<\%(function\|' . s:open_pat . '\)\>' |
| 36 | let s:bracket_pair_pat = '\(\[\|{\)\|\(\]\|}\)' |
| 37 | let s:zflag = has('patch-7.4.984') ? 'z' : '' |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 38 | |
Bram Moolenaar | 9d87a37 | 2018-12-18 21:41:50 +0100 | [diff] [blame] | 39 | " Returns whether a comment or string envelops the specified column. |
| 40 | function! s:IsCommentOrString(lnum, col) |
| 41 | return synIDattr(synID(a:lnum, a:col, 1), "name") =~# 'matlabComment\|matlabMultilineComment\|matlabString' |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 42 | endfunction |
| 43 | |
Bram Moolenaar | 9d87a37 | 2018-12-18 21:41:50 +0100 | [diff] [blame] | 44 | " Returns whether the specified line continues on the next line. |
| 45 | function! s:IsLineContinuation(lnum) |
| 46 | let l = getline(a:lnum) | let c = -3 |
| 47 | while 1 |
| 48 | let c = match(l, '\.\{3}', c + 3) |
| 49 | if c == -1 | return 0 |
| 50 | elseif !s:IsCommentOrString(a:lnum, c) | return 1 | endif |
| 51 | endwhile |
| 52 | endfunction |
| 53 | |
| 54 | function! s:SubmatchCount(lnum, pattern, ...) |
| 55 | let endcol = a:0 >= 1 ? a:1 : 1 / 0 | let x = [0, 0, 0, 0] |
| 56 | call cursor(a:lnum, 1) |
| 57 | while 1 |
| 58 | let [lnum, c, submatch] = searchpos(a:pattern, 'cpe' . s:zflag, a:lnum) |
| 59 | if !submatch || c >= endcol | break | endif |
| 60 | if !s:IsCommentOrString(lnum, c) | let x[submatch - 2] += 1 | endif |
| 61 | if cursor(0, c + 1) == -1 || col('.') == c | break | endif |
| 62 | endwhile |
| 63 | return x |
| 64 | endfunction |
| 65 | |
| 66 | function! s:GetOpenCloseCount(lnum, pattern, ...) |
| 67 | let counts = call('s:SubmatchCount', [a:lnum, a:pattern] + a:000) |
| 68 | return counts[0] - counts[1] |
| 69 | endfunction |
| 70 | |
| 71 | function! GetMatlabIndent() |
| 72 | let prevlnum = prevnonblank(v:lnum - 1) |
| 73 | |
| 74 | if b:MATLAB_lasttick != b:changedtick || b:MATLAB_lastline != prevlnum |
| 75 | " Recalculate bracket count (only have to check same block and line above) |
| 76 | let b:MATLAB_bracketlevel = 0 |
| 77 | let previndent = indent(prevlnum) | let l = prevlnum |
| 78 | while 1 |
| 79 | let l = prevnonblank(l - 1) | let indent = indent(l) |
| 80 | if l <= 0 || previndent < indent | break | endif |
| 81 | let b:MATLAB_bracketlevel += s:GetOpenCloseCount(l, s:bracket_pair_pat) |
| 82 | if previndent != indent | break | endif |
| 83 | endwhile |
| 84 | |
| 85 | let b:MATLAB_waslc = s:IsLineContinuation(prevlnum - 1) |
| 86 | endif |
| 87 | " If line above was blank it can impossibly have been a LC |
| 88 | let above_lc = b:MATLAB_lasttick == b:changedtick && prevlnum != v:lnum - 1 && b:MATLAB_lastline == prevlnum ? 0 : s:IsLineContinuation(v:lnum - 1) |
| 89 | |
| 90 | let pair_pat = '\C\<\(' . s:open_pat . '\|' |
| 91 | \ . (b:MATLAB_function_indent == 1 ? '^\@<!' : '') |
| 92 | \ . (b:MATLAB_function_indent >= 1 ? 'function\|' : '') |
| 93 | \ . '\|\%(^\s*\)\@<=\%(else\|elseif\|case\|otherwise\|catch\)\)\>' |
| 94 | \ . '\|\S\s*\zs\(' . s:end . '\)' |
| 95 | let [open, close, b_open, b_close] = prevlnum ? s:SubmatchCount(prevlnum, |
| 96 | \ pair_pat . '\|' . s:bracket_pair_pat) : [0, 0, 0, 0] |
| 97 | let curbracketlevel = b:MATLAB_bracketlevel + b_open - b_close |
| 98 | |
| 99 | call cursor(v:lnum, 1) |
| 100 | let submatch = search(s:dedent_pat, 'cp' . s:zflag, v:lnum) |
| 101 | if submatch && !s:IsCommentOrString(v:lnum, col('.')) |
| 102 | " Align end, et cetera with start of block |
| 103 | let [lnum, col] = searchpairpos(s:start_pat, '', '\C' . s:end, 'bW', 's:IsCommentOrString(line("."), col("."))') |
| 104 | let result = lnum ? indent(lnum) + shiftwidth() * (s:GetOpenCloseCount(lnum, pair_pat, col) + submatch == 2) : 0 |
| 105 | else |
| 106 | " Count how many blocks the previous line opens/closes |
| 107 | " Line continuations/brackets indent once per statement |
| 108 | let result = indent(prevlnum) + shiftwidth() * (open - close |
| 109 | \ + (b:MATLAB_bracketlevel ? -!curbracketlevel : !!curbracketlevel) |
| 110 | \ + (curbracketlevel <= 0) * (above_lc - b:MATLAB_waslc)) |
| 111 | endif |
| 112 | |
| 113 | let b:MATLAB_waslc = above_lc |
| 114 | let b:MATLAB_bracketlevel = curbracketlevel |
| 115 | let b:MATLAB_lasttick = b:changedtick |
| 116 | let b:MATLAB_lastline = v:lnum |
| 117 | return result |
| 118 | endfunction |
| 119 | |
| 120 | let &cpo = s:keepcpo |
| 121 | unlet s:keepcpo |