diff options
| author | Dan Reif <dan.reif@collectivehealth.com> | 2018-04-30 12:00:42 -0700 | 
|---|---|---|
| committer | Dan Reif <dan.reif@collectivehealth.com> | 2018-04-30 12:00:42 -0700 | 
| commit | 3e0c887365bc1ebd55b91dd69ab73f2dee1f00ed (patch) | |
| tree | ce76003a08274cb805df101a44be8d37af1a4c4b /indent | |
| parent | b4d7993e7ea554153025c5072749f415e69e0323 (diff) | |
| download | vim-polyglot-3e0c887365bc1ebd55b91dd69ab73f2dee1f00ed.tar.gz vim-polyglot-3e0c887365bc1ebd55b91dd69ab73f2dee1f00ed.zip | |
Update (periodic rebuild)
I originally meant to run this before adding haproxy, but accidentally
pushed that into my branch.  If you'd like to see that content, it's at
https://github.com/CH-DanReif/vim-polyglot/commit/414ad25c3ad1ab9c4b6a99fe4f08d6c30b7e0f57.
Diffstat (limited to 'indent')
| -rw-r--r-- | indent/haskell.vim | 2 | ||||
| -rw-r--r-- | indent/html.vim | 1445 | ||||
| -rw-r--r-- | indent/javascript.vim | 47 | ||||
| -rw-r--r-- | indent/julia.vim | 15 | ||||
| -rw-r--r-- | indent/nix.vim | 8 | ||||
| -rw-r--r-- | indent/swift.vim | 80 | 
6 files changed, 1123 insertions, 474 deletions
| diff --git a/indent/haskell.vim b/indent/haskell.vim index 5a337144..11cca26b 100644 --- a/indent/haskell.vim +++ b/indent/haskell.vim @@ -320,7 +320,7 @@ function! GetHaskellIndent()    " newtype Foo = Foo    " >>deriving -  if l:prevline =~ '\C\s*\<\(newtype\|data\)\>[^{]\+' && l:line =~ '\C^\s*\<deriving\>' +  if l:prevline =~ '\C^\s*\<\(newtype\|data\)\>[^{]\+' && l:line =~ '\C^\s*\<deriving\>'      return match(l:prevline, '\S') + &shiftwidth    endif diff --git a/indent/html.vim b/indent/html.vim index 1e5691f7..defaca2a 100644 --- a/indent/html.vim +++ b/indent/html.vim @@ -1,466 +1,1065 @@  if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'html5') == -1 -" Description:      HTML5 and inline SVG indenter -" Changed By: HT de Beer <H.T.de.Beer@gmail.com> -" Last Change: 20121013 -"   Added the SVG elements to the list of indenting element. SVG elements -"   taken from http://www.w3.org/TR/SVG/eltindex.html -"    -" Description:        html5 (and html4) indenter -" Changed By:        Brian Gershon <brian.five@gmail.com> -" Last Change:        30 Jan 2011 -"  -"   1. Started with vim72 html indent file authored by Johannes Zellner (below) -"   2. Added html5 list as described here: -"      http://stackoverflow.com/questions/3232518/how-to-update-vim-to-color-code-new-html-elements -"   3. Added this to a fork of https://github.com/othree/html5.vim -"      which already provides nice html5 syntax highlighting. +" Vim indent script for HTML +" Header: "{{{ +" Maintainer:	Bram Moolenaar +" Original Author: Andy Wokula <anwoku@yahoo.de> +" Last Change:	2017 Jun 13 +" 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.  " -" Description:        html indenter -" Author:        Johannes Zellner <johannes@zellner.org> -" Last Change:        Mo, 05 Jun 2006 22:32:41 CEST -"                 Restoring 'cpo' and 'ic' added by Bram 2006 May 5 -" Globals: -" let g:html_indent_tags = 'html\|p\|time' -" let g:html_exclude_tags = ['html', 'style', 'script', 'body'] - - -" Only load this indent file when no other was loaded. -if exists("b:did_indent") -    finish +" 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  endif -runtime! indent/javascript.vim -let s:jsindent = &indentexpr -unlet b:did_indent -runtime! indent/css.vim -let s:cssindent = &indentexpr -let b:did_indent = 1 -" [-- local settings (must come before aborting the script) --] -setlocal indentexpr=HtmlIndentGet(v:lnum) -setlocal indentkeys=o,O,*<Return>,<>>,{,},!^F - - -let s:tags = [] -let s:no_tags = [] - -" [-- <ELEMENT ? - - ...> --] -call add(s:tags, 'a') -call add(s:tags, 'abbr') -call add(s:tags, 'acronym') -call add(s:tags, 'address') -call add(s:tags, 'b') -call add(s:tags, 'bdo') -call add(s:tags, 'big') -call add(s:tags, 'blockquote') -call add(s:tags, 'button') -call add(s:tags, 'caption') -call add(s:tags, 'center') -call add(s:tags, 'cite') -call add(s:tags, 'code') -call add(s:tags, 'colgroup') -call add(s:tags, 'del') -call add(s:tags, 'dfn') -call add(s:tags, 'dir') -call add(s:tags, 'div') -call add(s:tags, 'dl') -call add(s:tags, 'dt') -call add(s:tags, 'dd') -call add(s:tags, 'em') -call add(s:tags, 'fieldset') -call add(s:tags, 'font') -call add(s:tags, 'form') -call add(s:tags, 'frameset') -call add(s:tags, 'h1') -call add(s:tags, 'h2') -call add(s:tags, 'h3') -call add(s:tags, 'h4') -call add(s:tags, 'h5') -call add(s:tags, 'h6') -call add(s:tags, 'i') -call add(s:tags, 'iframe') -call add(s:tags, 'ins') -call add(s:tags, 'kbd') -call add(s:tags, 'label') -call add(s:tags, 'legend') -call add(s:tags, 'li') -call add(s:tags, 'map') -call add(s:tags, 'menu') -call add(s:tags, 'noframes') -call add(s:tags, 'noscript') -call add(s:tags, 'object') -call add(s:tags, 'ol') -call add(s:tags, 'optgroup') -call add(s:tags, 'p') -" call add(s:tags, 'pre') -call add(s:tags, 'q') -call add(s:tags, 's') -call add(s:tags, 'samp') -call add(s:tags, 'script') -call add(s:tags, 'select') -call add(s:tags, 'small') -call add(s:tags, 'span') -call add(s:tags, 'strong') -call add(s:tags, 'style') -call add(s:tags, 'sub') -call add(s:tags, 'sup') -call add(s:tags, 'table') -call add(s:tags, 'textarea') -call add(s:tags, 'title') -call add(s:tags, 'tt') -call add(s:tags, 'u') -call add(s:tags, 'ul') -call add(s:tags, 'var') - -" New HTML 5 elements -call add(s:tags, 'article') -call add(s:tags, 'aside') -call add(s:tags, 'audio') -call add(s:tags, 'canvas') -call add(s:tags, 'datalist') -call add(s:tags, 'details') -call add(s:tags, 'figcaption') -call add(s:tags, 'figure') -call add(s:tags, 'footer') -call add(s:tags, 'header') -call add(s:tags, 'hgroup') -call add(s:tags, 'main') -call add(s:tags, 'mark') -call add(s:tags, 'meter') -call add(s:tags, 'nav') -call add(s:tags, 'output') -call add(s:tags, 'progress') -call add(s:tags, 'picture') -call add(s:tags, 'rb') -call add(s:tags, 'rp') -call add(s:tags, 'rt') -call add(s:tags, 'rtc') -call add(s:tags, 'ruby') -call add(s:tags, 'section') -call add(s:tags, 'source') -call add(s:tags, 'summary') -call add(s:tags, 'time') -call add(s:tags, 'video') -call add(s:tags, 'bdi') -call add(s:tags, 'data') - -" Web Component -call add(s:tags, 'template') - -" Common inline used SVG elements -call add(s:tags, 'clipPath') -call add(s:tags, 'defs') -call add(s:tags, 'desc') -call add(s:tags, 'filter') -call add(s:tags, 'foreignObject') -call add(s:tags, 'g') -call add(s:tags, 'linearGradient') -call add(s:tags, 'marker') -call add(s:tags, 'mask') -call add(s:tags, 'pattern') -call add(s:tags, 'radialGradient') -call add(s:tags, 'svg') -call add(s:tags, 'switch') -call add(s:tags, 'symbol') -call add(s:tags, 'text') -call add(s:tags, 'textPath') -call add(s:tags, 'tref') -call add(s:tags, 'tspan') -" Common self closing SVG elements -call add(s:no_tags, 'animate') -call add(s:no_tags, 'animateTransform') -call add(s:no_tags, 'circle') -call add(s:no_tags, 'ellipse') -call add(s:no_tags, 'feBlend') -call add(s:no_tags, 'feColorMatrix') -call add(s:no_tags, 'feComposite') -call add(s:no_tags, 'feConvolveMatrix') -call add(s:no_tags, 'feDisplacementMap') -call add(s:no_tags, 'feFlood') -call add(s:no_tags, 'feFuncR') -call add(s:no_tags, 'feFuncG') -call add(s:no_tags, 'feFuncB') -call add(s:no_tags, 'feFuncA') -call add(s:no_tags, 'feGaussianBlur') -call add(s:no_tags, 'feImage') -call add(s:no_tags, 'feMergeNode') -call add(s:no_tags, 'feMorphology') -call add(s:no_tags, 'feOffset') -call add(s:no_tags, 'fePointLight') -call add(s:no_tags, 'feSpotLight') -call add(s:no_tags, 'feTile') -call add(s:no_tags, 'feTurbulence') -call add(s:no_tags, 'hatchpath') -call add(s:no_tags, 'hkern') -call add(s:no_tags, 'image') -call add(s:no_tags, 'line') -call add(s:no_tags, 'mpath') -call add(s:no_tags, 'polygon') -call add(s:no_tags, 'polyline') -call add(s:no_tags, 'path') -call add(s:no_tags, 'rect') -call add(s:no_tags, 'solidColor') -call add(s:no_tags, 'stop') -call add(s:no_tags, 'use') -call add(s:no_tags, 'view') -call add(s:no_tags, 'vkern') - -call add(s:tags, 'html') -call add(s:tags, 'head') -call add(s:tags, 'body') - -call add(s:tags, 'thead') -call add(s:tags, 'tbody') -call add(s:tags, 'tfoot') -call add(s:tags, 'tr') -call add(s:tags, 'th') -call add(s:tags, 'td') - -call add(s:no_tags, 'base') -call add(s:no_tags, 'link') -call add(s:no_tags, 'meta') -call add(s:no_tags, 'hr') -call add(s:no_tags, 'br') -call add(s:no_tags, 'wbr') -call add(s:no_tags, 'img') -call add(s:no_tags, 'embed') -call add(s:no_tags, 'param') -call add(s:no_tags, 'source') -call add(s:no_tags, 'track') -call add(s:no_tags, 'area') -call add(s:no_tags, 'col') -call add(s:no_tags, 'input') -call add(s:no_tags, 'keygen') -call add(s:no_tags, 'menuitem') - -let s:omittable = [  -  \  ['address', 'article', 'aside', 'blockquote', 'dir', 'div', 'dl', 'fieldset', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hr', 'menu', 'nav', 'ol', 'p', 'pre', 'section', 'table', 'ul'], -  \  ['dt', 'dd'], -  \  ['li'], -  \  ['thead', 'tbody', 'tfoot'], -  \  ['th', 'td'], -  \] - - -let s:html_noindent_tags = join(s:no_tags, '\|') - -if exists('g:html_exclude_tags') -    for tag in g:html_exclude_tags -        call remove(s:tags, index(s:tags, tag)) -    endfor -    let s:html_noindent_tags = s:html_noindent_tags.'\|'.join(g:html_exclude_tags, '\|') +" Load the Javascript indent script first, it defines GetJavascriptIndent(). +" Undo the rest. +" Load base python indent. +if !exists('*GetJavascriptIndent') +  runtime! indent/javascript.vim  endif +let b:did_indent = 1 + +setlocal indentexpr=HtmlIndent() +setlocal indentkeys=o,O,<Return>,<>>,{,},!^F + +" Needed for % to work when finding start/end of a tag. +setlocal matchpairs+=<:> + +let b:undo_indent = "setlocal inde< indk<" -" let s:html_indent_tags = join(s:tags, '\|') -let s:html_indent_tags = '[a-z_][a-z0-9_.-]*' -" if exists('g:html_indent_tags') -    " let s:html_indent_tags = s:html_indent_tags.'\|'.g:html_indent_tags -" endif +" b:hi_indent keeps state to speed up indenting consecutive lines. +let b:hi_indent = {"lnum": -1} +"""""" Code below this is loaded only once. """"" +if exists("*HtmlIndent") && !exists('g:force_reload_html') +  call HtmlIndent_CheckUserSettings() +  finish +endif + +" Allow for line continuation below.  let s:cpo_save = &cpo  set cpo-=C +"}}} -func! <SID>HtmlIndentPatternCount(content, pattern) -    let s = substitute('x'.a:content, a:pattern, "\1", 'g') -    let s = substitute(s, "[^\1].*$", '', '') -    return strlen(s) -endfun - -" [-- count indent-increasing tags of line a:lnum --] -fun! <SID>HtmlIndentOpen(lnum, pattern) -    return <SID>HtmlIndentPatternCount(getline(a:lnum), -    \ '.\{-}\(\(<\)\('.a:pattern.'\)\>\)') -endfun - -" [-- count indent-decreasing tags of line a:lnum --] -fun! <SID>HtmlIndentClose(lnum, pattern) -    return <SID>HtmlIndentPatternCount(getline(a:lnum), -    \ '.\{-}\(\(<\)/\('.a:pattern.'\)\>>\)') -endfun - -" [-- count self close tags of line a:lnum --] -fun! <SID>HtmlIndentSelfClose(lnum, pattern) -    return <SID>HtmlIndentPatternCount(getline(a:lnum), -    \ '.\{-}\(\(<\('.a:pattern.'\).*\)\@<!\/>\)') -endfun - -" [-- count indent-increasing '{' of (java|css) line a:lnum --] -fun! <SID>HtmlIndentOpenAlt(lnum) -    return strlen(substitute(getline(a:lnum), '[^{]\+', '', 'g')) -endfun - -" [-- count indent-decreasing '}' of (java|css) line a:lnum --] -fun! <SID>HtmlIndentCloseAlt(lnum) -    return strlen(substitute(getline(a:lnum), '[^}]\+', '', 'g')) -endfun - -" [-- return the sum of indents respecting the syntax of a:lnum --] -fun! <SID>HtmlIndentSum(lnum, style) -    if a:style == match(getline(a:lnum), '^\s*</') -        if a:style == match(getline(a:lnum), '^\s*</\<\('.s:html_indent_tags.'\)\>') -            let open = <SID>HtmlIndentOpen(a:lnum, s:html_indent_tags) - <SID>HtmlIndentOpen(a:lnum, s:html_noindent_tags) -            let close = <SID>HtmlIndentClose(a:lnum, s:html_indent_tags) - <SID>HtmlIndentClose(a:lnum, s:html_noindent_tags) -            let self_close = <SID>HtmlIndentSelfClose(a:lnum, s:html_noindent_tags) -            if 0 != open || 0 != close || 0 != self_close -                return open - close - self_close -            endif -        endif -    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 -    if '' != &syntax && -        \ synIDattr(synID(a:lnum, 1, 1), 'name') =~ '\(css\|java\).*' && -        \ synIDattr(synID(a:lnum, strlen(getline(a:lnum)), 1), 'name') -        \ =~ '\(css\|java\).*' -        if a:style == match(getline(a:lnum), '^\s*}') -            return <SID>HtmlIndentOpenAlt(a:lnum) - <SID>HtmlIndentCloseAlt(a:lnum) -        endif +  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 len(autotags) > 0 +    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 + 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 b:hi_lasttick = 0 +let b:hi_newstate = {} +let s:countonly = 0 + "}}} + +" 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 +" 6   conditional comment start +" -1  closing tag +" -2  "/pre" +" -3  "/script" +" -4  "/style" +" -5  comment end +" -6  conditional comment end +let s:indent_tags = {} +let s:endtags = [0,0,0,0,0,0,0]   " long enough for the highest index +"}}} + +" Add a list of tag names for a pair of <tag> </tag> to "tags". +func! s:AddITags(tags, taglist) +  "{{{ +  for itag in a:taglist +    let a:tags[itag] = 1 +    let a:tags['/' . itag] = -1 +  endfor +endfunc "}}} + +" 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 "}}} + +" 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] = "</" . a:tag . ">" +  else +    let s:indent_tags[a:1] = -a:id +    let s:endtags[a:id] = a:1 +  endif +endfunc "}}} + +" Add known tag pairs. +" Self-closing tags and tags that are sometimes {{{ +" self-closing (e.g., <p>) are not here (when encountering </p> we can find +" the matching <p>, 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', 'p', 'q', 's', 'samp', 'select', 'small', 'span', 'strong', 'sub', +    \ 'sup', 'table', 'textarea', 'title', 'tt', 'u', 'ul', 'var', 'th', 'td', +    \ 'tr', 'tbody', 'tfoot', 'thead']) + +" New HTML5 elements: +call s:AddITags(s:indent_tags, [ +    \ 'area', 'article', 'aside', 'audio', 'bdi', 'canvas', +    \ 'command', 'data', 'datalist', 'details', 'dislog', 'embed', 'figcaption', +    \ 'figure', 'footer', 'header', 'keygen', 'main', 'mark', 'meter', 'nav', 'output', +    \ 'picture', 'progress', 'rp', 'rt', 'ruby', 'section', 'source', 'summary', 'svg',  +    \ 'time', 'track', 'video', 'wbr']) + +" Tags added for web components: +call s:AddITags(s:indent_tags, [ +    \ 'content', 'shadow', 'template']) +"}}} + +" 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('<!--', 5, '-->') +call s:AddBlockTag('<!--[', 6, '![endif]-->') +"}}} + +" 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 "}}} + +" 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 -endfun +  endif +  if i == 0 +    let i = get(b:hi_tags, a:tagname) +  endif +  return i +endfunc "}}} -fun! HtmlIndentGet(lnum) -    " Get shiftwidth value. -    if exists('*shiftwidth') -        let sw = shiftwidth() +" 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\+\(-\w\+\)*\>\|<!--\[\|\[endif\]-->\|<!--\|-->', '\=s:CheckTag(submatch(0))', 'g') +  let s:countonly = 0 +endfunc "}}} + +" 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\+\(-\w\+\)*\>\|<!--\[\|\[endif\]-->\|<!--\|-->', '\=s:CheckTag(submatch(0))', 'g') +  if s:block == 3 +    let b:hi_newstate.scripttype = s:GetScriptType(matchstr(tmp, '\C.*<SCRIPT\>\zs[^>]*')) +  endif +  let b:hi_newstate.block = s:block +endfunc "}}} + +" 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 "<!--" or "-->" +  if (s:CheckCustomTag(a:itag)) +    return "" +  endif +  let ind = s:get_tag(a:itag) +  if ind == -1 +    " closing tag +    if s:block != 0 +      " ignore itag within a block +      return "" +    endif +    if s:nextrel == 0 +      let s:curind -= 1      else -        let sw = &sw +      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 "}}} -    " Find a non-empty line above the current line. -    let lnum = prevnonblank(a:lnum - 1) +" Used by s:CheckTag(). Returns an empty string or "SCRIPT". +func! s:CheckBlockTag(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 "" +    endif +    let s:block = a:ind		" block type +    if s:countonly +      return "" +    endif +    let b:hi_newstate.blocklnr = v:lnum +    " save allover indent for the endtag +    let b:hi_newstate.blocktagind = b:hi_indent.baseindent + (s:nextrel + s:curind) * 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 a block-tag on the same line +  endif +  return "" +endfunc "}}} -    " Hit the start of the file, use zero indent. -    if lnum == 0 -        return 0 +" Used by s:CheckTag(). +func! s:CheckCustomTag(ctag) +  "{{{ +  " Returns 1 if ctag is the tag for a custom element, 0 otherwise. +  " a:ctag can be "tag" or "/tag" or "<!--" or "-->" +  let pattern = '\%\(\w\+-\)\+\w\+' +  if match(a:ctag, pattern) == -1 +    return 0 +  endif +  if matchstr(a:ctag, '\/\ze.\+') == "/" +    " closing tag +    if s:block != 0 +      " ignore ctag within a block +      return 1 +    endif +    if s:nextrel == 0 +      let s:curind -= 1 +    else +      let s:nextrel -= 1      endif +  else +    " opening tag +    if s:block != 0 +      return 1 +    endif +    let s:nextrel += 1 +  endif +  return 1 +endfunc "}}} -    let restore_ic = &ic -    setlocal ic " ignore case +" Return the <script> type: either "javascript" or "" +func! s:GetScriptType(str) +  "{{{ +  if a:str == "" || a:str =~ "java" +    return "javascript" +  else +    return "" +  endif +endfunc "}}} -    " [-- special handling for <pre>: no indenting --] -    if getline(a:lnum) =~ '\c</pre>' -                \ || 0 < searchpair('\c<pre>', '', '\c</pre>', 'nWb') -                \ || 0 < searchpair('\c<pre>', '', '\c</pre>', 'nW') -        " we're in a line with </pre> or inside <pre> ... </pre> -        if restore_ic == 0 -          setlocal noic -        endif -        return -1 +" Look back in the file, starting at a:lnum - 1, to compute a state for the +" start of line a:lnum.  Return the new state. +func! s:FreshState(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). +  " TODO: this should be split up in detecting the block type and computing the +  " indent for the block type, so that when we do not know the indent we do +  " not need to clear the whole state and re-detect the block type again. +  " State: +  "	lnum		last indented line == prevnonblank(a:lnum - 1) +  "	block = 0	a:lnum located within special tag: 0:none, 2:<pre>, +  "			3:<script>, 4:<style>, 5:<!--, 6:<!--[ +  "	baseindent	use this indent for line a:lnum as a start - kind of +  "			autoindent (if block==0) +  "	scripttype = ''	type attribute of a script tag (if block==3) +  "	blocktagind	indent for current opening (get) and closing (set) +  "			blocktag (if block!=0) +  "	blocklnr	lnum of starting blocktag (if block!=0) +  "	inattr		line {lnum} starts with attributes of a tag +  let state = {} +  let state.lnum = prevnonblank(a:lnum - 1) +  let state.scripttype = "" +  let state.blocktagind = -1 +  let state.block = 0 +  let state.baseindent = 0 +  let state.blocklnr = 0 +  let state.inattr = 0 + +  if state.lnum == 0 +    return state +  endif + +  " Heuristic: +  " remember startline state.lnum +  " look back for <pre, </pre, <script, </script, <style, </style tags +  " remember stopline +  " if opening tag found, +  "	assume a:lnum within block +  " else +  "	look back in result range (stopline, startline) for comment +  "	    \ delimiters (<!--, -->) +  "	if comment opener found, +  "	    assume a:lnum within comment +  "	else +  "	    assume usual html for a:lnum +  "	    if a:lnum-1 has a closing comment +  "		look back to get indent of comment opener +  " FI + +  " look back for a blocktag +  let stopline2 = v:lnum + 1 +  if has_key(b:hi_indent, 'block') && b:hi_indent.block > 5 +    let [stopline2, stopcol2] = searchpos('<!--', 'bnW') +  endif +  let [stopline, stopcol] = searchpos('\c<\zs\/\=\%(pre\>\|script\>\|style\>\)', "bnW") +  if stopline > 0 && stopline < stopline2 +    " ugly ... why isn't there searchstr() +    let tagline = tolower(getline(stopline)) +    let blocktag = matchstr(tagline, '\/\=\%(pre\>\|script\>\|style\>\)', stopcol - 1) +    if blocktag[0] != "/" +      " opening tag found, assume a:lnum within block +      let state.block = s:indent_tags[blocktag] +      if state.block == 3 +        let state.scripttype = s:GetScriptType(matchstr(tagline, '\>[^>]*', stopcol)) +      endif +      let state.blocklnr = stopline +      " check preceding tags in the line: +      call s:CountITags(tagline[: stopcol-2]) +      let state.blocktagind = indent(stopline) + (s:curind + s:nextrel) * shiftwidth() +      return state +    elseif stopline == state.lnum +      " handle special case: previous line (= state.lnum) contains a +      " closing blocktag which is preceded by line-noise; +      " blocktag == "/..." +      let swendtag = match(tagline, '^\s*</') >= 0 +      if !swendtag +        let [bline, bcol] = searchpos('<'.blocktag[1:].'\>', "bnW") +        call s:CountITags(tolower(getline(bline)[: bcol-2])) +        let state.baseindent = indent(bline) + (s:curind + s:nextrel) * shiftwidth() +        return state +      endif      endif +  endif +  if stopline > stopline2 +    let stopline = stopline2 +    let stopcol = stopcol2 +  endif -    " [-- special handling for <javascript>: use cindent --] -    let js = '<script' -    let jse = '</script>' - -    """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -    " by Tye Zdrojewski <zdro@yahoo.com>, 05 Jun 2006 -    " ZDR: This needs to be an AND (we are 'after the start of the pair' AND -    "      we are 'before the end of the pair').  Otherwise, indentation -    "      before the start of the script block will be affected; the end of -    "      the pair will still match if we are before the beginning of the -    "      pair. -    " -    if   0 < searchpair(js, '', jse, 'nWb') -    \ && 0 < searchpair(js, '', jse, 'nW') -        " we're inside javascript -        if getline(searchpair(js, '', '</script>', 'nWb')) !~ '<script [^>]*type=["'']\?text\/\(html\|\(ng-\)\?template\)' -        \ && getline(lnum) !~ js && getline(a:lnum) !~ jse -            if restore_ic == 0 -              setlocal noic -            endif -            if s:jsindent == '' -              return cindent(a:lnum) -            else -              execute 'let ind = ' . s:jsindent -              return ind -            endif -        endif -        if getline(a:lnum) =~ jse -          return indent(searchpair(js, '', jse, 'nWb')) -        endif +  " else look back for comment +  let [comlnum, comcol, found] = searchpos('\(<!--\[\)\|\(<!--\)\|-->', 'bpnW', stopline) +  if found == 2 || found == 3 +    " comment opener found, assume a:lnum within comment +    let state.block = (found == 3 ? 5 : 6) +    let state.blocklnr = comlnum +    " check preceding tags in the line: +    call s:CountITags(tolower(getline(comlnum)[: comcol-2])) +    if found == 2 +      let state.baseindent = b:hi_indent.baseindent      endif +    let state.blocktagind = indent(comlnum) + (s:curind + s:nextrel) * shiftwidth() +    return state +  endif -    let css = '<style' -    let csse = '</style>' -    if   0 < searchpair(css, '', csse, 'nWb') -    \ && 0 < searchpair(css, '', csse, 'nW') -        " we're inside style -        if getline(lnum) !~ css && getline(a:lnum) !~ csse -            if restore_ic == 0 -              setlocal noic -            endif -            if s:cssindent == '' -              return cindent(a:lnum) -            else -              execute 'let ind = ' . s:cssindent -              return ind -            endif -        endif -        if getline(a:lnum) =~ csse -          return indent(searchpair(css, '', csse, 'nWb')) +  " else within usual HTML +  let text = tolower(getline(state.lnum)) + +  " Check a:lnum-1 for closing comment (we need indent from the opening line). +  " Not when other tags follow (might be --> inside a string). +  let comcol = stridx(text, '-->') +  if comcol >= 0 && match(text, '[<>]', comcol) <= 0 +    call cursor(state.lnum, comcol + 1) +    let [comlnum, comcol] = searchpos('<!--', 'bW') +    if comlnum == state.lnum +      let text = text[: comcol-2] +    else +      let text = tolower(getline(comlnum)[: comcol-2]) +    endif +    call s:CountITags(text) +    let state.baseindent = indent(comlnum) + (s:curind + s:nextrel) * shiftwidth() +    " TODO check tags that follow "-->" +    return state +  endif + +  " Check if the previous line starts with end tag. +  let swendtag = match(text, '^\s*</') >= 0 + +  " If previous line ended in a closing tag, line up with the opening tag. +  if !swendtag && text =~ '</\w\+\s*>\s*$' +    call cursor(state.lnum, 99999) +    normal! F< +    let start_lnum = HtmlIndent_FindStartTag() +    if start_lnum > 0 +      let state.baseindent = indent(start_lnum) +      if col('.') > 2 +        " check for tags before the matching opening tag. +        let text = getline(start_lnum) +        let swendtag = match(text, '^\s*</') >= 0 +        call s:CountITags(text[: col('.') - 2]) +        let state.baseindent += s:nextrel * shiftwidth() +        if !swendtag +          let state.baseindent += s:curind * shiftwidth()          endif +      endif +      return state      endif +  endif + +  " Else: no comments. Skip backwards to find the tag we're inside. +  let [state.lnum, found] = HtmlIndent_FindTagStart(state.lnum) +  " Check if that line starts with end tag. +  let text = getline(state.lnum) +  let swendtag = match(text, '^\s*</') >= 0 +  call s:CountITags(tolower(text)) +  let state.baseindent = indent(state.lnum) + s:nextrel * shiftwidth() +  if !swendtag +    let state.baseindent += s:curind * shiftwidth() +  endif +  return state +endfunc "}}} -    if getline(lnum) =~ '\c</pre>' -        " line before the current line a:lnum contains -        " a closing </pre>. --> search for line before -        " starting <pre> to restore the indent. -        let preline = prevnonblank(search('\c<pre>', 'bW') - 1) -        if preline > 0 -            if restore_ic == 0 -              setlocal noic -            endif - -            if 0 == match(getline(a:lnum), '^\s*</') -                return indent(preline) - (1*sw) -            else -                return indent(preline) -            endif +" Indent inside a <pre> block: Keep indent as-is. +func! s:Alien2() +  "{{{ +  return -1 +endfunc "}}} + +" Return the indent inside a <script> block for javascript. +func! s:Alien3() +  "{{{ +  let lnum = prevnonblank(v:lnum - 1) +  while lnum > 1 && getline(lnum) =~ '^\s*/[/*]' +    " Skip over comments to avoid that cindent() aligns with the <script> tag +    let lnum = prevnonblank(lnum - 1) +  endwhile +  if lnum == b:hi_indent.blocklnr +    " indent for the first line after <script> +    return eval(b:hi_js1indent) +  endif +  if b:hi_indent.scripttype == "javascript" +    return GetJavascriptIndent() +  else +    return -1 +  endif +endfunc "}}} + +" Return the indent inside a <style> block. +func! s:Alien4() +  "{{{ +  if prevnonblank(v:lnum-1) == b:hi_indent.blocklnr +    " indent for first content line +    return eval(b:hi_css1indent) +  endif +  return s:CSSIndent() +endfunc "}}} + +" Indending inside a <style> block.  Returns the indent. +func! s:CSSIndent() +  "{{{ +  " This handles standard CSS and also Closure stylesheets where special lines +  " start with @. +  " When the line starts with '*' or the previous line starts with "/*" +  " and does not end in "*/", use C indenting to format the comment. +  " Adopted $VIMRUNTIME/indent/css.vim +  let curtext = getline(v:lnum) +  if curtext =~ '^\s*[*]' +        \ || (v:lnum > 1 && getline(v:lnum - 1) =~ '\s*/\*' +        \     && getline(v:lnum - 1) !~ '\*/\s*$') +    return cindent(v:lnum) +  endif + +  let min_lnum = b:hi_indent.blocklnr +  let prev_lnum = s:CssPrevNonComment(v:lnum - 1, min_lnum) +  let [prev_lnum, found] = HtmlIndent_FindTagStart(prev_lnum) +  if prev_lnum <= min_lnum +    " Just below the <style> tag, indent for first content line after comments. +    return eval(b:hi_css1indent) +  endif + +  " If the current line starts with "}" align with it's match. +  if curtext =~ '^\s*}' +    call cursor(v:lnum, 1) +    try +      normal! % +      " Found the matching "{", align with it after skipping unfinished lines. +      let align_lnum = s:CssFirstUnfinished(line('.'), min_lnum) +      return indent(align_lnum) +    catch +      " can't find it, try something else, but it's most likely going to be +      " wrong +    endtry +  endif + +  " add indent after { +  let brace_counts = HtmlIndent_CountBraces(prev_lnum) +  let extra = brace_counts.c_open * shiftwidth() + +  let prev_text = getline(prev_lnum) +  let below_end_brace = prev_text =~ '}\s*$' + +  " Search back to align with the first line that's unfinished. +  let align_lnum = s:CssFirstUnfinished(prev_lnum, min_lnum) + +  " Handle continuation lines if aligning with previous line and not after a +  " "}". +  if extra == 0 && align_lnum == prev_lnum && !below_end_brace +    let prev_hasfield = prev_text =~ '^\s*[a-zA-Z0-9-]\+:' +    let prev_special = prev_text =~ '^\s*\(/\*\|@\)' +    if curtext =~ '^\s*\(/\*\|@\)' +      " if the current line is not a comment or starts with @ (used by template +      " systems) reduce indent if previous line is a continuation line +      if !prev_hasfield && !prev_special +        let extra = -shiftwidth() +      endif +    else +      let cur_hasfield = curtext =~ '^\s*[a-zA-Z0-9-]\+:' +      let prev_unfinished = s:CssUnfinished(prev_text) +      if !cur_hasfield && (prev_hasfield || prev_unfinished) +        " Continuation line has extra indent if the previous line was not a +        " continuation line. +        let extra = shiftwidth() +        " Align with @if +        if prev_text =~ '^\s*@if ' +          let extra = 4          endif +      elseif cur_hasfield && !prev_hasfield && !prev_special +        " less indent below a continuation line +        let extra = -shiftwidth() +      endif +    endif +  endif + +  if below_end_brace +    " find matching {, if that line starts with @ it's not the start of a rule +    " but something else from a template system +    call cursor(prev_lnum, 1) +    call search('}\s*$') +    try +      normal! % +      " Found the matching "{", align with it. +      let align_lnum = s:CssFirstUnfinished(line('.'), min_lnum) +      let special = getline(align_lnum) =~ '^\s*@' +    catch +      let special = 0 +    endtry +    if special +      " do not reduce indent below @{ ... } +      if extra < 0 +        let extra += shiftwidth() +      endif +    else +      let extra -= (brace_counts.c_close - (prev_text =~ '^\s*}')) * shiftwidth() +    endif +  endif + +  " if no extra indent yet... +  if extra == 0 +    if brace_counts.p_open > brace_counts.p_close +      " previous line has more ( than ): add a shiftwidth +      let extra = shiftwidth() +    elseif brace_counts.p_open < brace_counts.p_close +      " previous line has more ) than (: subtract a shiftwidth +      let extra = -shiftwidth()      endif +  endif + +  return indent(align_lnum) + extra +endfunc "}}} + +" Inside <style>: Whether a line is unfinished. +func! s:CssUnfinished(text) +  "{{{ +  return a:text =~ '\s\(||\|&&\|:\)\s*$' +endfunc "}}} + +" Search back for the first unfinished line above "lnum". +func! s:CssFirstUnfinished(lnum, min_lnum) +  "{{{ +  let align_lnum = a:lnum +  while align_lnum > a:min_lnum && s:CssUnfinished(getline(align_lnum - 1)) +    let align_lnum -= 1 +  endwhile +  return align_lnum +endfunc "}}} + +" Find the non-empty line at or before "lnum" that is not a comment. +func! s:CssPrevNonComment(lnum, stopline) +  "{{{ +  " caller starts from a line a:lnum + 1 that is not a comment +  let lnum = prevnonblank(a:lnum) +  while 1 +    let ccol = match(getline(lnum), '\*/') +    if ccol < 0 +      " No comment end thus it's something else. +      return lnum +    endif +    call cursor(lnum, ccol + 1) +    " Search back for the /* that starts the comment +    let lnum = search('/\*', 'bW', a:stopline) +    if indent(".") == virtcol(".") - 1 +      " The  found /* is at the start of the line. Now go back to the line +      " above it and again check if it is a comment. +      let lnum = prevnonblank(lnum - 1) +    else +      " /* is after something else, thus it's not a comment line. +      return lnum +    endif +  endwhile +endfunc "}}} + +" Check the number of {} and () in line "lnum". Return a dict with the counts. +func! HtmlIndent_CountBraces(lnum) +  "{{{ +  let brs = substitute(getline(a:lnum), '[''"].\{-}[''"]\|/\*.\{-}\*/\|/\*.*$\|[^{}()]', '', 'g') +  let c_open = 0 +  let c_close = 0 +  let p_open = 0 +  let p_close = 0 +  for brace in split(brs, '\zs') +    if brace == "{" +      let c_open += 1 +    elseif brace == "}" +      if c_open > 0 +        let c_open -= 1 +      else +        let c_close += 1 +      endif +    elseif brace == '(' +      let p_open += 1 +    elseif brace == ')' +      if p_open > 0 +        let p_open -= 1 +      else +        let p_close += 1 +      endif +    endif +  endfor +  return {'c_open': c_open, +        \ 'c_close': c_close, +        \ 'p_open': p_open, +        \ 'p_close': p_close} +endfunc "}}} + +" Return the indent for a comment: <!-- --> +func! s:Alien5() +  "{{{ +  let curtext = getline(v:lnum) +  if curtext =~ '^\s*\zs-->' +    " current line starts with end of comment, line up with comment start. +    call cursor(v:lnum, 0) +    let lnum = search('<!--', 'b') +    if lnum > 0 +      " TODO: what if <!-- is not at the start of the line? +      return indent(lnum) +    endif + +    " Strange, can't find it. +    return -1 +  endif + +  let prevlnum = prevnonblank(v:lnum - 1) +  let prevtext = getline(prevlnum) +  let idx = match(prevtext, '^\s*\zs<!--') +  if idx >= 0 +    " just below comment start, add a shiftwidth +    return idx + shiftwidth() +  endif + +  " Some files add 4 spaces just below a TODO line.  It's difficult to detect +  " the end of the TODO, so let's not do that. -    let ind = <SID>HtmlIndentSum(lnum, -1) -    let ind = ind + <SID>HtmlIndentSum(a:lnum, 0) +  " Align with the previous non-blank line. +  return indent(prevlnum) +endfunc "}}} -    " Fix for conditional comment -    if getline(a:lnum) =~ '\c<!--.*<\(html\|body\).*-->' -        let ind = ind - 1 +" Return the indent for conditional comment: <!--[ ![endif]--> +func! s:Alien6() +  "{{{ +  let curtext = getline(v:lnum) +  if curtext =~ '\s*\zs<!\[endif\]-->' +    " current line starts with end of comment, line up with comment start. +    let lnum = search('<!--', 'bn') +    if lnum > 0 +      return indent(lnum)      endif +  endif +  return b:hi_indent.baseindent + shiftwidth() +endfunc "}}} -    let lind = indent(lnum) - -    " for tags in s:omittable -      " let tags_exp = '<\(' . join(tags, '\|') . '\)>' -      " let close_tags_exp = '</\(' . join(tags, '\|') . '\)>' -      " if getline(a:lnum) =~ tags_exp -        " let block_start = search('^'.repeat(' ', lind + (sw * ind - 1)).'\S'  , 'bnW') -        " let prev_tag = search(tags_exp, 'bW', block_start) -        " let prev_closetag = search(close_tags_exp, 'W', a:lnum) -        " if prev_tag && !prev_closetag -          " let ind = ind - 1 -        " endif -      " endif - -      " if getline(a:lnum) =~ '</\w\+>' -        " let block_start = search('^'.repeat(' ', lind + (sw * ind - 1)).'\S'  , 'bnW') -        " let prev_tag = search(tags_exp, 'bW', block_start) -        " let prev_closetag = search(close_tags_exp, 'W', a:lnum) -        " if prev_tag && !prev_closetag -          " let ind = ind - 1 -        " endif -      " endif -    " endfor - -    if restore_ic == 0 -        setlocal noic +" When the "lnum" line ends in ">" find the line containing the matching "<". +func! HtmlIndent_FindTagStart(lnum) +  "{{{ +  " Avoids using the indent of a continuation line. +  " Moves the cursor. +  " Return two values: +  " - the matching line number or "lnum". +  " - a flag indicating whether we found the end of a tag. +  " This method is global so that HTML-like indenters can use it. +  " To avoid matching " > " or " < " inside a string require that the opening +  " "<" is followed by a word character and the closing ">" comes after a +  " non-white character. +  let idx = match(getline(a:lnum), '\S>\s*$') +  if idx > 0 +    call cursor(a:lnum, idx) +    let lnum = searchpair('<\w', '' , '\S>', 'bW', '', max([a:lnum - b:html_indent_line_limit, 0])) +    if lnum > 0 +      return [lnum, 1]      endif +  endif +  return [a:lnum, 0] +endfunc "}}} + +" Find the unclosed start tag from the current cursor position. +func! HtmlIndent_FindStartTag() +  "{{{ +  " The cursor must be on or before a closing tag. +  " If found, positions the cursor at the match and returns the line number. +  " Otherwise returns 0. +  let tagname = matchstr(getline('.')[col('.') - 1:], '</\zs\w\+\(-\w\+\)*\ze') +  let start_lnum = searchpair('<' . tagname . '\>', '', '</' . tagname . '\>', 'bW') +  if start_lnum > 0 +    return start_lnum +  endif +  return 0 +endfunc "}}} + +" Moves the cursor from a "<" to the matching ">". +func! HtmlIndent_FindTagEnd() +  "{{{ +  " Call this with the cursor on the "<" of a start tag. +  " This will move the cursor to the ">" of the matching end tag or, when it's +  " a self-closing tag, to the matching ">". +  " Limited to look up to b:html_indent_line_limit lines away. +  let text = getline('.') +  let tagname = matchstr(text, '\w\+\(-\w\+\)*\|!--', col('.')) +  if tagname == '!--' +    call search('--\zs>') +  elseif s:get_tag('/' . tagname) != 0 +    " tag with a closing tag, find matching "</tag>" +    call searchpair('<' . tagname, '', '</' . tagname . '\zs>', 'W', '', line('.') + b:html_indent_line_limit) +  else +    " self-closing tag, find the ">" +    call search('\S\zs>') +  endif +endfunc "}}} + +" Indenting inside a start tag. Return the correct indent or -1 if unknown. +func! s:InsideTag(foundHtmlString) +  "{{{ +  if a:foundHtmlString +    " Inside an attribute string. +    " Align with the previous line or use an external function. +    let lnum = v:lnum - 1 +    if lnum > 1 +      if exists('b:html_indent_tag_string_func') +        return b:html_indent_tag_string_func(lnum) +      endif +      return indent(lnum) +    endif +  endif + +  " Should be another attribute: " attr="val".  Align with the previous +  " attribute start. +  let lnum = v:lnum +  while lnum > 1 +    let lnum -= 1 +    let text = getline(lnum) +    " Find a match with one of these, align with "attr": +    "       attr= +    "  <tag attr= +    "  text<tag attr= +    "  <tag>text</tag>text<tag attr= +    " For long lines search for the first match, finding the last match +    " gets very slow. +    if len(text) < 300 +      let idx = match(text, '.*\s\zs[_a-zA-Z0-9-]\+="') +    else +      let idx = match(text, '\s\zs[_a-zA-Z0-9-]\+="') +    endif +    if idx == -1 +      let idx = match(text, '<\w\+\(-\w\+\)*\s\zs\w') +    endif +    if idx == -1 +      let idx = match(text, '<\w\+\(-\w\+\)*') +      if idx >= 0 +        let idx = idx + shiftwidth() +      endif +    endif +    if idx > 0 +      " Found the attribute.  TODO: assumes spaces, no Tabs. +      return idx +    endif +  endwhile +  return -1 +endfunc "}}} + +" THE MAIN INDENT FUNCTION. Return the amount of indent for v:lnum. +func! HtmlIndent() +  "{{{ +  if prevnonblank(v:lnum - 1) < 1 +    " First non-blank line has no indent. +    return 0 +  endif + +  let curtext = tolower(getline(v:lnum)) +  let indentunit = shiftwidth() + +  let b:hi_newstate = {} +  let b:hi_newstate.lnum = v:lnum + +  " When syntax HL is enabled, detect we are inside a tag.  Indenting inside +  " a tag works very differently. Do not do this when the line starts with +  " "<", it gets the "htmlTag" ID but we are not inside a tag then. +  if curtext !~ '^\s*<' +    normal! ^ +    let stack = synstack(v:lnum, col('.'))  " assumes there are no tabs +    let foundHtmlString = 0 +    for synid in reverse(stack) +      let name = synIDattr(synid, "name") +      if index(b:hi_insideStringNames, name) >= 0 +        let foundHtmlString = 1 +      elseif index(b:hi_insideTagNames, name) >= 0 +        " Yes, we are inside a tag. +        let indent = s:InsideTag(foundHtmlString) +        if indent >= 0 +          " Do not keep the state. TODO: could keep the block type. +          let b:hi_indent.lnum = 0 +          return indent +        endif +      endif +    endfor +  endif + +  " does the line start with a closing tag? +  let swendtag = match(curtext, '^\s*</') >= 0 + +  if prevnonblank(v:lnum - 1) == b:hi_indent.lnum && b:hi_lasttick == b:changedtick - 1 +    " use state (continue from previous line) +  else +    " start over (know nothing) +    let b:hi_indent = s:FreshState(v:lnum) +  endif + +  if b:hi_indent.block >= 2 +    " within block +    let endtag = s:endtags[b:hi_indent.block] +    let blockend = stridx(curtext, endtag) +    if blockend >= 0 +      " block ends here +      let b:hi_newstate.block = 0 +      " calc indent for REST OF LINE (may start more blocks): +      call s:CountTagsAndState(strpart(curtext, blockend + strlen(endtag))) +      if swendtag && b:hi_indent.block != 5 +        let indent = b:hi_indent.blocktagind + s:curind * indentunit +        let b:hi_newstate.baseindent = indent + s:nextrel * indentunit +      else +        let indent = s:Alien{b:hi_indent.block}() +        let b:hi_newstate.baseindent = b:hi_indent.blocktagind + s:nextrel * indentunit +      endif +    else +      " block continues +      " indent this line with alien method +      let indent = s:Alien{b:hi_indent.block}() +    endif +  else +    " not within a block - within usual html +    let b:hi_newstate.block = b:hi_indent.block +    if swendtag +      " The current line starts with an end tag, align with its start tag. +      call cursor(v:lnum, 1) +      let start_lnum = HtmlIndent_FindStartTag() +      if start_lnum > 0 +        " check for the line starting with something inside a tag: +        " <sometag               <- align here +        "    attr=val><open>     not here +        let text = getline(start_lnum) +        let angle = matchstr(text, '[<>]') +        if angle == '>' +          call cursor(start_lnum, 1) +          normal! f>% +          let start_lnum = line('.') +          let text = getline(start_lnum) +        endif + +        let indent = indent(start_lnum) +        if col('.') > 2 +          let swendtag = match(text, '^\s*</') >= 0 +          call s:CountITags(text[: col('.') - 2]) +          let indent += s:nextrel * shiftwidth() +          if !swendtag +            let indent += s:curind * shiftwidth() +          endif +        endif +      else +        " not sure what to do +        let indent = b:hi_indent.baseindent +      endif +      let b:hi_newstate.baseindent = indent +    else +      call s:CountTagsAndState(curtext) +      let indent = b:hi_indent.baseindent +      let b:hi_newstate.baseindent = indent + (s:curind + s:nextrel) * indentunit +    endif +  endif + +  let b:hi_lasttick = b:changedtick +  call extend(b:hi_indent, b:hi_newstate, "force") +  return indent +endfunc "}}} -    return lind + (sw * ind) -endfun +" Check user settings when loading this script the first time. +call HtmlIndent_CheckUserSettings()  let &cpo = s:cpo_save  unlet s:cpo_save -" [-- EOF <runtime>/indent/html.vim --] +" vim: fdm=marker ts=8 sw=2 tw=78  endif diff --git a/indent/javascript.vim b/indent/javascript.vim index a31268d2..f50fbc82 100644 --- a/indent/javascript.vim +++ b/indent/javascript.vim @@ -89,22 +89,22 @@ function s:SynAt(l,c)  endfunction  function s:ParseCino(f) -  let [divider, n, cstr] = [0] + matchlist(&cino, -        \ '\%(.*,\)\=\%(\%d'.char2nr(a:f).'\(-\)\=\([.s0-9]*\)\)\=')[1:2] -  for c in split(cstr,'\zs') -    if c == '.' && !divider +  let [s, n, divider] = [strridx(&cino, a:f)+1, '', 0] +  while s && &cino[ s ] =~ '[^,]' +    if &cino[ s ] == '.'        let divider = 1 -    elseif c ==# 's' +    elseif &cino[ s ] ==# 's'        if n !~ '\d'          return n . s:sw() + 0        endif        let n = str2nr(n) * s:sw()        break      else -      let [n, divider] .= [c, 0] +      let [n, divider] .= [&cino[ s ], 0]      endif -  endfor -  return str2nr(n) / max([str2nr(divider),1]) +    let s += 1 +  endwhile +  return str2nr(n) / max([divider, 1])  endfunction  " Optimized {skip} expr, only callable from the search loop which @@ -208,18 +208,15 @@ function s:ExprCol()    let bal = 0    while s:SearchLoop('[{}?:]','bW',s:skip_expr)      if s:LookingAt() == ':' -      if getline('.')[col('.')-2] == ':' -        call cursor(0,col('.')-1) -        continue -      endif -      let bal -= 1 +      let bal -= !search('\m:\%#','bW')      elseif s:LookingAt() == '?'        if getline('.')[col('.'):col('.')+1] =~ '^\.\d\@!' -        continue +        " ?. conditional chain, not ternary start        elseif !bal          return 1 +      else +        let bal += 1        endif -      let bal += 1      elseif s:LookingAt() == '{'        return !s:IsBlock()      elseif !s:GetPair('{','}','bW',s:skip_expr) @@ -316,8 +313,8 @@ function s:IsContOne(cont)  endfunction  function s:IsSwitch() -  return search('\m\C\%'.join(b:js_cache[1:],'l\%'). -        \ 'c{\_s*\%(\%(\/\/.*\_$\|\/\*\_.\{-}\*\/\)\@>\_s*\)*\%(case\|default\)\>','nW'.s:z) +  return search(printf('\m\C\%%%dl\%%%dc%s',b:js_cache[1],b:js_cache[2], +        \ '{\_s*\%(\%(\/\/.*\_$\|\/\*\_.\{-}\*\/\)\@>\_s*\)*\%(case\|default\)\>'),'nW'.s:z)  endfunction  " https://github.com/sweet-js/sweet.js/wiki/design#give-lookbehind-to-the-reader @@ -367,8 +364,8 @@ function GetJavascriptIndent()      return -1    endif -  let s:l1 = max([0,prevnonblank(v:lnum) - (s:rel ? 2000 : 1000), -        \ get(get(b:,'hi_indent',{}),'blocklnr')]) +  let nest = get(get(b:,'hi_indent',{}),'blocklnr') +  let s:l1 = max([0, prevnonblank(v:lnum) - (s:rel ? 2000 : 1000), nest])    call cursor(v:lnum,1)    if s:PreviousToken() is ''      return @@ -376,7 +373,7 @@ function GetJavascriptIndent()    let [l:lnum, lcol, pline] = getpos('.')[1:2] + [getline('.')[:col('.')-1]]    let l:line = substitute(l:line,'^\s*','','') -  let l:line_raw = l:line +  let l:line_s = l:line[0]    if l:line[:1] == '/*'      let l:line = substitute(l:line,'^\%(\/\*.\{-}\*\/\s*\)*','','')    endif @@ -450,7 +447,7 @@ function GetJavascriptIndent()      let pval = s:ParseCino('(')      if !pval        let [Wval, vcol] = [s:ParseCino('W'), virtcol('.')] -      if search('\m\S','W',num) +      if search('\m'.get(g:,'javascript_indent_W_pat','\S'),'W',num)          return s:ParseCino('w') ? vcol : virtcol('.')-1        endif        return Wval ? s:Nat(num_ind + Wval) : vcol @@ -460,7 +457,7 @@ function GetJavascriptIndent()    " main return    if l:line =~ '^[])}]\|^|}' -    if l:line_raw[0] == ')' +    if l:line_s == ')'        if s:ParseCino('M')          return indent(l:lnum)        elseif num && &cino =~# 'm' && !s:ParseCino('m') @@ -470,10 +467,8 @@ function GetJavascriptIndent()      return num_ind    elseif num      return s:Nat(num_ind + get(l:,'case_offset',s:sw()) + l:switch_offset + b_l + is_op) -  endif -  let nest = get(get(b:,'hi_indent',{}),'blocklnr') -  if nest -    return indent(nest) + s:sw() + b_l + is_op +  elseif nest +    return indent(nextnonblank(nest+1)) + b_l + is_op    endif    return b_l + is_op  endfunction diff --git a/indent/julia.vim b/indent/julia.vim index 4833d7e5..88e90e57 100644 --- a/indent/julia.vim +++ b/indent/julia.vim @@ -27,13 +27,13 @@ function JuliaMatch(lnum, str, regex, st, ...)    let s = a:st    let e = a:0 > 0 ? a:1 : -1    while 1 -    let f = match(a:str, a:regex, s) +    let f = match(a:str, '\C' . a:regex, s)      if e >= 0 && f >= e        return -1      endif      if f >= 0        let attr = synIDattr(synID(a:lnum,f+1,1),"name") -      if attr =~ s:skipPatterns +      if attr =~# s:skipPatterns          let s = f+1          continue        endif @@ -84,7 +84,7 @@ function GetJuliaNestingStruct(lnum, ...)        let i = JuliaMatch(a:lnum, line, '@\@<!\<else\>', s)        if i >= 0 && i == fb          let s = i+1 -        if len(blocks_stack) > 0 && blocks_stack[-1] =~ '\<\%(else\)\=if\>' +        if len(blocks_stack) > 0 && blocks_stack[-1] =~# '\<\%(else\)\=if\>'            let blocks_stack[-1] = 'else'          else            call add(blocks_stack, 'else') @@ -135,7 +135,7 @@ function GetJuliaNestingStruct(lnum, ...)        let i = JuliaMatch(a:lnum, line, '@\@<!\<\%(while\|for\|\%(staged\)\?function\|macro\|begin\|\%(mutable\s\+\)\?struct\|\%(\%(abstract\|primitive\)\s\+\)\?type\|immutable\|let\|quote\|do\)\>', s)        if i >= 0 && i == fb -        if match(line, '\<\%(mutable\|abstract\|primitive\)', i) != -1 +        if match(line, '\C\<\%(mutable\|abstract\|primitive\)', i) != -1            let s = i+11          else            let s = i+1 @@ -290,16 +290,11 @@ function LastBlockIndent(lnum)  endfunction  function GetJuliaIndent() -  let s:save_ignorecase = &ignorecase -  set noignorecase -    " Find a non-blank line above the current line.    let lnum = prevnonblank(v:lnum - 1)    " At the start of the file use zero indent.    if lnum == 0 -    let &ignorecase = s:save_ignorecase -    unlet s:save_ignorecase      return 0    endif @@ -387,8 +382,6 @@ function GetJuliaIndent()      let num_closed_blocks -= 1    endwhile -  let &ignorecase = s:save_ignorecase -  unlet s:save_ignorecase    return ind  endfunction diff --git a/indent/nix.vim b/indent/nix.vim index 679b224f..fd277dcc 100644 --- a/indent/nix.vim +++ b/indent/nix.vim @@ -33,6 +33,12 @@ function! GetNixIndent()      return 0    endif +  " Skip indentation for single line comments explicitly, in case a +  " comment was just inserted (eg. visual block mode) +  if getline(v:lnum) =~ '^\s*#' +    return indent(v:lnum) +  endif +    if synIDattr(synID(v:lnum, 1, 1), "name") !~ s:skip_syntax      let current_line = getline(v:lnum)      let last_line = getline(lnum) @@ -63,7 +69,7 @@ function! GetNixIndent()      let ind = indent(v:lnum)      let bslnum = searchpair('''''', '', '''''', 'bnW', -          \ 'synIDattr(synID(line("."), col("."), 0), "name") =~? "InterpolationSpecial$"') +          \ 'synIDattr(synID(line("."), col("."), 0), "name") =~? "StringSpecial$"')      if ind <= indent(bslnum)        let ind = indent(bslnum) + &sw diff --git a/indent/swift.vim b/indent/swift.vim index 92df0fc8..14e851ee 100644 --- a/indent/swift.vim +++ b/indent/swift.vim @@ -42,11 +42,15 @@ endfunction  function! s:IsExcludedFromIndentAtPosition(line, column)    let name = s:SyntaxNameAtPosition(a:line, a:column) -  return name ==# "swiftComment" || name ==# "swiftString" +  return s:IsSyntaxNameExcludedFromIndent(name)  endfunction  function! s:IsExcludedFromIndent() -  return s:SyntaxName() ==# "swiftComment" || s:SyntaxName() ==# "swiftString" +  return s:IsSyntaxNameExcludedFromIndent(s:SyntaxName()) +endfunction + +function! s:IsSyntaxNameExcludedFromIndent(name) +  return a:name ==# "swiftComment" || a:name ==# "swiftString" || a:name ==# "swiftInterpolatedWrapper" || a:name ==# "swiftMultilineInterpolatedWrapper" || a:name ==# "swiftMultilineString"  endfunction  function! s:IsCommentLine(lnum) @@ -103,10 +107,10 @@ function! SwiftIndent(...)      return indent(openingSquare) + shiftwidth()    endif -  if line =~ ":$" +  if line =~ ":$" && (line =~ '^\s*case\W' || line =~ '^\s*default\W')      let switch = search("switch", "bWn")      return indent(switch) -  elseif previous =~ ":$" +  elseif previous =~ ":$" && (previous =~ '^\s*case\W' || previous =~ '^\s*default\W')      return previousIndent + shiftwidth()    endif @@ -133,12 +137,26 @@ function! SwiftIndent(...)        return previousIndent + shiftwidth()      elseif line =~ "}.*{"        let openingBracket = searchpair("{", "", "}", "bWn", "s:IsExcludedFromIndent()") + +      let bracketLine = getline(openingBracket) +      let numOpenParensBracketLine = s:NumberOfMatches("(", bracketLine, openingBracket) +      let numCloseParensBracketLine = s:NumberOfMatches(")", bracketLine, openingBracket) +      if numOpenParensBracketLine > numCloseParensBracketLine +        let line = line(".") +        let column = col(".") +        call cursor(openingParen, column) +        let openingParenCol = searchpairpos("(", "", ")", "bWn", "s:IsExcludedFromIndent()")[1] +        call cursor(line, column) +        return openingParenCol +      endif +        return indent(openingBracket)      elseif currentCloseBrackets > currentOpenBrackets        let column = col(".") -      call cursor(line("."), 1) +      let line = line(".") +      call cursor(line, 1)        let openingBracket = searchpair("{", "", "}", "bWn", "s:IsExcludedFromIndent()") -      call cursor(line("."), column) +      call cursor(line, column)        let bracketLine = getline(openingBracket) @@ -151,8 +169,23 @@ function! SwiftIndent(...)          let openingParen = searchpair("(", "", ")", "bWn", "s:IsExcludedFromIndent()")          call cursor(line, column)          return indent(openingParen) +      elseif numOpenParensBracketLine > numCloseParensBracketLine +        let line = line(".") +        let column = col(".") +        call cursor(openingParen, column) +        let openingParenCol = searchpairpos("(", "", ")", "bWn", "s:IsExcludedFromIndent()")[1] +        call cursor(line, column) +        return openingParenCol        endif +        return indent(openingBracket) +    elseif line =~ '^\s*)$' +      let line = line(".") +      let column = col(".") +      call cursor(line, 1) +      let openingParen = searchpair("(", "", ")", "bWn", "s:IsExcludedFromIndent()") +      call cursor(line, column) +      return indent(openingParen)      else        " - Current line is blank, and the user presses 'o'        return previousIndent @@ -196,8 +229,19 @@ function! SwiftIndent(...)          return previousIndent + shiftwidth()        endif -      let previousParen = match(previous, "(") -      return indent(previousParen) + shiftwidth() +      let previousParen = match(previous, '\v\($') +      if previousParen != -1 +        return previousIndent + shiftwidth() +      endif + +      let line = line(".") +      let column = col(".") +      call cursor(previousNum, col([previousNum, "$"])) +      let previousParen = searchpairpos("(", "", ")", "cbWn", "s:IsExcludedFromIndent()") +      call cursor(line, column) + +      " Match the last non escaped paren on the previous line +      return previousParen[1]      endif      if numOpenBrackets > numCloseBrackets @@ -206,7 +250,7 @@ function! SwiftIndent(...)        call cursor(previousNum, column)        let openingParen = searchpair("(", "", ")", "bWn", "s:IsExcludedFromIndent()")        call cursor(line, column) -      return indent(openingParen) + shiftwidth() +      return openingParen + 1      endif      " - Previous line has close then open braces, indent previous + 1 'sw' @@ -226,11 +270,23 @@ function! SwiftIndent(...)    " - Line above has (unmatched) open paren, next line needs indent    if numOpenParens > 0      let savePosition = getcurpos() +    let lastColumnOfPreviousLine = col([previousNum, "$"]) - 1      " Must be at EOL because open paren has to be above (left of) the cursor -    call cursor(previousNum, [previousNum, col("$")]) -    let previousParen = searchpair("(", "", ")", "cbWn", "s:IsExcludedFromIndent()") +    call cursor(previousNum, lastColumnOfPreviousLine) +    let previousParen = searchpairpos("(", "", ")", "cbWn", "s:IsExcludedFromIndent()")[1] +    " If the paren on the last line is the last character, indent the contents +    " at shiftwidth + previous indent +    if previousParen == lastColumnOfPreviousLine +      return previousIndent + shiftwidth() +    endif + +    " The previous line opens a closure and doesn't close it +    if numOpenBrackets > numCloseBrackets +      return previousParen + shiftwidth() +    endif +      call setpos(".", savePosition) -    return indent(previousParen) + shiftwidth() +    return previousParen    endif    return cindent | 
