From 8bb1c3e53ef0ee259cfa5f9b3a3a91ec1fa90fb0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 4 Jul 2014 16:43:17 +0200 Subject: [PATCH] Updated runtime files. Overhauled HTML indent script. --- runtime/doc/change.txt | 6 +- runtime/doc/eval.txt | 7 +- runtime/doc/options.txt | 2 +- runtime/doc/spell.txt | 9 +- runtime/doc/syntax.txt | 4 +- runtime/doc/todo.txt | 35 +- runtime/indent/html.vim | 1306 ++++++++++++++++++++++++++------------- 7 files changed, 936 insertions(+), 433 deletions(-) diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt index da981c483..de340ec8b 100644 --- a/runtime/doc/change.txt +++ b/runtime/doc/change.txt @@ -1,4 +1,4 @@ -*change.txt* For Vim version 7.4. Last change: 2014 Feb 11 +*change.txt* For Vim version 7.4. Last change: 2014 Jun 26 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1717,8 +1717,8 @@ Note that using `:sort` with `:global` doesn't sort the matching lines, it's quite useless. The details about sorting depend on the library function used. There is no -guarantee that sorting is "stable" or obeys the current locale. You will have -to try it out. +guarantee that sorting obeys the current locale. You will have to try it out. +Vim does do a "stable" sort. The sorting can be interrupted, but if you interrupt it too late in the process you may end up with duplicated lines. This also depends on the system diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index c61ac07f4..42cf14cbb 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 7.4. Last change: 2014 Jun 25 +*eval.txt* For Vim version 7.4. Last change: 2014 Jul 02 VIM REFERENCE MANUAL by Bram Moolenaar @@ -5651,6 +5651,11 @@ sort({list} [, {func} [, {dict}]]) *sort()* *E702* {dict} is for functions with the "dict" attribute. It will be used to set the local variable "self". |Dictionary-function| + The sort is stable, items which compare equal (as number or as + string) will keep their relative position. E.g., when sorting + on numbers, text strings will sort next to eachother, in the + same order as they were originally. + Also see |uniq()|. Example: > diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index e1e1154a0..763dab178 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1,4 +1,4 @@ -*options.txt* For Vim version 7.4. Last change: 2014 Jun 25 +*options.txt* For Vim version 7.4. Last change: 2014 Jun 26 VIM REFERENCE MANUAL by Bram Moolenaar diff --git a/runtime/doc/spell.txt b/runtime/doc/spell.txt index a39bec905..3ffd8932e 100644 --- a/runtime/doc/spell.txt +++ b/runtime/doc/spell.txt @@ -1,4 +1,4 @@ -*spell.txt* For Vim version 7.4. Last change: 2013 Nov 12 +*spell.txt* For Vim version 7.4. Last change: 2014 Jul 02 VIM REFERENCE MANUAL by Bram Moolenaar @@ -939,9 +939,10 @@ be combined without errors. If you get an E763 warning that the word tables differ you need to update your ".spl" spell files. If you downloaded the files, get the latest version of -all spell files you use. Otherwise generate the .spl file again with -|:mkspell|. If you still get errors check the FOL, LOW and UPP lines in the -used .aff files. +all spell files you use. If you are only using one, e.g., German, then also +download the recent English spell files. Otherwise generate the .spl file +again with |:mkspell|. If you still get errors check the FOL, LOW and UPP +lines in the used .aff files. The XX.ascii.spl spell file generated with the "-ascii" argument will not contain the table with characters, so that it can be combine with spell files diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index e68ad4379..35ea3ad7b 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -1,4 +1,4 @@ -*syntax.txt* For Vim version 7.4. Last change: 2014 Jun 03 +*syntax.txt* For Vim version 7.4. Last change: 2014 Jun 27 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1688,7 +1688,7 @@ vimrc file: > HTML comments are rather special (see an HTML reference document for the details), and the syntax coloring scheme will highlight all errors. However, if you prefer to use the wrong style (starts with ) you can define > +ends with -->) you can define > :let html_wrong_comments=1 JavaScript and Visual Basic embedded inside HTML documents are highlighted as diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt index d0ddf5b46..3752f2daf 100644 --- a/runtime/doc/todo.txt +++ b/runtime/doc/todo.txt @@ -1,4 +1,4 @@ -*todo.txt* For Vim version 7.4. Last change: 2014 Jun 25 +*todo.txt* For Vim version 7.4. Last change: 2014 Jul 04 VIM REFERENCE MANUAL by Bram Moolenaar @@ -34,6 +34,14 @@ not be repeated below, unless there is extra information. *known-bugs* -------------------- Known bugs and current work ----------------------- +Sort is still not stable, add an index in the array. +See patch from Takimoto. + +Another follow-up patch for breakindent. (Christian, 2014 Jun 28) + +After patch 7.4.305 the termresponse isn't requested at all? +(Tomas Janousek, 2014 Jul 1, Jul 2) + Regexp problems: - Bug with pattern: '\vblock (\d+)\.\n.*\d+%(\1)@ -" Last Change: 2014 Jun 19 -" Rev Days: 13 -" Version: 0.9 -" Vim Version: Vim7 -" Description: -" Improved version of the distributed html indent script, faster on a -" range of lines. +" Header: "{{{ +" Maintainer: Bram Moolenaar +" Original Author: Andy Wokula +" Last Change: 2014 Jul 04 +" Version: 1.0 +" Description: HTML indent script with cached state for faster indenting on a +" range of lines. +" Supports template systems through hooks. +" Supports Closure stylesheets. " " Credits: " indent/html.vim (2006 Jun 05) from J. Zellner " indent/css.vim (2006 Dec 20) from N. Weibull " " History: +" 2014 June (v1.0) overhaul (Bram) " 2012 Oct 21 (v0.9) added support for shiftwidth() " 2011 Sep 09 (v0.8) added HTML5 tags (thx to J. Zuckerman) " 2008 Apr 28 (v0.6) revised customization " 2008 Mar 09 (v0.5) fixed 'indk' issue (thx to C.J. Robinson) -" }}} +"}}} -" Init Folklore, check user settings (2nd time ++) "{{{ -if exists("b:did_indent") - finish +" Init Folklore, check user settings (2nd time ++) +if exists("b:did_indent") "{{{ + finish endif let b:did_indent = 1 setlocal indentexpr=HtmlIndent() setlocal indentkeys=o,O,,<>>,{,},!^F -" Needed for % to work when finding start of a tag. +" "j1" is included to make cindent() work better with Javascript. +setlocal cino=j1 +" "J1" should be included, but it doen't work properly before 7.4.355. +if has("patch-7.4.355") + setlocal cino+=J1 +endif +" Before patch 7.4.355 indenting after "(function() {" does not work well, add +" )2 to limit paren search. +if !has("patch-7.4.355") + setlocal cino+=)2 +endif + +" Needed for % to work when finding start/end of a tag. setlocal matchpairs+=<:> -let b:indent = {"lnum": -1} -let b:undo_indent = "set inde< indk<| unlet b:indent" +let b:undo_indent = "setlocal inde< indk< cino<" + +" b:hi_indent keeps state to speed up indenting consecutive lines. +let b:hi_indent = {"lnum": -1} -" Load Once: -if exists("*HtmlIndent") - call HtmlIndent_CheckUserSettings() - finish +"""""" Code below this is loaded only once. """"" +if exists("*HtmlIndent") && !exists('g:force_reload_html') + call HtmlIndent_CheckUserSettings() + finish endif -" Patch 7.3.694 +" shiftwidth() exists since patch 7.3.694 if exists('*shiftwidth') - let s:ShiftWidth = function('shiftwidth') + let s:ShiftWidth = function('shiftwidth') else - func! s:ShiftWidth() - return &shiftwidth - endfunc + func! s:ShiftWidth() + return &shiftwidth + endfunc endif +" Allow for line continuation below. let s:cpo_save = &cpo set cpo-=C "}}} -func! HtmlIndent_CheckUserSettings() "{{{ - if exists("g:html_indent_inctags") - call s:AddITags(split(g:html_indent_inctags, ",")) - endif - if exists("g:html_indent_autotags") - call s:RemoveITags(split(g:html_indent_autotags, ",")) - endif +" Check and process settings from b:html_indent and g:html_indent... variables. +" Prefer using buffer-local settings over global settings, so that there can +" be defaults for all HTML files and exceptions for specific types of HTML +" files. +func! HtmlIndent_CheckUserSettings() + "{{{ + let inctags = '' + if exists("b:html_indent_inctags") + let inctags = b:html_indent_inctags + elseif exists("g:html_indent_inctags") + let inctags = g:html_indent_inctags + endif + let b:hi_tags = {} + if len(inctags) > 0 + call s:AddITags(b:hi_tags, split(inctags, ",")) + endif - let indone = {"zero": 0 - \,"auto": "indent(prevnonblank(v:lnum-1))" - \,"inc": "b:indent.blocktagind + s:ShiftWidth()"} - if exists("g:html_indent_script1") - let s:js1indent = get(indone, g:html_indent_script1, indone.zero) - endif - if exists("g:html_indent_style1") - let s:css1indent = get(indone, g:html_indent_style1, indone.zero) + let autotags = '' + if exists("b:html_indent_autotags") + let autotags = b:html_indent_autotags + elseif exists("g:html_indent_autotags") + let autotags = g:html_indent_autotags + endif + let b:hi_removed_tags = {} + if autotags + call s:RemoveITags(b:hi_removed_tags, split(autotags, ",")) + endif + + " Syntax names indicating being inside a string of an attribute value. + let string_names = [] + if exists("b:html_indent_string_names") + let string_names = b:html_indent_string_names + elseif exists("g:html_indent_string_names") + let string_names = g:html_indent_string_names + endif + let b:hi_insideStringNames = ['htmlString'] + if len(string_names) > 0 + for s in string_names + call add(b:hi_insideStringNames, s) + endfor + endif + + " Syntax names indicating being inside a tag. + let tag_names = [] + if exists("b:html_indent_tag_names") + let tag_names = b:html_indent_tag_names + elseif exists("g:html_indent_tag_names") + let tag_names = g:html_indent_tag_names + endif + let b:hi_insideTagNames = ['htmlTag', 'htmlScriptTag'] + if len(tag_names) > 0 + for s in tag_names + call add(b:hi_insideTagNames, s) + endfor + endif + + let indone = {"zero": 0 + \,"auto": "indent(prevnonblank(v:lnum-1))" + \,"inc": "b:hi_indent.blocktagind + s:ShiftWidth()"} + + let script1 = '' + if exists("b:html_indent_script1") + let script1 = b:html_indent_script1 + elseif exists("g:html_indent_script1") + let script1 = g:html_indent_script1 + endif + if len(script1) > 0 + let b:hi_js1indent = get(indone, script1, indone.zero) + else + let b:hi_js1indent = 0 + endif + + let style1 = '' + if exists("b:html_indent_style1") + let style1 = b:html_indent_style1 + elseif exists("g:html_indent_style1") + let style1 = g:html_indent_style1 + endif + if len(style1) > 0 + let b:hi_css1indent = get(indone, style1, indone.zero) + else + let b:hi_css1indent = 0 + endif + + if !exists('b:html_indent_line_limit') + if exists('g:html_indent_line_limit') + let b:html_indent_line_limit = g:html_indent_line_limit + else + let b:html_indent_line_limit = 200 endif + endif endfunc "}}} -" Init Script Vars "{{{ -let s:lasttick = 0 -let s:css1indent = 0 -let s:js1indent = 0 -" not to be changed: -let s:endtags = [0,0,0,0,0,0,0,0] " some places unused -let s:newstate = {} +" Init Script Vars +"{{{ +let b:hi_lasttick = 0 +let b:hi_newstate = {} let s:countonly = 0 "}}} -func! s:AddITags(taglist) "{{{ - for itag in a:taglist - let s:indent_tags[itag] = 1 - let s:indent_tags['/'.itag] = -1 - endfor + +" Fill the s:indent_tags dict with known tags. +" The key is "tagname" or "/tagname". {{{ +" The value is: +" 1 opening tag +" 2 "pre" +" 3 "script" +" 4 "style" +" 5 comment start +" -1 closing tag +" -2 "/pre" +" -3 "/script" +" -4 "/style" +" -5 comment end +let s:indent_tags = {} +let s:endtags = [0,0,0,0,0,0] " long enough for the highest index +"}}} + +" Add a list of tag names for a pair of to "tags". +func! s:AddITags(tags, taglist) + "{{{ + for itag in a:taglist + let a:tags[itag] = 1 + let a:tags['/' . itag] = -1 + endfor endfunc "}}} -func! s:AddBlockTag(tag, id, ...) "{{{ - if !(a:id >= 2 && a:id < 2+len(s:endtags)) - return - endif - let s:indent_tags[a:tag] = a:id - if a:0 == 0 - let s:indent_tags['/'.a:tag] = -a:id - let s:endtags[a:id-2] = "" - else - let s:indent_tags[a:1] = -a:id - let s:endtags[a:id-2] = a:1 - endif + +" Take a list of tag name pairs that are not to be used as tag pairs. +func! s:RemoveITags(tags, taglist) + "{{{ + for itag in a:taglist + let a:tags[itag] = 1 + let a:tags['/' . itag] = 1 + endfor endfunc "}}} -func! s:RemoveITags(taglist) "{{{ - " remove itags (protect blocktags from being removed) - for itag in a:taglist - if !has_key(s:indent_tags, itag) || s:indent_tags[itag] != 1 - continue - endif - unlet s:indent_tags[itag] - if itag =~ '^\w\+$' - unlet s:indent_tags["/".itag] - endif - endfor + +" Add a block tag, that is a tag with a different kind of indenting. +func! s:AddBlockTag(tag, id, ...) + "{{{ + if !(a:id >= 2 && a:id < len(s:endtags)) + echoerr 'AddBlockTag ' . a:id + return + endif + let s:indent_tags[a:tag] = a:id + if a:0 == 0 + let s:indent_tags['/' . a:tag] = -a:id + let s:endtags[a:id] = "" + else + let s:indent_tags[a:1] = -a:id + let s:endtags[a:id] = a:1 + endif endfunc "}}} -" Add Indent Tags: {{{ -if !exists("s:indent_tags") - let s:indent_tags = {} -endif -" old tags: -call s:AddITags(['a', 'abbr', 'acronym', 'address', 'b', 'bdo', 'big', - \ 'blockquote', 'button', 'caption', 'center', 'cite', 'code', 'colgroup', - \ 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', 'form', - \ 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'i', 'iframe', 'ins', 'kbd', - \ 'label', 'legend', 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', +" Add known tag pairs. +" Self-closing tags and tags that are sometimes {{{ +" self-closing (e.g.,

) are not here (when encountering

we can find +" the matching

, but not the other way around). +" Old HTML tags: +call s:AddITags(s:indent_tags, [ + \ 'a', 'abbr', 'acronym', 'address', 'b', 'bdo', 'big', + \ 'blockquote', 'body', 'button', 'caption', 'center', 'cite', 'code', + \ 'colgroup', 'del', 'dfn', 'dir', 'div', 'dl', 'em', 'fieldset', 'font', + \ 'form', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'html', + \ 'i', 'iframe', 'ins', 'kbd', 'label', 'legend', 'li', + \ 'map', 'menu', 'noframes', 'noscript', 'object', 'ol', \ 'optgroup', 'q', 's', 'samp', 'select', 'small', 'span', 'strong', 'sub', \ 'sup', 'table', 'textarea', 'title', 'tt', 'u', 'ul', 'var', 'th', 'td', - \ 'tr', 'tfoot', 'thead']) + \ 'tr', 'tbody', 'tfoot', 'thead']) -" tags added 2011 Sep 09 (especially HTML5 tags): -call s:AddITags(['area', 'article', 'aside', 'audio', 'bdi', 'canvas', +" Tags added 2011 Sep 09 (especially HTML5 tags): +call s:AddITags(s:indent_tags, [ + \ 'area', 'article', 'aside', 'audio', 'bdi', 'canvas', \ 'command', 'datalist', 'details', 'embed', 'figure', 'footer', \ 'header', 'group', 'keygen', 'mark', 'math', 'meter', 'nav', 'output', \ 'progress', 'ruby', 'section', 'svg', 'texture', 'time', 'video', \ 'wbr', 'text']) - "}}} -" Add Block Tags: contain alien content "{{{ + +" Add Block Tags: these contain alien content +"{{{ call s:AddBlockTag('pre', 2) call s:AddBlockTag('script', 3) call s:AddBlockTag('style', 4) call s:AddBlockTag('') "}}} -func! s:CountITags(...) "{{{ +" Return non-zero when "tagname" is an opening tag, not being a block tag, for +" which there should be a closing tag. Can be used by scripts that include +" HTML indenting. +func! HtmlIndent_IsOpenTag(tagname) + "{{{ + if get(s:indent_tags, a:tagname) == 1 + return 1 + endif + return get(b:hi_tags, a:tagname) == 1 +endfunc "}}} - " relative indent steps for current line [unit &sw]: - let s:curind = 0 - " relative indent steps for next line [unit &sw]: - let s:nextrel = 0 +" Get the value for "tagname", taking care of buffer-local tags. +func! s:get_tag(tagname) + "{{{ + let i = get(s:indent_tags, a:tagname) + if (i == 1 || i == -1) && get(b:hi_removed_tags, a:tagname) != 0 + return 0 + endif + if i == 0 + let i = get(b:hi_tags, a:tagname) + endif + return i +endfunc "}}} - if a:0==0 - let s:block = s:newstate.block - let tmpline = substitute(s:curline, '<\zs/\=\w\+\>\|', '\=s:CheckTag(submatch(0))', 'g') - if s:block == 3 - let s:newstate.scripttype = s:GetScriptType(matchstr(tmpline, '\C.*\zs[^>]*')) - endif - let s:newstate.block = s:block - else - let s:block = 0 " assume starting outside of a block - let s:countonly = 1 " don't change state - let tmpline = substitute(s:altline, '<\zs/\=\w\+\>\|', '\=s:CheckTag(submatch(0))', 'g') - let s:countonly = 0 - endif +" Count the number of start and end tags in "text". +func! s:CountITags(text) + "{{{ + " Store the result in s:curind and s:nextrel. + let s:curind = 0 " relative indent steps for current line [unit &sw]: + let s:nextrel = 0 " relative indent steps for next line [unit &sw]: + let s:block = 0 " assume starting outside of a block + let s:countonly = 1 " don't change state + call substitute(a:text, '<\zs/\=\w\+\>\|', '\=s:CheckTag(submatch(0))', 'g') + let s:countonly = 0 endfunc "}}} -func! s:CheckTag(itag) "{{{ - " "tag" or "/tag" or "" - let ind = get(s:indent_tags, a:itag) - if ind == -1 - " closing tag - if s:block != 0 - " ignore itag within a block - return "foo" - endif - if s:nextrel == 0 - let s:curind -= 1 - else - let s:nextrel -= 1 - endif - " if s:curind >= 1 - " let s:curind -= 1 - " else - " let s:nextrel -= 1 - " endif - elseif ind == 1 - " opening tag - if s:block != 0 - return "foo" - endif - let s:nextrel += 1 - elseif ind != 0 - " block-tag (opening or closing) - return s:Blocktag(a:itag, ind) - endif - " else ind==0 (other tag found): keep indent - return "foo" " no matter + +" Count the number of start and end tags in text. +func! s:CountTagsAndState(text) + "{{{ + " Store the result in s:curind and s:nextrel. Update b:hi_newstate.block. + let s:curind = 0 " relative indent steps for current line [unit &sw]: + let s:nextrel = 0 " relative indent steps for next line [unit &sw]: + + let s:block = b:hi_newstate.block + let tmp = substitute(a:text, '<\zs/\=\w\+\>\|', '\=s:CheckTag(submatch(0))', 'g') + if s:block == 3 + let b:hi_newstate.scripttype = s:GetScriptType(matchstr(tmp, '\C.*\zs[^>]*')) + endif + let b:hi_newstate.block = s:block endfunc "}}} -func! s:Blocktag(blocktag, ind) "{{{ - if a:ind > 0 - " a block starts here - if s:block != 0 - " already in a block (nesting) - ignore - " especially ignore comments after other blocktags - return "foo" - endif - let s:block = a:ind " block type - if s:countonly - return "foo" - endif - let s:newstate.blocklnr = v:lnum - " save allover indent for the endtag - let s:newstate.blocktagind = b:indent.baseindent + (s:nextrel + s:curind) * s:ShiftWidth() - if a:ind == 3 - return "SCRIPT" " all except this must be lowercase - " line is to be checked again for the type attribute - endif - else - let s:block = 0 - " we get here if starting and closing block-tag on same line + +" Used by s:CountITags() and s:CountTagsAndState(). +func! s:CheckTag(itag) + "{{{ + " Returns an empty string or "SCRIPT". + " a:itag can be "tag" or "/tag" or "" + let ind = s:get_tag(a:itag) + if ind == -1 + " closing tag + if s:block != 0 + " ignore itag within a block + return "" endif - return "foo" -endfunc "}}} -func! s:GetScriptType(str) "{{{ - if a:str == "" || a:str =~ "java" - return "javascript" + if s:nextrel == 0 + let s:curind -= 1 else - return "" + let s:nextrel -= 1 + endif + elseif ind == 1 + " opening tag + if s:block != 0 + return "" endif + let s:nextrel += 1 + elseif ind != 0 + " block-tag (opening or closing) + return s:CheckBlockTag(a:itag, ind) + " else ind==0 (other tag found): keep indent + endif + return "" endfunc "}}} -func! s:FreshState(lnum) "{{{ - " Look back in the file (lines 1 to a:lnum-1) to calc a state for line - " a:lnum. A state is to know ALL relevant details about the lines - " 1..a:lnum-1, initial calculating (here!) can be slow, but updating is - " fast (incremental). - " State: - " lnum last indented line == prevnonblank(a:lnum - 1) - " block = 0 a:lnum located within special tag: 0:none, 2:

,
-    "			3: