| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
 | if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'elixir') == -1
  
if exists("b:did_indent")
  finish
endif
let b:did_indent = 1
setlocal nosmartindent
setlocal indentexpr=GetElixirIndent()
setlocal indentkeys+=0),0],0=end,0=else,0=match,0=elsif,0=catch,0=after,0=rescue
if exists("*GetElixirIndent")
  finish
endif
let s:cpo_save = &cpo
set cpo&vim
let s:no_colon_before        = ':\@<!'
let s:no_colon_after         = ':\@!'
let s:symbols_end            = '\]\|}\|)'
let s:symbols_start          = '\[\|{\|('
let s:arrow                  = '^.*->$'
let s:skip_syntax            = '\%(Comment\|String\)$'
let s:block_skip             = "synIDattr(synID(line('.'),col('.'),1),'name') =~? '".s:skip_syntax."'"
let s:block_start            = '\<\%(do\|fn\)\>'
let s:block_middle           = 'else\|match\|elsif\|catch\|after\|rescue'
let s:block_end              = 'end'
let s:starts_with_pipeline   = '^\s*|>.*$'
let s:ending_with_assignment = '=\s*$'
let s:indent_keywords   = '\<'.s:no_colon_before.'\%('.s:block_start.'\|'.s:block_middle.'\)$'.'\|'.s:arrow
let s:deindent_keywords = '^\s*\<\%('.s:block_end.'\|'.s:block_middle.'\)\>'.'\|'.s:arrow
let s:pair_start  = '\<\%('.s:no_colon_before.s:block_start.'\)\>'.s:no_colon_after
let s:pair_middle = '\<\%('.s:block_middle.'\)\>'.s:no_colon_after.'\zs'
let s:pair_end    = '\<\%('.s:no_colon_before.s:block_end.'\)\>\zs'
let s:inside_block = 0
function! GetElixirIndent()
  let lnum = prevnonblank(v:lnum - 1)
  " At the start of the file use zero indent.
  if lnum == 0
    return 0
  endif
  let opened_symbol = 0
  let current_line  = getline(v:lnum)
  let last_line     = getline(lnum)
  let ind           = indent(lnum)
  " TODO: Remove these 2 lines
  " I don't know why, but for the test on spec/indent/lists_spec.rb:24.
  " Vim is making some mess on parsing the syntax of 'end', it is being
  " recognized as 'elixirString' when should be recognized as 'elixirBlock'.
  " This forces vim to sync the syntax.
  call synID(v:lnum, 1, 1)
  syntax sync fromstart
  if synIDattr(synID(v:lnum, 1, 1), "name") !~ s:skip_syntax
    if last_line !~ s:arrow
      let split_line = split(last_line, '\zs')
      let opened_symbol += count(split_line, '(') - count(split_line, ')')
      let opened_symbol += count(split_line, '[') - count(split_line, ']')
      let opened_symbol += count(split_line, '{') - count(split_line, '}')
    end
    " if start symbol is followed by a character, indent based on the
    " whitespace after the symbol, otherwise use the default shiftwidth
    if last_line =~ '\('.s:symbols_start.'\).'
      let opened_prefix = matchlist(last_line, '\('.s:symbols_start.'\)\s*')[0]
      let ind += (opened_symbol * strlen(opened_prefix))
    else
      let ind += (opened_symbol * &sw)
    endif
    if last_line =~ '^\s*\('.s:symbols_end.'\)' || last_line =~ s:indent_keywords
      let ind += &sw
    endif
    if current_line =~ '^\s*\('.s:symbols_end.'\)'
      let ind -= &sw
    endif
    if last_line =~ s:ending_with_assignment && opened_symbol == 0
      let b:old_ind = indent(lnum)
      let ind += &sw
    end
    " if line starts with pipeline
    " and last line ends with a pipeline,
    " align them
    if last_line =~ '|>.*$' &&
          \ current_line =~ s:starts_with_pipeline
      let ind = float2nr(match(last_line, '|>') / &sw) * &sw
    " if line starts with pipeline
    " and last line is an attribution
    " indents pipeline in same level as attribution
    elseif current_line =~ s:starts_with_pipeline &&
          \ last_line =~ '^[^=]\+=.\+$'
      if !exists('b:old_ind') || b:old_ind == 0
        let b:old_ind = indent(lnum)
      end
      let ind = float2nr(matchend(last_line, '=\s*[^ ]') / &sw) * &sw
    endif
    " if last line starts with pipeline
    " and current line doesn't start with pipeline
    " returns the indentation before the pipeline
    if last_line =~ s:starts_with_pipeline &&
          \ current_line !~ s:starts_with_pipeline
      let ind = b:old_ind
    endif
    if current_line =~ s:deindent_keywords
      let bslnum = searchpair(
            \ s:pair_start,
            \ s:pair_middle,
            \ s:pair_end,
            \ 'nbW',
            \ s:block_skip
            \ )
      let ind = indent(bslnum)
    endif
    " indent case statements '->'
    if current_line =~ s:arrow
      let ind += &sw
    endif
  endif
  return ind
endfunction
let &cpo = s:cpo_save
unlet s:cpo_save
endif
 |