From 7c33b14a84fd506904a010239adb92eefb41e0e4 Mon Sep 17 00:00:00 2001 From: ache Date: Mon, 13 Nov 2017 14:33:55 +0100 Subject: New SVG/HTML syntax support --- ftplugin/svg.vim | 105 +++++++++++++ indent/html.vim | 462 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ plugin/svg.vim | 105 ------------- syntax/html.vim | 185 ++++++++++++++++++++++ 4 files changed, 752 insertions(+), 105 deletions(-) create mode 100644 ftplugin/svg.vim create mode 100644 indent/html.vim delete mode 100644 plugin/svg.vim create mode 100644 syntax/html.vim diff --git a/ftplugin/svg.vim b/ftplugin/svg.vim new file mode 100644 index 0000000..b1597a9 --- /dev/null +++ b/ftplugin/svg.vim @@ -0,0 +1,105 @@ +" Vim indent file +" +" Language: svg +" Maintainer: Jason Shell +" Last Change: 2015 Sep 23 +" Notes: 1) will be confused by unbalanced tags in comments + +" Only load this indent file when no other was loaded. +if exists('b:did_indent') + finish +endif +let b:did_indent = 1 +let s:keepcpo= &cpo +set cpo&vim + +" [-- local settings (must come before aborting the script) --] +setlocal indentexpr=SvgIndentGet(v:lnum,1) +setlocal indentkeys=o,O,*,<>>,<<>,/,{,} + +if !exists('b:svg_indent_open') + let b:svg_indent_open = '.\{-}<\a' + " pre tag, e.g.
+ " let b:svg_indent_open = '.\{-}<[/]\@!\(address\)\@!' +endif + +if !exists('b:svg_indent_close') + let b:svg_indent_close = '.\{-} + " let b:svg_indent_close = '.\{-}SvgIndentWithPattern(line, pat) + let s = substitute('x'.a:line, a:pat, "\1", 'g') + return strlen(substitute(s, "[^\1].*$", '', '')) +endfun + +" [-- check if it's svg --] +fun! SvgIndentSynCheck(lnum) + if '' != &syntax + let syn1 = synIDattr(synID(a:lnum, 1, 1), 'name') + let syn2 = synIDattr(synID(a:lnum, strlen(getline(a:lnum)) - 1, 1), 'name') + if '' != syn1 && syn1 !~ 'svg' && '' != syn2 && syn2 !~ 'svg' + " don't indent pure non-xml code + return 0 + + " elseif syn1 =~ '^xmlComment' && syn2 =~ '^xmlComment' + elseif syn1 =~ '^svgComment' && syn2 =~ '^svgComment' + " indent comments specially + return -1 + endif + endif + return 1 +endfun + +" [-- return the sum of indents of a:lnum --] +fun! SvgIndentSum(lnum, style, add) + let line = getline(a:lnum) + if a:style == match(line, '^\s*SvgIndentWithPattern(line, b:svg_indent_open) + \ - SvgIndentWithPattern(line, b:svg_indent_close) + \ - SvgIndentWithPattern(line, '.\{-}/>'))) + a:add + else + return a:add + endif +endfun + +fun! SvgIndentGet(lnum, use_syntax_check) + " Find a non-empty line above the current line. + let lnum = prevnonblank(a:lnum - 1) + + " Hit the start of the file, use zero indent. + if lnum == 0 + return 0 + endif + + if a:use_syntax_check + let check_lnum = SvgIndentSynCheck(lnum) + let check_alnum = SvgIndentSynCheck(a:lnum) + if 0 == check_lnum || 0 == check_alnum + return indent(a:lnum) + elseif -1 == check_lnum || -1 == check_alnum + return -1 + endif + endif + + let ind = SvgIndentSum(lnum, -1, indent(lnum)) + let ind = SvgIndentSum(a:lnum, 0, ind) + + return ind +endfun + +let &cpo = s:keepcpo +unlet s:keepcpo diff --git a/indent/html.vim b/indent/html.vim new file mode 100644 index 0000000..2e8216d --- /dev/null +++ b/indent/html.vim @@ -0,0 +1,462 @@ +" Description: HTML5 and inline SVG indenter +" Changed By: HT de Beer +" 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 +" 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. +" +" Description: html indenter +" Author: Johannes Zellner +" 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 +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,*,<>>,{,},!^F + + +let s:tags = [] +let s:no_tags = [] + +" [-- --] +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, '\|') +endif + +" 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 + +let s:cpo_save = &cpo +set cpo-=C + +func! 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! HtmlIndentOpen(lnum, pattern) + return HtmlIndentPatternCount(getline(a:lnum), + \ '.\{-}\(\(<\)\('.a:pattern.'\)\>\)') +endfun + +" [-- count indent-decreasing tags of line a:lnum --] +fun! HtmlIndentClose(lnum, pattern) + return HtmlIndentPatternCount(getline(a:lnum), + \ '.\{-}\(\(<\)/\('.a:pattern.'\)\>>\)') +endfun + +" [-- count self close tags of line a:lnum --] +fun! HtmlIndentSelfClose(lnum, pattern) + return HtmlIndentPatternCount(getline(a:lnum), + \ '.\{-}\(\(<\('.a:pattern.'\).*\)\@\)') +endfun + +" [-- count indent-increasing '{' of (java|css) line a:lnum --] +fun! HtmlIndentOpenAlt(lnum) + return strlen(substitute(getline(a:lnum), '[^{]\+', '', 'g')) +endfun + +" [-- count indent-decreasing '}' of (java|css) line a:lnum --] +fun! HtmlIndentCloseAlt(lnum) + return strlen(substitute(getline(a:lnum), '[^}]\+', '', 'g')) +endfun + +" [-- return the sum of indents respecting the syntax of a:lnum --] +fun! HtmlIndentSum(lnum, style) + if a:style == match(getline(a:lnum), '^\s*') + let open = HtmlIndentOpen(a:lnum, s:html_indent_tags) - HtmlIndentOpen(a:lnum, s:html_noindent_tags) + let close = HtmlIndentClose(a:lnum, s:html_indent_tags) - HtmlIndentClose(a:lnum, s:html_noindent_tags) + let self_close = HtmlIndentSelfClose(a:lnum, s:html_noindent_tags) + if 0 != open || 0 != close || 0 != self_close + return open - close - self_close + endif + endif + 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 HtmlIndentOpenAlt(a:lnum) - HtmlIndentCloseAlt(a:lnum) + endif + endif + return 0 +endfun + +fun! HtmlIndentGet(lnum) + " Get shiftwidth value. + if exists('*shiftwidth') + let sw = shiftwidth() + else + let sw = &sw + endif + + " Find a non-empty line above the current line. + let lnum = prevnonblank(a:lnum - 1) + + " Hit the start of the file, use zero indent. + if lnum == 0 + return 0 + endif + + let restore_ic = &ic + setlocal ic " ignore case + + " [-- special handling for
: no indenting --]
+    if getline(a:lnum) =~ '\c
' + \ || 0 < searchpair('\c
', '', '\c
', 'nWb') + \ || 0 < searchpair('\c
', '', '\c
', 'nW') + " we're in a line with or inside
 ... 
+ if restore_ic == 0 + setlocal noic + endif + return -1 + endif + + " [-- special handling for : use cindent --] + let js = ', 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, '', '', 'nWb')) !~ '