let s:bx = '{\%("[^"]*"\|''[^'']*''\|\$#\|\${\w\+}\|\$\+\|{[^{]\+\|[^{}]\)\{-}}' let s:mx = '\([+>]\|[<^]\+\)\{-}' \ .'\((*\)\{-}' \ .'\([@#.]\{-}[a-zA-Z_\!][a-zA-Z0-9:_\!\-$]*\|' . s:bx . '\|\[[^\]]\+\]\)' \ .'\(' \ .'\%(' \ .'\%(#{[{}a-zA-Z0-9_\-\$]\+\|#[a-zA-Z0-9_\-\$]\+\)' \ .'\|\%(\[\%(\[[^\]]*\]\|"[^"]*"\|[^"\[\]]*\)\+\]\)' \ .'\|\%(\.{[{}a-zA-Z0-9_\-\$\.]\+\|\.[a-zA-Z0-9_\-\$]\+\)' \ .'\)*' \ .'\)' \ .'\%(\(' . s:bx . '\+\)\)\{0,1}' \ .'\%(\(@-\{0,1}[0-9]*\)\{0,1}\*\([0-9]\+\)\)\{0,1}' \ .'\(\%()\%(\(@-\{0,1}[0-9]*\)\{0,1}\*[0-9]\+\)\{0,1}\)*\)' function! emmet#lang#html#findTokens(str) abort let l:str = a:str let [l:pos, l:last_pos] = [0, 0] while 1 let l:tag = matchstr(l:str, '<[a-zA-Z].\{-}>', l:pos) if len(l:tag) == 0 break endif let l:pos = stridx(l:str, l:tag, l:pos) + len(l:tag) endwhile while 1 let l:tag = matchstr(l:str, '{%[^%]\{-}%}', l:pos) if len(l:tag) == 0 break endif let l:pos = stridx(l:str, l:tag, l:pos) + len(l:tag) endwhile let l:last_pos = l:pos while len(l:str) > 0 let l:white = matchstr(l:str, '^\s\+', l:pos) if l:white != '' let l:last_pos = l:pos + len(l:white) let l:pos = l:last_pos endif let l:token = matchstr(l:str, s:mx, l:pos) if l:token ==# '' break endif let l:pos = stridx(l:str, l:token, l:pos) + len(l:token) endwhile let l:str = a:str[l:last_pos :-1] if l:str =~# '^\w\+="[^"]*$' return '' endif return l:str endfunction function! emmet#lang#html#parseIntoTree(abbr, type) abort let l:abbr = a:abbr let l:type = a:type let l:settings = emmet#getSettings() if !has_key(l:settings, l:type) let l:type = 'html' endif if len(l:type) == 0 | let l:type = 'html' | endif let l:indent = emmet#getIndentation(l:type) let l:pmap = { \'p': 'span', \'ul': 'li', \'ol': 'li', \'table': 'tr', \'tr': 'td', \'tbody': 'tr', \'thead': 'tr', \'tfoot': 'tr', \'colgroup': 'col', \'select': 'option', \'optgroup': 'option', \'audio': 'source', \'video': 'source', \'object': 'param', \'map': 'area' \} let l:inlineLevel = split('a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var',',') let l:custom_expands = emmet#getResource(l:type, 'custom_expands', {}) if empty(l:custom_expands) && has_key(l:settings, 'custom_expands') let l:custom_expands = l:settings['custom_expands'] endif " try 'foo' to (foo-x) let l:rabbr = emmet#getExpandos(l:type, l:abbr) if l:rabbr == l:abbr " try 'foo+(' to (foo-x) let l:rabbr = substitute(l:abbr, '\%(+\|^\)\([a-zA-Z][a-zA-Z0-9+]\+\)+\([(){}>]\|$\)', '\="(".emmet#getExpandos(l:type, submatch(1)).")".submatch(2)', 'i') endif let l:abbr = l:rabbr let l:root = emmet#newNode() let l:root['variables'] = {} let l:parent = l:root let l:last = l:root let l:pos = [] while len(l:abbr) " parse line let l:match = matchstr(l:abbr, s:mx) let l:str = substitute(l:match, s:mx, '\0', 'ig') let l:operator = substitute(l:match, s:mx, '\1', 'ig') let l:block_start = substitute(l:match, s:mx, '\2', 'ig') let l:tag_name = substitute(l:match, s:mx, '\3', 'ig') let l:attributes = substitute(l:match, s:mx, '\4', 'ig') let l:value = substitute(l:match, s:mx, '\5', 'ig') let l:basevalue = substitute(l:match, s:mx, '\6', 'ig') let l:multiplier = 0 + substitute(l:match, s:mx, '\7', 'ig') let l:block_end = substitute(l:match, s:mx, '\8', 'ig') let l:custom = '' let l:important = 0 if len(l:str) == 0 break endif if l:tag_name =~# '^#' let l:attributes = l:tag_name . l:attributes let l:tag_name = '' endif if l:tag_name =~# '[^!]!$' let l:tag_name = l:tag_name[:-2] let l:important = 1 endif if l:tag_name =~# '^\.' let l:attributes = l:tag_name . l:attributes let l:tag_name = '' endif if l:tag_name =~# '^\[.*\]$' let l:attributes = l:tag_name . l:attributes let l:tag_name = '' endif for l:k in keys(l:custom_expands) if l:tag_name =~ l:k let l:custom = l:tag_name let l:tag_name = '' break endif endfor if empty(l:tag_name) let l:pname = len(l:parent.child) > 0 ? l:parent.child[0].name : '' if !empty(l:pname) && has_key(l:pmap, l:pname) && l:custom == '' let l:tag_name = l:pmap[l:pname] elseif !empty(l:pname) && index(l:inlineLevel, l:pname) > -1 let l:tag_name = 'span' elseif len(l:custom) == 0 let l:tag_name = 'div' elseif len(l:custom) != 0 && l:multiplier > 1 let l:tag_name = 'div' else let l:tag_name = l:custom endif endif let l:basedirect = l:basevalue[1] ==# '-' ? -1 : 1 if l:basevalue != '' let l:basevalue = 0 + abs(l:basevalue[1:]) else let l:basevalue = 1 endif if l:multiplier <= 0 | let l:multiplier = 1 | endif " make default node let l:current = emmet#newNode() let l:current.name = l:tag_name let l:current.important = l:important " aliases let l:aliases = emmet#getResource(l:type, 'aliases', {}) if has_key(l:aliases, l:tag_name) let l:current.name = l:aliases[l:tag_name] endif let l:use_pipe_for_cursor = emmet#getResource(l:type, 'use_pipe_for_cursor', 1) " snippets let l:snippets = emmet#getResource(l:type, 'snippets', {}) if !empty(l:snippets) let l:snippet_name = l:tag_name if has_key(l:snippets, l:snippet_name) let l:snippet = l:snippet_name while has_key(l:snippets, l:snippet) let l:snippet = l:snippets[l:snippet] endwhile if l:use_pipe_for_cursor let l:snippet = substitute(l:snippet, '|', '${cursor}', 'g') endif " just redirect to expanding if l:type == 'html' && l:snippet !~ '^\s*[{\[<]' return emmet#lang#html#parseIntoTree(l:snippet, a:type) endif let l:lines = split(l:snippet, "\n", 1) call map(l:lines, 'substitute(v:val, "\\( \\|\\t\\)", escape(l:indent, "\\\\"), "g")') let l:current.snippet = join(l:lines, "\n") let l:current.name = '' endif endif for l:k in keys(l:custom_expands) if l:tag_name =~# l:k let l:snippet = '${' . (empty(l:custom) ? l:tag_name : l:custom) . '}' let l:current.name = '' let l:current.snippet = l:snippet break elseif l:custom =~# l:k let l:snippet = '${' . l:custom . '}' let l:current.snippet = '${' . l:custom . '}' if l:current.name != '' let l:snode = emmet#newNode() let l:snode.snippet = l:snippet let l:snode.parent = l:current call add(l:current.child, l:snode) else let l:current.snippet = l:snippet endif break endif endfor " default_attributes let l:default_attributes = emmet#getResource(l:type, 'default_attributes', {}) if !empty(l:default_attributes) for l:pat in [l:current.name, l:tag_name] if has_key(l:default_attributes, l:pat) if type(l:default_attributes[l:pat]) == 4 let l:a = l:default_attributes[l:pat] let l:current.attrs_order += keys(l:a) if l:use_pipe_for_cursor for l:k in keys(l:a) if type(l:a[l:k]) == 7 call remove(l:current.attr, l:k) continue endif let l:current.attr[l:k] = len(l:a[l:k]) ? substitute(l:a[l:k], '|', '${cursor}', 'g') : '${cursor}' endfor else for l:k in keys(l:a) if type(l:a[l:k]) == 7 call remove(l:current.attr, l:k) continue endif let l:current.attr[l:k] = l:a[l:k] endfor endif else for l:a in l:default_attributes[l:pat] let l:current.attrs_order += keys(l:a) if l:use_pipe_for_cursor for l:k in keys(l:a) if type(l:a[l:k]) == 7 call remove(l:current.attr, l:k) continue endif let l:current.attr[l:k] = len(l:a[l:k]) ? substitute(l:a[l:k], '|', '${cursor}', 'g') : '${cursor}' endfor else for l:k in keys(l:a) if type(l:a[l:k]) == 7 call remove(l:current.attr, l:k) continue endif let l:current.attr[l:k] = l:a[l:k] endfor endif endfor endif if has_key(l:settings.html.default_attributes, l:current.name) let l:current.name = substitute(l:current.name, ':.*$', '', '') endif break endif endfor endif " parse attributes if len(l:attributes) let l:attr = l:attributes while len(l:attr) let l:item = matchstr(l:attr, '\(\%(\%(#[{}a-zA-Z0-9_\-\$]\+\)\|\%(\[\%(\[[^\]]*\]\|"[^"]*"\|[^"\[\]]*\)\+\]\)\|\%(\.[{}a-zA-Z0-9_\-\$]\+\)*\)\)') if g:emmet_debug > 1 echomsg 'attr=' . l:item endif if len(l:item) == 0 break endif if l:item[0] ==# '#' let l:current.attr.id = l:item[1:] let l:root['variables']['id'] = l:current.attr.id endif if l:item[0] ==# '.' let l:current.attr.class = substitute(l:item[1:], '\.', ' ', 'g') let l:root['variables']['class'] = l:current.attr.class endif if l:item[0] ==# '[' let l:atts = l:item[1:-2] if matchstr(l:atts, '^\s*\zs[0-9a-zA-Z_\-:]\+\(="[^"]*"\|=''[^'']*''\|=[^ ''"]\+\)') ==# '' let l:ks = [] if has_key(l:default_attributes, l:current.name) let l:dfa = l:default_attributes[l:current.name] let l:ks = type(l:dfa) == 3 ? len(l:dfa) > 0 ? keys(l:dfa[0]) : [] : keys(l:dfa) endif if len(l:ks) == 0 && has_key(l:default_attributes, l:current.name . ':src') let l:dfa = l:default_attributes[l:current.name . ':src'] let l:ks = type(l:dfa) == 3 ? len(l:dfa) > 0 ? keys(l:dfa[0]) : [] : keys(l:dfa) endif if len(l:ks) > 0 let l:current.attr[l:ks[0]] = l:atts elseif l:atts =~# '\.$' let l:current.attr[l:atts[:-2]] = function('emmet#types#true') else let l:current.attr[l:atts] = '' endif else while len(l:atts) let l:amat = matchstr(l:atts, '^\s*\zs\([0-9a-zA-Z-:]\+\%(={{.\{-}}}\|="[^"]*"\|=''[^'']*''\|=[^ ''"]\+\|[^ ''"\]]*\)\{0,1}\)') if len(l:amat) == 0 break endif let l:key = split(l:amat, '=')[0] let l:Val = l:amat[len(l:key)+1:] if l:key =~# '\.$' && l:Val ==# '' let l:key = l:key[:-2] unlet l:Val let l:Val = function('emmet#types#true') elseif l:Val =~# '^["'']' let l:Val = l:Val[1:-2] endif let l:current.attr[l:key] = l:Val if index(l:current.attrs_order, l:key) == -1 let l:current.attrs_order += [l:key] endif let l:atts = l:atts[stridx(l:atts, l:amat) + len(l:amat):] unlet l:Val endwhile endif endif let l:attr = substitute(strpart(l:attr, len(l:item)), '^\s*', '', '') endwhile endif " parse text if l:tag_name =~# '^{.*}$' let l:current.name = '' let l:current.value = l:tag_name else let l:current.value = l:value endif let l:current.basedirect = l:basedirect let l:current.basevalue = l:basevalue let l:current.multiplier = l:multiplier " parse step inside/outside if !empty(l:last) if l:operator =~# '>' unlet! l:parent let l:parent = l:last let l:current.parent = l:last let l:current.pos = l:last.pos + 1 else let l:current.parent = l:parent let l:current.pos = l:last.pos endif else let l:current.parent = l:parent let l:current.pos = 1 endif if l:operator =~# '[<^]' for l:c in range(len(l:operator)) let l:tmp = l:parent.parent if empty(l:tmp) break endif let l:parent = l:tmp let l:current.parent = l:tmp endfor endif call add(l:parent.child, l:current) let l:last = l:current " parse block if l:block_start =~# '(' if l:operator =~# '>' let l:last.pos += 1 endif let l:last.block = 1 for l:n in range(len(l:block_start)) let l:pos += [l:last.pos] endfor endif if l:block_end =~# ')' for l:n in split(substitute(substitute(l:block_end, ' ', '', 'g'), ')', ',),', 'g'), ',') if l:n ==# ')' if len(l:pos) > 0 && l:last.pos >= l:pos[-1] for l:c in range(l:last.pos - l:pos[-1]) let l:tmp = l:parent.parent if !has_key(l:tmp, 'parent') break endif let l:parent = l:tmp endfor if len(l:pos) > 0 call remove(l:pos, -1) endif let l:last = l:parent let l:last.pos += 1 endif elseif len(l:n) let l:st = 0 for l:nc in range(len(l:last.child)) if l:last.child[l:nc].block let l:st = l:nc break endif endfor let l:cl = l:last.child[l:st :] let l:cls = [] for l:c in range(l:n[1:]) for l:cc in l:cl if l:cc.multiplier > 1 let l:cc.basedirect = l:c + 1 else let l:cc.basevalue = l:c + 1 endif endfor let l:cls += deepcopy(l:cl) endfor if l:st > 0 let l:last.child = l:last.child[:l:st-1] + l:cls else let l:last.child = l:cls endif endif endfor endif let l:abbr = l:abbr[stridx(l:abbr, l:match) + len(l:match):] if l:abbr == '/' let l:current.empty = 1 endif if g:emmet_debug > 1 echomsg 'str='.l:str echomsg 'block_start='.l:block_start echomsg 'tag_name='.l:tag_name echomsg 'operator='.l:operator echomsg 'attributes='.l:attributes echomsg 'value='.l:value echomsg 'basevalue='.l:basevalue echomsg 'multiplier='.l:multiplier echomsg 'block_end='.l:block_end echomsg 'abbr='.l:abbr echomsg 'pos='.string(l:pos) echomsg '---' endif endwhile return l:root endfunction function! s:dollar_add(base,no) abort if a:base > 0 return a:base + a:no - 1 elseif a:base < 0 return a:base - a:no + 1 else return a:no endif endfunction function! emmet#lang#html#toString(settings, current, type, inline, filters, itemno, indent) abort let l:settings = a:settings let l:current = a:current let l:type = a:type let l:inline = a:inline let l:filters = a:filters let l:itemno = a:itemno let l:indent = a:indent let l:dollar_expr = emmet#getResource(l:type, 'dollar_expr', 1) let l:q = emmet#getResource(l:type, 'quote_char', '"') let l:ct = emmet#getResource(l:type, 'comment_type', 'both') let l:an = emmet#getResource(l:type, 'attribute_name', {}) let l:empty_elements = emmet#getResource(l:type, 'empty_elements', l:settings.html.empty_elements) let l:empty_element_suffix = emmet#getResource(l:type, 'empty_element_suffix', l:settings.html.empty_element_suffix) if emmet#useFilter(l:filters, 'haml') return emmet#lang#haml#toString(l:settings, l:current, l:type, l:inline, l:filters, l:itemno, l:indent) endif if emmet#useFilter(l:filters, 'slim') return emmet#lang#slim#toString(l:settings, l:current, l:type, l:inline, l:filters, l:itemno, l:indent) endif let l:comment = '' let l:current_name = l:current.name if l:dollar_expr let l:current_name = substitute(l:current_name, '\$$', l:itemno+1, '') endif let l:str = '' if len(l:current_name) == 0 let l:text = l:current.value[1:-2] if l:dollar_expr " TODO: regexp engine specified let l:nr = l:itemno + 1 if exists('®expengine') let l:text = substitute(l:text, '\%#=1\%(\\\)\@\ 0 let l:str .= '<' . l:current_name endif for l:attr in emmet#util#unique(l:current.attrs_order + keys(l:current.attr)) if !has_key(l:current.attr, l:attr) continue endif let l:Val = l:current.attr[l:attr] if type(l:Val) == 2 && l:Val == function('emmet#types#true') unlet l:Val let l:Val = 'true' if g:emmet_html5 let l:str .= ' ' . l:attr else let l:str .= ' ' . l:attr . '=' . l:q . l:attr . l:q endif if emmet#useFilter(l:filters, 'c') if l:attr ==# 'id' | let l:comment .= '#' . l:Val | endif if l:attr ==# 'class' | let l:comment .= '.' . l:Val | endif endif else if l:dollar_expr while l:Val =~# '\$\([^#{]\|$\)' " TODO: regexp engine specified if exists('®expengine') let l:Val = substitute(l:Val, '\%#=1\(\$\+\)\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d", l:itemno+1).submatch(2)', 'g') else let l:Val = substitute(l:Val, '\(\$\+\)\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d", l:itemno+1).submatch(2)', 'g') endif endwhile let l:attr = substitute(l:attr, '\$$', l:itemno+1, '') endif if l:attr ==# 'class' && emmet#useFilter(l:filters, 'bem') let l:vals = split(l:Val, '\s\+') let l:Val = '' let l:lead = '' for l:_val in l:vals if len(l:Val) > 0 let l:Val .= ' ' endif if l:_val =~# '^_' if has_key(l:current.parent.attr, 'class') let l:lead = l:current.parent.attr["class"] if l:_val =~# '^__' let l:Val .= l:lead . l:_val else let l:Val .= l:lead . ' ' . l:lead . l:_val endif else let l:lead = split(l:vals[0], '_')[0] let l:Val .= l:lead . l:_val endif elseif l:_val =~# '^-' for l:l in split(l:_val, '_') if len(l:Val) > 0 let l:Val .= ' ' endif let l:l = substitute(l:l, '^-', '__', '') if len(l:lead) == 0 let l:pattr = l:current.parent.attr if has_key(l:pattr, 'class') let l:lead = split(l:pattr['class'], '\s\+')[0] endif endif let l:Val .= l:lead . l:l let l:lead .= l:l . '_' endfor else let l:Val .= l:_val endif endfor endif if has_key(l:an, l:attr) let l:attr = l:an[l:attr] endif if emmet#isExtends(l:type, 'jsx') && l:Val =~ '^{.*}$' let l:str .= ' ' . l:attr . '=' . l:Val else let l:str .= ' ' . l:attr . '=' . l:q . l:Val . l:q endif if emmet#useFilter(l:filters, 'c') if l:attr ==# 'id' | let l:comment .= '#' . l:Val | endif if l:attr ==# 'class' | let l:comment .= '.' . l:Val | endif endif endif unlet l:Val endfor if len(l:comment) > 0 && l:ct ==# 'both' let l:str = '\n" . l:str endif if l:current.empty let l:str .= ' />' elseif stridx(','.l:empty_elements.',', ','.l:current_name.',') != -1 let l:str .= l:empty_element_suffix else let l:str .= '>' let l:text = l:current.value[1:-2] if l:dollar_expr " TODO: regexp engine specified let l:nr = l:itemno + 1 if exists('®expengine') let l:text = substitute(l:text, '\%#=1\%(\\\)\@\ 0 for l:n in range(l:nc) let l:child = l:current.child[l:n] if l:child.multiplier > 1 || (l:child.multiplier == 1 && len(l:child.child) > 0 && stridx(','.l:settings.html.inline_elements.',', ','.l:current_name.',') == -1) || l:settings.html.block_all_childless let l:str .= "\n" . l:indent let l:dr = 1 elseif len(l:current_name) > 0 && stridx(','.l:settings.html.inline_elements.',', ','.l:current_name.',') == -1 if l:nc > 1 || (len(l:child.name) > 0 && stridx(','.l:settings.html.inline_elements.',', ','.l:child.name.',') == -1) let l:str .= "\n" . l:indent let l:dr = 1 elseif l:current.multiplier == 1 && l:nc == 1 && len(l:child.name) == 0 let l:str .= "\n" . l:indent let l:dr = 1 endif endif let l:inner = emmet#toString(l:child, l:type, 0, l:filters, l:itemno, l:indent) let l:inner = substitute(l:inner, "^\n", '', 'g') let l:inner = substitute(l:inner, "\n", "\n" . escape(l:indent, '\'), 'g') let l:inner = substitute(l:inner, "\n" . escape(l:indent, '\') . '$', '', 'g') let l:str .= l:inner endfor else if l:settings.html.indent_blockelement && len(l:current_name) > 0 && stridx(','.l:settings.html.inline_elements.',', ','.l:current_name.',') == -1 || l:settings.html.block_all_childless let l:str .= "\n" . l:indent . '${cursor}' . "\n" else let l:str .= '${cursor}' endif endif if l:dr let l:str .= "\n" endif let l:str .= '' endif if len(l:comment) > 0 if l:ct ==# 'lastonly' let l:str .= '' else let l:str .= "\n' endif endif if len(l:current_name) > 0 && l:current.multiplier > 0 || stridx(','.l:settings.html.block_elements.',', ','.l:current_name.',') != -1 let l:str .= "\n" endif return l:str endfunction function! emmet#lang#html#imageSize() abort let l:img_region = emmet#util#searchRegion('') if !emmet#util#regionIsValid(l:img_region) || !emmet#util#cursorInRegion(l:img_region) return endif let l:content = emmet#util#getContent(l:img_region) if l:content !~# '^<]\+>$' return endif let l:current = emmet#lang#html#parseTag(l:content) if empty(l:current) || !has_key(l:current.attr, 'src') return endif let l:fn = l:current.attr.src if l:fn =~# '^\s*$' return elseif l:fn !~# '^\(/\|http\)' let l:fn = simplify(expand('%:h') . '/' . l:fn) endif let [l:width, l:height] = emmet#util#getImageSize(l:fn) if l:width == -1 && l:height == -1 return endif let l:current.attr.width = l:width let l:current.attr.height = l:height let l:current.attrs_order += ['width', 'height'] let l:html = substitute(emmet#toString(l:current, 'html', 1), '\n', '', '') let l:html = substitute(l:html, '\${cursor}', '', '') call emmet#util#setContent(l:img_region, l:html) endfunction function! emmet#lang#html#imageEncode() abort let l:img_region = emmet#util#searchRegion('') if !emmet#util#regionIsValid(l:img_region) || !emmet#util#cursorInRegion(l:img_region) return endif let l:content = emmet#util#getContent(l:img_region) if l:content !~# '^<]\+>$' return endif let l:current = emmet#lang#html#parseTag(l:content) if empty(l:current) || !has_key(l:current.attr, 'src') return endif let l:fn = l:current.attr.src if l:fn =~# '^\s*$' return elseif l:fn !~# '^\(/\|http\)' let l:fn = simplify(expand('%:h') . '/' . l:fn) endif let l:encoded = emmet#util#imageEncodeDecode(l:fn, 0) let l:current.attr.src = l:encoded let l:content = substitute(emmet#toString(l:current, 'html', 1), '\n', '', '') let l:content = substitute(l:content, '\${cursor}', '', '') call emmet#util#setContent(l:img_region, l:content) endfunction function! emmet#lang#html#parseTag(tag) abort let l:current = emmet#newNode() let l:mx = '<\([a-zA-Z][a-zA-Z0-9-]*\)\(\%(\s[a-zA-Z][a-zA-Z0-9-]\+=\?\%([^"'' \t]\+\|"[^"]\{-}"\|''[^'']\{-}''\)\s*\)*\)\(/\{0,1}\)>' let l:match = matchstr(a:tag, l:mx) let l:current.name = substitute(l:match, l:mx, '\1', 'i') let l:attrs = substitute(l:match, l:mx, '\2', 'i') let l:mx = '\([a-zA-Z0-9-]\+\)\(\(=[^"'' \t]\+\)\|="\([^"]\{-}\)"\|=''\([^'']\{-}\)''\)\?' while len(l:attrs) > 0 let l:match = matchstr(l:attrs, l:mx) if len(l:match) == 0 break endif let l:attr_match = matchlist(l:match, l:mx) let l:name = l:attr_match[1] if len(l:attr_match[2]) let l:Val = len(l:attr_match[3]) ? l:attr_match[3] : l:attr_match[4] else let l:Val = function('emmet#types#true') endif let l:current.attr[l:name] = l:Val let l:current.attrs_order += [l:name] let l:attrs = l:attrs[stridx(l:attrs, l:match) + len(l:match):] endwhile return l:current endfunction function! emmet#lang#html#toggleComment() abort let l:orgpos = getpos('.') let l:curpos = getpos('.') let l:mx = '<\%#[^>]*>' while 1 let l:block = emmet#util#searchRegion('') if emmet#util#regionIsValid(l:block) let l:block[1][1] += 2 let l:content = emmet#util#getContent(l:block) let l:content = substitute(l:content, '^$', '\1', '') call emmet#util#setContent(l:block, l:content) silent! call setpos('.', l:orgpos) return endif let l:block = emmet#util#searchRegion('<[^>]', '>') if !emmet#util#regionIsValid(l:block) let l:pos1 = searchpos('<', 'bcW') if l:pos1[0] == 0 && l:pos1[1] == 0 return endif let l:curpos = getpos('.') continue endif let l:pos1 = l:block[0] let l:pos2 = l:block[1] let l:content = emmet#util#getContent(l:block) let l:tag_name = matchstr(l:content, '^<\zs/\{0,1}[^ \r\n>]\+') if l:tag_name[0] ==# '/' call setpos('.', [0, l:pos1[0], l:pos1[1], 0]) let l:pos2 = searchpairpos('<'. l:tag_name[1:] . '\>[^/>]*>', '', '', 'bnW') let l:pos1 = searchpos('>', 'cneW') let l:block = [l:pos2, l:pos1] elseif l:tag_name =~# '/$' if !emmet#util#pointInRegion(l:orgpos[1:2], l:block) " it's broken tree call setpos('.', l:orgpos) let l:block = emmet#util#searchRegion('>', '<') let l:content = '><' call emmet#util#setContent(l:block, l:content) silent! call setpos('.', l:orgpos) return endif else call setpos('.', [0, l:pos2[0], l:pos2[1], 0]) let l:pos3 = searchpairpos('<'. l:tag_name . '\>[^/>]*>', '', '', 'nW') if l:pos3 == [0, 0] let l:block = [l:pos1, l:pos2] else call setpos('.', [0, l:pos3[0], l:pos3[1], 0]) let l:pos2 = searchpos('>', 'neW') let l:block = [l:pos1, l:pos2] endif endif if !emmet#util#regionIsValid(l:block) silent! call setpos('.', l:orgpos) return endif if emmet#util#pointInRegion(l:curpos[1:2], l:block) let l:content = '' call emmet#util#setContent(l:block, l:content) silent! call setpos('.', l:orgpos) return endif endwhile endfunction function! emmet#lang#html#balanceTag(flag) range abort let l:vblock = emmet#util#getVisualBlock() let l:curpos = emmet#util#getcurpos() let l:settings = emmet#getSettings() if a:flag > 0 let l:mx = '<\([a-zA-Z][a-zA-Z0-9:_\-]*\)[^>]*' let l:last = l:curpos[1:2] while 1 let l:pos1 = searchpos(l:mx, 'bW') let l:content = matchstr(getline(l:pos1[0])[l:pos1[1]-1:], l:mx) let l:tag_name = matchstr(l:content, '^<\zs[a-zA-Z0-9:_\-]*\ze') if stridx(','.l:settings.html.empty_elements.',', ','.l:tag_name.',') != -1 let l:pos2 = searchpos('>', 'nW') else let l:pos2 = searchpairpos('<' . l:tag_name . '[^>]*>', '', '', 'nW') endif let l:block = [l:pos1, l:pos2] if l:pos1 == [0, 0] break endif if emmet#util#pointInRegion(l:last, l:block) && emmet#util#regionIsValid(l:block) call emmet#util#selectRegion(l:block) return endif if l:pos1 == l:last break endif let l:last = l:pos1 endwhile else let l:mx = '<\([a-zA-Z][a-zA-Z0-9:_\-]*\)[^>]*>' while 1 let l:pos1 = searchpos(l:mx, 'W') if l:pos1 == [0, 0] || l:pos1 == l:curpos[1:2] let l:pos1 = searchpos('>\zs', 'W') let l:pos2 = searchpos('.\ze<', 'W') let l:block = [l:pos1, l:pos2] if emmet#util#regionIsValid(l:block) call emmet#util#selectRegion(l:block) return endif endif let l:content = matchstr(getline(l:pos1[0])[l:pos1[1]-1:], l:mx) let l:tag_name = matchstr(l:content, '^<\zs[a-zA-Z0-9:_\-]*\ze') if stridx(','.l:settings.html.empty_elements.',', ','.l:tag_name.',') != -1 let l:pos2 = searchpos('>', 'nW') else let l:pos2 = searchpairpos('<' . l:tag_name . '[^>]*>', '', '', 'nW') endif let l:block = [l:pos1, l:pos2] if l:pos1 == [0, 0] break endif if emmet#util#regionIsValid(l:block) call emmet#util#selectRegion(l:block) return endif endwhile endif call setpos('.', l:curpos) endfunction function! emmet#lang#html#moveNextPrevItem(flag) abort silent! exe "normal \" let l:mx = '\%([0-9a-zA-Z-:]\+\%(="[^"]*"\|=''[^'']*''\|[^ ''">\]]*\)\{0,1}\)' let l:pos = searchpos('\s'.l:mx.'\zs', '') if l:pos != [0,0] call feedkeys('v?\s\zs'.l:mx."\", '') endif return '' endfunction function! emmet#lang#html#moveNextPrev(flag) abort let l:pos = search('\%(<\/\|\(""\)\|^\(\s*\)$', a:flag ? 'Wpb' : 'Wp') if l:pos == 3 startinsert! elseif l:pos != 0 silent! normal! l startinsert endif return '' endfunction function! emmet#lang#html#splitJoinTag() abort let l:curpos = emmet#util#getcurpos() let l:mx = '<\(/\{0,1}[a-zA-Z][-a-zA-Z0-9:_\-]*\)\%(\%(\s[a-zA-Z][a-zA-Z0-9]\+=\%([^"'' \t]\+\|"[^"]\{-}"\|''[^'']\{-}''\)\s*\)*\)\s*\%(/\{0,1}\)>' while 1 let l:old = getpos('.')[1:2] let l:pos1 = searchpos(l:mx, 'bcnW') let l:content = matchstr(getline(l:pos1[0])[l:pos1[1]-1:], l:mx) let l:tag_name = substitute(l:content, '^<\(/\{0,1}[a-zA-Z][a-zA-Z0-9:_\-]*\).*$', '\1', '') let l:block = [l:pos1, [l:pos1[0], l:pos1[1] + len(l:content) - 1]] if l:content[-2:] ==# '/>' && emmet#util#cursorInRegion(l:block) let l:content = substitute(l:content[:-3], '\s*$', '', '') . '>' call emmet#util#setContent(l:block, l:content) call setpos('.', [0, l:block[0][0], l:block[0][1], 0]) return endif if l:tag_name[0] ==# '/' let l:pos1 = searchpos('<' . l:tag_name[1:] . '[^a-zA-Z0-9]', 'bcnW') call setpos('.', [0, l:pos1[0], l:pos1[1], 0]) let l:pos2 = searchpairpos('<'. l:tag_name[1:] . '\>[^/>]*>', '', '', 'W') else let l:pos2 = searchpairpos('<'. l:tag_name . '[^/>]*>', '', '', 'W') endif if l:pos2 == [0, 0] return endif let l:pos2 = searchpos('>', 'neW') let l:block = [l:pos1, l:pos2] if emmet#util#pointInRegion(l:curpos[1:2], l:block) let l:content = matchstr(l:content, l:mx)[:-2] . ' />' call emmet#util#setContent(l:block, l:content) call setpos('.', [0, l:block[0][0], l:block[0][1], 0]) return endif if l:block[0][0] > 0 call setpos('.', [0, l:block[0][0]-1, l:block[0][1], 0]) else call setpos('.', l:curpos) return endif if l:pos1 == l:old call setpos('.', l:curpos) return endif endwhile endfunction function! emmet#lang#html#removeTag() abort let l:curpos = emmet#util#getcurpos() let l:mx = '<\(/\{0,1}[a-zA-Z][-a-zA-Z0-9:_\-]*\)\%(\%(\s[a-zA-Z][a-zA-Z0-9]\+=\%([^"'' \t]\+\|"[^"]\{-}"\|''[^'']\{-}''\)\s*\)*\)\s*\%(/\{0,1}\)>' let l:pos1 = searchpos(l:mx, 'bcnW') let l:content = matchstr(getline(l:pos1[0])[l:pos1[1]-1:], l:mx) let l:tag_name = substitute(l:content, '^<\(/\{0,1}[a-zA-Z][a-zA-Z0-9:_\-]*\).*$', '\1', '') let l:block = [l:pos1, [l:pos1[0], l:pos1[1] + len(l:content) - 1]] if l:content[-2:] ==# '/>' && emmet#util#cursorInRegion(l:block) call emmet#util#setContent(l:block, '') call setpos('.', [0, l:block[0][0], l:block[0][1], 0]) return endif if l:tag_name[0] ==# '/' let l:pos1 = searchpos('<' . l:tag_name[1:] . '[^a-zA-Z0-9]', 'bcnW') call setpos('.', [0, l:pos1[0], l:pos1[1], 0]) let l:pos2 = searchpairpos('<'. l:tag_name[1:] . '\>[^/>]*>', '', '', 'W') else let l:pos2 = searchpairpos('<'. l:tag_name . '[^/>]*>', '', '', 'W') endif if l:pos2 == [0, 0] return endif let l:pos2 = searchpos('>', 'neW') let l:block = [l:pos1, l:pos2] if emmet#util#pointInRegion(l:curpos[1:2], l:block) call emmet#util#setContent(l:block, '') call setpos('.', [0, l:block[0][0], l:block[0][1], 0]) return endif if l:block[0][0] > 0 call setpos('.', [0, l:block[0][0]-1, l:block[0][1], 0]) else call setpos('.', l:curpos) endif endfunction function! emmet#lang#html#mergeLines() abort let l:curpos = emmet#util#getcurpos() let l:settings = emmet#getSettings() let l:mx = '<\([a-zA-Z][a-zA-Z0-9:_\-]*\)[^>]*>' let l:last = l:curpos[1:2] while 1 let l:pos1 = searchpos(l:mx, 'bcW') let l:content = matchstr(getline(l:pos1[0])[l:pos1[1]-1:], l:mx) echomsg string(l:content) let l:tag_name = matchstr(l:content, '^<\zs[a-zA-Z0-9:_\-]*\ze') if stridx(','.l:settings.html.empty_elements.',', ','.l:tag_name.',') != -1 let l:pos2 = searchpos('>', 'nW') else let l:pos2 = searchpairpos('<' . l:tag_name . '[^>]*>', '', '', 'nW') endif if l:pos1 == [0, 0] || l:pos2 == [0, 0] call setpos('.', l:curpos) return endif let l:block = [l:pos1, l:pos2] if emmet#util#pointInRegion(l:last, l:block) && emmet#util#regionIsValid(l:block) break endif if l:pos1 == l:last call setpos('.', l:curpos) return endif let l:last = l:pos1 endwhile let l:content = emmet#util#getContent(l:block) let l:mx = '<\(/\{0,1}[a-zA-Z][-a-zA-Z0-9:_\-]*\)\%(\%(\s[a-zA-Z][a-zA-Z0-9]\+=\%([^"'' \t]\+\|"[^"]\{-}"\|''[^'']\{-}''\)\s*\)*\)\s*\%(/\{0,1}\)>' let l:content = join(map(split(l:content, l:mx . '\zs\s*'), 'trim(v:val)'), '') call emmet#util#setContent(l:block, l:content) if l:block[0][0] > 0 call setpos('.', [0, l:block[0][0], l:block[0][1], 0]) else call setpos('.', l:curpos) endif endfunction