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
Fix HTML indent lasttick update #3673
Comments
An alternative would be to change the check instead of making My rationale for making the change this way is motivated by backward compatibility: setl inde=FixedHtmlIndent()
func! FixedHtmlIndent()
let indent = HtmlIndent()
let b:hi_lasttick = b:changedtick - 1
return indent
endfunc Placed in ~/.vim/after, this snippet monkey-patches the current version of the code to reuse state appropriately. Changing the assignment to |
There appears to be an inconsistency such that when the previous line
then the freshly computed state's baseindent is based on the closing tag, while HtmlIndent's incremental update computes baseindent based on the tags being opened. This leads to a behaviour difference between the two modes of operation. A small example: <p>
https://thesaurus.weblio.jp/content/%E6%B0%97<wbr>%E3%81%8C<wbr>%E5%A4%A7<wbr>%E3%81%8D<wbr>%E3%81%8F<wbr>%E3%81%AA<wbr>%E3%82%8B</p>
This line gets indented inconsistently.```
Notice the element in the example, `<wbr>`, is one of the HTML 5 tags which is mistakenly listed as a paired tag, but is in fact a void element. This edge case occurs only when tags expected to close are not closed, which can only correctly occur for self-closing tags.
I have amended the patch above to remove the following self-closing HTML 5 tags from the list of indented tags: area, keygen, rp, rt, track, wbr.
In addition, the following tags *may* be self-closing under certain conditions: body, dd, dt, head, html, li, optgroup, option, td, tfoot, th, thead, tr. However, all of these are likely to contain contents which it may be desirable to indent. |
Since 7.4.345 (2014-06-25), when the check was introduced, the html
indent checks and sets b:hi_lasttick inconsistently:
```vim
993 if prevnonblank(v:lnum - 1) == b:hi_indent.lnum && b:hi_lasttick == b:changedtick - 1
1062 let b:hi_lasttick = b:changedtick
```
This results in always recomputing a fresh state when the buffer has
_not_ changed, and very rarely may attempt to reuse a state after a
buffer change. The only case where this is likely to be correct is
when indenting the line immediately following a line whose indentation
was just changed by the indenter, and can mistakenly reuse state when
exactly one unrelated change has occurred in the meantime.
Always using a fresh state almost always gets the right _indentation_,
but has noticeably awful O(n^2) performance when reindenting the
entirety of HTML files with many lines.
The fix is trivial. However, I have not checked that the state update
in HtmlIndent() is correct and matches the logic in FreshState(); it
seems fine on casual inspection, but there may be bugs lurking there
that haven't had a chance to manifest in the past four years because
state reuse occurs so rarely.
```diff
diff --git a/runtime/indent/html.vim b/runtime/indent/html.vim
index bece6614b..03bf207b9 100644
--- a/runtime/indent/html.vim
+++ b/runtime/indent/html.vim
@@ -1059,7 +1059,7 @@ func! HtmlIndent()
endif
endif
- let b:hi_lasttick = b:changedtick
+ let b:hi_lasttick = b:changedtick - 1
call extend(b:hi_indent, b:hi_newstate, "force")
return indent
endfunc "}}}
```
I started looking into this and improving a few things, but quickly got
lost in the undocumented parts. I'll have to get back to this when I
have more time.
I'll include the parts that should be OK.
…--
ARTHUR: What are you going to do. bleed on me?
"Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD
/// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
|
See also: vim/vim#3673 In addition, set as "auto" tags that apply to "content" (as opposed to e.g. layout, metadata), so that the former can be flush at left margin.
Since 7.4.345 (2014-06-25), when the check was introduced, the html indent checks and sets b:hi_lasttick inconsistently:
This results in always recomputing a fresh state when the buffer has not changed, and very rarely may attempt to reuse a state after a buffer change. The only case where this is likely to be correct is when indenting the line immediately following a line whose indentation was just changed by the indenter, and can mistakenly reuse state when exactly one unrelated change has occurred in the meantime.
Always using a fresh state almost always gets the right indentation, but has noticeably awful O(n^2) performance when reindenting the entirety of HTML files with many lines.
The fix is trivial. However, I have not checked that the state update in HtmlIndent() is correct and matches the logic in FreshState(); it seems fine on casual inspection, but there may be bugs lurking there that haven't had a chance to manifest in the past four years because state reuse occurs so rarely.
The text was updated successfully, but these errors were encountered: