Skip to content

Commit 0e643f9

Browse files
committed
Indent embedded views
1 parent 527e6fd commit 0e643f9

File tree

3 files changed

+371
-1
lines changed

3 files changed

+371
-1
lines changed

autoload/elixir/indent.vim

+111
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
if !exists("g:elixir_indent_max_lookbehind")
22
let g:elixir_indent_max_lookbehind = 30
33
endif
4+
let g:elixir_indent_debug = 1
45

56
" Return the effective value of 'shiftwidth'
67
function! s:sw()
@@ -20,6 +21,7 @@ function! elixir#indent#indent(lnum)
2021
call cursor(lnum, 0)
2122

2223
let handlers = [
24+
\'inside_embedded_view',
2325
\'top_of_file',
2426
\'starts_with_string_continuation',
2527
\'following_trailing_binary_operator',
@@ -65,6 +67,17 @@ function! s:prev_starts_with(context, expr)
6567
return s:_starts_with(a:context.prev_nb_text, a:expr, a:context.prev_nb_lnum)
6668
endfunction
6769

70+
function! s:in_embedded_view()
71+
let groups = map(synstack(line('.'), col('.')), "synIDattr(v:val, 'name')")
72+
for group in ['elixirPhoenixESigil', 'elixirLiveViewSigil', 'elixirSurfaceSigil']
73+
if index(groups, group) >= 0
74+
return 1
75+
endif
76+
endfor
77+
78+
return 0
79+
endfunction
80+
6881
" Returns 0 or 1 based on whether or not the text starts with the given
6982
" expression and is not a string or comment
7083
function! s:_starts_with(text, expr, lnum)
@@ -156,6 +169,104 @@ function! s:find_last_pos(lnum, text, match)
156169
return -1
157170
endfunction
158171

172+
function! elixir#indent#handle_inside_embedded_view(context)
173+
if !s:in_embedded_view()
174+
return -1
175+
endif
176+
177+
" Multi-line Surface data delimiters
178+
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]))
179+
if pair_lnum
180+
if a:context.text =~ '}}$'
181+
return indent(pair_lnum)
182+
elseif a:context.text =~ '}}*>$'
183+
return -1
184+
elseif s:prev_ends_with(a:context, '[\|%{')
185+
return indent(a:context.prev_nb_lnum) + s:sw()
186+
elseif a:context.prev_nb_text =~ ',$'
187+
return indent(a:context.prev_nb_lnum)
188+
else
189+
return indent(pair_lnum) + s:sw()
190+
endif
191+
endif
192+
193+
" Multi-line opening tag -- >, />, or %> are on a different line that their opening <
194+
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]))
195+
if pair_lnum
196+
if a:context.text =~ '^\s\+\%\(>\|\/>\|%>\|}}>\)$'
197+
call s:debug("current line is a lone >, />, or %>")
198+
return indent(pair_lnum)
199+
elseif a:context.text =~ '\%\(>\|\/>\|%>\|}}>\)$'
200+
call s:debug("current line ends in >, />, or %>")
201+
if s:prev_ends_with(a:context, ',')
202+
return indent(a:context.prev_nb_lnum)
203+
else
204+
return -1
205+
endif
206+
else
207+
call s:debug("in the body of a multi-line opening tag")
208+
return indent(pair_lnum) + s:sw()
209+
endif
210+
endif
211+
212+
" Special cases
213+
if s:prev_ends_with(a:context, '^[^<]*do\s%>')
214+
call s:debug("prev line closes a multi-line do block")
215+
return indent(a:context.prev_nb_lnum)
216+
elseif a:context.prev_nb_text =~ 'do\s*%>$'
217+
call s:debug("prev line opens a do block")
218+
return indent(a:context.prev_nb_lnum) + s:sw()
219+
elseif a:context.text =~ '^\s\+<\/[a-zA-Z0-9\.\-_]\+>\|<% end %>'
220+
call s:debug("a single closing tag")
221+
if a:context.prev_nb_text =~ '^\s\+<[^%\/]*[^/]>.*<\/[a-zA-Z0-9\.\-_]\+>$'
222+
call s:debug("opening and closing tags are on the same line")
223+
return indent(a:context.prev_nb_lnum) - s:sw()
224+
elseif a:context.prev_nb_text =~ '^\s\+<[^%\/]*[^/]>\|\s\+>'
225+
call s:debug("prev line is opening html tag or single >")
226+
return indent(a:context.prev_nb_lnum)
227+
elseif s:prev_ends_with(a:context, '^[^<]*\%\(do\s\)\@<!%>')
228+
call s:debug("prev line closes a multi-line eex tag")
229+
return indent(a:context.prev_nb_lnum) - 2 * s:sw()
230+
else
231+
return indent(a:context.prev_nb_lnum) - s:sw()
232+
endif
233+
elseif a:context.text =~ '^\s*<%\s*\%(end\|else\|catch\|rescue\)\>.*%>'
234+
call s:debug("eex middle or closing eex tag")
235+
return indent(a:context.prev_nb_lnum) - s:sw()
236+
elseif a:context.prev_nb_text =~ '\s*<\/\|<% end %>$'
237+
call s:debug("prev is closing tag")
238+
return indent(a:context.prev_nb_lnum)
239+
elseif a:context.prev_nb_text =~ '^\s\+<[^%\/]*[^/]>.*<\/[a-zA-Z0-9\.\-_]\+>$'
240+
call s:debug("opening and closing tags are on the same line")
241+
return indent(a:context.prev_nb_lnum)
242+
elseif s:prev_ends_with(a:context, '\s\+\/>')
243+
call s:debug("prev ends with a single \>")
244+
return indent(a:context.prev_nb_lnum)
245+
elseif s:prev_ends_with(a:context, '^[^<]*\/>')
246+
call s:debug("prev line is closing a multi-line self-closing tag")
247+
return indent(a:context.prev_nb_lnum) - s:sw()
248+
elseif s:prev_ends_with(a:context, '^<*\/>')
249+
call s:debug("prev line is closing self-closing tag")
250+
return indent(a:context.prev_nb_lnum)
251+
elseif a:context.prev_nb_text =~ '^\s\+%\?>$'
252+
call s:debug("prev line is a single > or %>")
253+
return indent(a:context.prev_nb_lnum) + s:sw()
254+
endif
255+
256+
" Simple HTML (ie, opening tag is not split across lines)
257+
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]))
258+
if pair_lnum
259+
call s:debug("simple HTML")
260+
if a:context.text =~ '^\s\+<\/\w\+>$'
261+
return indent(pair_lnum)
262+
else
263+
return indent(pair_lnum) + s:sw()
264+
endif
265+
endif
266+
267+
return -1
268+
endfunction
269+
159270
function! elixir#indent#handle_top_of_file(context)
160271
if a:context.prev_nb_lnum == 0
161272
return 0

indent/elixir.vim

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ let b:did_indent = 1
66
setlocal indentexpr=elixir#indent(v:lnum)
77

88
setlocal indentkeys+==after,=catch,=do,=else,=end,=rescue,
9-
setlocal indentkeys+=*<Return>,=->,=\|>,=<>,0},0],0)
9+
setlocal indentkeys+=*<Return>,=->,=\|>,=<>,0},0],0),>
1010

1111
" TODO: @jbodah 2017-02-27: all operators should cause reindent when typed
1212

0 commit comments

Comments
 (0)