Files
emmet-vim/autoload/emmet/lang/css.vim
Yasuhiro Matsumoto 7c44caa0e6 Refactoring
2026-03-07 11:08:24 +09:00

386 lines
14 KiB
VimL

function! emmet#lang#css#findTokens(str) abort
let l:tmp = substitute(substitute(a:str, '^.*[;{]\s*', '', ''), '}\s*$', '', '')
if l:tmp =~ '/' && l:tmp =~ '^[a-zA-Z0-9/_.]\+$'
" maybe path or something
return ''
endif
return substitute(substitute(a:str, '^.*[;{]\s*', '', ''), '}\s*$', '', '')
endfunction
function! emmet#lang#css#parseIntoTree(abbr, type) abort
let l:abbr = a:abbr
let l:type = a:type
let l:prefix = 0
let l:value = ''
let l:indent = emmet#getIndentation(l:type)
let l:aliases = emmet#getResource(l:type, 'aliases', {})
let l:snippets = emmet#getResource(l:type, 'snippets', {})
let l:use_pipe_for_cursor = emmet#getResource(l:type, 'use_pipe_for_cursor', 1)
let l:root = emmet#newNode()
" emmet
let l:tokens = split(l:abbr, '+\ze[^+)!]')
let l:block = emmet#util#searchRegion('{', '}')
if l:abbr !~# '^@' && emmet#getBaseType(l:type) ==# 'css' && l:type !=# 'sass' && l:type !=# 'styled' && l:block[0] ==# [0,0] && l:block[1] ==# [0,0]
let l:current = emmet#newNode()
let l:current.snippet = substitute(l:abbr, '\s\+$', '', '') . " {\n" . l:indent . "${cursor}\n}"
let l:current.name = ''
call add(l:root.child, deepcopy(l:current))
else
for l:n in range(len(l:tokens))
let l:token = l:tokens[l:n]
let l:prop = matchlist(l:token, '^\(-\{0,1}[a-zA-Z]\+\|[a-zA-Z0-9]\++\{0,1}\|([a-zA-Z0-9]\++\{0,1})\)\(\%([0-9.-]\+\%(p\|e\|em\|x\|vh\|vw\|re\|rem\|%\)\{0,}-\{0,1}\|-auto\)*\)$')
if len(l:prop)
let l:token = substitute(l:prop[1], '^(\(.*\))', '\1', '')
if l:token =~# '^-'
let l:prefix = 1
let l:token = l:token[1:]
endif
let l:value = ''
for l:vt in split(l:prop[2], '\a\+\zs')
let l:ut = matchstr(l:vt, '[a-z]\+$')
if l:ut == 'auto'
let l:ut = ''
endif
for l:v in split(l:vt, '\d\zs-')
if len(l:value) > 0
let l:value .= ' '
endif
if l:v !~ '[a-z]\+$'
let l:v .= l:ut
endif
if l:token =~# '^[z]'
" TODO
let l:value .= substitute(l:v, '[^0-9.]*$', '', '')
elseif l:v =~# 'em$'
let l:value .= l:v
elseif l:v =~# 'ex$'
let l:value .= l:v
elseif l:v =~# 'vh$'
let l:value .= l:v
elseif l:v =~# 'vw$'
let l:value .= l:v
elseif l:v =~# 'rem$'
let l:value .= l:v
elseif l:v ==# 'auto'
let l:value .= l:v
elseif l:v =~# 'p$'
let l:value .= substitute(l:v, 'p$', '%', '')
elseif l:v =~# '%$'
let l:value .= l:v
elseif l:v =~# 'e$'
let l:value .= substitute(l:v, 'e$', 'em', '')
elseif l:v =~# 'x$'
let l:value .= substitute(l:v, 'x$', 'ex', '')
elseif l:v =~# 're$'
let l:value .= substitute(l:v, 're$', 'rem', '')
elseif l:v =~# '\.'
let l:value .= l:v . 'em'
elseif l:v ==# '0'
let l:value .= '0'
else
let l:value .= l:v . 'px'
endif
endfor
endfor
endif
let l:tag_name = l:token
if l:tag_name =~# '.!$'
let l:tag_name = l:tag_name[:-2]
let l:important = 1
else
let l:important = 0
endif
" make default node
let l:current = emmet#newNode()
let l:current.important = l:important
let l:current.name = l:tag_name
" aliases
if has_key(l:aliases, l:tag_name)
let l:current.name = l:aliases[l:tag_name]
endif
" snippets
if !empty(l:snippets)
let l:snippet_name = l:tag_name
if !has_key(l:snippets, l:snippet_name)
let l:pat = '^' . join(split(l:tag_name, '\zs'), '\%(\|[^:-]\+-\)')
let l:vv = filter(sort(keys(l:snippets)), 'l:snippets[v:val] =~ l:pat')
if len(l:vv) == 0
let l:vv = filter(sort(keys(l:snippets)), 'substitute(v:val, ":", "", "g") == l:snippet_name')
endif
if len(l:vv) > 0
let l:snippet_name = l:vv[0]
else
let l:pat = '^' . join(split(l:tag_name, '\zs'), '\%(\|[^:-]\+-*\)')
let l:vv = filter(sort(keys(l:snippets)), 'l:snippets[v:val] =~ l:pat')
if len(l:vv) == 0
let l:pat = '^' . join(split(l:tag_name, '\zs'), '[^:]\{-}')
let l:vv = filter(sort(keys(l:snippets)), 'l:snippets[v:val] =~ l:pat')
if len(l:vv) == 0
let l:pat = '^' . join(split(l:tag_name, '\zs'), '.\{-}')
let l:vv = filter(sort(keys(l:snippets)), 'l:snippets[v:val] =~ l:pat')
endif
endif
let l:minl = -1
for l:vk in l:vv
let l:vvs = l:snippets[l:vk]
if l:minl == -1 || len(l:vvs) < l:minl
let l:snippet_name = l:vk
let l:minl = len(l:vvs)
endif
endfor
endif
endif
if has_key(l:snippets, l:snippet_name)
let l:snippet = l:snippets[l:snippet_name]
if l:use_pipe_for_cursor
let l:snippet = substitute(l:snippet, '|', '${cursor}', 'g')
endif
let l:lines = split(l:snippet, "\n")
call map(l:lines, 'substitute(v:val, "\\( \\|\\t\\)", escape(l:indent, "\\\\"), "g")')
let l:current.snippet = join(l:lines, "\n")
let l:current.name = ''
let l:current.snippet = substitute(l:current.snippet, ';', l:value . ';', '')
if l:use_pipe_for_cursor && len(l:value) > 0
let l:current.snippet = substitute(l:current.snippet, '\${cursor}', '', 'g')
endif
if l:n < len(l:tokens) - 1
let l:current.snippet .= "\n"
endif
endif
endif
let l:current.pos = 0
let l:lg = matchlist(l:token, '^\%(linear-gradient\|lg\)(\s*\(\S\+\)\s*,\s*\([^,]\+\)\s*,\s*\([^)]\+\)\s*)$')
if len(l:lg) == 0
let l:lg = matchlist(l:token, '^\%(linear-gradient\|lg\)(\s*\(\S\+\)\s*,\s*\([^,]\+\)\s*)$')
if len(l:lg)
let [l:lg[1], l:lg[2], l:lg[3]] = ['linear', l:lg[1], l:lg[2]]
endif
endif
if len(l:lg)
let l:current.name = ''
let l:current.snippet = printf("background-image:-webkit-gradient(%s, 0 0, 0 100%%, from(%s), to(%s));\n", l:lg[1], l:lg[2], l:lg[3])
call add(l:root.child, deepcopy(l:current))
let l:current.snippet = printf("background-image:-webkit-linear-gradient(%s, %s);\n", l:lg[2], l:lg[3])
call add(l:root.child, deepcopy(l:current))
let l:current.snippet = printf("background-image:-moz-linear-gradient(%s, %s);\n", l:lg[2], l:lg[3])
call add(l:root.child, deepcopy(l:current))
let l:current.snippet = printf("background-image:-o-linear-gradient(%s, %s);\n", l:lg[2], l:lg[3])
call add(l:root.child, deepcopy(l:current))
let l:current.snippet = printf("background-image:linear-gradient(%s, %s);\n", l:lg[2], l:lg[3])
call add(l:root.child, deepcopy(l:current))
elseif l:prefix
let l:snippet = l:current.snippet
let l:current.snippet = '-webkit-' . l:snippet . "\n"
call add(l:root.child, deepcopy(l:current))
let l:current.snippet = '-moz-' . l:snippet . "\n"
call add(l:root.child, deepcopy(l:current))
let l:current.snippet = '-o-' . l:snippet . "\n"
call add(l:root.child, deepcopy(l:current))
let l:current.snippet = '-ms-' . l:snippet . "\n"
call add(l:root.child, deepcopy(l:current))
let l:current.snippet = l:snippet
call add(l:root.child, l:current)
elseif l:token =~# '^c#\([0-9a-fA-F]\{3}\|[0-9a-fA-F]\{6}\)\(\.[0-9]\+\)\?'
let l:cs = split(l:token, '\.')
let l:current.name = ''
let [l:r,l:g,l:b] = [0,0,0]
if len(l:cs[0]) == 5
let l:rgb = matchlist(l:cs[0], 'c#\(.\)\(.\)\(.\)')
let l:r = eval('0x'.l:rgb[1].l:rgb[1])
let l:g = eval('0x'.l:rgb[2].l:rgb[2])
let l:b = eval('0x'.l:rgb[3].l:rgb[3])
elseif len(l:cs[0]) == 8
let l:rgb = matchlist(l:cs[0], 'c#\(..\)\(..\)\(..\)')
let l:r = eval('0x'.l:rgb[1])
let l:g = eval('0x'.l:rgb[2])
let l:b = eval('0x'.l:rgb[3])
endif
if len(l:cs) == 1
let l:current.snippet = printf('color:rgb(%d, %d, %d);', l:r, l:g, l:b)
else
let l:current.snippet = printf('color:rgb(%d, %d, %d, %s);', l:r, l:g, l:b, string(str2float('0.'.l:cs[1])))
endif
call add(l:root.child, l:current)
elseif l:token =~# '^c#'
let l:current.name = ''
let l:current.snippet = 'color:\${cursor};'
call add(l:root.child, l:current)
else
call add(l:root.child, l:current)
endif
endfor
endif
return l:root
endfunction
function! emmet#lang#css#toString(settings, current, type, inline, filters, itemno, indent) abort
let l:current = a:current
let l:value = l:current.value[1:-2]
let l:tmp = substitute(l:value, '\${cursor}', '', 'g')
if l:tmp !~ '.*{[ \t\r\n]*}$'
if emmet#useFilter(a:filters, 'fc')
let l:value = substitute(l:value, '\([^:]\+\):\([^;]*\)', '\1: \2', 'g')
else
let l:value = substitute(l:value, '\([^:]\+\):\([^;]*\)', '\1:\2', 'g')
endif
if l:current.important
let l:value = substitute(l:value, ';', ' !important;', '')
endif
endif
return l:value
endfunction
function! emmet#lang#css#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)
let l:fn = matchstr(l:content, '\<url(\zs[^)]\+\ze)')
let l:fn = substitute(l:fn, '[''" \t]', '', 'g')
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:indent = emmet#getIndentation('css')
if l:content =~# '.*\<width\s*:[^;]*;.*'
let l:content = substitute(l:content, '\<width\s*:[^;]*;', 'width: ' . l:width . 'px;', '')
else
let l:content = substitute(l:content, '}', l:indent . 'width: ' . l:width . "px;\n}", '')
endif
if l:content =~# '.*\<height\s*:[^;]*;.*'
let l:content = substitute(l:content, '\<height\s*:[^;]*;', 'height: ' . l:height . 'px;', '')
else
let l:content = substitute(l:content, '}', l:indent . 'height: ' . l:height . "px;\n}", '')
endif
call emmet#util#setContent(l:img_region, l:content)
endfunction
function! emmet#lang#css#imageEncode() abort
let l:img_region = emmet#util#searchRegion('url(', ')')
if !emmet#util#regionIsValid(l:img_region) || !emmet#util#cursorInRegion(l:img_region)
return
endif
let l:content = emmet#util#getContent(l:img_region)
let l:fn = matchstr(l:content, '\<url(\zs[^)]\+\ze)')
let l:fn = substitute(l:fn, '[''" \t]', '', 'g')
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)
call emmet#util#setContent(l:img_region, 'url(' . l:encoded . ')')
endfunction
function! emmet#lang#css#parseTag(tag) abort
return {}
endfunction
function! emmet#lang#css#toggleComment() abort
let l:line = getline('.')
let l:mx = '^\(\s*\)/\*\s*\(.*\)\s*\*/\s*$'
if l:line =~# '{\s*$'
let l:block = emmet#util#searchRegion('/\*', '\*/\zs')
if emmet#util#regionIsValid(l:block)
let l:content = emmet#util#getContent(l:block)
let l:content = substitute(l:content, '/\*\s\(.*\)\s\*/', '\1', '')
call emmet#util#setContent(l:block, l:content)
else
let l:node = expand('<cword>')
if len(l:node)
exe "normal ciw\<c-r>='/* '.l:node.' */'\<cr>"
endif
endif
else
if l:line =~# l:mx
let l:space = substitute(matchstr(l:line, l:mx), l:mx, '\1', '')
let l:line = substitute(matchstr(l:line, l:mx), l:mx, '\2', '')
let l:line = l:space . substitute(l:line, '^\s*\|\s*$', '\1', 'g')
else
let l:mx = '^\(\s*\)\(''[^'']*''\|[^'']*\|;\)\s*$'
" TODO multi-property
"let l:mx = '^\(\s*\)\(\%(''[^'']*''\|[^'';]\+\)*;\{0,1}\)'
let l:line = substitute(l:line, l:mx, '\1/* \2 */', '')
endif
call setline('.', l:line)
endif
endfunction
function! emmet#lang#css#balanceTag(flag) range abort
if a:flag == -2 || a:flag == 2
let l:curpos = [0, line("'<"), col("'<"), 0]
else
let l:curpos = emmet#util#getcurpos()
endif
let l:block = emmet#util#getVisualBlock()
if !emmet#util#regionIsValid(l:block)
if a:flag > 0
let l:block = emmet#util#searchRegion('^', ';')
if emmet#util#regionIsValid(l:block)
call emmet#util#selectRegion(l:block)
return
endif
endif
else
if a:flag > 0
let l:content = emmet#util#getContent(l:block)
if l:content !~# '^{.*}$'
let l:block = emmet#util#searchRegion('{', '}')
if emmet#util#regionIsValid(l:block)
call emmet#util#selectRegion(l:block)
return
endif
endif
else
let l:pos = searchpos('.*;', 'nW')
if l:pos[0] != 0
call setpos('.', [0, l:pos[0], l:pos[1], 0])
let l:block = emmet#util#searchRegion('^', ';')
if emmet#util#regionIsValid(l:block)
call emmet#util#selectRegion(l:block)
return
endif
endif
endif
endif
if a:flag == -2 || a:flag == 2
silent! exe 'normal! gv'
else
call setpos('.', l:curpos)
endif
endfunction
function! emmet#lang#css#moveNextPrevItem(flag) abort
return emmet#lang#css#moveNextPrev(a:flag)
endfunction
function! emmet#lang#css#moveNextPrev(flag) abort
call search('""\|()\|\(:\s*\zs;\{1,0}$\)', a:flag ? 'Wbp' : 'Wp')
return ''
endfunction
function! emmet#lang#css#splitJoinTag() abort
" nothing to do
endfunction
function! emmet#lang#css#removeTag() abort
" nothing to do
endfunction
function! emmet#lang#css#mergeLines() abort
" nothing to do
endfunction