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