@@ -20,6 +20,7 @@ function! elixir#indent#indent(lnum)
2020 call cursor (lnum, 0 )
2121
2222 let handlers = [
23+ \' inside_embedded_view',
2324 \' top_of_file',
2425 \' starts_with_string_continuation',
2526 \' following_trailing_binary_operator',
@@ -65,6 +66,17 @@ function! s:prev_starts_with(context, expr)
6566 return s: _starts_with (a: context .prev_nb_text, a: expr , a: context .prev_nb_lnum)
6667endfunction
6768
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+
6880" Returns 0 or 1 based on whether or not the text starts with the given
6981" expression and is not a string or comment
7082function ! s: _starts_with (text, expr , lnum)
@@ -156,6 +168,104 @@ function! s:find_last_pos(lnum, text, match)
156168 return -1
157169endfunction
158170
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 , ' ^<*\/>' )
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+
159269function ! elixir#indent#handle_top_of_file (context)
160270 if a: context .prev_nb_lnum == 0
161271 return 0
0 commit comments