@@ -20,6 +20,7 @@ function! elixir#indent#indent(lnum)
20
20
call cursor (lnum, 0 )
21
21
22
22
let handlers = [
23
+ \' inside_embedded_view',
23
24
\' top_of_file',
24
25
\' starts_with_string_continuation',
25
26
\' following_trailing_binary_operator',
@@ -65,6 +66,17 @@ function! s:prev_starts_with(context, expr)
65
66
return s: _starts_with (a: context .prev_nb_text, a: expr , a: context .prev_nb_lnum)
66
67
endfunction
67
68
69
+ function ! s: in_embedded_view ()
70
+ let groups = map (synstack (line (' .' ), col (' .' )), " synIDattr(v:val, 'name')" )
71
+ for group in [' elixirPhoenixESigil' , ' elixirLiveViewSigil' , ' elixirSurfaceSigil' ]
72
+ if index (groups, group) >= 0
73
+ return 1
74
+ endif
75
+ endfor
76
+
77
+ return 0
78
+ endfunction
79
+
68
80
" Returns 0 or 1 based on whether or not the text starts with the given
69
81
" expression and is not a string or comment
70
82
function ! s: _starts_with (text, expr , lnum)
@@ -156,6 +168,104 @@ function! s:find_last_pos(lnum, text, match)
156
168
return -1
157
169
endfunction
158
170
171
+ function ! elixir#indent#handle_inside_embedded_view (context)
172
+ if ! s: in_embedded_view ()
173
+ return -1
174
+ endif
175
+
176
+ " Multi-line Surface data delimiters
177
+ let pair_lnum = searchpair (' {{' , ' ' , ' }}' , ' bW' , " line('.') == " .a: context .lnum." || s:is_string_or_comment(line('.'), col('.'))" , max ([0 , a: context .lnum - g: elixir_indent_max_lookbehind ]))
178
+ if pair_lnum
179
+ if a: context .text = ~ ' }}$'
180
+ return indent (pair_lnum)
181
+ elseif a: context .text = ~ ' }}*>$'
182
+ return -1
183
+ elseif s: prev_ends_with (a: context , ' [\|%{' )
184
+ return indent (a: context .prev_nb_lnum) + s: sw ()
185
+ elseif a: context .prev_nb_text = ~ ' ,$'
186
+ return indent (a: context .prev_nb_lnum)
187
+ else
188
+ return indent (pair_lnum) + s: sw ()
189
+ endif
190
+ endif
191
+
192
+ " Multi-line opening tag -- >, />, or %> are on a different line that their opening <
193
+ let pair_lnum = searchpair (' ^\s\+<.*[^>]$' , ' ' , ' ^[^<]*[/%}]\?>$' , ' bW' , " line('.') == " .a: context .lnum." || s:is_string_or_comment(line('.'), col('.'))" , max ([0 , a: context .lnum - g: elixir_indent_max_lookbehind ]))
194
+ if pair_lnum
195
+ if a: context .text = ~ ' ^\s\+\%\(>\|\/>\|%>\|}}>\)$'
196
+ call s: debug (" current line is a lone >, />, or %>" )
197
+ return indent (pair_lnum)
198
+ elseif a: context .text = ~ ' \%\(>\|\/>\|%>\|}}>\)$'
199
+ call s: debug (" current line ends in >, />, or %>" )
200
+ if s: prev_ends_with (a: context , ' ,' )
201
+ return indent (a: context .prev_nb_lnum)
202
+ else
203
+ return -1
204
+ endif
205
+ else
206
+ call s: debug (" in the body of a multi-line opening tag" )
207
+ return indent (pair_lnum) + s: sw ()
208
+ endif
209
+ endif
210
+
211
+ " Special cases
212
+ if s: prev_ends_with (a: context , ' ^[^<]*do\s%>' )
213
+ call s: debug (" prev line closes a multi-line do block" )
214
+ return indent (a: context .prev_nb_lnum)
215
+ elseif a: context .prev_nb_text = ~ ' do\s*%>$'
216
+ call s: debug (" prev line opens a do block" )
217
+ return indent (a: context .prev_nb_lnum) + s: sw ()
218
+ elseif a: context .text = ~ ' ^\s\+<\/[a-zA-Z0-9\.\-_]\+>\|<% end %>'
219
+ call s: debug (" a single closing tag" )
220
+ if a: context .prev_nb_text = ~ ' ^\s\+<[^%\/]*[^/]>.*<\/[a-zA-Z0-9\.\-_]\+>$'
221
+ call s: debug (" opening and closing tags are on the same line" )
222
+ return indent (a: context .prev_nb_lnum) - s: sw ()
223
+ elseif a: context .prev_nb_text = ~ ' ^\s\+<[^%\/]*[^/]>\|\s\+>'
224
+ call s: debug (" prev line is opening html tag or single >" )
225
+ return indent (a: context .prev_nb_lnum)
226
+ elseif s: prev_ends_with (a: context , ' ^[^<]*\%\(do\s\)\@<!%>' )
227
+ call s: debug (" prev line closes a multi-line eex tag" )
228
+ return indent (a: context .prev_nb_lnum) - 2 * s: sw ()
229
+ else
230
+ return indent (a: context .prev_nb_lnum) - s: sw ()
231
+ endif
232
+ elseif a: context .text = ~ ' ^\s*<%\s*\%(end\|else\|catch\|rescue\)\>.*%>'
233
+ call s: debug (" eex middle or closing eex tag" )
234
+ return indent (a: context .prev_nb_lnum) - s: sw ()
235
+ elseif a: context .prev_nb_text = ~ ' \s*<\/\|<% end %>$'
236
+ call s: debug (" prev is closing tag" )
237
+ return indent (a: context .prev_nb_lnum)
238
+ elseif a: context .prev_nb_text = ~ ' ^\s\+<[^%\/]*[^/]>.*<\/[a-zA-Z0-9\.\-_]\+>$'
239
+ call s: debug (" opening and closing tags are on the same line" )
240
+ return indent (a: context .prev_nb_lnum)
241
+ elseif s: prev_ends_with (a: context , ' \s\+\/>' )
242
+ call s: debug (" prev ends with a single \> " )
243
+ return indent (a: context .prev_nb_lnum)
244
+ elseif s: prev_ends_with (a: context , ' ^[^<]*\/>' )
245
+ call s: debug (" prev line is closing a multi-line self-closing tag" )
246
+ return indent (a: context .prev_nb_lnum) - s: sw ()
247
+ elseif s: prev_ends_with (a: context , ' ^\s\+<.*\/>' )
248
+ call s: debug (" prev line is closing self-closing tag" )
249
+ return indent (a: context .prev_nb_lnum)
250
+ elseif a: context .prev_nb_text = ~ ' ^\s\+%\?>$'
251
+ call s: debug (" prev line is a single > or %>" )
252
+ return indent (a: context .prev_nb_lnum) + s: sw ()
253
+ endif
254
+
255
+ " Simple HTML (ie, opening tag is not split across lines)
256
+ let pair_lnum = searchpair (' ^\s\+<[^%\/].*[^\/>]>$' , ' ' , ' ^\s\+<\/\w\+>$' , ' bW' , " line('.') == " .a: context .lnum." || s:is_string_or_comment(line('.'), col('.'))" , max ([0 , a: context .lnum - g: elixir_indent_max_lookbehind ]))
257
+ if pair_lnum
258
+ call s: debug (" simple HTML" )
259
+ if a: context .text = ~ ' ^\s\+<\/\w\+>$'
260
+ return indent (pair_lnum)
261
+ else
262
+ return indent (pair_lnum) + s: sw ()
263
+ endif
264
+ endif
265
+
266
+ return -1
267
+ endfunction
268
+
159
269
function ! elixir#indent#handle_top_of_file (context)
160
270
if a: context .prev_nb_lnum == 0
161
271
return 0
0 commit comments