Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hanging attributes #55

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
5 changes: 5 additions & 0 deletions example.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
{{!-- Should not see unquoted "=", ".", or "/" as a mustacheOperator
unless inside mustacheInside or mustacheParam --}}
<a href=/index.html>
</a>

{{#repo}}
This is a mustache [enumerable] section
Expand Down Expand Up @@ -77,6 +78,10 @@
... with optional else added. Try matchit `%` command over if/else/if.
{{/if}}

{{component-with hanging="attributes"
over="several"
lines="."}}

Thanks goes to {{@defunkt}}
Feedback/blames go to {{@juvenn}}
{{Frustrations}} go to /dev/null
Expand Down
49 changes: 45 additions & 4 deletions indent/handlebars.vim
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ if exists("*GetHandlebarsIndent")
finish
endif

let s:componentClosingPattern = '\v^\s*\{\{\/\S*\}\}\s*'

function! GetHandlebarsIndent(...)
" The value of a single shift-width
if exists('*shiftwidth')
Expand Down Expand Up @@ -79,16 +81,55 @@ function! GetHandlebarsIndent(...)
" all indent rules only apply if the block opening/closing
" tag is on a separate line

" indent after block {{#block
" check for a hanging attribute
let lastLnumCol = col([lnum, '$']) - 1
if synIDattr(synID(lnum, lastLnumCol, 1), "name") =~ '^mustache'
\ && prevLine !~# '}}\s*$'
let hangingAttributePattern = '{{[#^]\=\%(\k\|[/-]\)\+\s\+\zs\k\+='
let standaloneComponentPattern = '^\s*{{\%(\k\|[/-]\)\+\s*$'

if prevLine =~ hangingAttributePattern
" {{component attribute=value
" other=value}}
let [line, col] = searchpos(hangingAttributePattern, 'Wbn', lnum)
if line == lnum
return col - 1
endif
elseif prevLine =~ standaloneComponentPattern
" {{component
" attribute=value}}
return indent(lnum) + sw
endif
endif

" check for a closing }}, indent according to the opening one
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this part of hanging indent, too? Or is this a separate improvement? I just want to keep this PR as clean as possible.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see now that this is necessary for the hanging indent. However, it looks like it duplicates some other functionality.

I notice that on this line:

https://github.com/mustache/vim-mustache-handlebars/pull/55/files#diff-eeee5d46b419bb17834d0b1a86a43f8fR114

It's returning indent(line) + sw, which is also happening later:

  " indent after block: {{#block, {{^block
  if prevLine =~# '\v\s*\{\{[#^].*\s*'
    let ind = ind + sw
  endif

Would it be possible to restrict this section to just the "hanging indent"-related conditionals?

Copy link
Contributor Author

@AndrewRadev AndrewRadev Aug 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't the same case, though. The case that was already there applies on prevLine, while this new case is about the opening line of the prevLine.

Basically, the one that maches prevLine (the existing code) works for this case:

{{#foo}}
  [Cursor]
{{/foo}}

While the new code works on this case:

{{#foo one=two
       three=four}}
  [Cursor]
{{/foo}}

The previous line in this case is not the block opener, it's the three=four}} line. What's the indent on the next line from this one? Well, we need to find its opening line, which is the {{#foo line and take that one + one shiftwidth (if it's a block opener).

For a different explanation, consider the comments -- the existing code is indent after block: {{#block, {{^block. The new code is not indenting after a block tag, it's indenting after the closing part of any tag.

The only way I can see to unify them is to extend the new code to handle the old code's case, because "find the opening part" is the more generic logic. But trying it out, I seem to be breaking the {{else if case in the example, and I don't know why.

To be honest, I don't think it's worth the risk to try to combine the two cases, especially since it would make the one merged case more complicated and possibly trickier to change in the future. Let me know what you think and whether I've explained the difference between the cases well enough.

let saved_pos = getpos('.')
if prevLine =~# '}}$' && prevLine !~# '^\s*{{' &&
\ currentLine !~# s:componentClosingPattern &&
\ search('}}$', 'Wb')
let [line, col] = searchpairpos('{{', '', '}}', 'Wb')
if line > 0
if strpart(getline(line), col - 1, 3) =~ '{{[#^]'
" then it's a block component, indent a shiftwidth more
return indent(line) + sw
else
return indent(line)
endif
Comment on lines +112 to +117
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if strpart(getline(line), col - 1, 3) =~ '{{[#^]'
" then it's a block component, indent a shiftwidth more
return indent(line) + sw
else
return indent(line)
endif
if strpart(getline(line), col - 1, 3) !=~ '{{[#^]'
return indent(line)
endif

We could almost do this, see what I mean? the indent(line) + sw for "normal" indents is happening later anyway, so it would be nice to keep that there.

else
call setpos('.', saved_pos)
endif
endif

" indent after block: {{#block, {{^block
if prevLine =~# '\v\s*\{\{[#^].*\s*'
let ind = ind + sw
endif
" but not if the block ends on the same line
if prevLine =~# '\v\s*\{\{\#(.+)(\s+|\}\}).*\{\{\/\1'
if prevLine =~# '\v\s*\{\{[#^](.+)(\s+|\}\}).*\{\{\/\1'
let ind = ind - sw
endif
" unindent after block close {{/block}}
if currentLine =~# '\v^\s*\{\{\/\S*\}\}\s*'
if currentLine =~# s:componentClosingPattern
let ind = ind - sw
endif
" indent after component block {{a-component
Expand All @@ -105,7 +146,7 @@ function! GetHandlebarsIndent(...)
let closingLnum = search('}}\s*$', 'Wbc', lnum)
let [openingLnum, col] = searchpairpos('{{', '', '}}', 'Wb')
if openingLnum > 0 && closingLnum > 0
if strpart(getline(openingLnum), col - 1, 3) !~ '{{[#^]'
if strpart(getline(openingLnum), col - 1, 3) !~# '{{[#^]'
let ind = ind - sw
endif
else
Expand Down