From 01ced0b7ce47d279789efb2dc70d1cd009ac56ad Mon Sep 17 00:00:00 2001
From: davidovski <david@davidovski.xyz>
Date: Sat, 9 Oct 2021 22:20:41 +0100
Subject: initial commit

---
 config/vim/autoload/colorizer.vim                  |  377 ++++
 config/vim/autoload/emmet.vim                      | 2135 ++++++++++++++++++++
 config/vim/autoload/emmet/lang.vim                 |   52 +
 config/vim/autoload/emmet/lang/css.vim             |  385 ++++
 config/vim/autoload/emmet/lang/elm.vim             |  241 +++
 config/vim/autoload/emmet/lang/haml.vim            |  337 +++
 config/vim/autoload/emmet/lang/html.vim            | 1036 ++++++++++
 config/vim/autoload/emmet/lang/jade.vim            |  335 +++
 config/vim/autoload/emmet/lang/less.vim            |   51 +
 config/vim/autoload/emmet/lang/sass.vim            |  163 ++
 config/vim/autoload/emmet/lang/scss.vim            |  129 ++
 config/vim/autoload/emmet/lang/slim.vim            |  284 +++
 config/vim/autoload/emmet/lorem/en.vim             |   65 +
 config/vim/autoload/emmet/lorem/ja.vim             |   27 +
 config/vim/autoload/emmet/util.vim                 |  410 ++++
 config/vim/autoload/rainbow_parentheses.vim        |   98 +
 config/vim/plugin/colorizer.vim                    |   62 +
 config/vim/plugin/emmet.vim                        |  191 ++
 config/vim/plugin/pickachu.vim                     |   45 +
 config/vim/plugin/pickachu/__init__.py             |    0
 .../pickachu/__pycache__/__init__.cpython-39.pyc   |  Bin 0 -> 142 bytes
 .../pickachu/__pycache__/apps.cpython-39.pyc       |  Bin 0 -> 1107 bytes
 .../pickachu/__pycache__/main.cpython-39.pyc       |  Bin 0 -> 719 bytes
 .../pickachu/__pycache__/processors.cpython-39.pyc |  Bin 0 -> 1896 bytes
 config/vim/plugin/pickachu/apps.py                 |   68 +
 config/vim/plugin/pickachu/main.py                 |   36 +
 config/vim/plugin/pickachu/processors.py           |   80 +
 config/vim/plugin/rainbow_parentheses.vim          |   13 +
 config/vim/spell/fr.utf-8.spl                      |  Bin 0 -> 571627 bytes
 config/vim/spell/fr.utf-8.sug                      |  Bin 0 -> 2324315 bytes
 config/vim/viminfo                                 |  Bin 0 -> 160313 bytes
 config/vim/vimrc                                   |   34 +
 32 files changed, 6654 insertions(+)
 create mode 100644 config/vim/autoload/colorizer.vim
 create mode 100644 config/vim/autoload/emmet.vim
 create mode 100644 config/vim/autoload/emmet/lang.vim
 create mode 100644 config/vim/autoload/emmet/lang/css.vim
 create mode 100644 config/vim/autoload/emmet/lang/elm.vim
 create mode 100644 config/vim/autoload/emmet/lang/haml.vim
 create mode 100644 config/vim/autoload/emmet/lang/html.vim
 create mode 100644 config/vim/autoload/emmet/lang/jade.vim
 create mode 100644 config/vim/autoload/emmet/lang/less.vim
 create mode 100644 config/vim/autoload/emmet/lang/sass.vim
 create mode 100644 config/vim/autoload/emmet/lang/scss.vim
 create mode 100644 config/vim/autoload/emmet/lang/slim.vim
 create mode 100644 config/vim/autoload/emmet/lorem/en.vim
 create mode 100644 config/vim/autoload/emmet/lorem/ja.vim
 create mode 100644 config/vim/autoload/emmet/util.vim
 create mode 100644 config/vim/autoload/rainbow_parentheses.vim
 create mode 100644 config/vim/plugin/colorizer.vim
 create mode 100644 config/vim/plugin/emmet.vim
 create mode 100644 config/vim/plugin/pickachu.vim
 create mode 100644 config/vim/plugin/pickachu/__init__.py
 create mode 100644 config/vim/plugin/pickachu/__pycache__/__init__.cpython-39.pyc
 create mode 100644 config/vim/plugin/pickachu/__pycache__/apps.cpython-39.pyc
 create mode 100644 config/vim/plugin/pickachu/__pycache__/main.cpython-39.pyc
 create mode 100644 config/vim/plugin/pickachu/__pycache__/processors.cpython-39.pyc
 create mode 100644 config/vim/plugin/pickachu/apps.py
 create mode 100644 config/vim/plugin/pickachu/main.py
 create mode 100644 config/vim/plugin/pickachu/processors.py
 create mode 100644 config/vim/plugin/rainbow_parentheses.vim
 create mode 100644 config/vim/spell/fr.utf-8.spl
 create mode 100644 config/vim/spell/fr.utf-8.sug
 create mode 100644 config/vim/viminfo
 create mode 100644 config/vim/vimrc

(limited to 'config/vim')

diff --git a/config/vim/autoload/colorizer.vim b/config/vim/autoload/colorizer.vim
new file mode 100644
index 0000000..19b10be
--- /dev/null
+++ b/config/vim/autoload/colorizer.vim
@@ -0,0 +1,377 @@
+" colorizer.vim	Colorize all text in the form #rrggbb or #rgb; autoload functions
+" Maintainer:	lilydjwg <lilydjwg@gmail.com>
+" Version:	1.4.1
+" License:	Vim License  (see vim's :help license)
+"
+" See plugin/colorizer.vim for more info.
+
+let s:keepcpo = &cpo
+set cpo&vim
+
+function! s:FGforBG(bg) "{{{1
+  " takes a 6hex color code and returns a matching color that is visible
+  let pure = substitute(a:bg,'^#','','')
+  let r = eval('0x'.pure[0].pure[1])
+  let g = eval('0x'.pure[2].pure[3])
+  let b = eval('0x'.pure[4].pure[5])
+  let fgc = g:colorizer_fgcontrast
+  if r*30 + g*59 + b*11 > 12000
+    return s:predefined_fgcolors['dark'][fgc]
+  else
+    return s:predefined_fgcolors['light'][fgc]
+  end
+endfunction
+
+function! s:Rgb2xterm(color) "{{{1
+  " selects the nearest xterm color for a rgb value like #FF0000
+  let best_match=0
+  let smallest_distance = 10000000000
+  let r = eval('0x'.a:color[1].a:color[2])
+  let g = eval('0x'.a:color[3].a:color[4])
+  let b = eval('0x'.a:color[5].a:color[6])
+  let colortable = s:GetXterm2rgbTable()
+  for c in range(0,254)
+    let d = pow(colortable[c][0]-r,2) + pow(colortable[c][1]-g,2) + pow(colortable[c][2]-b,2)
+    if d<smallest_distance
+      let smallest_distance = d
+      let best_match = c
+    endif
+  endfor
+  return best_match
+endfunction
+
+"" the 6 value iterations in the xterm color cube {{{1
+let s:valuerange = [0x00, 0x5F, 0x87, 0xAF, 0xD7, 0xFF]
+
+"" 16 basic colors {{{1
+let s:basic16 = [
+      \ [0x00, 0x00, 0x00], [0xCD, 0x00, 0x00],
+      \ [0x00, 0xCD, 0x00], [0xCD, 0xCD, 0x00],
+      \ [0x00, 0x00, 0xEE], [0xCD, 0x00, 0xCD],
+      \ [0x00, 0xCD, 0xCD], [0xE5, 0xE5, 0xE5],
+      \ [0x7F, 0x7F, 0x7F], [0xFF, 0x00, 0x00],
+      \ [0x00, 0xFF, 0x00], [0xFF, 0xFF, 0x00],
+      \ [0x5C, 0x5C, 0xFF], [0xFF, 0x00, 0xFF],
+      \ [0x00, 0xFF, 0xFF], [0xFF, 0xFF, 0xFF]]
+
+function! s:Xterm2rgb(color) "{{{1
+  " 16 basic colors
+  let r = 0
+  let g = 0
+  let b = 0
+  if a:color<16
+    let r = s:basic16[a:color][0]
+    let g = s:basic16[a:color][1]
+    let b = s:basic16[a:color][2]
+  endif
+
+  " color cube color
+  if a:color>=16 && a:color<=232
+    let l:color=a:color-16
+    let r = s:valuerange[(l:color/36)%6]
+    let g = s:valuerange[(l:color/6)%6]
+    let b = s:valuerange[l:color%6]
+  endif
+
+  " gray tone
+  if a:color>=233 && a:color<=253
+    let r=8+(a:color-232)*0x0a
+    let g=r
+    let b=r
+  endif
+  let rgb=[r,g,b]
+  return rgb
+endfunction
+
+function! s:SetMatcher(color, pat) "{{{1
+  " "color" is the converted color and "pat" is what to highlight
+  let group = 'Color' . strpart(a:color, 1)
+  if !hlexists(group) || s:force_group_update
+    let fg = g:colorizer_fgcontrast < 0 ? a:color : s:FGforBG(a:color)
+    if &t_Co == 256
+      exe 'hi '.group.' ctermfg='.s:Rgb2xterm(fg).' ctermbg='.s:Rgb2xterm(a:color)
+    endif
+    " Always set gui* as user may switch to GUI version and it's cheap
+    exe 'hi '.group.' guifg='.fg.' guibg='.a:color
+  endif
+  if !exists("w:colormatches[a:pat]")
+    let w:colormatches[a:pat] = matchadd(group, a:pat)
+  endif
+endfunction
+
+"ColorFinders {{{1
+function! s:HexCode(str, lineno) "{{{2
+  let ret = []
+  let place = 0
+  let colorpat = '#[0-9A-Fa-f]\{3\}\>\|#[0-9A-Fa-f]\{6\}\>'
+  while 1
+    let foundcolor = matchstr(a:str, colorpat, place)
+    if foundcolor == ''
+      break
+    endif
+    let place = matchend(a:str, colorpat, place)
+    let pat = foundcolor . '\>'
+    if len(foundcolor) == 4
+      let foundcolor = substitute(foundcolor, '[[:xdigit:]]', '&&', 'g')
+    endif
+    call add(ret, [foundcolor, pat])
+  endwhile
+  return ret
+endfunction
+
+function! s:RgbColor(str, lineno) "{{{2
+  let ret = []
+  let place = 0
+  let colorpat = '\<rgb(\v\s*(\d+(\%)?)\s*,\s*(\d+%(\2))\s*,\s*(\d+%(\2))\s*\)'
+  while 1
+    let foundcolor = matchlist(a:str, colorpat, place)
+    if empty(foundcolor)
+      break
+    endif
+    let place = matchend(a:str, colorpat, place)
+    if foundcolor[2] == '%'
+      let r = foundcolor[1] * 255 / 100
+      let g = foundcolor[3] * 255 / 100
+      let b = foundcolor[4] * 255 / 100
+    else
+      let r = foundcolor[1]
+      let g = foundcolor[3]
+      let b = foundcolor[4]
+    endif
+    if r > 255 || g > 255 || b > 255
+      break
+    endif
+    let pat = printf('\<rgb(\v\s*%s\s*,\s*%s\s*,\s*%s\s*\)', foundcolor[1], foundcolor[3], foundcolor[4])
+    if foundcolor[2] == '%'
+      let pat = substitute(pat, '%', '\\%', 'g')
+    endif
+    let l:color = printf('#%02x%02x%02x', r, g, b)
+    call add(ret, [l:color, pat])
+  endwhile
+  return ret
+endfunction
+
+function! s:RgbaColor(str, lineno) "{{{2
+  if has("gui_running")
+    let bg = synIDattr(synIDtrans(hlID("Normal")), "bg")
+    let bg_r = str2nr(bg[1].bg[2], 16)
+    let bg_g = str2nr(bg[3].bg[4], 16)
+    let bg_b = str2nr(bg[5].bg[6], 16)
+  else
+    " translucent colors would display incorrectly, so ignore the alpha value
+    return s:RgbaColorForTerm(a:str, a:lineno)
+  endif
+  let ret = []
+  let place = 0
+  let colorpat = '\<rgba(\v\s*(\d+(\%)?)\s*,\s*(\d+%(\2))\s*,\s*(\d+%(\2))\s*,\s*(-?[.[:digit:]]+)\s*\)'
+  while 1
+    let foundcolor = matchlist(a:str, colorpat, place)
+    if empty(foundcolor)
+      break
+    endif
+    let place = matchend(a:str, colorpat, place)
+    if foundcolor[2] == '%'
+      let ar = foundcolor[1] * 255 / 100
+      let ag = foundcolor[3] * 255 / 100
+      let ab = foundcolor[4] * 255 / 100
+    else
+      let ar = foundcolor[1]
+      let ag = foundcolor[3]
+      let ab = foundcolor[4]
+    endif
+    if ar > 255 || ag > 255 || ab > 255
+      break
+    endif
+    let alpha = str2float(foundcolor[5])
+    if alpha < 0
+      let alpha = 0.0
+    elseif alpha > 1
+      let alpha = 1.0
+    endif
+    let pat = printf('\<rgba(\v\s*%s\s*,\s*%s\s*,\s*%s\s*,\s*%s0*\s*\)', foundcolor[1], foundcolor[3], foundcolor[4], foundcolor[5])
+    if foundcolor[2] == '%'
+      let pat = substitute(pat, '%', '\\%', 'g')
+    endif
+    let r = float2nr(ceil(ar * alpha) + ceil(bg_r * (1 - alpha)))
+    let g = float2nr(ceil(ag * alpha) + ceil(bg_g * (1 - alpha)))
+    let b = float2nr(ceil(ab * alpha) + ceil(bg_b * (1 - alpha)))
+    if r > 255
+      let r = 255
+    endif
+    if g > 255
+      let g = 255
+    endif
+    if b > 255
+      let b = 255
+    endif
+    let l:color = printf('#%02x%02x%02x', r, g, b)
+    call add(ret, [l:color, pat])
+  endwhile
+  return ret
+endfunction
+
+function! s:RgbaColorForTerm(str, lineno) "{{{2
+  let ret = []
+  let place = 0
+  let colorpat = '\<rgba(\v\s*(\d+(\%)?)\s*,\s*(\d+%(\2))\s*,\s*(\d+%(\2))\s*,\s*(-?[.[:digit:]]+)\s*\)'
+  while 1
+    let foundcolor = matchlist(a:str, colorpat, place)
+    if empty(foundcolor)
+      break
+    endif
+    let place = matchend(a:str, colorpat, place)
+    if foundcolor[2] == '%'
+      let ar = foundcolor[1] * 255 / 100
+      let ag = foundcolor[3] * 255 / 100
+      let ab = foundcolor[4] * 255 / 100
+    else
+      let ar = foundcolor[1]
+      let ag = foundcolor[3]
+      let ab = foundcolor[4]
+    endif
+    if ar > 255 || ag > 255 || ab > 255
+      break
+    endif
+    let pat = printf('\<rgba(\v\s*%s\s*,\s*%s\s*,\s*%s\s*,\ze\s*(-?[.[:digit:]]+)\s*\)', foundcolor[1], foundcolor[3], foundcolor[4])
+    if foundcolor[2] == '%'
+      let pat = substitute(pat, '%', '\\%', 'g')
+    endif
+    let l:color = printf('#%02x%02x%02x', ar, ag, ab)
+    call add(ret, [l:color, pat])
+  endwhile
+  return ret
+endfunction
+
+function! s:PreviewColorInLine(where) "{{{1
+  let line = getline(a:where)
+  for Func in s:ColorFinder
+    let ret = Func(line, a:where)
+    " returned a list of a list: color as #rrggbb, text pattern to highlight
+    for r in ret
+      call s:SetMatcher(r[0], r[1])
+    endfor
+  endfor
+endfunction
+
+function! s:CursorMoved() "{{{1
+  if !exists('w:colormatches')
+    return
+  endif
+  if exists('b:colorizer_last_update')
+    if b:colorizer_last_update == b:changedtick
+      " Nothing changed
+      return
+    endif
+  endif
+  call s:PreviewColorInLine('.')
+  let b:colorizer_last_update = b:changedtick
+endfunction
+
+function! s:TextChanged() "{{{1
+  if !exists('w:colormatches')
+    return
+  endif
+  echomsg "TextChanged"
+  call s:PreviewColorInLine('.')
+endfunction
+
+function! colorizer#ColorHighlight(update, ...) "{{{1
+  if exists('w:colormatches')
+    if !a:update
+      return
+    endif
+    call s:ClearMatches()
+  endif
+  let w:colormatches = {}
+  if g:colorizer_fgcontrast != s:saved_fgcontrast || (exists("a:1") && a:1 == '!')
+    let s:force_group_update = 1
+  endif
+  for i in range(1, line("$"))
+    call s:PreviewColorInLine(i)
+  endfor
+  let s:force_group_update = 0
+  let s:saved_fgcontrast = g:colorizer_fgcontrast
+  augroup Colorizer
+    au!
+    if exists('##TextChanged')
+      autocmd TextChanged * silent call s:TextChanged()
+      if v:version > 704 || v:version == 704 && has('patch143')
+        autocmd TextChangedI * silent call s:TextChanged()
+      else
+        " TextChangedI does not work as expected
+        autocmd CursorMovedI * silent call s:CursorMoved()
+      endif
+    else
+      autocmd CursorMoved,CursorMovedI * silent call s:CursorMoved()
+    endif
+    " rgba handles differently, so need updating
+    autocmd GUIEnter * silent call colorizer#ColorHighlight(1)
+    autocmd BufRead * silent call colorizer#ColorHighlight(1)
+    autocmd WinEnter * silent call colorizer#ColorHighlight(1)
+    autocmd ColorScheme * let s:force_group_update=1 | silent call colorizer#ColorHighlight(1)
+  augroup END
+endfunction
+
+function! colorizer#ColorClear() "{{{1
+  augroup Colorizer
+    au!
+  augroup END
+  let save_tab = tabpagenr()
+  let save_win = winnr()
+  tabdo windo call s:ClearMatches()
+  exe 'tabn '.save_tab
+  exe save_win . 'wincmd w'
+endfunction
+
+function! s:ClearMatches() "{{{1
+  if !exists('w:colormatches')
+    return
+  endif
+  for i in values(w:colormatches)
+    call matchdelete(i)
+  endfor
+  unlet w:colormatches
+endfunction
+
+function! colorizer#ColorToggle() "{{{1
+  if exists('#Colorizer#BufRead')
+    call colorizer#ColorClear()
+    echomsg 'Disabled color code highlighting.'
+  else
+    call colorizer#ColorHighlight(0)
+    echomsg 'Enabled color code highlighting.'
+  endif
+endfunction
+
+function! s:GetXterm2rgbTable()
+  if !exists('s:table_xterm2rgb')
+    let s:table_xterm2rgb = []
+    for c in range(0, 254)
+      let s:color = s:Xterm2rgb(c)
+      call add(s:table_xterm2rgb, s:color)
+    endfor
+  endif
+  return s:table_xterm2rgb
+endfun
+
+" Setups {{{1
+let s:ColorFinder = [function('s:HexCode'), function('s:RgbColor'), function('s:RgbaColor')]
+let s:force_group_update = 0
+let s:predefined_fgcolors = {}
+let s:predefined_fgcolors['dark']  = ['#444444', '#222222', '#000000']
+let s:predefined_fgcolors['light'] = ['#bbbbbb', '#dddddd', '#ffffff']
+if !exists("g:colorizer_fgcontrast")
+  " Default to black / white
+  let g:colorizer_fgcontrast = len(s:predefined_fgcolors['dark']) - 1
+elseif g:colorizer_fgcontrast >= len(s:predefined_fgcolors['dark'])
+  echohl WarningMsg
+  echo "g:colorizer_fgcontrast value invalid, using default"
+  echohl None
+  let g:colorizer_fgcontrast = len(s:predefined_fgcolors['dark']) - 1
+endif
+let s:saved_fgcontrast = g:colorizer_fgcontrast
+
+" Restoration and modelines {{{1
+let &cpo = s:keepcpo
+unlet s:keepcpo
+" vim:ft=vim:fdm=marker:fmr={{{,}}}:
diff --git a/config/vim/autoload/emmet.vim b/config/vim/autoload/emmet.vim
new file mode 100644
index 0000000..12ed9a9
--- /dev/null
+++ b/config/vim/autoload/emmet.vim
@@ -0,0 +1,2135 @@
+"=============================================================================
+" emmet.vim
+" Author: Yasuhiro Matsumoto <mattn.jp@gmail.com>
+" Last Change: 26-Jul-2015.
+
+let s:save_cpo = &cpoptions
+set cpoptions&vim
+
+let s:filtermx = '|\(\%(bem\|html\|blade\|haml\|slim\|e\|c\|s\|fc\|xsl\|t\|\/[^ ]\+\)\s*,\{0,1}\s*\)*$'
+
+function! emmet#getExpandos(type, key) abort
+  let expandos = emmet#getResource(a:type, 'expandos', {})
+  if has_key(expandos, a:key)
+    return expandos[a:key]
+  endif
+  return a:key
+endfunction
+
+function! emmet#splitFilterArg(filters) abort
+  for f in a:filters
+    if f =~# '^/'
+      return f[1:]
+    endif
+  endfor
+  return ''
+endfunction
+
+function! emmet#useFilter(filters, filter) abort
+  for f in a:filters
+    if a:filter ==# '/' && f =~# '^/'
+      return 1
+    elseif f ==# a:filter
+      return 1
+    endif
+  endfor
+  return 0
+endfunction
+
+function! emmet#getIndentation(...) abort
+  if a:0 > 0
+    let type = a:1
+  else
+    let type = emmet#getFileType()
+  endif
+  if has_key(s:emmet_settings, type) && has_key(s:emmet_settings[type], 'indentation')
+    let indent = s:emmet_settings[type].indentation
+  elseif has_key(s:emmet_settings, 'indentation')
+    let indent = s:emmet_settings.indentation
+  elseif has_key(s:emmet_settings.variables, 'indentation')
+    let indent = s:emmet_settings.variables.indentation
+  else
+    let sw = exists('*shiftwidth') ? shiftwidth() : &l:shiftwidth
+    let indent = (&l:expandtab || &l:tabstop !=# sw) ? repeat(' ', sw) : "\t"
+  endif
+  return indent
+endfunction
+
+function! emmet#getBaseType(type) abort
+  if !has_key(s:emmet_settings, a:type)
+    return ''
+  endif
+  if !has_key(s:emmet_settings[a:type], 'extends')
+    return a:type
+  endif
+  let extends = s:emmet_settings[a:type].extends
+  if type(extends) ==# 1
+    let tmp = split(extends, '\s*,\s*')
+    let ext = tmp[0]
+  else
+    let ext = extends[0]
+  endif
+  if a:type !=# ext
+    return emmet#getBaseType(ext)
+  endif
+  return ''
+endfunction
+
+function! emmet#isExtends(type, extend) abort
+  if a:type ==# a:extend
+    return 1
+  endif
+  if !has_key(s:emmet_settings, a:type)
+    return 0
+  endif
+  if !has_key(s:emmet_settings[a:type], 'extends')
+    return 0
+  endif
+  let extends = emmet#lang#getExtends(a:type)
+  for ext in extends
+    if a:extend ==# ext
+      return 1
+    endif
+  endfor
+  return 0
+endfunction
+
+function! emmet#parseIntoTree(abbr, type) abort
+  let abbr = a:abbr
+  let type = a:type
+  return emmet#lang#{emmet#lang#type(type)}#parseIntoTree(abbr, type)
+endfunction
+
+function! emmet#expandAbbrIntelligent(feedkey) abort
+  if !emmet#isExpandable()
+    return a:feedkey
+  endif
+  return "\<plug>(emmet-expand-abbr)"
+endfunction
+
+function! emmet#isExpandable() abort
+  let line = getline('.')
+  if col('.') < len(line)
+    let line = matchstr(line, '^\(.*\%'.col('.').'c\)')
+  endif
+  let part = matchstr(line, '\(\S.*\)$')
+  let type = emmet#getFileType()
+  let rtype = emmet#lang#type(type)
+  let part = emmet#lang#{rtype}#findTokens(part)
+  return len(part) > 0
+endfunction
+
+function! emmet#mergeConfig(lhs, rhs) abort
+  let [lhs, rhs] = [a:lhs, a:rhs]
+  if type(lhs) ==# 3
+    if type(rhs) ==# 3
+      let lhs += rhs
+      if len(lhs)
+        call remove(lhs, 0, len(lhs)-1)
+      endif
+      for rhi in rhs
+        call add(lhs, rhs[rhi])
+      endfor
+    elseif type(rhs) ==# 4
+      let lhs += map(keys(rhs), '{v:val : rhs[v:val]}')
+    endif
+  elseif type(lhs) ==# 4
+    if type(rhs) ==# 3
+      for V in rhs
+        if type(V) != 4
+          continue
+        endif
+        for k in keys(V)
+          let lhs[k] = V[k]
+        endfor
+      endfor
+    elseif type(rhs) ==# 4
+      for key in keys(rhs)
+        if type(rhs[key]) ==# 3
+          if !has_key(lhs, key)
+            let lhs[key] = []
+          endif
+          if type(lhs[key]) == 3
+            let lhs[key] += rhs[key]
+          elseif type(lhs[key]) == 4
+            for k in keys(rhs[key])
+              let lhs[key][k] = rhs[key][k]
+            endfor
+          endif
+        elseif type(rhs[key]) ==# 4
+          if has_key(lhs, key)
+            call emmet#mergeConfig(lhs[key], rhs[key])
+          else
+            let lhs[key] = rhs[key]
+          endif
+        else
+          let lhs[key] = rhs[key]
+        endif
+      endfor
+    endif
+  endif
+endfunction
+
+function! emmet#newNode() abort
+  return { 'name': '', 'attr': {}, 'child': [], 'snippet': '', 'basevalue': 0, 'basedirect': 1, 'multiplier': 1, 'parent': {}, 'value': '', 'pos': 0, 'important': 0, 'attrs_order': ['id', 'class'], 'block': 0, 'empty': 0 }
+endfunction
+
+function! s:itemno(itemno, current) abort
+  let current = a:current
+  if current.basedirect > 0
+    return current.basevalue - 1 + a:itemno
+  else
+    return current.multiplier + current.basevalue - 2 - a:itemno
+  endif
+endfunction
+
+function! s:localvar(current, key) abort
+  let val = ''
+  let cur = a:current
+  while !empty(cur)
+    if has_key(cur, 'variables') && has_key(cur.variables, a:key)
+      return cur.variables[a:key]
+    endif
+    let cur = cur.parent
+  endwhile
+  return ''
+endfunction
+
+function! emmet#toString(...) abort
+  let current = a:1
+  if a:0 > 1
+    let type = a:2
+  else
+    let type = &filetype
+  endif
+  if len(type) ==# 0 | let type = 'html' | endif
+  if a:0 > 2
+    let inline = a:3
+  else
+    let inline = 0
+  endif
+  if a:0 > 3
+    if type(a:4) ==# 1
+      let filters = split(a:4, '\s*,\s*')
+    else
+      let filters = a:4
+    endif
+  else
+    let filters = ['html']
+  endif
+  if a:0 > 4
+    let group_itemno = a:5
+  else
+    let group_itemno = 0
+  endif
+  if a:0 > 5
+    let indent = a:6
+  else
+    let indent = ''
+  endif
+
+  let dollar_expr = emmet#getResource(type, 'dollar_expr', 1)
+  let itemno = 0
+  let str = ''
+  let rtype = emmet#lang#type(type)
+  while itemno < current.multiplier
+    if len(current.name)
+      if current.multiplier ==# 1
+        let inner = emmet#lang#{rtype}#toString(s:emmet_settings, current, type, inline, filters, s:itemno(group_itemno, current), indent)
+      else
+        let inner = emmet#lang#{rtype}#toString(s:emmet_settings, current, type, inline, filters, s:itemno(itemno, current), indent)
+      endif
+      if current.multiplier > 1
+        let inner = substitute(inner, '\$#', '$line'.(itemno+1).'$', 'g')
+      endif
+      let str .= inner
+    else
+      let snippet = current.snippet
+      if len(snippet) ==# 0
+        let snippets = emmet#getResource(type, 'snippets', {})
+        if !empty(snippets) && has_key(snippets, 'emmet_snippet')
+          let snippet = snippets['emmet_snippet']
+        endif
+      endif
+      if len(snippet) > 0
+        let tmp = snippet
+        let tmp = substitute(tmp, '\${emmet_name}', current.name, 'g')
+        let snippet_node = emmet#newNode()
+        let snippet_node.value = '{'.tmp.'}'
+        let snippet_node.important = current.important
+        let snippet_node.multiplier = current.multiplier
+        let str .= emmet#lang#{rtype}#toString(s:emmet_settings, snippet_node, type, inline, filters, s:itemno(group_itemno, current), indent)
+        if current.multiplier > 1
+          let str .= "\n"
+        endif
+      else
+        if len(current.name)
+          let str .= current.name
+        endif
+        if len(current.value)
+          let text = current.value[1:-2]
+          if dollar_expr
+            " TODO: regexp engine specified
+            if exists('&regexpengine')
+              let text = substitute(text, '\%#=1\%(\\\)\@\<!\(\$\+\)\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d", max([itemno, group_itemno])+1).submatch(2)', 'g')
+            else
+              let text = substitute(text, '\%(\\\)\@\<!\(\$\+\)\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d", max([itemno, group_itemno])+1).submatch(2)', 'g')
+            endif
+            let text = substitute(text, '\${nr}', "\n", 'g')
+            let text = substitute(text, '\\\$', '$', 'g')
+          endif
+          let str .= text
+        endif
+      endif
+      let inner = ''
+      if len(current.child)
+        for n in current.child
+          let inner .= emmet#toString(n, type, inline, filters, s:itemno(group_itemno, n), indent)
+        endfor
+      else
+        let inner = current.value[1:-2]
+      endif
+      let inner = substitute(inner, "\n", "\n" . indent, 'g')
+      let str = substitute(str, '\${:\(\w\+\)}', '\=s:localvar(current, submatch(1))', '')
+      let str = substitute(str, '\${child}', inner, '')
+    endif
+    let itemno = itemno + 1
+  endwhile
+  return str
+endfunction
+
+function! emmet#getSettings() abort
+  return s:emmet_settings
+endfunction
+
+function! emmet#getFilters(type) abort
+  let filterstr = emmet#getResource(a:type, 'filters', '')
+  return split(filterstr, '\s*,\s*')
+endfunction
+
+function! emmet#getResource(type, name, default) abort
+  if exists('b:emmet_' . a:name)
+    return get(b:, 'emmet_' . a:name)
+  endif
+  let global = {}
+  if has_key(s:emmet_settings, '*') && has_key(s:emmet_settings['*'], a:name)
+    let global = extend(global, s:emmet_settings['*'][a:name])
+  endif
+
+  if has_key(s:emmet_settings, a:type)
+    let types = [a:type]
+  else
+    let types = split(a:type, '\.')
+  endif
+
+  for type in types
+    if !has_key(s:emmet_settings, type)
+      continue
+    endif
+    let ret = a:default
+
+    if has_key(s:emmet_settings[type], 'extends')
+      let extends = emmet#lang#getExtends(a:type)
+      call reverse(extends) " reverse to overwrite the correct way
+      for ext in extends
+        if !has_key(s:emmet_settings, ext)
+          continue
+        endif
+
+        if has_key(s:emmet_settings[ext], a:name)
+          if type(ret) ==# 3 || type(ret) ==# 4
+            call emmet#mergeConfig(ret, s:emmet_settings[ext][a:name])
+          else
+            let ret = s:emmet_settings[ext][a:name]
+          endif
+        endif
+      endfor
+    endif
+
+    if has_key(s:emmet_settings[type], a:name)
+      if type(ret) ==# 3 || type(ret) ==# 4
+        call emmet#mergeConfig(ret, s:emmet_settings[type][a:name])
+        return extend(global, ret)
+      else
+        return s:emmet_settings[type][a:name]
+      endif
+    endif
+    if !empty(ret)
+      if type(ret) ==# 3 || type(ret) ==# 4
+        let ret = extend(global, ret)
+      endif
+      return ret
+    endif
+  endfor
+
+  let ret = a:default
+  if type(ret) ==# 3 || type(ret) ==# 4
+    let ret = extend(global, ret)
+  endif
+  return ret
+endfunction
+
+function! emmet#getFileType(...) abort
+  let flg = get(a:000, 0, 0)
+  
+  if has_key(s:emmet_settings, &filetype)
+    let type = &filetype
+    if emmet#getResource(type, 'ignore_embeded_filetype', 0)
+      return type 
+    endif
+  endif 
+
+  let pos = emmet#util#getcurpos()
+  let type = synIDattr(synID(max([pos[1], 1]), max([pos[2], 1]), 1), 'name')
+
+  " ignore htmlTagName as it seems to occur too often
+  if type == 'htmlTagName'
+    let type = ''
+  endif
+  if type =~ '^mkdSnippet'
+    let type = tolower(type[10:])
+  endif
+
+  if type =~? '^css'
+    let type = 'css'
+  elseif type =~? '^html'
+    let type = 'html'
+  elseif type =~? '^jsx'
+    let type = 'jsx'
+  elseif (type =~? '^js\w' || type =~? '^javascript') && !(&filetype =~? 'jsx')
+    let type = 'javascript'
+  elseif type =~? '^tsx'
+    let type = 'tsx'
+  elseif type =~? '^ts\w' || type =~? '^typescript'
+    let type = 'typescript'
+  elseif type =~? '^xml'
+    let type = 'xml'
+  elseif type == 'styledEmmetAbbreviation'
+    let type = 'styled'
+  else
+    let types = split(&filetype, '\.')
+    for part in types
+      if has_key(s:emmet_settings, part)
+        let type = part
+        break
+      endif
+      let base = emmet#getBaseType(part)
+      if base !=# ''
+        if flg
+          let type = &filetype
+        else
+          let type = base
+        endif
+        unlet base
+        break
+      endif
+    endfor
+  endif
+
+  return len(type) == 0 ? 'html' : type
+endfunction
+
+function! emmet#getDollarExprs(expand) abort
+  let expand = a:expand
+  let dollar_list = []
+  let dollar_reg = '\%(\\\)\@<!\${\(\([^{}]\|\%(\\\)\@\<=[{}]\)\{}\)}'
+  while 1
+    let matcharr = matchlist(expand, dollar_reg)
+    if len(matcharr) > 0
+      let key = get(matcharr, 1)
+      if key !~# '^\d\+:'
+        let key = substitute(key, '\\{', '{', 'g')
+        let key = substitute(key, '\\}', '}', 'g')
+        let value = emmet#getDollarValueByKey(key)
+        if type(value) ==# type('')
+          let expr = get(matcharr, 0)
+          call add(dollar_list, {'expr': expr, 'value': value})
+        endif
+      endif
+    else
+      break
+    endif
+    let expand = substitute(expand, dollar_reg, '', '')
+  endwhile
+  return dollar_list
+endfunction
+
+function! emmet#getDollarValueByKey(key) abort
+  let ret = 0
+  let key = a:key
+  let ftsetting = get(s:emmet_settings, emmet#getFileType())
+  if type(ftsetting) ==# 4 && has_key(ftsetting, key)
+    let V = get(ftsetting, key)
+    if type(V) ==# 1 | return V | endif
+  endif
+  if type(ret) !=# 1 && has_key(s:emmet_settings.variables, key)
+    let V = get(s:emmet_settings.variables, key)
+    if type(V) ==# 1 | return V | endif
+  endif
+  if has_key(s:emmet_settings, 'custom_expands') && type(s:emmet_settings['custom_expands']) ==# 4
+    for k in keys(s:emmet_settings['custom_expands'])
+      if key =~# k
+        let V = get(s:emmet_settings['custom_expands'], k)
+        if type(V) ==# 1 | return V | endif
+        if type(V) ==# 2 | return V(key) | endif
+      endif
+    endfor
+  endif
+  return ret
+endfunction
+
+function! emmet#reExpandDollarExpr(expand, times) abort
+  let expand = a:expand
+  let dollar_exprs = emmet#getDollarExprs(expand)
+  if len(dollar_exprs) > 0
+    if a:times < 9
+      for n in range(len(dollar_exprs))
+        let pair = get(dollar_exprs, n)
+        let pat = get(pair, 'expr')
+        let sub = get(pair, 'value')
+        let expand = substitute(expand, pat, sub, '')
+      endfor
+      return emmet#reExpandDollarExpr(expand, a:times + 1)
+    endif
+  endif
+  return expand
+endfunction
+
+function! emmet#expandDollarExpr(expand) abort
+  return emmet#reExpandDollarExpr(a:expand, 0)
+endfunction
+
+function! emmet#expandCursorExpr(expand, mode) abort
+  let expand = a:expand
+  if expand !~# '\${cursor}'
+    if a:mode ==# 2
+      let expand = '${cursor}' . expand
+    else
+      let expand .= '${cursor}'
+    endif
+  endif
+  let expand = substitute(expand, '\${\d\+:\?\([^}]\+\)}', '$select$$cursor$\1$select$', 'g')
+  let expand = substitute(expand, '\${\d\+}', '$select$$cursor$$select$', 'g')
+  let expand = substitute(expand, '\${cursor}', '$cursor$', '')
+  let expand = substitute(expand, '\${cursor}', '', 'g')
+  let expand = substitute(expand, '\${cursor}', '', 'g')
+  return expand
+endfunction
+
+function! emmet#unescapeDollarExpr(expand) abort
+  return substitute(a:expand, '\\\$', '$', 'g')
+endfunction
+
+function! emmet#expandAbbr(mode, abbr) range abort
+  let type = emmet#getFileType(1)
+  let indent = emmet#getIndentation(type)
+  let expand = ''
+  let line = ''
+  let part = ''
+  let rest = ''
+
+  let filters = emmet#getFilters(type)
+  if len(filters) ==# 0
+    let filters = ['html']
+  endif
+
+  if a:mode ==# 2
+    let leader = substitute(input('Tag: ', ''), '^\s*\(.*\)\s*$', '\1', 'g')
+    if len(leader) ==# 0
+      return ''
+    endif
+    if leader =~# s:filtermx
+      let filters = map(split(matchstr(leader, s:filtermx)[1:], '\s*[^\\]\zs,\s*'), 'substitute(v:val, "\\\\\\\\zs.\\\\ze", "&", "g")')
+      let leader = substitute(leader, s:filtermx, '', '')
+    endif
+    if leader =~# '\*'
+      let query = substitute(leader, '*', '*' . (a:lastline - a:firstline + 1), '')
+      if query !~# '}\s*$' && query !~# '\$#'
+        let query .= '>{$#}'
+      endif
+      if emmet#useFilter(filters, '/')
+        let spl = emmet#splitFilterArg(filters)
+        let fline = getline(a:firstline)
+        let query = substitute(query, '>\{0,1}{\$#}\s*$', '{\\$column\\$}*' . len(split(fline, spl)), '')
+      else
+        let spl = ''
+      endif
+      let items = emmet#parseIntoTree(query, type).child
+      let itemno = 0
+      for item in items
+        let inner = emmet#toString(item, type, 0, filters, 0, indent)
+        let inner = substitute(inner, '\$#', '$line'.(itemno*(a:lastline - a:firstline + 1)/len(items)+1).'$', 'g')
+        let expand .= inner
+        let itemno = itemno + 1
+      endfor
+      if emmet#useFilter(filters, 'e')
+        let expand = substitute(expand, '&', '\&amp;', 'g')
+        let expand = substitute(expand, '<', '\&lt;', 'g')
+        let expand = substitute(expand, '>', '\&gt;', 'g')
+      endif
+      let line = getline(a:firstline)
+      let part = substitute(line, '^\s*', '', '')
+      for n in range(a:firstline, a:lastline)
+        let lline = getline(n)
+        let lpart = substitute(lline, '^\s\+', '', '')
+        if emmet#useFilter(filters, 't')
+          let lpart = substitute(lpart, '^[0-9.-]\+\s\+', '', '')
+          let lpart = substitute(lpart, '\s\+$', '', '')
+        endif
+        if emmet#useFilter(filters, '/')
+          for column in split(lpart, spl)
+            let expand = substitute(expand, '\$column\$', '\=column', '')
+          endfor
+        else
+          let expand = substitute(expand, '\$line'.(n-a:firstline+1).'\$', '\=lpart', 'g')
+        endif
+      endfor
+      let expand = substitute(expand, '\$line\d*\$', '', 'g')
+      let expand = substitute(expand, '\$column\$', '', 'g')
+      let content = join(getline(a:firstline, a:lastline), "\n")
+      if stridx(expand, '$#') < len(expand)-2
+        let expand = substitute(expand, '^\(.*\)\$#\s*$', '\1', '')
+      endif
+      let expand = substitute(expand, '\$#', '\=content', 'g')
+    else
+      let str = ''
+      if visualmode() ==# 'V'
+        let line = getline(a:firstline)
+        let lspaces = matchstr(line, '^\s*', '', '')
+        let part = substitute(line, '^\s*', '', '')
+        for n in range(a:firstline, a:lastline)
+          if len(leader) > 0
+            let line = getline(a:firstline)
+            let spaces = matchstr(line, '^\s*', '', '')
+            if len(spaces) >= len(lspaces)
+              let str .= indent . getline(n)[len(lspaces):] . "\n"
+            else
+              let str .= getline(n) . "\n"
+            endif
+          else
+            let lpart = substitute(getline(n), '^\s*', '', '')
+            let str .= lpart . "\n"
+          endif
+        endfor
+        if stridx(leader, '{$#}') ==# -1
+          let leader .= '{$#}'
+        endif
+        let items = emmet#parseIntoTree(leader, type).child
+      else
+        let save_regcont = @"
+        let save_regtype = getregtype('"')
+        silent! normal! gvygv
+        let str = @"
+        call setreg('"', save_regcont, save_regtype)
+        if stridx(leader, '{$#}') ==# -1
+          let leader .= '{$#}'
+        endif
+        let items = emmet#parseIntoTree(leader, type).child
+      endif
+      for item in items
+        let expand .= emmet#toString(item, type, 0, filters, 0, '')
+      endfor
+      if emmet#useFilter(filters, 'e')
+        let expand = substitute(expand, '&', '\&amp;', 'g')
+        let expand = substitute(expand, '<', '\&lt;', 'g')
+        let expand = substitute(expand, '>', '\&gt;', 'g')
+      endif
+      if stridx(leader, '{$#}') !=# -1
+        let expand = substitute(expand, '\$#', '\="\n" . str', 'g')
+      endif
+    endif
+  elseif a:mode ==# 4
+    let line = getline('.')
+    let spaces = matchstr(line, '^\s*')
+    if line !~# '^\s*$'
+      put =spaces.a:abbr
+    else
+      call setline('.', spaces.a:abbr)
+    endif
+    normal! $
+    call emmet#expandAbbr(0, '')
+    return ''
+  else
+    let line = getline('.')
+    if col('.') < len(line)
+      let line = matchstr(line, '^\(.*\%'.col('.').'c\)')
+    endif
+    if a:mode ==# 1
+      let part = matchstr(line, '\([a-zA-Z0-9:_\-\@|]\+\)$')
+    else
+      let part = matchstr(line, '\(\S.*\)$')
+      let rtype = emmet#lang#type(type)
+      let part = emmet#lang#{rtype}#findTokens(part)
+      let line = line[0: strridx(line, part) + len(part) - 1]
+    endif
+    if col('.') ==# col('$')
+      let rest = ''
+    else
+      let rest = getline('.')[len(line):]
+    endif
+    let str = part
+    if str =~# s:filtermx
+      let filters = split(matchstr(str, s:filtermx)[1:], '\s*,\s*')
+      let str = substitute(str, s:filtermx, '', '')
+    endif
+    let items = emmet#parseIntoTree(str, type).child
+    for item in items
+      let expand .= emmet#toString(item, type, 0, filters, 0, indent)
+    endfor
+    if emmet#useFilter(filters, 'e')
+      let expand = substitute(expand, '&', '\&amp;', 'g')
+      let expand = substitute(expand, '<', '\&lt;', 'g')
+      let expand = substitute(expand, '>', '\&gt;', 'g')
+    endif
+    let expand = substitute(expand, '\$line\([0-9]\+\)\$', '\=submatch(1)', 'g')
+  endif
+  let expand = emmet#expandDollarExpr(expand)
+  let expand = emmet#expandCursorExpr(expand, a:mode)
+  if len(expand)
+    if has_key(s:emmet_settings, 'timezone') && len(s:emmet_settings.timezone)
+      let expand = substitute(expand, '${datetime}', strftime('%Y-%m-%dT%H:%M:%S') . s:emmet_settings.timezone, 'g')
+    else
+      " TODO: on windows, %z/%Z is 'Tokyo(Standard)'
+      let expand = substitute(expand, '${datetime}', strftime('%Y-%m-%dT%H:%M:%S %z'), 'g')
+    endif
+    let expand = emmet#unescapeDollarExpr(expand)
+    if a:mode ==# 2 && visualmode() ==# 'v'
+      if a:firstline ==# a:lastline
+        let expand = substitute(expand, '[\r\n]\s*', '', 'g')
+      else
+        let expand = substitute(expand, '[\n]$', '', 'g')
+      endif
+      silent! normal! gv
+      let col = col('''<')
+      silent! normal! c
+      let line = getline('.')
+      let lhs = matchstr(line, '.*\%<'.col.'c.')
+      let rhs = matchstr(line, '\%>'.(col-1).'c.*')
+      let expand = lhs.expand.rhs
+      let lines = split(expand, '\n')
+      call setline(line('.'), lines[0])
+      if len(lines) > 1
+        call append(line('.'), lines[1:])
+      endif
+    else
+      if line[:-len(part)-1] =~# '^\s\+$'
+        let indent = line[:-len(part)-1]
+      else
+        let indent = ''
+      endif
+      let expand = substitute(expand, '[\r\n]\s*$', '', 'g')
+      if emmet#useFilter(filters, 's')
+        let epart = substitute(expand, '[\r\n]\s*', '', 'g')
+      else
+        let epart = substitute(expand, '[\r\n]', "\n" . indent, 'g')
+      endif
+      let expand = line[:-len(part)-1] . epart . rest
+      let lines = split(expand, '[\r\n]', 1)
+      if a:mode ==# 2
+        silent! exe 'normal! gvc'
+      endif
+      call setline('.', lines[0])
+      if len(lines) > 1
+        call append('.', lines[1:])
+      endif
+    endif
+  endif
+  if g:emmet_debug > 1
+    call getchar()
+  endif
+  if search('\ze\$\(cursor\|select\)\$', 'c')
+    let oldselection = &selection
+    let &selection = 'inclusive'
+    if foldclosed(line('.')) !=# -1
+      silent! foldopen
+    endif
+    let pos = emmet#util#getcurpos()
+    let use_selection = emmet#getResource(type, 'use_selection', 0)
+    try
+      let l:gdefault = &gdefault
+      let &gdefault = 0
+      if use_selection && getline('.')[col('.')-1:] =~# '^\$select'
+        let pos[2] += 1
+        silent! s/\$select\$//
+        let next = searchpos('.\ze\$select\$', 'nW')
+        silent! %s/\$\(cursor\|select\)\$//g
+        call emmet#util#selectRegion([pos[1:2], next])
+        return "\<esc>gv"
+      else
+        silent! %s/\$\(cursor\|select\)\$//g
+        silent! call setpos('.', pos)
+        if col('.') < col('$')
+          return "\<right>"
+        endif
+      endif
+    finally
+      let &gdefault = l:gdefault
+    endtry
+    let &selection = oldselection
+  endif
+  return ''
+endfunction
+
+function! emmet#updateTag() abort
+  let type = emmet#getFileType()
+  let region = emmet#util#searchRegion('<\S', '>')
+  if !emmet#util#regionIsValid(region) || !emmet#util#cursorInRegion(region)
+    return ''
+  endif
+  let content = emmet#util#getContent(region)
+  let content = matchstr(content,  '^<[^><]\+>')
+  if content !~# '^<[^><]\+>$'
+    return ''
+  endif
+  let current = emmet#lang#html#parseTag(content)
+  if empty(current)
+    return ''
+  endif
+
+  let str = substitute(input('Enter Abbreviation: ', ''), '^\s*\(.*\)\s*$', '\1', 'g')
+  let item = emmet#parseIntoTree(str, type).child[0]
+  for k in keys(item.attr)
+    let current.attr[k] = item.attr[k]
+  endfor
+  let html = substitute(emmet#toString(current, 'html', 1), '\n', '', '')
+  let html = substitute(html, '\${cursor}', '', '')
+  let html = matchstr(html,  '^<[^><]\+>')
+  call emmet#util#setContent(region, html)
+  return ''
+endfunction
+
+function! emmet#moveNextPrevItem(flag) abort
+  let type = emmet#getFileType()
+  return emmet#lang#{emmet#lang#type(type)}#moveNextPrevItem(a:flag)
+endfunction
+
+function! emmet#moveNextPrev(flag) abort
+  let type = emmet#getFileType()
+  return emmet#lang#{emmet#lang#type(type)}#moveNextPrev(a:flag)
+endfunction
+
+function! emmet#imageSize() abort
+  let orgpos = emmet#util#getcurpos()
+  let type = emmet#getFileType()
+  call emmet#lang#{emmet#lang#type(type)}#imageSize()
+  silent! call setpos('.', orgpos)
+  return ''
+endfunction
+
+function! emmet#imageEncode() abort
+  let type = emmet#getFileType()
+  return emmet#lang#{emmet#lang#type(type)}#imageEncode()
+endfunction
+
+function! emmet#toggleComment() abort
+  let type = emmet#getFileType()
+  call emmet#lang#{emmet#lang#type(type)}#toggleComment()
+  return ''
+endfunction
+
+function! emmet#balanceTag(flag) range abort
+  let type = emmet#getFileType()
+  return emmet#lang#{emmet#lang#type(type)}#balanceTag(a:flag)
+endfunction
+
+function! emmet#splitJoinTag() abort
+  let type = emmet#getFileType()
+  return emmet#lang#{emmet#lang#type(type)}#splitJoinTag()
+endfunction
+
+function! emmet#mergeLines() range abort
+  let lines = join(map(getline(a:firstline, a:lastline), 'matchstr(v:val, "^\\s*\\zs.*\\ze\\s*$")'), '')
+  let indent = substitute(getline('.'), '^\(\s*\).*', '\1', '')
+  silent! exe 'normal! gvc'
+  call setline('.', indent . lines)
+endfunction
+
+function! emmet#removeTag() abort
+  let type = emmet#getFileType()
+  call emmet#lang#{emmet#lang#type(type)}#removeTag()
+  return ''
+endfunction
+
+function! emmet#mergeLines() abort
+  let type = emmet#getFileType()
+  call emmet#lang#{emmet#lang#type(type)}#mergeLines()
+  return ''
+endfunction
+
+function! emmet#anchorizeURL(flag) abort
+  let mx = 'https\=:\/\/[-!#$%&*+,./:;=?@0-9a-zA-Z_~]\+'
+  let pos1 = searchpos(mx, 'bcnW')
+  let url = matchstr(getline(pos1[0])[pos1[1]-1:], mx)
+  let block = [pos1, [pos1[0], pos1[1] + len(url) - 1]]
+  if !emmet#util#cursorInRegion(block)
+    return ''
+  endif
+
+  let mx = '.*<title[^>]*>\s*\zs\([^<]\+\)\ze\s*<\/title[^>]*>.*'
+  let content = emmet#util#getContentFromURL(url)
+  let content = substitute(content, '\r', '', 'g')
+  let content = substitute(content, '[ \n]\+', ' ', 'g')
+  let content = substitute(content, '<!--.\{-}-->', '', 'g')
+  let title = matchstr(content, mx)
+
+  let type = emmet#getFileType()
+  let rtype = emmet#lang#type(type)
+  if &filetype ==# 'markdown'
+    let expand = printf('[%s](%s)', substitute(title, '[\[\]]', '\\&', 'g'), url)
+  elseif &filetype ==# 'rst'
+    let expand = printf('`%s <%s>`_', substitute(title, '[\[\]]', '\\&', 'g'), url)
+  elseif a:flag ==# 0
+    let a = emmet#lang#html#parseTag('<a>')
+    let a.attr.href = url
+    let a.value = '{' . title . '}'
+    let expand = emmet#toString(a, rtype, 0, [])
+    let expand = substitute(expand, '\${cursor}', '', 'g')
+  else
+    let body = emmet#util#getTextFromHTML(content)
+    let body = '{' . substitute(body, '^\(.\{0,100}\).*', '\1', '') . '...}'
+
+    let blockquote = emmet#lang#html#parseTag('<blockquote class="quote">')
+    let a = emmet#lang#html#parseTag('<a>')
+    let a.attr.href = url
+    let a.value = '{' . title . '}'
+    call add(blockquote.child, a)
+    call add(blockquote.child, emmet#lang#html#parseTag('<br/>'))
+    let p = emmet#lang#html#parseTag('<p>')
+    let p.value = body
+    call add(blockquote.child, p)
+    let cite = emmet#lang#html#parseTag('<cite>')
+    let cite.value = '{' . url . '}'
+    call add(blockquote.child, cite)
+    let expand = emmet#toString(blockquote, rtype, 0, [])
+    let expand = substitute(expand, '\${cursor}', '', 'g')
+  endif
+  let indent = substitute(getline('.'), '^\(\s*\).*', '\1', '')
+  let expand = substitute(expand, "\n", "\n" . indent, 'g')
+  call emmet#util#setContent(block, expand)
+  return ''
+endfunction
+
+function! emmet#codePretty() range abort
+  let type = input('FileType: ', &filetype, 'filetype')
+  if len(type) ==# 0
+    return
+  endif
+  let block = emmet#util#getVisualBlock()
+  let content = emmet#util#getContent(block)
+  silent! 1new
+  let &l:filetype = type
+  call setline(1, split(content, "\n"))
+  let old_lazyredraw = &lazyredraw
+  set lazyredraw
+  silent! TOhtml
+  let &lazyredraw = old_lazyredraw
+  let content = join(getline(1, '$'), "\n")
+  silent! bw!
+  silent! bw!
+  let content = matchstr(content, '<body[^>]*>[\s\n]*\zs.*\ze</body>')
+  call emmet#util#setContent(block, content)
+endfunction
+
+function! emmet#expandWord(abbr, type, orig) abort
+  let str = a:abbr
+  let type = a:type
+  let indent = emmet#getIndentation(type)
+
+  if len(type) ==# 0 | let type = 'html' | endif
+  if str =~# s:filtermx
+    let filters = split(matchstr(str, s:filtermx)[1:], '\s*,\s*')
+    let str = substitute(str, s:filtermx, '', '')
+  else
+    let filters = emmet#getFilters(a:type)
+    if len(filters) ==# 0
+      let filters = ['html']
+    endif
+  endif
+  let str = substitute(str, '|', '${cursor}', 'g')
+  let items = emmet#parseIntoTree(str, a:type).child
+  let expand = ''
+  for item in items
+    let expand .= emmet#toString(item, a:type, 0, filters, 0, indent)
+  endfor
+  if emmet#useFilter(filters, 'e')
+    let expand = substitute(expand, '&', '\&amp;', 'g')
+    let expand = substitute(expand, '<', '\&lt;', 'g')
+    let expand = substitute(expand, '>', '\&gt;', 'g')
+  endif
+  if emmet#useFilter(filters, 's')
+    let expand = substitute(expand, "\n\s\*", '', 'g')
+  endif
+  if a:orig ==# 0
+    let expand = emmet#expandDollarExpr(expand)
+    let expand = substitute(expand, '\${cursor}', '', 'g')
+  endif
+  return expand
+endfunction
+
+function! emmet#getSnippets(type) abort
+  let type = a:type
+  if len(type) ==# 0 || !has_key(s:emmet_settings, type)
+    let type = 'html'
+  endif
+  return emmet#getResource(type, 'snippets', {})
+endfunction
+
+function! emmet#completeTag(findstart, base) abort
+  if a:findstart
+    let line = getline('.')
+    let start = col('.') - 1
+    while start > 0 && line[start - 1] =~# '[a-zA-Z0-9:_\@\-]'
+      let start -= 1
+    endwhile
+    return start
+  else
+    let type = emmet#getFileType()
+    let res = []
+
+    let snippets = emmet#getResource(type, 'snippets', {})
+    for item in keys(snippets)
+      if stridx(item, a:base) !=# -1
+        call add(res, substitute(item, '\${cursor}\||', '', 'g'))
+      endif
+    endfor
+    let aliases = emmet#getResource(type, 'aliases', {})
+    for item in values(aliases)
+      if stridx(item, a:base) !=# -1
+        call add(res, substitute(item, '\${cursor}\||', '', 'g'))
+      endif
+    endfor
+    return res
+  endif
+endfunction
+
+unlet! s:emmet_settings
+let s:emmet_settings = {
+\    'variables': {
+\      'lang': "en",
+\      'locale': "en-US",
+\      'charset': "UTF-8",
+\      'newline': "\n",
+\      'use_selection': 0,
+\    },
+\    'custom_expands' : {
+\      '^\%(lorem\|lipsum\)\(\d*\)$' : function('emmet#lorem#en#expand'),
+\    },
+\    'css': {
+\        'snippets': {
+\           "@i": "@import url(|);",
+\           "@import": "@import url(|);",
+\           "@m": "@media ${1:screen} {\n\t|\n}",
+\           "@media": "@media ${1:screen} {\n\t|\n}",
+\           "@f": "@font-face {\n\tfont-family:|;\n\tsrc:url(|);\n}",
+\           "@f+": "@font-face {\n\tfont-family: '${1:FontName}';\n\tsrc: url('${2:FileName}.eot');\n\tsrc: url('${2:FileName}.eot?#iefix') format('embedded-opentype'),\n\t\t url('${2:FileName}.woff') format('woff'),\n\t\t url('${2:FileName}.ttf') format('truetype'),\n\t\t url('${2:FileName}.svg#${1:FontName}') format('svg');\n\tfont-style: ${3:normal};\n\tfont-weight: ${4:normal};\n}",
+\           "@kf": "@-webkit-keyframes ${1:identifier} {\n\t${2:from} { ${3} }${6}\n\t${4:to} { ${5} }\n}\n@-o-keyframes ${1:identifier} {\n\t${2:from} { ${3} }${6}\n\t${4:to} { ${5} }\n}\n@-moz-keyframes ${1:identifier} {\n\t${2:from} { ${3} }${6}\n\t${4:to} { ${5} }\n}\n@keyframes ${1:identifier} {\n\t${2:from} { ${3} }${6}\n\t${4:to} { ${5} }\n}",
+\           "anim": "animation:|;",
+\           "anim-": "animation:${1:name} ${2:duration} ${3:timing-function} ${4:delay} ${5:iteration-count} ${6:direction} ${7:fill-mode};",
+\           "animdel": "animation-delay:${1:time};",
+\           "animdir": "animation-direction:${1:normal};",
+\           "animdir:n": "animation-direction:normal;",
+\           "animdir:r": "animation-direction:reverse;",
+\           "animdir:a": "animation-direction:alternate;",
+\           "animdir:ar": "animation-direction:alternate-reverse;",
+\           "animdur": "animation-duration:${1:0}s;",
+\           "animfm": "animation-fill-mode:${1:both};",
+\           "animfm:f": "animation-fill-mode:forwards;",
+\           "animfm:b": "animation-fill-mode:backwards;",
+\           "animfm:bt": "animation-fill-mode:both;",
+\           "animfm:bh": "animation-fill-mode:both;",
+\           "animic": "animation-iteration-count:${1:1};",
+\           "animic:i": "animation-iteration-count:infinite;",
+\           "animn": "animation-name:${1:none};",
+\           "animps": "animation-play-state:${1:running};",
+\           "animps:p": "animation-play-state:paused;",
+\           "animps:r": "animation-play-state:running;",
+\           "animtf": "animation-timing-function:${1:linear};",
+\           "animtf:e": "animation-timing-function:ease;",
+\           "animtf:ei": "animation-timing-function:ease-in;",
+\           "animtf:eo": "animation-timing-function:ease-out;",
+\           "animtf:eio": "animation-timing-function:ease-in-out;",
+\           "animtf:l": "animation-timing-function:linear;",
+\           "animtf:cb": "animation-timing-function:cubic-bezier(${1:0.1}, ${2:0.7}, ${3:1.0}, ${3:0.1});",
+\           "ap": "appearance:${none};",
+\           "!": "!important",
+\           "pos": "position:${1:relative};",
+\           "pos:s": "position:static;",
+\           "pos:a": "position:absolute;",
+\           "pos:r": "position:relative;",
+\           "pos:f": "position:fixed;",
+\           "t": "top:|;",
+\           "t:a": "top:auto;",
+\           "r": "right:|;",
+\           "r:a": "right:auto;",
+\           "b": "bottom:|;",
+\           "b:a": "bottom:auto;",
+\           "l": "left:|;",
+\           "l:a": "left:auto;",
+\           "z": "z-index:|;",
+\           "z:a": "z-index:auto;",
+\           "fl": "float:${1:left};",
+\           "fl:n": "float:none;",
+\           "fl:l": "float:left;",
+\           "fl:r": "float:right;",
+\           "cl": "clear:${1:both};",
+\           "cl:n": "clear:none;",
+\           "cl:l": "clear:left;",
+\           "cl:r": "clear:right;",
+\           "cl:b": "clear:both;",
+\           "colm": "columns:|;",
+\           "colmc": "column-count:|;",
+\           "colmf": "column-fill:|;",
+\           "colmg": "column-gap:|;",
+\           "colmr": "column-rule:|;",
+\           "colmrc": "column-rule-color:|;",
+\           "colmrs": "column-rule-style:|;",
+\           "colmrw": "column-rule-width:|;",
+\           "colms": "column-span:|;",
+\           "colmw": "column-width:|;",
+\           "d": "display:${1:block};",
+\           "d:n": "display:none;",
+\           "d:b": "display:block;",
+\           "d:f": "display:flex;",
+\           "d:if": "display:inline-flex;",
+\           "d:i": "display:inline;",
+\           "d:ib": "display:inline-block;",
+\           "d:ib+": "display: inline-block;\n*display: inline;\n*zoom: 1;",
+\           "d:li": "display:list-item;",
+\           "d:ri": "display:run-in;",
+\           "d:cp": "display:compact;",
+\           "d:tb": "display:table;",
+\           "d:itb": "display:inline-table;",
+\           "d:tbcp": "display:table-caption;",
+\           "d:tbcl": "display:table-column;",
+\           "d:tbclg": "display:table-column-group;",
+\           "d:tbhg": "display:table-header-group;",
+\           "d:tbfg": "display:table-footer-group;",
+\           "d:tbr": "display:table-row;",
+\           "d:tbrg": "display:table-row-group;",
+\           "d:tbc": "display:table-cell;",
+\           "d:rb": "display:ruby;",
+\           "d:rbb": "display:ruby-base;",
+\           "d:rbbg": "display:ruby-base-group;",
+\           "d:rbt": "display:ruby-text;",
+\           "d:rbtg": "display:ruby-text-group;",
+\           "v": "visibility:${1:hidden};",
+\           "v:v": "visibility:visible;",
+\           "v:h": "visibility:hidden;",
+\           "v:c": "visibility:collapse;",
+\           "ov": "overflow:${1:hidden};",
+\           "ov:v": "overflow:visible;",
+\           "ov:h": "overflow:hidden;",
+\           "ov:s": "overflow:scroll;",
+\           "ov:a": "overflow:auto;",
+\           "ovx": "overflow-x:${1:hidden};",
+\           "ovx:v": "overflow-x:visible;",
+\           "ovx:h": "overflow-x:hidden;",
+\           "ovx:s": "overflow-x:scroll;",
+\           "ovx:a": "overflow-x:auto;",
+\           "ovy": "overflow-y:${1:hidden};",
+\           "ovy:v": "overflow-y:visible;",
+\           "ovy:h": "overflow-y:hidden;",
+\           "ovy:s": "overflow-y:scroll;",
+\           "ovy:a": "overflow-y:auto;",
+\           "ovs": "overflow-style:${1:scrollbar};",
+\           "ovs:a": "overflow-style:auto;",
+\           "ovs:s": "overflow-style:scrollbar;",
+\           "ovs:p": "overflow-style:panner;",
+\           "ovs:m": "overflow-style:move;",
+\           "ovs:mq": "overflow-style:marquee;",
+\           "zoo": "zoom:1;",
+\           "zm": "zoom:1;",
+\           "cp": "clip:|;",
+\           "cp:a": "clip:auto;",
+\           "cp:r": "clip:rect(${1:top} ${2:right} ${3:bottom} ${4:left});",
+\           "bxz": "box-sizing:${1:border-box};",
+\           "bxz:cb": "box-sizing:content-box;",
+\           "bxz:bb": "box-sizing:border-box;",
+\           "bxsh": "box-shadow:${1:inset }${2:hoff} ${3:voff} ${4:blur} ${5:color};",
+\           "bxsh:r": "box-shadow:${1:inset }${2:hoff} ${3:voff} ${4:blur} ${5:spread }rgb(${6:0}, ${7:0}, ${8:0});",
+\           "bxsh:ra": "box-shadow:${1:inset }${2:h} ${3:v} ${4:blur} ${5:spread }rgba(${6:0}, ${7:0}, ${8:0}, .${9:5});",
+\           "bxsh:n": "box-shadow:none;",
+\           "m": "margin:|;",
+\           "m:a": "margin:auto;",
+\           "mt": "margin-top:|;",
+\           "mt:a": "margin-top:auto;",
+\           "mr": "margin-right:|;",
+\           "mr:a": "margin-right:auto;",
+\           "mb": "margin-bottom:|;",
+\           "mb:a": "margin-bottom:auto;",
+\           "ml": "margin-left:|;",
+\           "ml:a": "margin-left:auto;",
+\           "p": "padding:|;",
+\           "pt": "padding-top:|;",
+\           "pr": "padding-right:|;",
+\           "pb": "padding-bottom:|;",
+\           "pl": "padding-left:|;",
+\           "w": "width:|;",
+\           "w:a": "width:auto;",
+\           "h": "height:|;",
+\           "h:a": "height:auto;",
+\           "maw": "max-width:|;",
+\           "maw:n": "max-width:none;",
+\           "mah": "max-height:|;",
+\           "mah:n": "max-height:none;",
+\           "miw": "min-width:|;",
+\           "mih": "min-height:|;",
+\           "mar": "max-resolution:${1:res};",
+\           "mir": "min-resolution:${1:res};",
+\           "ori": "orientation:|;",
+\           "ori:l": "orientation:landscape;",
+\           "ori:p": "orientation:portrait;",
+\           "ol": "outline:|;",
+\           "ol:n": "outline:none;",
+\           "olo": "outline-offset:|;",
+\           "olw": "outline-width:|;",
+\           "olw:tn": "outline-width:thin;",
+\           "olw:m": "outline-width:medium;",
+\           "olw:tc": "outline-width:thick;",
+\           "ols": "outline-style:|;",
+\           "ols:n": "outline-style:none;",
+\           "ols:dt": "outline-style:dotted;",
+\           "ols:ds": "outline-style:dashed;",
+\           "ols:s": "outline-style:solid;",
+\           "ols:db": "outline-style:double;",
+\           "ols:g": "outline-style:groove;",
+\           "ols:r": "outline-style:ridge;",
+\           "ols:i": "outline-style:inset;",
+\           "ols:o": "outline-style:outset;",
+\           "olc": "outline-color:#${1:000};",
+\           "olc:i": "outline-color:invert;",
+\           "bfv": "backface-visibility:|;",
+\           "bfv:h": "backface-visibility:hidden;",
+\           "bfv:v": "backface-visibility:visible;",
+\           "bd": "border:|;",
+\           "bd+": "border:${1:1px} ${2:solid} ${3:#000};",
+\           "bd:n": "border:none;",
+\           "bdbk": "border-break:${1:close};",
+\           "bdbk:c": "border-break:close;",
+\           "bdcl": "border-collapse:|;",
+\           "bdcl:c": "border-collapse:collapse;",
+\           "bdcl:s": "border-collapse:separate;",
+\           "bdc": "border-color:#${1:000};",
+\           "bdc:t": "border-color:transparent;",
+\           "bdi": "border-image:url(|);",
+\           "bdi:n": "border-image:none;",
+\           "bdti": "border-top-image:url(|);",
+\           "bdti:n": "border-top-image:none;",
+\           "bdri": "border-right-image:url(|);",
+\           "bdri:n": "border-right-image:none;",
+\           "bdbi": "border-bottom-image:url(|);",
+\           "bdbi:n": "border-bottom-image:none;",
+\           "bdli": "border-left-image:url(|);",
+\           "bdli:n": "border-left-image:none;",
+\           "bdci": "border-corner-image:url(|);",
+\           "bdci:n": "border-corner-image:none;",
+\           "bdci:c": "border-corner-image:continue;",
+\           "bdtli": "border-top-left-image:url(|);",
+\           "bdtli:n": "border-top-left-image:none;",
+\           "bdtli:c": "border-top-left-image:continue;",
+\           "bdtri": "border-top-right-image:url(|);",
+\           "bdtri:n": "border-top-right-image:none;",
+\           "bdtri:c": "border-top-right-image:continue;",
+\           "bdbri": "border-bottom-right-image:url(|);",
+\           "bdbri:n": "border-bottom-right-image:none;",
+\           "bdbri:c": "border-bottom-right-image:continue;",
+\           "bdbli": "border-bottom-left-image:url(|);",
+\           "bdbli:n": "border-bottom-left-image:none;",
+\           "bdbli:c": "border-bottom-left-image:continue;",
+\           "bdf": "border-fit:${1:repeat};",
+\           "bdf:c": "border-fit:clip;",
+\           "bdf:r": "border-fit:repeat;",
+\           "bdf:sc": "border-fit:scale;",
+\           "bdf:st": "border-fit:stretch;",
+\           "bdf:ow": "border-fit:overwrite;",
+\           "bdf:of": "border-fit:overflow;",
+\           "bdf:sp": "border-fit:space;",
+\           "bdlen": "border-length:|;",
+\           "bdlen:a": "border-length:auto;",
+\           "bdsp": "border-spacing:|;",
+\           "bds": "border-style:|;",
+\           "bds:n": "border-style:none;",
+\           "bds:h": "border-style:hidden;",
+\           "bds:dt": "border-style:dotted;",
+\           "bds:ds": "border-style:dashed;",
+\           "bds:s": "border-style:solid;",
+\           "bds:db": "border-style:double;",
+\           "bds:dtds": "border-style:dot-dash;",
+\           "bds:dtdtds": "border-style:dot-dot-dash;",
+\           "bds:w": "border-style:wave;",
+\           "bds:g": "border-style:groove;",
+\           "bds:r": "border-style:ridge;",
+\           "bds:i": "border-style:inset;",
+\           "bds:o": "border-style:outset;",
+\           "bdw": "border-width:|;",
+\           "bdtw": "border-top-width:|;",
+\           "bdrw": "border-right-width:|;",
+\           "bdbw": "border-bottom-width:|;",
+\           "bdlw": "border-left-width:|;",
+\           "bdt": "border-top:|;",
+\           "bt": "border-top:|;",
+\           "bdt+": "border-top:${1:1px} ${2:solid} ${3:#000};",
+\           "bdt:n": "border-top:none;",
+\           "bdts": "border-top-style:|;",
+\           "bdts:n": "border-top-style:none;",
+\           "bdtc": "border-top-color:#${1:000};",
+\           "bdtc:t": "border-top-color:transparent;",
+\           "bdr": "border-right:|;",
+\           "br": "border-right:|;",
+\           "bdr+": "border-right:${1:1px} ${2:solid} ${3:#000};",
+\           "bdr:n": "border-right:none;",
+\           "bdrst": "border-right-style:|;",
+\           "bdrst:n": "border-right-style:none;",
+\           "bdrc": "border-right-color:#${1:000};",
+\           "bdrc:t": "border-right-color:transparent;",
+\           "bdb": "border-bottom:|;",
+\           "bb": "border-bottom:|;",
+\           "bdb+": "border-bottom:${1:1px} ${2:solid} ${3:#000};",
+\           "bdb:n": "border-bottom:none;",
+\           "bdbs": "border-bottom-style:|;",
+\           "bdbs:n": "border-bottom-style:none;",
+\           "bdbc": "border-bottom-color:#${1:000};",
+\           "bdbc:t": "border-bottom-color:transparent;",
+\           "bdl": "border-left:|;",
+\           "bl": "border-left:|;",
+\           "bdl+": "border-left:${1:1px} ${2:solid} ${3:#000};",
+\           "bdl:n": "border-left:none;",
+\           "bdls": "border-left-style:|;",
+\           "bdls:n": "border-left-style:none;",
+\           "bdlc": "border-left-color:#${1:000};",
+\           "bdlc:t": "border-left-color:transparent;",
+\           "bdrs": "border-radius:|;",
+\           "bdtrrs": "border-top-right-radius:|;",
+\           "bdtlrs": "border-top-left-radius:|;",
+\           "bdbrrs": "border-bottom-right-radius:|;",
+\           "bdblrs": "border-bottom-left-radius:|;",
+\           "bg": "background:#${1:000};",
+\           "bg+": "background:${1:#fff} url(${2}) ${3:0} ${4:0} ${5:no-repeat};",
+\           "bg:n": "background:none;",
+\           "bg:ie": "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${1:x}.png',sizingMethod='${2:crop}');",
+\           "bgc": "background-color:#${1:fff};",
+\           "bgc:t": "background-color:transparent;",
+\           "bgi": "background-image:url(|);",
+\           "bgi:n": "background-image:none;",
+\           "bgr": "background-repeat:|;",
+\           "bgr:n": "background-repeat:no-repeat;",
+\           "bgr:x": "background-repeat:repeat-x;",
+\           "bgr:y": "background-repeat:repeat-y;",
+\           "bgr:sp": "background-repeat:space;",
+\           "bgr:rd": "background-repeat:round;",
+\           "bga": "background-attachment:|;",
+\           "bga:f": "background-attachment:fixed;",
+\           "bga:s": "background-attachment:scroll;",
+\           "bgp": "background-position:${1:0} ${2:0};",
+\           "bgpx": "background-position-x:|;",
+\           "bgpy": "background-position-y:|;",
+\           "bgbk": "background-break:|;",
+\           "bgbk:bb": "background-break:bounding-box;",
+\           "bgbk:eb": "background-break:each-box;",
+\           "bgbk:c": "background-break:continuous;",
+\           "bgcp": "background-clip:${1:padding-box};",
+\           "bgcp:bb": "background-clip:border-box;",
+\           "bgcp:pb": "background-clip:padding-box;",
+\           "bgcp:cb": "background-clip:content-box;",
+\           "bgcp:nc": "background-clip:no-clip;",
+\           "bgo": "background-origin:|;",
+\           "bgo:pb": "background-origin:padding-box;",
+\           "bgo:bb": "background-origin:border-box;",
+\           "bgo:cb": "background-origin:content-box;",
+\           "bgsz": "background-size:|;",
+\           "bgsz:a": "background-size:auto;",
+\           "bgsz:ct": "background-size:contain;",
+\           "bgsz:cv": "background-size:cover;",
+\           "c": "color:#${1:000};",
+\           "c:r": "color:rgb(${1:0}, ${2:0}, ${3:0});",
+\           "c:ra": "color:rgba(${1:0}, ${2:0}, ${3:0}, .${4:5});",
+\           "cm": "/* |${child} */",
+\           "cnt": "content:'|';",
+\           "cnt:n": "content:normal;",
+\           "cnt:oq": "content:open-quote;",
+\           "cnt:noq": "content:no-open-quote;",
+\           "cnt:cq": "content:close-quote;",
+\           "cnt:ncq": "content:no-close-quote;",
+\           "cnt:a": "content:attr(|);",
+\           "cnt:c": "content:counter(|);",
+\           "cnt:cs": "content:counters(|);",
+\           "tbl": "table-layout:|;",
+\           "tbl:a": "table-layout:auto;",
+\           "tbl:f": "table-layout:fixed;",
+\           "cps": "caption-side:|;",
+\           "cps:t": "caption-side:top;",
+\           "cps:b": "caption-side:bottom;",
+\           "ec": "empty-cells:|;",
+\           "ec:s": "empty-cells:show;",
+\           "ec:h": "empty-cells:hide;",
+\           "lis": "list-style:|;",
+\           "lis:n": "list-style:none;",
+\           "lisp": "list-style-position:|;",
+\           "lisp:i": "list-style-position:inside;",
+\           "lisp:o": "list-style-position:outside;",
+\           "list": "list-style-type:|;",
+\           "list:n": "list-style-type:none;",
+\           "list:d": "list-style-type:disc;",
+\           "list:c": "list-style-type:circle;",
+\           "list:s": "list-style-type:square;",
+\           "list:dc": "list-style-type:decimal;",
+\           "list:dclz": "list-style-type:decimal-leading-zero;",
+\           "list:lr": "list-style-type:lower-roman;",
+\           "list:ur": "list-style-type:upper-roman;",
+\           "lisi": "list-style-image:|;",
+\           "lisi:n": "list-style-image:none;",
+\           "q": "quotes:|;",
+\           "q:n": "quotes:none;",
+\           "q:ru": "quotes:'\\00AB' '\\00BB' '\\201E' '\\201C';",
+\           "q:en": "quotes:'\\201C' '\\201D' '\\2018' '\\2019';",
+\           "ct": "content:|;",
+\           "ct:n": "content:normal;",
+\           "ct:oq": "content:open-quote;",
+\           "ct:noq": "content:no-open-quote;",
+\           "ct:cq": "content:close-quote;",
+\           "ct:ncq": "content:no-close-quote;",
+\           "ct:a": "content:attr(|);",
+\           "ct:c": "content:counter(|);",
+\           "ct:cs": "content:counters(|);",
+\           "coi": "counter-increment:|;",
+\           "cor": "counter-reset:|;",
+\           "va": "vertical-align:${1:top};",
+\           "va:sup": "vertical-align:super;",
+\           "va:t": "vertical-align:top;",
+\           "va:tt": "vertical-align:text-top;",
+\           "va:m": "vertical-align:middle;",
+\           "va:bl": "vertical-align:baseline;",
+\           "va:b": "vertical-align:bottom;",
+\           "va:tb": "vertical-align:text-bottom;",
+\           "va:sub": "vertical-align:sub;",
+\           "ta": "text-align:${1:left};",
+\           "ta:l": "text-align:left;",
+\           "ta:c": "text-align:center;",
+\           "ta:r": "text-align:right;",
+\           "ta:j": "text-align:justify;",
+\           "ta-lst": "text-align-last:|;",
+\           "tal:a": "text-align-last:auto;",
+\           "tal:l": "text-align-last:left;",
+\           "tal:c": "text-align-last:center;",
+\           "tal:r": "text-align-last:right;",
+\           "td": "text-decoration:${1:none};",
+\           "td:n": "text-decoration:none;",
+\           "td:u": "text-decoration:underline;",
+\           "td:o": "text-decoration:overline;",
+\           "td:l": "text-decoration:line-through;",
+\           "te": "text-emphasis:|;",
+\           "te:n": "text-emphasis:none;",
+\           "te:ac": "text-emphasis:accent;",
+\           "te:dt": "text-emphasis:dot;",
+\           "te:c": "text-emphasis:circle;",
+\           "te:ds": "text-emphasis:disc;",
+\           "te:b": "text-emphasis:before;",
+\           "te:a": "text-emphasis:after;",
+\           "th": "text-height:|;",
+\           "th:a": "text-height:auto;",
+\           "th:f": "text-height:font-size;",
+\           "th:t": "text-height:text-size;",
+\           "th:m": "text-height:max-size;",
+\           "ti": "text-indent:|;",
+\           "ti:-": "text-indent:-9999px;",
+\           "tj": "text-justify:|;",
+\           "tj:a": "text-justify:auto;",
+\           "tj:iw": "text-justify:inter-word;",
+\           "tj:ii": "text-justify:inter-ideograph;",
+\           "tj:ic": "text-justify:inter-cluster;",
+\           "tj:d": "text-justify:distribute;",
+\           "tj:k": "text-justify:kashida;",
+\           "tj:t": "text-justify:tibetan;",
+\           "tov": "text-overflow:${ellipsis};",
+\           "tov:e": "text-overflow:ellipsis;",
+\           "tov:c": "text-overflow:clip;",
+\           "to": "text-outline:|;",
+\           "to+": "text-outline:${1:0} ${2:0} ${3:#000};",
+\           "to:n": "text-outline:none;",
+\           "tr": "text-replace:|;",
+\           "tr:n": "text-replace:none;",
+\           "tt": "text-transform:${1:uppercase};",
+\           "tt:n": "text-transform:none;",
+\           "tt:c": "text-transform:capitalize;",
+\           "tt:u": "text-transform:uppercase;",
+\           "tt:l": "text-transform:lowercase;",
+\           "tw": "text-wrap:|;",
+\           "tw:n": "text-wrap:normal;",
+\           "tw:no": "text-wrap:none;",
+\           "tw:u": "text-wrap:unrestricted;",
+\           "tw:s": "text-wrap:suppress;",
+\           "tsh": "text-shadow:${1:hoff} ${2:voff} ${3:blur} ${4:#000};",
+\           "tsh:r": "text-shadow:${1:h} ${2:v} ${3:blur} rgb(${4:0}, ${5:0}, ${6:0});",
+\           "tsh:ra": "text-shadow:${1:h} ${2:v} ${3:blur} rgba(${4:0}, ${5:0}, ${6:0}, .${7:5});",
+\           "tsh+": "text-shadow:${1:0} ${2:0} ${3:0} ${4:#000};",
+\           "tsh:n": "text-shadow:none;",
+\           "trf": "transform:|;",
+\           "trf:skx": "transform: skewX(${1:angle});",
+\           "trf:sky": "transform: skewY(${1:angle});",
+\           "trf:sc": "transform: scale(${1:x}, ${2:y});",
+\           "trf:scx": "transform: scaleX(${1:x});",
+\           "trf:scy": "transform: scaleY(${1:y});",
+\           "trf:scz": "transform: scaleZ(${1:z});",
+\           "trf:sc3": "transform: scale3d(${1:x}, ${2:y}, ${3:z});",
+\           "trf:r": "transform: rotate(${1:angle});",
+\           "trf:rx": "transform: rotateX(${1:angle});",
+\           "trf:ry": "transform: rotateY(${1:angle});",
+\           "trf:rz": "transform: rotateZ(${1:angle});",
+\           "trf:t": "transform: translate(${1:x}, ${2:y});",
+\           "trf:tx": "transform: translateX(${1:x});",
+\           "trf:ty": "transform: translateY(${1:y});",
+\           "trf:tz": "transform: translateZ(${1:z});",
+\           "trf:t3": "transform: translate3d(${1:tx}, ${2:ty}, ${3:tz});",
+\           "trfo": "transform-origin:|;",
+\           "trfs": "transform-style:${1:preserve-3d};",
+\           "trs": "transition:${1:prop} ${2:time};",
+\           "trsde": "transition-delay:${1:time};",
+\           "trsdu": "transition-duration:${1:time};",
+\           "trsp": "transition-property:${1:prop};",
+\           "trstf": "transition-timing-function:${1:tfunc};",
+\           "lh": "line-height:|;",
+\           "whs": "white-space:|;",
+\           "whs:n": "white-space:normal;",
+\           "whs:p": "white-space:pre;",
+\           "whs:nw": "white-space:nowrap;",
+\           "whs:pw": "white-space:pre-wrap;",
+\           "whs:pl": "white-space:pre-line;",
+\           "whsc": "white-space-collapse:|;",
+\           "whsc:n": "white-space-collapse:normal;",
+\           "whsc:k": "white-space-collapse:keep-all;",
+\           "whsc:l": "white-space-collapse:loose;",
+\           "whsc:bs": "white-space-collapse:break-strict;",
+\           "whsc:ba": "white-space-collapse:break-all;",
+\           "wob": "word-break:|;",
+\           "wob:n": "word-break:normal;",
+\           "wob:k": "word-break:keep-all;",
+\           "wob:ba": "word-break:break-all;",
+\           "wos": "word-spacing:|;",
+\           "wow": "word-wrap:|;",
+\           "wow:nm": "word-wrap:normal;",
+\           "wow:n": "word-wrap:none;",
+\           "wow:u": "word-wrap:unrestricted;",
+\           "wow:s": "word-wrap:suppress;",
+\           "wow:b": "word-wrap:break-word;",
+\           "wm": "writing-mode:${1:lr-tb};",
+\           "wm:lrt": "writing-mode:lr-tb;",
+\           "wm:lrb": "writing-mode:lr-bt;",
+\           "wm:rlt": "writing-mode:rl-tb;",
+\           "wm:rlb": "writing-mode:rl-bt;",
+\           "wm:tbr": "writing-mode:tb-rl;",
+\           "wm:tbl": "writing-mode:tb-lr;",
+\           "wm:btl": "writing-mode:bt-lr;",
+\           "wm:btr": "writing-mode:bt-rl;",
+\           "lts": "letter-spacing:|;",
+\           "lts-n": "letter-spacing:normal;",
+\           "f": "font:|;",
+\           "f+": "font:${1:1em} ${2:Arial,sans-serif};",
+\           "fw": "font-weight:|;",
+\           "fw:n": "font-weight:normal;",
+\           "fw:b": "font-weight:bold;",
+\           "fw:br": "font-weight:bolder;",
+\           "fw:lr": "font-weight:lighter;",
+\           "fs": "font-style:${italic};",
+\           "fs:n": "font-style:normal;",
+\           "fs:i": "font-style:italic;",
+\           "fs:o": "font-style:oblique;",
+\           "fv": "font-variant:|;",
+\           "fv:n": "font-variant:normal;",
+\           "fv:sc": "font-variant:small-caps;",
+\           "fz": "font-size:|;",
+\           "fza": "font-size-adjust:|;",
+\           "fza:n": "font-size-adjust:none;",
+\           "ff": "font-family:|;",
+\           "ff:s": "font-family:serif;",
+\           "ff:ss": "font-family:sans-serif;",
+\           "ff:c": "font-family:cursive;",
+\           "ff:f": "font-family:fantasy;",
+\           "ff:m": "font-family:monospace;",
+\           "ff:a": "font-family: Arial, \"Helvetica Neue\", Helvetica, sans-serif;",
+\           "ff:t": "font-family: \"Times New Roman\", Times, Baskerville, Georgia, serif;",
+\           "ff:v": "font-family: Verdana, Geneva, sans-serif;",
+\           "fef": "font-effect:|;",
+\           "fef:n": "font-effect:none;",
+\           "fef:eg": "font-effect:engrave;",
+\           "fef:eb": "font-effect:emboss;",
+\           "fef:o": "font-effect:outline;",
+\           "fem": "font-emphasize:|;",
+\           "femp": "font-emphasize-position:|;",
+\           "femp:b": "font-emphasize-position:before;",
+\           "femp:a": "font-emphasize-position:after;",
+\           "fems": "font-emphasize-style:|;",
+\           "fems:n": "font-emphasize-style:none;",
+\           "fems:ac": "font-emphasize-style:accent;",
+\           "fems:dt": "font-emphasize-style:dot;",
+\           "fems:c": "font-emphasize-style:circle;",
+\           "fems:ds": "font-emphasize-style:disc;",
+\           "fsm": "font-smooth:|;",
+\           "fsm:a": "font-smooth:auto;",
+\           "fsm:n": "font-smooth:never;",
+\           "fsm:aw": "font-smooth:always;",
+\           "fst": "font-stretch:|;",
+\           "fst:n": "font-stretch:normal;",
+\           "fst:uc": "font-stretch:ultra-condensed;",
+\           "fst:ec": "font-stretch:extra-condensed;",
+\           "fst:c": "font-stretch:condensed;",
+\           "fst:sc": "font-stretch:semi-condensed;",
+\           "fst:se": "font-stretch:semi-expanded;",
+\           "fst:e": "font-stretch:expanded;",
+\           "fst:ee": "font-stretch:extra-expanded;",
+\           "fst:ue": "font-stretch:ultra-expanded;",
+\           "op": "opacity:|;",
+\           "op+": "opacity: $1;\nfilter: alpha(opacity=$2);",
+\           "op:ie": "filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);",
+\           "op:ms": "-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=100)';",
+\           "rsz": "resize:|;",
+\           "rsz:n": "resize:none;",
+\           "rsz:b": "resize:both;",
+\           "rsz:h": "resize:horizontal;",
+\           "rsz:v": "resize:vertical;",
+\           "cur": "cursor:${pointer};",
+\           "cur:a": "cursor:auto;",
+\           "cur:d": "cursor:default;",
+\           "cur:c": "cursor:crosshair;",
+\           "cur:ha": "cursor:hand;",
+\           "cur:he": "cursor:help;",
+\           "cur:m": "cursor:move;",
+\           "cur:p": "cursor:pointer;",
+\           "cur:t": "cursor:text;",
+\           "fxd": "flex-direction:|;",
+\           "fxd:r": "flex-direction:row;",
+\           "fxd:rr": "flex-direction:row-reverse;",
+\           "fxd:c": "flex-direction:column;",
+\           "fxd:cr": "flex-direction:column-reverse;",
+\           "fxw": "flex-wrap: |;",
+\           "fxw:n": "flex-wrap:nowrap;",
+\           "fxw:w": "flex-wrap:wrap;",
+\           "fxw:wr": "flex-wrap:wrap-reverse;",
+\           "fxf": "flex-flow:|;",
+\           "jc": "justify-content:|;",
+\           "jc:fs": "justify-content:flex-start;",
+\           "jc:fe": "justify-content:flex-end;",
+\           "jc:c": "justify-content:center;",
+\           "jc:sb": "justify-content:space-between;",
+\           "jc:sa": "justify-content:space-around;",
+\           "ai": "align-items:|;",
+\           "ai:fs": "align-items:flex-start;",
+\           "ai:fe": "align-items:flex-end;",
+\           "ai:c": "align-items:center;",
+\           "ai:b": "align-items:baseline;",
+\           "ai:s": "align-items:stretch;",
+\           "ac": "align-content:|;",
+\           "ac:fs": "align-content:flex-start;",
+\           "ac:fe": "align-content:flex-end;",
+\           "ac:c": "align-content:center;",
+\           "ac:sb": "align-content:space-between;",
+\           "ac:sa": "align-content:space-around;",
+\           "ac:s": "align-content:stretch;",
+\           "ord": "order:|;",
+\           "fxg": "flex-grow:|;",
+\           "fxsh": "flex-shrink:|;",
+\           "fxb": "flex-basis:|;",
+\           "fx": "flex:|;",
+\           "as": "align-self:|;",
+\           "as:a": "align-self:auto;",
+\           "as:fs": "align-self:flex-start;",
+\           "as:fe": "align-self:flex-end;",
+\           "as:c": "align-self:center;",
+\           "as:b": "align-self:baseline;",
+\           "as:s": "align-self:stretch;",
+\           "pgbb": "page-break-before:|;",
+\           "pgbb:au": "page-break-before:auto;",
+\           "pgbb:al": "page-break-before:always;",
+\           "pgbb:l": "page-break-before:left;",
+\           "pgbb:r": "page-break-before:right;",
+\           "pgbi": "page-break-inside:|;",
+\           "pgbi:au": "page-break-inside:auto;",
+\           "pgbi:av": "page-break-inside:avoid;",
+\           "pgba": "page-break-after:|;",
+\           "pgba:au": "page-break-after:auto;",
+\           "pgba:al": "page-break-after:always;",
+\           "pgba:l": "page-break-after:left;",
+\           "pgba:r": "page-break-after:right;",
+\           "orp": "orphans:|;",
+\           "us": "user-select:${none};",
+\           "wid": "widows:|;",
+\           "wfsm": "-webkit-font-smoothing:${antialiased};",
+\           "wfsm:a": "-webkit-font-smoothing:antialiased;",
+\           "wfsm:s": "-webkit-font-smoothing:subpixel-antialiased;",
+\           "wfsm:sa": "-webkit-font-smoothing:subpixel-antialiased;",
+\           "wfsm:n": "-webkit-font-smoothing:none;"
+\        },
+\        'filters': 'fc',
+\        'ignore_embeded_filetype': 1,
+\    },
+\    'sass': {
+\        'extends': 'css',
+\        'snippets': {
+\            '@if': "@if {\n\t|\n}",
+\            '@e': "@else {\n\t|\n}",
+\            '@in': "@include |",
+\            '@ex': "@extend |",
+\            '@mx': "@mixin {\n\t|\n}",
+\            '@fn': "@function {\n\t|\n}",
+\            '@r': "@return |",
+\        },
+\    },
+\    'scss': {
+\        'extends': 'css',
+\    },
+\    'less': {
+\        'extends': 'css',
+\    },
+\    'css.drupal': {
+\        'extends': 'css',
+\    },
+\    'styled': {
+\        'extends': 'css',
+\    },
+\    'html': {
+\        'snippets': {
+\            '!': "html:5",
+\            '!!!': "<!DOCTYPE html>\n",
+\            '!!!4t':  "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n",
+\            '!!!4s':  "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n",
+\            '!!!xt':  "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n",
+\            '!!!xs':  "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n",
+\            '!!!xxs': "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n",
+\            'c': "<!-- |${child} -->",
+\            'cc:ie6': "<!--[if lte IE 6]>\n\t${child}|\n<![endif]-->",
+\            'cc:ie': "<!--[if IE]>\n\t${child}|\n<![endif]-->",
+\            'cc:noie': "<!--[if !IE]><!-->\n\t${child}|\n<!--<![endif]-->",
+\            'html:4t': "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n"
+\                    ."<html lang=\"${lang}\">\n"
+\                    ."<head>\n"
+\                    ."\t<meta http-equiv=\"Content-Type\" content=\"text/html;charset=${charset}\">\n"
+\                    ."\t<title></title>\n"
+\                    ."</head>\n"
+\                    ."<body>\n\t${child}|\n</body>\n"
+\                    ."</html>",
+\            'html:4s': "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n"
+\                    ."<html lang=\"${lang}\">\n"
+\                    ."<head>\n"
+\                    ."\t<meta http-equiv=\"Content-Type\" content=\"text/html;charset=${charset}\">\n"
+\                    ."\t<title></title>\n"
+\                    ."</head>\n"
+\                    ."<body>\n\t${child}|\n</body>\n"
+\                    ."</html>",
+\            'html:xt': "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
+\                    ."<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"${lang}\">\n"
+\                    ."<head>\n"
+\                    ."\t<meta http-equiv=\"Content-Type\" content=\"text/html;charset=${charset}\" />\n"
+\                    ."\t<title></title>\n"
+\                    ."</head>\n"
+\                    ."<body>\n\t${child}|\n</body>\n"
+\                    ."</html>",
+\            'html:xs': "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
+\                    ."<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"${lang}\">\n"
+\                    ."<head>\n"
+\                    ."\t<meta http-equiv=\"Content-Type\" content=\"text/html;charset=${charset}\" />\n"
+\                    ."\t<title></title>\n"
+\                    ."</head>\n"
+\                    ."<body>\n\t${child}|\n</body>\n"
+\                    ."</html>",
+\            'html:xxs': "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
+\                    ."<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"${lang}\">\n"
+\                    ."<head>\n"
+\                    ."\t<meta http-equiv=\"Content-Type\" content=\"text/html;charset=${charset}\" />\n"
+\                    ."\t<title></title>\n"
+\                    ."</head>\n"
+\                    ."<body>\n\t${child}|\n</body>\n"
+\                    ."</html>",
+\            'html:5': "<!DOCTYPE html>\n"
+\                    ."<html lang=\"${lang}\">\n"
+\                    ."<head>\n"
+\                    ."\t<meta charset=\"${charset}\">\n"
+\                    ."\t<title></title>\n"
+\                    ."</head>\n"
+\                    ."<body>\n\t${child}|\n</body>\n"
+\                    ."</html>",
+\        },
+\        'default_attributes': {
+\            'a': [{'href': ''}],
+\            'a:blank': [{'href': 'http://|'},{'target': '_blank'},{'rel': 'noopener noreferrer'}],
+\            'a:link': [{'href': 'http://|'}],
+\            'a:mail': [{'href': 'mailto:|'}],
+\            'a:tel': [{'href': 'tel:+|'}],
+\            'abbr': [{'title': ''}],
+\            'acronym': [{'title': ''}],
+\            'acr': [{'title': ''}],
+\            'base': [{'href': ''}],
+\            'bdo': [{'dir': ''}],
+\            'bdo:r': [{'dir': 'rtl'}],
+\            'bdo:l': [{'dir': 'ltr'}],
+\            'button:disabled': [{'disabled': 'disabled'}],
+\            'button:d': [{'disabled': 'disabled'}],
+\            'btn:d': [{'disabled': 'disabled'}],
+\            'button:submit': [{'type': 'submit'}],
+\            'button:s': [{'type': 'submit'}],
+\            'btn:s': [{'type': 'submit'}],
+\            'button:reset': [{'type': 'reset'}],
+\            'button:r': [{'type': 'reset'}],
+\            'btn:r': [{'type': 'reset'}],
+\            'del': [{'datetime': '${datetime}'}],
+\            'ins': [{'datetime': '${datetime}'}],
+\            'link:css': [{'rel': 'stylesheet'}, g:emmet_html5 ? {} : {'type': 'text/css'}, {'href': '|style.css'}, {'media': 'all'}],
+\            'link:manifest': [{'rel': 'manifest'},{'href': '|manifest.json'}],
+\            'link:mf': [{'rel': 'manifest'},{'href': '|manifest.json'}],
+\            'link:print': [{'rel': 'stylesheet'}, g:emmet_html5 ? {} : {'type': 'text/css'}, {'href': '|print.css'}, {'media': 'print'}],
+\            'link:import': [{'rel': 'import'}, {'href': '|.html'}],
+\            'link:im': [{'rel': 'import'}, {'href': '|.html'}],
+\            'link:favicon': [{'rel': 'shortcut icon'}, {'type': 'image/x-icon'}, {'href': '|favicon.ico'}],
+\            'link:touch': [{'rel': 'apple-touch-icon'}, {'href': '|favicon.png'}],
+\            'link:rss': [{'rel': 'alternate'}, {'type': 'application/rss+xml'}, {'title': 'RSS'}, {'href': '|rss.xml'}],
+\            'link:atom': [{'rel': 'alternate'}, {'type': 'application/atom+xml'}, {'title': 'Atom'}, {'href': 'atom.xml'}],
+\            'marquee': [{'behavior': ''},{'direction': ''}],
+\            'meta:utf': [{'http-equiv': 'Content-Type'}, {'content': 'text/html;charset=UTF-8'}],
+\            'meta:vp': [{'name': 'viewport'}, {'content': 'width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0'}],
+\            'meta:win': [{'http-equiv': 'Content-Type'}, {'content': 'text/html;charset=Win-1251'}],
+\            'meta:compat': [{'http-equiv': 'X-UA-Compatible'}, {'content': 'IE=7'}],
+\            'meta:desc': [{'name': 'description'},{'content': ''}],
+\            'meta:edge': [{'http-equiv': 'X-UA-Compatible'}, {'content': 'ie=edge'}],
+\            'meta:kw': [{'name': 'keywords'},{'content': ''}],
+\            'meta:redirect': [{'http-equiv': 'Content-Type'}, {'content': '0; url=http://example.com'}],
+\            'style': g:emmet_html5 ? [] : [{'type': 'text/css'}],
+\            'script': g:emmet_html5 ? [] : [{'type': 'text/javascript'}],
+\            'script:src': (g:emmet_html5 ? [] : [{'type': 'text/javascript'}]) + [{'src': ''}],
+\            'img': [{'src': ''}, {'alt': ''}],
+\            'img:srcset': [{'srcset': ''},{'src': ''}, {'alt': ''}],
+\            'img:s': [{'srcset': ''},{'src': ''}, {'alt': ''}],
+\            'img:sizes': [{'sizes': ''},{'srcset': ''},{'src': ''}, {'alt': ''}],
+\            'img:z': [{'sizes': ''},{'srcset': ''},{'src': ''}, {'alt': ''}],
+\            'iframe': [{'src': ''}, {'frameborder': '0'}],
+\            'embed': [{'src': ''}, {'type': ''}],
+\            'object': [{'data': ''}, {'type': ''}],
+\            'param': [{'name': ''}, {'value': ''}],
+\            'map': {'name': ''},
+\            'area': [{'shape': ''}, {'coords': ''}, {'href': ''}, {'alt': ''}],
+\            'area:d': [{'shape': 'default'}, {'href': ''}, {'alt': ''}],
+\            'area:c': [{'shape': 'circle'}, {'coords': ''}, {'href': ''}, {'alt': ''}],
+\            'area:r': [{'shape': 'rect'}, {'coords': ''}, {'href': ''}, {'alt': ''}],
+\            'area:p': [{'shape': 'poly'}, {'coords': ''}, {'href': ''}, {'alt': ''}],
+\            'link': [{'rel': 'stylesheet'}, {'href': ''}],
+\            'fieldset:disabled': [{'disabled': 'disabled'}],
+\            'fieldset:d': [{'disabled': 'disabled'}],
+\            'fset:d': [{'disabled': 'disabled'}],
+\            'fst:disabled': [{'disabled': 'disabled'}],
+\            'form': [{'action': ''}],
+\            'form:get': [{'action': ''}, {'method': 'get'}],
+\            'form:post': [{'action': ''}, {'method': 'post'}],
+\            'form:upload': [{'action': ''}, {'method': 'post'}, {'enctype': 'multipart/form-data'}],
+\            'label': [{'for': ''}],
+\            'input': [{'type': ''}],
+\            'input:hidden': [{'type': 'hidden'}, {'name': ''}],
+\            'input:h': [{'type': 'hidden'}, {'name': ''}],
+\            'input:text': [{'type': 'text'}, {'name': ''}, {'id': ''}],
+\            'input:t': [{'type': 'text'}, {'name': ''}, {'id': ''}],
+\            'input:search': [{'type': 'search'}, {'name': ''}, {'id': ''}],
+\            'input:email': [{'type': 'email'}, {'name': ''}, {'id': ''}],
+\            'input:tel': [{'type': 'tel'}, {'name': ''}, {'id': ''}],
+\            'input:url': [{'type': 'url'}, {'name': ''}, {'id': ''}],
+\            'input:password': [{'type': 'password'}, {'name': ''}, {'id': ''}],
+\            'input:p': [{'type': 'password'}, {'name': ''}, {'id': ''}],
+\            'input:datetime': [{'type': 'datetime'}, {'name': ''}, {'id': ''}],
+\            'input:date': [{'type': 'date'}, {'name': ''}, {'id': ''}],
+\            'input:datetime-local': [{'type': 'datetime-local'}, {'name': ''}, {'id': ''}],
+\            'input:month': [{'type': 'month'}, {'name': ''}, {'id': ''}],
+\            'input:week': [{'type': 'week'}, {'name': ''}, {'id': ''}],
+\            'input:time': [{'type': 'time'}, {'name': ''}, {'id': ''}],
+\            'input:number': [{'type': 'number'}, {'name': ''}, {'id': ''}],
+\            'input:color': [{'type': 'color'}, {'name': ''}, {'id': ''}],
+\            'input:checkbox': [{'type': 'checkbox'}, {'name': ''}, {'id': ''}],
+\            'input:c': [{'type': 'checkbox'}, {'name': ''}, {'id': ''}],
+\            'input:radio': [{'type': 'radio'}, {'name': ''}, {'id': ''}],
+\            'input:r': [{'type': 'radio'}, {'name': ''}, {'id': ''}],
+\            'input:range': [{'type': 'range'}, {'name': ''}, {'id': ''}],
+\            'input:file': [{'type': 'file'}, {'name': ''}, {'id': ''}],
+\            'input:f': [{'type': 'file'}, {'name': ''}, {'id': ''}],
+\            'input:submit': [{'type': 'submit'}, {'value': ''}],
+\            'input:s': [{'type': 'submit'}, {'value': ''}],
+\            'input:image': [{'type': 'image'}, {'src': ''}, {'alt': ''}],
+\            'input:i': [{'type': 'image'}, {'src': ''}, {'alt': ''}],
+\            'input:reset': [{'type': 'reset'}, {'value': ''}],
+\            'input:button': [{'type': 'button'}, {'value': ''}],
+\            'input:b': [{'type': 'button'}, {'value': ''}],
+\            'select': [{'name': ''}, {'id': ''}],
+\            'select:disabled': [{'name': ''}, {'id': ''}, {'disabled': 'disabled'}],
+\            'source:media': [{'media': '(minwidth: )'},{'srcset': ''}],
+\            'source:m': [{'media': '(minwidth: )'},{'srcset': ''}],
+\            'source:media:type': [{'media': '(minwidth: )'},{'srcset': ''},{'type': 'image/'}],
+\            'source:media:sizes': [{'media': '(minwidth: )'},{'srcset': ''},{'sizes': ''}],
+\            'source:sizes:type': [{'sizes': ''},{'srcset': ''},{'type': 'image/'}],
+\            'source:src': [{'src': ''},{'type': ''}],
+\            'source:sc': [{'src': ''},{'type': ''}],
+\            'source:srcset': [{'srcset': ''}],
+\            'source:s': [{'srcset': ''}],
+\            'source:type': [{'srcset': ''},{'type': 'image/'}],
+\            'source:t': [{'srcset': ''},{'type': 'image/'}],
+\            'source:sizes': [{'sizes': ''},{'srcset': ''}],
+\            'source:z': [{'sizes': ''},{'srcset': ''}],
+\            'option': [{'value': ''}],
+\            'textarea': [{'name': ''}, {'id': ''}, {'cols': '30'}, {'rows': '10'}],
+\            'menu:context': [{'type': 'context'}],
+\            'menu:c': [{'type': 'context'}],
+\            'menu:toolbar': [{'type': 'toolbar'}],
+\            'menu:t': [{'type': 'toolbar'}],
+\            'video': [{'src': ''}],
+\            'audio': [{'src': ''}],
+\            'html:xml': [{'xmlns': 'http://www.w3.org/1999/xhtml'}, {'xml:lang': '${lang}'}],
+\        },
+\        'aliases': {
+\            'link:*': 'link',
+\            'meta:*': 'meta',
+\            'area:*': 'area',
+\            'bdo:*': 'bdo',
+\            'form:*': 'form',
+\            'input:*': 'input',
+\            'script:*': 'script',
+\            'html:*': 'html',
+\            'a:*': 'a',
+\            'menu:*': 'menu',
+\            'mn': 'main',
+\            'tem': 'template',
+\            'bq': 'blockquote',
+\            'acr': 'acronym',
+\            'fig': 'figure',
+\            'figc': 'figcaption',
+\            'ifr': 'iframe',
+\            'emb': 'embed',
+\            'obj': 'object',
+\            'src:*': 'source',
+\            'cap': 'caption',
+\            'colg': 'colgroup',
+\            'fst': 'fieldset',
+\            'btn:': 'button',
+\            'optg': 'optgroup',
+\            'opt': 'option',
+\            'pic': 'picture',
+\            'tarea': 'textarea',
+\            'leg': 'legend',
+\            'sect': 'section',
+\            'art': 'article',
+\            'hdr': 'header',
+\            'ftr': 'footer',
+\            'adr': 'address',
+\            'dlg': 'dialog',
+\            'str': 'strong',
+\            'sty': 'style',
+\            'prog': 'progress',
+\            'fset': 'fieldset',
+\            'datag': 'datagrid',
+\            'datal': 'datalist',
+\            'kg': 'keygen',
+\            'out': 'output',
+\            'det': 'details',
+\            'cmd': 'command',
+\            'sum': 'summary',
+\        },
+\        'expandos': {
+\            'ol': 'ol>li',
+\            'ul': 'ul>li',
+\            'dl': 'dl>dt+dd',
+\            'map': 'map>area',
+\            'table': 'table>tr>td',
+\            'colgroup': 'colgroup>col',
+\            'colg': 'colgroup>col',
+\            'tr': 'tr>td',
+\            'select': 'select>option',
+\            'optgroup': 'optgroup>option',
+\            'optg': 'optgroup>option',
+\            'ri:dpr': 'img:s',
+\            'ri:d': 'img:s',
+\            'ri:viewport': 'img:z',
+\            'ri:vp': 'img:z',
+\            'ri:art': 'pic>source:m+img',
+\            'ri:a': 'pic>source:m+img',
+\            'ri:type': 'pic>source:t+img',
+\            'ri:t': 'pic>source:t+img',
+\        },
+\        'empty_elements': 'area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed,keygen,command',
+\        'block_elements': 'address,applet,blockquote,button,center,dd,del,dir,div,dl,dt,fieldset,form,frameset,hr,iframe,ins,isindex,li,link,map,menu,noframes,noscript,object,ol,p,pre,script,table,tbody,td,tfoot,th,thead,tr,ul,h1,h2,h3,h4,h5,h6',
+\        'inline_elements': '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,script,small,span,strike,strong,sub,sup,textarea,tt,u,var',
+\        'empty_element_suffix': g:emmet_html5 ? '>' : ' />',
+\        'indent_blockelement': 0,
+\        'block_all_childless': 0,
+\    },
+\    'elm': {
+\        'indentation': '    ',
+\        'extends': 'html',
+\    },
+\    'xml': {
+\        'extends': 'html',
+\        'empty_elements': '',
+\        'block_elements': '',
+\        'inline_elements': '',
+\    },
+\    'htmldjango': {
+\        'extends': 'html',
+\    },
+\    'html.django_template': {
+\        'extends': 'html',
+\    },
+\    'jade': {
+\        'indentation': '  ',
+\        'extends': 'html',
+\        'snippets': {
+\            '!': "html:5",
+\            '!!!': "doctype html\n",
+\            '!!!4t': "doctype HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\"\n",
+\            '!!!4s': "doctype HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\"\n",
+\            '!!!xt': "doctype transitional\n",
+\            '!!!xs': "doctype strict\n",
+\            '!!!xxs': "doctype 1.1\n",
+\            'c': "\/\/ |${child}",
+\            'html:4t': "doctype HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\"\n"
+\                    ."html(lang=\"${lang}\")\n"
+\                    ."\thead\n"
+\                    ."\t\tmeta(http-equiv=\"Content-Type\", content=\"text/html;charset=${charset}\")\n"
+\                    ."\t\ttitle\n"
+\                    ."\tbody\n\t\t${child}|",
+\            'html:4s': "doctype HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\"\n"
+\                    ."html(lang=\"${lang}\")\n"
+\                    ."\thead\n"
+\                    ."\t\tmeta(http-equiv=\"Content-Type\", content=\"text/html;charset=${charset}\")\n"
+\                    ."\t\ttitle\n"
+\                    ."\tbody\n\t\t${child}|",
+\            'html:xt': "doctype transitional\n"
+\                    ."html(xmlns=\"http://www.w3.org/1999/xhtml\", xml:lang=\"${lang}\")\n"
+\                    ."\thead\n"
+\                    ."\t\tmeta(http-equiv=\"Content-Type\", content=\"text/html;charset=${charset}\")\n"
+\                    ."\t\ttitle\n"
+\                    ."\tbody\n\t\t${child}|",
+\            'html:xs': "doctype strict\n"
+\                    ."html(xmlns=\"http://www.w3.org/1999/xhtml\", xml:lang=\"${lang}\")\n"
+\                    ."\thead\n"
+\                    ."\t\tmeta(http-equiv=\"Content-Type\", content=\"text/html;charset=${charset}\")\n"
+\                    ."\t\ttitle\n"
+\                    ."\tbody\n\t\t${child}|",
+\            'html:xxs': "doctype 1.1\n"
+\                    ."html(xmlns=\"http://www.w3.org/1999/xhtml\", xml:lang=\"${lang}\")\n"
+\                    ."\thead\n"
+\                    ."\t\tmeta(http-equiv=\"Content-Type\", content=\"text/html;charset=${charset}\")\n"
+\                    ."\t\ttitle\n"
+\                    ."\tbody\n\t\t${child}|",
+\            'html:5': "doctype html\n"
+\                    ."html(lang=\"${lang}\")\n"
+\                    ."\thead\n"
+\                    ."\t\tmeta(charset=\"${charset}\")\n"
+\                    ."\t\ttitle\n"
+\                    ."\tbody\n\t\t${child}|",
+\        },
+\    },
+\    'pug': {
+\        'extends': 'jade',
+\    },
+\    'xsl': {
+\        'extends': 'html',
+\        'default_attributes': {
+\            'tmatch': [{'match': ''}, {'mode': ''}],
+\            'tname': [{'name': ''}],
+\            'xsl:when': {'test': ''},
+\            'var': [{'name': ''}, {'select': ''}],
+\            'vari': {'name': ''},
+\            'if': {'test': ''},
+\            'call': {'name': ''},
+\            'attr': {'name': ''},
+\            'wp': [{'name': ''}, {'select': ''}],
+\            'par': [{'name': ''}, {'select': ''}],
+\            'val': {'select': ''},
+\            'co': {'select': ''},
+\            'each': {'select': ''},
+\            'ap': [{'select': ''}, {'mode': ''}]
+\        },
+\        'aliases': {
+\            'tmatch': 'xsl:template',
+\            'tname': 'xsl:template',
+\            'var': 'xsl:variable',
+\            'vari': 'xsl:variable',
+\            'if': 'xsl:if',
+\            'choose': 'xsl:choose',
+\            'call': 'xsl:call-template',
+\            'wp': 'xsl:with-param',
+\            'par': 'xsl:param',
+\            'val': 'xsl:value-of',
+\            'attr': 'xsl:attribute',
+\            'co' : 'xsl:copy-of',
+\            'each' : 'xsl:for-each',
+\            'ap' : 'xsl:apply-templates',
+\        },
+\        'expandos': {
+\            'choose': 'xsl:choose>xsl:when+xsl:otherwise',
+\        }
+\    },
+\    'jsx': {
+\        'extends': 'html',
+\        'attribute_name': {'class': 'className', 'for': 'htmlFor'},
+\        'empty_element_suffix': ' />',
+\    },
+\    'javascriptreact': {
+\        'extends': 'html',
+\        'attribute_name': {'class': 'className', 'for': 'htmlFor'},
+\        'empty_element_suffix': ' />',
+\    },
+\    'tsx': {
+\        'extends': 'jsx',
+\    },
+\    'typescriptreact': {
+\        'extends': 'html',
+\        'attribute_name': {'class': 'className', 'for': 'htmlFor'},
+\        'empty_element_suffix': ' />',
+\    },
+\    'xslt': {
+\        'extends': 'xsl',
+\    },
+\    'haml': {
+\        'indentation': '  ',
+\        'extends': 'html',
+\        'snippets': {
+\            'html:5': "!!! 5\n"
+\                    ."%html{:lang => \"${lang}\"}\n"
+\                    ."\t%head\n"
+\                    ."\t\t%meta{:charset => \"${charset}\"}\n"
+\                    ."\t\t%title\n"
+\                    ."\t%body\n"
+\                    ."\t\t${child}|\n",
+\        },
+\        'attribute_style': 'hash',
+\    },
+\    'slim': {
+\        'indentation': '  ',
+\        'extends': 'html',
+\        'snippets': {
+\            'html:5': "doctype 5\n"
+\                    ."html lang=\"${lang}\"\n"
+\                    ."\thead\n"
+\                    ."\t\tmeta charset=\"${charset}\"\n"
+\                    ."\t\ttitle\n"
+\                    ."\tbody\n"
+\                    ."\t\t${child}|\n",
+\        },
+\        'ignore_embeded_filetype': 1,
+\    },
+\    'xhtml': {
+\        'extends': 'html'
+\    },
+\    'mustache': {
+\        'extends': 'html'
+\    },
+\    'xsd': {
+\        'extends': 'html',
+\        'snippets': {
+\            'xsd:w3c': "<?xml version=\"1.0\"?>\n"
+\                    ."<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\n"
+\                    ."\t<xsd:element name=\"\" type=\"\"/>\n"
+\                    ."</xsd:schema>\n"
+\        }
+\    },
+\}
+
+if exists('g:user_emmet_settings')
+  call emmet#mergeConfig(s:emmet_settings, g:user_emmet_settings)
+endif
+
+let &cpoptions = s:save_cpo
+unlet s:save_cpo
+
+" vim:set et:
diff --git a/config/vim/autoload/emmet/lang.vim b/config/vim/autoload/emmet/lang.vim
new file mode 100644
index 0000000..37e426b
--- /dev/null
+++ b/config/vim/autoload/emmet/lang.vim
@@ -0,0 +1,52 @@
+let s:exists = {}
+function! emmet#lang#exists(type) abort
+  if len(a:type) == 0
+    return 0
+  elseif has_key(s:exists, a:type)
+    return s:exists[a:type]
+  endif
+  let s:exists[a:type] = len(globpath(&rtp, 'autoload/emmet/lang/'.a:type.'.vim')) > 0
+  return s:exists[a:type]
+endfunction
+
+function! emmet#lang#type(type) abort
+  let type = a:type
+  let base = type
+  let settings = emmet#getSettings()
+  while base != ''
+    for b in split(base, '\.')
+      if emmet#lang#exists(b)
+        return b
+      endif
+      if has_key(settings, b) && has_key(settings[b], 'extends')
+        let base = settings[b].extends
+        break
+      else
+        let base = ''
+      endif
+    endfor
+  endwhile
+  return 'html'
+endfunction
+
+" get all extends for a type recursively
+function! emmet#lang#getExtends(type) abort
+  let settings = emmet#getSettings()
+
+  if !has_key(settings[a:type], 'extends')
+    return []
+  endif
+
+  let extends = settings[a:type].extends
+  if type(extends) ==# 1
+    let tmp = split(extends, '\s*,\s*')
+    unlet! extends
+    let extends = tmp
+  endif
+
+  for ext in extends
+    let extends = extends + emmet#lang#getExtends(ext)
+  endfor
+
+  return extends
+endfunction
diff --git a/config/vim/autoload/emmet/lang/css.vim b/config/vim/autoload/emmet/lang/css.vim
new file mode 100644
index 0000000..d26f942
--- /dev/null
+++ b/config/vim/autoload/emmet/lang/css.vim
@@ -0,0 +1,385 @@
+function! emmet#lang#css#findTokens(str) abort
+  let tmp = substitute(substitute(a:str, '^.*[;{]\s*', '', ''), '}\s*$', '', '')
+  if tmp =~ '/' && 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 abbr = a:abbr
+  let type = a:type
+  let prefix = 0
+  let value = ''
+
+  let indent = emmet#getIndentation(type)
+  let aliases = emmet#getResource(type, 'aliases', {})
+  let snippets = emmet#getResource(type, 'snippets', {})
+  let use_pipe_for_cursor = emmet#getResource(type, 'use_pipe_for_cursor', 1)
+
+  let root = emmet#newNode()
+
+  " emmet
+  let tokens = split(abbr, '+\ze[^+)!]')
+  let block = emmet#util#searchRegion('{', '}')
+  if abbr !~# '^@' && emmet#getBaseType(type) ==# 'css' && type !=# 'sass' && type !=# 'styled' && block[0] ==# [0,0] && block[1] ==# [0,0]
+    let current = emmet#newNode()
+    let current.snippet = substitute(abbr, '\s\+$', '', '') . " {\n" . indent . "${cursor}\n}"
+    let current.name = ''
+    call add(root.child, deepcopy(current))
+  else
+    for n in range(len(tokens))
+      let token = tokens[n]
+      let prop = matchlist(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(prop)
+        let token = substitute(prop[1], '^(\(.*\))', '\1', '')
+        if token =~# '^-'
+          let prefix = 1
+          let token = token[1:]
+        endif
+        let value = ''
+        for vt in split(prop[2], '\a\+\zs')
+          let ut = matchstr(vt, '[a-z]\+$')
+          if ut == 'auto'
+            let ut = ''
+          endif
+          for v in split(vt, '\d\zs-')
+            if len(value) > 0
+              let value .= ' '
+            endif
+            if v !~ '[a-z]\+$'
+              let v .= ut
+            endif
+            if token =~# '^[z]'
+              " TODO
+              let value .= substitute(v, '[^0-9.]*$', '', '')
+            elseif v =~# 'em$'
+              let value .= v
+            elseif v =~# 'ex$'
+              let value .= v
+            elseif v =~# 'vh$'
+              let value .= v
+            elseif v =~# 'vw$'
+              let value .= v
+            elseif v =~# 'rem$'
+              let value .= v
+            elseif v ==# 'auto'
+              let value .= v
+            elseif v =~# 'p$'
+              let value .= substitute(v, 'p$', '%', '')
+            elseif v =~# '%$'
+              let value .= v
+            elseif v =~# 'e$'
+              let value .= substitute(v, 'e$', 'em', '')
+            elseif v =~# 'x$'
+              let value .= substitute(v, 'x$', 'ex', '')
+            elseif v =~# 're$'
+              let value .= substitute(v, 're$', 'rem', '')
+            elseif v =~# '\.'
+              let value .= v . 'em'
+            elseif v ==# '0'
+              let value .= '0'
+            else
+              let value .= v . 'px'
+            endif
+          endfor
+        endfor
+      endif
+
+      let tag_name = token
+      if tag_name =~# '.!$'
+        let tag_name = tag_name[:-2]
+        let important = 1
+      else
+        let important = 0
+      endif
+      " make default node
+      let current = emmet#newNode()
+      let current.important = important
+      let current.name = tag_name
+
+      " aliases
+      if has_key(aliases, tag_name)
+        let current.name = aliases[tag_name]
+      endif
+
+      " snippets
+      if !empty(snippets)
+        let snippet_name = tag_name
+        if !has_key(snippets, snippet_name)
+          let pat = '^' . join(split(tag_name, '\zs'), '\%(\|[^:-]\+-\)')
+          let vv = filter(sort(keys(snippets)), 'snippets[v:val] =~ pat')
+          if len(vv) == 0
+            let vv = filter(sort(keys(snippets)), 'substitute(v:val, ":", "", "g") == snippet_name')
+          endif
+          if len(vv) > 0
+            let snippet_name = vv[0]
+          else
+            let pat = '^' . join(split(tag_name, '\zs'), '\%(\|[^:-]\+-*\)')
+            let vv = filter(sort(keys(snippets)), 'snippets[v:val] =~ pat')
+            if len(vv) == 0
+              let pat = '^' . join(split(tag_name, '\zs'), '[^:]\{-}')
+              let vv = filter(sort(keys(snippets)), 'snippets[v:val] =~ pat')
+              if len(vv) == 0
+                let pat = '^' . join(split(tag_name, '\zs'), '.\{-}')
+                let vv = filter(sort(keys(snippets)), 'snippets[v:val] =~ pat')
+              endif
+            endif
+            let minl = -1
+            for vk in vv
+              let vvs = snippets[vk]
+              if minl == -1 || len(vvs) < minl
+                let snippet_name = vk
+                let minl = len(vvs)
+              endif
+            endfor
+          endif
+        endif
+        if has_key(snippets, snippet_name)
+          let snippet = snippets[snippet_name]
+          if use_pipe_for_cursor
+            let snippet = substitute(snippet, '|', '${cursor}', 'g')
+          endif
+          let lines = split(snippet, "\n")
+          call map(lines, 'substitute(v:val, "\\(    \\|\\t\\)", escape(indent, "\\\\"), "g")')
+          let current.snippet = join(lines, "\n")
+          let current.name = ''
+          let current.snippet = substitute(current.snippet, ';', value . ';', '')
+          if use_pipe_for_cursor && len(value) > 0
+            let current.snippet = substitute(current.snippet, '\${cursor}', '', 'g')
+          endif
+          if n < len(tokens) - 1
+            let current.snippet .= "\n"
+          endif
+        endif
+      endif
+
+      let current.pos = 0
+      let lg = matchlist(token, '^\%(linear-gradient\|lg\)(\s*\(\S\+\)\s*,\s*\([^,]\+\)\s*,\s*\([^)]\+\)\s*)$')
+      if len(lg) == 0
+        let lg = matchlist(token, '^\%(linear-gradient\|lg\)(\s*\(\S\+\)\s*,\s*\([^,]\+\)\s*)$')
+        if len(lg)
+          let [lg[1], lg[2], lg[3]] = ['linear', lg[1], lg[2]]
+        endif
+      endif
+      if len(lg)
+        let current.name = ''
+        let current.snippet = printf("background-image:-webkit-gradient(%s, 0 0, 0 100%, from(%s), to(%s));\n", lg[1], lg[2], lg[3])
+        call add(root.child, deepcopy(current))
+        let current.snippet = printf("background-image:-webkit-linear-gradient(%s, %s);\n", lg[2], lg[3])
+        call add(root.child, deepcopy(current))
+        let current.snippet = printf("background-image:-moz-linear-gradient(%s, %s);\n", lg[2], lg[3])
+        call add(root.child, deepcopy(current))
+        let current.snippet = printf("background-image:-o-linear-gradient(%s, %s);\n", lg[2], lg[3])
+        call add(root.child, deepcopy(current))
+        let current.snippet = printf("background-image:linear-gradient(%s, %s);\n", lg[2], lg[3])
+        call add(root.child, deepcopy(current))
+      elseif prefix
+        let snippet = current.snippet
+        let current.snippet = '-webkit-' . snippet . "\n"
+        call add(root.child, deepcopy(current))
+        let current.snippet = '-moz-' . snippet . "\n"
+        call add(root.child, deepcopy(current))
+        let current.snippet = '-o-' . snippet . "\n"
+        call add(root.child, deepcopy(current))
+        let current.snippet = '-ms-' . snippet . "\n"
+        call add(root.child, deepcopy(current))
+        let current.snippet = snippet
+        call add(root.child, current)
+      elseif token =~# '^c#\([0-9a-fA-F]\{3}\|[0-9a-fA-F]\{6}\)\(\.[0-9]\+\)\?'
+        let cs = split(token, '\.')
+        let current.name = ''
+        let [r,g,b] = [0,0,0]
+        if len(cs[0]) == 5
+          let rgb = matchlist(cs[0], 'c#\(.\)\(.\)\(.\)')
+          let r = eval('0x'.rgb[1].rgb[1])
+          let g = eval('0x'.rgb[2].rgb[2])
+          let b = eval('0x'.rgb[3].rgb[3])
+        elseif len(cs[0]) == 8
+          let rgb = matchlist(cs[0], 'c#\(..\)\(..\)\(..\)')
+          let r = eval('0x'.rgb[1])
+          let g = eval('0x'.rgb[2])
+          let b = eval('0x'.rgb[3])
+        endif
+        if len(cs) == 1
+          let current.snippet = printf('color:rgb(%d, %d, %d);', r, g, b)
+        else
+          let current.snippet = printf('color:rgb(%d, %d, %d, %s);', r, g, b, string(str2float('0.'.cs[1])))
+        endif
+        call add(root.child, current)
+      elseif token =~# '^c#'
+        let current.name = ''
+        let current.snippet = 'color:\${cursor};'
+        call add(root.child, current)
+      else
+        call add(root.child, current)
+      endif
+    endfor
+  endif
+  return root
+endfunction
+
+function! emmet#lang#css#toString(settings, current, type, inline, filters, itemno, indent) abort
+  let current = a:current
+  let value = current.value[1:-2]
+  let tmp = substitute(value, '\${cursor}', '', 'g')
+  if tmp !~ '.*{[ \t\r\n]*}$'
+    if emmet#useFilter(a:filters, 'fc')
+      let value = substitute(value, '\([^:]\+\):\([^;]*\)', '\1: \2', 'g')
+    else
+      let value = substitute(value, '\([^:]\+\):\([^;]*\)', '\1:\2', 'g')
+    endif
+    if current.important
+      let value = substitute(value, ';', ' !important;', '')
+    endif
+  endif
+  return value
+endfunction
+
+function! emmet#lang#css#imageSize() abort
+  let img_region = emmet#util#searchRegion('{', '}')
+  if !emmet#util#regionIsValid(img_region) || !emmet#util#cursorInRegion(img_region)
+    return
+  endif
+  let content = emmet#util#getContent(img_region)
+  let fn = matchstr(content, '\<url(\zs[^)]\+\ze)')
+  let fn = substitute(fn, '[''" \t]', '', 'g')
+  if fn =~# '^\s*$'
+    return
+  elseif fn !~# '^\(/\|http\)'
+    let fn = simplify(expand('%:h') . '/' . fn)
+  endif
+  let [width, height] = emmet#util#getImageSize(fn)
+  if width == -1 && height == -1
+    return
+  endif
+  let indent = emmet#getIndentation('css')
+  if content =~# '.*\<width\s*:[^;]*;.*'
+    let content = substitute(content, '\<width\s*:[^;]*;', 'width: ' . width . 'px;', '')
+  else
+    let content = substitute(content, '}', indent . 'width: ' . width . "px;\n}", '')
+  endif
+  if content =~# '.*\<height\s*:[^;]*;.*'
+    let content = substitute(content, '\<height\s*:[^;]*;', 'height: ' . height . 'px;', '')
+  else
+    let content = substitute(content, '}', indent . 'height: ' . height . "px;\n}", '')
+  endif
+  call emmet#util#setContent(img_region, content)
+endfunction
+
+function! emmet#lang#css#imageEncode() abort
+  let img_region = emmet#util#searchRegion('url(', ')')
+  if !emmet#util#regionIsValid(img_region) || !emmet#util#cursorInRegion(img_region)
+    return
+  endif
+  let content = emmet#util#getContent(img_region)
+  let fn = matchstr(content, '\<url(\zs[^)]\+\ze)')
+  let fn = substitute(fn, '[''" \t]', '', 'g')
+  if fn =~# '^\s*$'
+    return
+  elseif fn !~# '^\(/\|http\)'
+    let fn = simplify(expand('%:h') . '/' . fn)
+  endif
+  let encoded = emmet#util#imageEncodeDecode(fn, 0)
+  call emmet#util#setContent(img_region, 'url(' . encoded . ')')
+endfunction
+
+function! emmet#lang#css#parseTag(tag) abort
+  return {}
+endfunction
+
+function! emmet#lang#css#toggleComment() abort
+  let line = getline('.')
+  let mx = '^\(\s*\)/\*\s*\(.*\)\s*\*/\s*$'
+  if line =~# '{\s*$'
+    let block = emmet#util#searchRegion('/\*', '\*/\zs')
+    if emmet#util#regionIsValid(block)
+      let content = emmet#util#getContent(block)
+      let content = substitute(content, '/\*\s\(.*\)\s\*/', '\1', '')
+      call emmet#util#setContent(block, content)
+    else
+      let node = expand('<cword>')
+      if len(node)
+        exe "normal ciw\<c-r>='/* '.node.' */'\<cr>"
+      endif
+    endif
+  else
+    if line =~# mx
+      let space = substitute(matchstr(line, mx), mx, '\1', '')
+      let line = substitute(matchstr(line, mx), mx, '\2', '')
+      let line = space . substitute(line, '^\s*\|\s*$', '\1', 'g')
+    else
+      let mx = '^\(\s*\)\(''[^'']*''\|[^'']*\|;\)\s*$'
+      " TODO multi-property
+      "let mx = '^\(\s*\)\(\%(''[^'']*''\|[^'';]\+\)*;\{0,1}\)'
+      let line = substitute(line, mx, '\1/* \2 */', '')
+    endif
+    call setline('.', line)
+  endif
+endfunction
+
+function! emmet#lang#css#balanceTag(flag) range abort
+  if a:flag == -2 || a:flag == 2
+    let curpos = [0, line("'<"), col("'<"), 0]
+  else
+    let curpos = emmet#util#getcurpos()
+  endif
+  let block = emmet#util#getVisualBlock()
+  if !emmet#util#regionIsValid(block)
+    if a:flag > 0
+      let block = emmet#util#searchRegion('^', ';')
+      if emmet#util#regionIsValid(block)
+        call emmet#util#selectRegion(block)
+        return
+      endif
+    endif
+  else
+    if a:flag > 0
+      let content = emmet#util#getContent(block)
+      if content !~# '^{.*}$'
+        let block = emmet#util#searchRegion('{', '}')
+        if emmet#util#regionIsValid(block)
+          call emmet#util#selectRegion(block)
+          return
+        endif
+      endif
+    else
+      let pos = searchpos('.*;', 'nW')
+      if pos[0] != 0
+        call setpos('.', [0, pos[0], pos[1], 0])
+        let block = emmet#util#searchRegion('^', ';')
+        if emmet#util#regionIsValid(block)
+          call emmet#util#selectRegion(block)
+          return
+        endif
+      endif
+    endif
+  endif
+  if a:flag == -2 || a:flag == 2
+    silent! exe 'normal! gv'
+  else
+    call setpos('.', 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
diff --git a/config/vim/autoload/emmet/lang/elm.vim b/config/vim/autoload/emmet/lang/elm.vim
new file mode 100644
index 0000000..ce663bd
--- /dev/null
+++ b/config/vim/autoload/emmet/lang/elm.vim
@@ -0,0 +1,241 @@
+function! emmet#lang#elm#findTokens(str) abort
+  return emmet#lang#html#findTokens(a:str)
+endfunction
+
+function! emmet#lang#elm#parseIntoTree(abbr, type) abort
+  let tree = emmet#lang#html#parseIntoTree(a:abbr, a:type)
+  if len(tree.child) < 2 | return tree | endif
+
+  " Add ',' nodes between root elements.
+  let new_children = []
+  for child in tree.child[0:-2]
+    let comma = emmet#newNode()
+    let comma.name = ','
+    call add(new_children, child)
+    call add(new_children, comma)
+  endfor
+  call add(new_children, tree.child[-1])
+  let tree.child = new_children
+  return tree
+endfunction
+
+function! emmet#lang#elm#renderNode(node)
+  let elm_nodes = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'
+        \, 'div', 'p', 'hr', 'pre', 'blockquote'
+        \, 'span', 'a', 'code', 'em', 'strong', 'i', 'b', 'u', 'sub', 'sup', 'br'
+        \, 'ol', 'ul', 'li', 'dl', 'dt', 'dd'
+        \, 'img', 'iframe', 'canvas', 'math'
+        \, 'form', 'input', 'textarea', 'button', 'select', 'option'
+        \, 'section', 'nav', 'article', 'aside', 'header', 'footer', 'address', 'main_', 'body'
+        \, 'figure', 'figcaption'
+        \, 'table', 'caption', 'colgroup', 'col', 'tbody', 'thead', 'tfoot', 'tr', 'td', 'th'
+        \, 'fieldset', 'legend', 'label', 'datalist', 'optgroup', 'keygen', 'output', 'progress', 'meter'
+        \, 'audio', 'video', 'source', 'track'
+        \, 'embed', 'object', 'param'
+        \, 'ins', 'del'
+        \, 'small', 'cite', 'dfn', 'abbr', 'time', 'var', 'samp', 'kbd', 's', 'q'
+        \, 'mark', 'ruby', 'rt', 'rp', 'bdi', 'bdo', 'wbr'
+        \, 'details', 'summary', 'menuitem', 'menu']
+
+  if index(elm_nodes, a:node) >= 0
+    return a:node
+  endif
+  return 'node "' . a:node . '"'
+endfunction
+
+function! emmet#lang#elm#renderParam(param)
+  let elm_events = ["onClick", "onDoubleClick"
+        \, "onMouseDown", "onMouseUp"
+        \, "onMouseEnter", "onMouseLeave"
+        \, "onMouseOver", "onMouseOut"
+        \, "onInput", "onCheck", "onSubmit"
+        \, "onBlur", "onFocus"
+        \, "on", "onWithOptions", "Options", "defaultOptions"
+        \, "targetValue", "targetChecked", "keyCode"]
+  if index(elm_events, a:param) >= 0
+    return a:param
+  endif
+  let elm_attributes = ["style", "map" , "class", "id", "title", "hidden"
+        \, "type", "type_", "value", "defaultValue", "checked", "placeholder", "selected"
+        \, "accept", "acceptCharset", "action", "autocomplete", "autofocus"
+        \, "disabled", "enctype", "formaction", "list", "maxlength", "minlength", "method", "multiple"
+        \, "name", "novalidate", "pattern", "readonly", "required", "size", "for", "form"
+        \, "max", "min", "step"
+        \, "cols", "rows", "wrap"
+        \, "href", "target", "download", "downloadAs", "hreflang", "media", "ping", "rel"
+        \, "ismap", "usemap", "shape", "coords"
+        \, "src", "height", "width", "alt"
+        \, "autoplay", "controls", "loop", "preload", "poster", "default", "kind", "srclang"
+        \, "sandbox", "seamless", "srcdoc"
+        \, "reversed", "start"
+        \, "align", "colspan", "rowspan", "headers", "scope"
+        \, "async", "charset", "content", "defer", "httpEquiv", "language", "scoped"
+        \, "accesskey", "contenteditable", "contextmenu", "dir", "draggable", "dropzone"
+        \, "itemprop", "lang", "spellcheck", "tabindex"
+        \, "challenge", "keytype"
+        \, "cite", "datetime", "pubdate", "manifest"]
+
+  if index(elm_attributes, a:param) >= 0
+    if a:param == 'type'
+      return 'type_'
+    endif
+    return a:param
+  endif
+  return 'attribute "' . a:param . '"'
+endfunction
+
+function! emmet#lang#elm#toString(settings, current, type, inline, filters, itemno, indent) abort
+  let settings = a:settings
+  let current = a:current
+  let type = a:type
+  let inline = a:inline
+  let filters = a:filters
+  let itemno = a:itemno
+  let indent = emmet#getIndentation(type)
+  let dollar_expr = emmet#getResource(type, 'dollar_expr', 1)
+  let str = ''
+
+  " comma between items with *, eg. li*3
+  if itemno > 0
+    let str = ", "
+  endif
+
+  let current_name = current.name
+  if dollar_expr
+    let current_name = substitute(current.name, '\$$', itemno+1, '')
+  endif
+
+  if len(current.name) > 0
+    " inserted root comma nodes
+    if current_name == ','
+      return "\n, "
+    endif
+    let str .= emmet#lang#elm#renderNode(current_name)
+    let tmp = ''
+    for attr in emmet#util#unique(current.attrs_order + keys(current.attr))
+      if !has_key(current.attr, attr)
+        continue
+      endif
+      let Val = current.attr[attr]
+
+      let attr = emmet#lang#elm#renderParam(attr)
+
+      if type(Val) == 2 && Val == function('emmet#types#true')
+        let tmp .= ', ' . attr . ' True'
+      else
+        if dollar_expr
+          while Val =~# '\$\([^#{]\|$\)'
+            let Val = substitute(Val, '\(\$\+\)\([^{]\|$\)', '\=printf("%0".len(submatch(1))."d", itemno+1).submatch(2)', 'g')
+          endwhile
+          let attr = substitute(attr, '\$$', itemno+1, '')
+        endif
+        let valtmp = substitute(Val, '\${cursor}', '', '')
+        if attr ==# 'id' && len(valtmp) > 0
+          let tmp .=', id "' . Val . '"'
+        elseif attr ==# 'class' && len(valtmp) > 0
+          let tmp .= ', class "' . substitute(Val, '\.', ' ', 'g') . '"'
+        else
+          let tmp .= ', ' . attr . ' "' . Val . '"'
+        endif
+      endif
+    endfor
+
+    if ! len(tmp)
+      let str .= ' []'
+    else
+      let tmp = strpart(tmp, 2)
+      let str .= ' [ ' . tmp . ' ]'
+    endif
+
+    " No children quit early
+    if len(current.child) == 0 && len(current.value) == 0
+      "Place cursor in node with no value or children
+      let str .= ' [${cursor}]'
+      return str
+    endif
+
+    let inner = ''
+
+    " Parent contex text
+    if len(current.value) > 0
+      let text = current.value[1:-2]
+      if dollar_expr
+        let text = substitute(text, '\%(\\\)\@\<!\(\$\+\)\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d", itemno+1).submatch(2)', 'g')
+        let text = substitute(text, '\${nr}', "\n", 'g')
+        let text = substitute(text, '\\\$', '$', 'g')
+        " let str = substitute(str, '\$#', text, 'g')
+        let inner .= ', text "' . text . '"'
+      endif
+    endif
+
+
+    " Has children
+    for child in current.child
+      if len(child.name) == 0 && len(child.value) > 0
+        "  Text node
+        let text = child.value[1:-2]
+        if dollar_expr
+          let text = substitute(text, '\%(\\\)\@\<!\(\$\+\)\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d", itemno+1).submatch(2)', 'g')
+          let text = substitute(text, '\${nr}', "\n", 'g')
+          let text = substitute(text, '\\\$', '$', 'g')
+        endif
+        let inner .= ', text "' . text . '"'
+      else
+        " Other nodes
+        let inner .= ', ' . emmet#toString(child, type, inline, filters, 0, indent)
+      endif
+    endfor
+
+    let inner = substitute(inner, "\n", "\n" . escape(indent, '\'), 'g')
+    let inner = substitute(inner, "\n" . escape(indent, '\') . '$', '', 'g')
+    let inner = strpart(inner, 2)
+
+    let inner = substitute(inner, '  ', '', 'g')
+
+    if ! len(inner)
+      let str .= ' []'
+    else
+      let str .= ' [ ' . inner . ' ]'
+    endif
+
+  else
+    let str = current.value[1:-2]
+    if dollar_expr
+      let str = substitute(str, '\%(\\\)\@\<!\(\$\+\)\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d", itemno+1).submatch(2)', 'g')
+      let str = substitute(str, '\${nr}', "\n", 'g')
+      let str = substitute(str, '\\\$', '$', 'g')
+    endif
+  endif
+
+  let str .= "\n"
+  return str
+endfunction
+
+function! emmet#lang#elm#imageEncode() abort
+endfunction
+
+function! emmet#lang#elm#parseTag(tag) abort
+  return {}
+endfunction
+
+function! emmet#lang#elm#toggleComment() abort
+endfunction
+
+function! emmet#lang#elm#balanceTag(flag) range abort
+endfunction
+
+function! emmet#lang#elm#moveNextPrevItem(flag) abort
+  return emmet#lang#elm#moveNextPrev(a:flag)
+endfunction
+
+function! emmet#lang#elm#moveNextPrev(flag) abort
+endfunction
+
+function! emmet#lang#elm#splitJoinTag() abort
+endfunction
+
+function! emmet#lang#elm#removeTag() abort
+endfunction
+
+function! emmet#lang#elm#mergeLines() abort
+endfunction
diff --git a/config/vim/autoload/emmet/lang/haml.vim b/config/vim/autoload/emmet/lang/haml.vim
new file mode 100644
index 0000000..7ea97d1
--- /dev/null
+++ b/config/vim/autoload/emmet/lang/haml.vim
@@ -0,0 +1,337 @@
+function! emmet#lang#haml#findTokens(str) abort
+  return emmet#lang#html#findTokens(a:str)
+endfunction
+
+function! emmet#lang#haml#parseIntoTree(abbr, type) abort
+  return emmet#lang#html#parseIntoTree(a:abbr, a:type)
+endfunction
+
+function! emmet#lang#haml#toString(settings, current, type, inline, filters, itemno, indent) abort
+  let settings = a:settings
+  let current = a:current
+  let type = a:type
+  let inline = a:inline
+  let filters = a:filters
+  let itemno = a:itemno
+  let indent = emmet#getIndentation(type)
+  let dollar_expr = emmet#getResource(type, 'dollar_expr', 1)
+  let attribute_style = emmet#getResource('haml', 'attribute_style', 'hash')
+  let str = ''
+
+  let current_name = current.name
+  if dollar_expr
+    let current_name = substitute(current.name, '\$$', itemno+1, '')
+  endif
+  if len(current.name) > 0
+    let str .= '%' . current_name
+    let tmp = ''
+    for attr in emmet#util#unique(current.attrs_order + keys(current.attr))
+      if !has_key(current.attr, attr)
+        continue
+      endif
+      let Val = current.attr[attr]
+      if type(Val) == 2 && Val == function('emmet#types#true')
+        if attribute_style ==# 'hash'
+          let tmp .= ' :' . attr . ' => true'
+        elseif attribute_style ==# 'html'
+          let tmp .= attr . '=true'
+        end
+      else
+        if dollar_expr
+          while Val =~# '\$\([^#{]\|$\)'
+            let Val = substitute(Val, '\(\$\+\)\([^{]\|$\)', '\=printf("%0".len(submatch(1))."d", itemno+1).submatch(2)', 'g')
+          endwhile
+          let attr = substitute(attr, '\$$', itemno+1, '')
+        endif
+        let valtmp = substitute(Val, '\${cursor}', '', '')
+        if attr ==# 'id' && len(valtmp) > 0
+          let str .= '#' . Val
+        elseif attr ==# 'class' && len(valtmp) > 0
+          let str .= '.' . substitute(Val, ' ', '.', 'g')
+        else
+          if len(tmp) > 0 
+            if attribute_style ==# 'hash'
+              let tmp .= ',' 
+            elseif attribute_style ==# 'html'
+              let tmp .= ' ' 
+            endif
+          endif
+          if attribute_style ==# 'hash'
+            let tmp .= ' :' . attr . ' => "' . Val . '"'
+          elseif attribute_style ==# 'html'
+            let tmp .= attr . '="' . Val . '"'
+          end
+        endif
+      endif
+    endfor
+    if len(tmp)
+      if attribute_style ==# 'hash'
+        let str .= '{' . tmp . ' }'
+      elseif attribute_style ==# 'html'
+        let str .= '(' . tmp . ')'
+      end
+    endif
+    if stridx(','.settings.html.empty_elements.',', ','.current_name.',') != -1 && len(current.value) == 0
+      let str .= '/'
+    endif
+
+    let inner = ''
+    if len(current.value) > 0
+      let text = current.value[1:-2]
+      if dollar_expr
+        let text = substitute(text, '\%(\\\)\@\<!\(\$\+\)\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d", itemno+1).submatch(2)', 'g')
+        let text = substitute(text, '\${nr}', "\n", 'g')
+        let text = substitute(text, '\\\$', '$', 'g')
+        let str = substitute(str, '\$#', text, 'g')
+      endif
+      let lines = split(text, "\n")
+      if len(lines) == 1
+        let str .= ' ' . text
+      else
+        for line in lines
+          let str .= "\n" . indent . line . ' |'
+        endfor
+      endif
+    elseif len(current.child) == 0
+      let str .= '${cursor}'
+    endif
+    if len(current.child) == 1 && len(current.child[0].name) == 0
+      let text = current.child[0].value[1:-2]
+      if dollar_expr
+        let text = substitute(text, '\%(\\\)\@\<!\(\$\+\)\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d", itemno+1).submatch(2)', 'g')
+        let text = substitute(text, '\${nr}', "\n", 'g')
+        let text = substitute(text, '\\\$', '$', 'g')
+      endif
+      let lines = split(text, "\n")
+      if len(lines) == 1
+        let str .= ' ' . text
+      else
+        for line in lines
+          let str .= "\n" . indent . line . ' |'
+        endfor
+      endif
+    elseif len(current.child) > 0
+      for child in current.child
+        let inner .= emmet#toString(child, type, inline, filters, itemno, indent)
+      endfor
+      let inner = substitute(inner, "\n", "\n" . escape(indent, '\'), 'g')
+      let inner = substitute(inner, "\n" . escape(indent, '\') . '$', '', 'g')
+      let str .= "\n" . indent . inner
+    endif
+  else
+    let str = current.value[1:-2]
+    if dollar_expr
+      let str = substitute(str, '\%(\\\)\@\<!\(\$\+\)\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d", itemno+1).submatch(2)', 'g')
+      let str = substitute(str, '\${nr}', "\n", 'g')
+      let str = substitute(str, '\\\$', '$', 'g')
+    endif
+  endif
+  let str .= "\n"
+  return str
+endfunction
+
+function! emmet#lang#haml#imageSize() abort
+  let line = getline('.')
+  let current = emmet#lang#haml#parseTag(line)
+  if empty(current) || !has_key(current.attr, 'src')
+    return
+  endif
+  let fn = current.attr.src
+  if fn =~# '^\s*$'
+    return
+  elseif fn !~# '^\(/\|http\)'
+    let fn = simplify(expand('%:h') . '/' . fn)
+  endif
+
+  let [width, height] = emmet#util#getImageSize(fn)
+  if width == -1 && height == -1
+    return
+  endif
+  let current.attr.width = width
+  let current.attr.height = height
+  let current.attrs_order += ['width', 'height']
+  let haml = emmet#toString(current, 'haml', 1)
+  let haml = substitute(haml, '\${cursor}', '', '')
+  call setline('.', substitute(matchstr(line, '^\s*') . haml, "\n", '', 'g'))
+endfunction
+
+function! emmet#lang#haml#imageEncode() abort
+endfunction
+
+function! emmet#lang#haml#parseTag(tag) abort
+  let current = emmet#newNode()
+  let mx = '%\([a-zA-Z][a-zA-Z0-9]*\)\s*\%({\(.*\)}\)'
+  let match = matchstr(a:tag, mx)
+  let current.name = substitute(match, mx, '\1', '')
+  let attrs = substitute(match, mx, '\2', '')
+  let mx = '\([a-zA-Z0-9]\+\)\s*=>\s*\%(\([^"'' \t]\+\)\|"\([^"]\{-}\)"\|''\([^'']\{-}\)''\)'
+  while len(attrs) > 0
+    let match = matchstr(attrs, mx)
+    if len(match) ==# 0
+      break
+    endif
+    let attr_match = matchlist(match, mx)
+    let name = attr_match[1]
+    let value = len(attr_match[2]) ? attr_match[2] : attr_match[3]
+    let current.attr[name] = value
+    let current.attrs_order += [name]
+    let attrs = attrs[stridx(attrs, match) + len(match):]
+  endwhile
+  return current
+endfunction
+
+function! emmet#lang#haml#toggleComment() abort
+  let line = getline('.')
+  let space = matchstr(line, '^\s*')
+  if line =~# '^\s*-#'
+    call setline('.', space . matchstr(line[len(space)+2:], '^\s*\zs.*'))
+  elseif line =~# '^\s*%[a-z]'
+    call setline('.', space . '-# ' . line[len(space):])
+  endif
+endfunction
+
+function! emmet#lang#haml#balanceTag(flag) range abort
+  let block = emmet#util#getVisualBlock()
+  if a:flag == -2 || a:flag == 2
+    let curpos = [0, line("'<"), col("'<"), 0]
+  else
+    let curpos = emmet#util#getcurpos()
+  endif
+  let n = curpos[1]
+  let ml = len(matchstr(getline(n), '^\s*'))
+
+  if a:flag > 0
+    if a:flag == 1 || !emmet#util#regionIsValid(block)
+      let n = line('.')
+    else
+      while n > 0
+        let l = len(matchstr(getline(n), '^\s*\ze%[a-z]'))
+        if l > 0 && l < ml
+          let ml = l
+          break
+        endif
+        let n -= 1
+      endwhile
+    endif
+    let sn = n
+    if n == 0
+      let ml = 0
+    endif
+    while n < line('$')
+      let l = len(matchstr(getline(n), '^\s*%[a-z]'))
+      if l > 0 && l <= ml
+        let n -= 1
+        break
+      endif
+      let n += 1
+    endwhile
+    call setpos('.', [0, n, 1, 0])
+    normal! V
+    call setpos('.', [0, sn, 1, 0])
+  else
+    while n > 0
+      let l = len(matchstr(getline(n), '^\s*\ze[a-z]'))
+      if l > 0 && l > ml
+        let ml = l
+        break
+      endif
+      let n += 1
+    endwhile
+    let sn = n
+    if n == 0
+      let ml = 0
+    endif
+    while n < line('$')
+      let l = len(matchstr(getline(n), '^\s*%[a-z]'))
+      if l > 0 && l <= ml
+        let n -= 1
+        break
+      endif
+      let n += 1
+    endwhile
+    call setpos('.', [0, n, 1, 0])
+    normal! V
+    call setpos('.', [0, sn, 1, 0])
+  endif
+endfunction
+
+function! emmet#lang#haml#moveNextPrevItem(flag) abort
+  return emmet#lang#haml#moveNextPrev(a:flag)
+endfunction
+
+function! emmet#lang#haml#moveNextPrev(flag) abort
+  let pos = search('""', a:flag ? 'Wb' : 'W')
+  if pos != 0
+    silent! normal! l
+    startinsert
+  endif
+endfunction
+
+function! emmet#lang#haml#splitJoinTag() abort
+  let n = line('.')
+  let sml = len(matchstr(getline(n), '^\s*%[a-z]'))
+  while n > 0
+    if getline(n) =~# '^\s*\ze%[a-z]'
+      if len(matchstr(getline(n), '^\s*%[a-z]')) < sml
+        break
+      endif
+      let line = getline(n)
+      call setline(n, substitute(line, '^\s*%\w\+\%(\s*{[^}]*}\|\s\)\zs.*', '', ''))
+      let sn = n
+      let n += 1
+      let ml = len(matchstr(getline(n), '^\s*%[a-z]'))
+      if len(matchstr(getline(n), '^\s*')) > ml
+        while n <= line('$')
+          let l = len(matchstr(getline(n), '^\s*'))
+          if l <= ml
+            break
+          endif
+          exe n 'delete'
+        endwhile
+        call setpos('.', [0, sn, 1, 0])
+      else
+        let tag = matchstr(getline(sn), '^\s*%\zs\(\w\+\)')
+        let spaces = matchstr(getline(sn), '^\s*')
+        let settings = emmet#getSettings()
+        if stridx(','.settings.html.inline_elements.',', ','.tag.',') == -1
+          call append(sn, spaces . '   ')
+          call setpos('.', [0, sn+1, 1, 0])
+        else
+          call setpos('.', [0, sn, 1, 0])
+        endif
+        startinsert!
+      endif
+      break
+    endif
+    let n -= 1
+  endwhile
+endfunction
+
+function! emmet#lang#haml#removeTag() abort
+  let n = line('.')
+  let ml = 0
+  while n > 0
+    if getline(n) =~# '^\s*\ze[a-z]'
+      let ml = len(matchstr(getline(n), '^\s*%[a-z]'))
+      break
+    endif
+    let n -= 1
+  endwhile
+  let sn = n
+  while n < line('$')
+    let l = len(matchstr(getline(n), '^\s*%[a-z]'))
+    if l > 0 && l <= ml
+      let n -= 1
+      break
+    endif
+    let n += 1
+  endwhile
+  if sn == n
+    exe 'delete'
+  else
+    exe sn ',' (n-1) 'delete'
+  endif
+endfunction
+
+function! emmet#lang#haml#mergeLines() abort
+endfunction
diff --git a/config/vim/autoload/emmet/lang/html.vim b/config/vim/autoload/emmet/lang/html.vim
new file mode 100644
index 0000000..fad887a
--- /dev/null
+++ b/config/vim/autoload/emmet/lang/html.vim
@@ -0,0 +1,1036 @@
+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 str = a:str
+  let [pos, last_pos] = [0, 0]
+  while 1
+    let tag = matchstr(str, '<[a-zA-Z].\{-}>', pos)
+    if len(tag) == 0
+      break
+    endif
+    let pos = stridx(str, tag, pos) + len(tag)
+  endwhile
+  while 1
+    let tag = matchstr(str, '{%[^%]\{-}%}', pos)
+    if len(tag) == 0
+      break
+    endif
+    let pos = stridx(str, tag, pos) + len(tag)
+  endwhile
+  let last_pos = pos
+  while len(str) > 0
+    let white = matchstr(str, '^\s\+', pos)
+    if white != ''
+      let last_pos = pos + len(white)
+	  let pos = last_pos
+    endif
+    let token = matchstr(str, s:mx, pos)
+    if token ==# ''
+      break
+    endif
+    let pos = stridx(str, token, pos) + len(token)
+  endwhile
+  let str = a:str[last_pos :-1]
+  if str =~# '^\w\+="[^"]*$'
+    return ''
+  endif
+  return str
+endfunction
+
+function! emmet#lang#html#parseIntoTree(abbr, type) abort
+  let abbr = a:abbr
+  let type = a:type
+
+  let settings = emmet#getSettings()
+  if !has_key(settings, type)
+    let type = 'html'
+  endif
+  if len(type) == 0 | let type = 'html' | endif
+
+  let indent = emmet#getIndentation(type)
+  let 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 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 custom_expands = emmet#getResource(type, 'custom_expands', {})
+  if empty(custom_expands) && has_key(settings, 'custom_expands')
+    let custom_expands = settings['custom_expands']
+  endif
+
+  " try 'foo' to (foo-x)
+  let rabbr = emmet#getExpandos(type, abbr)
+  if rabbr == abbr
+    " try 'foo+(' to (foo-x)
+    let rabbr = substitute(abbr, '\%(+\|^\)\([a-zA-Z][a-zA-Z0-9+]\+\)+\([(){}>]\|$\)', '\="(".emmet#getExpandos(type, submatch(1)).")".submatch(2)', 'i')
+  endif
+  let abbr = rabbr
+
+  let root = emmet#newNode()
+  let root['variables'] = {}
+  let parent = root
+  let last = root
+  let pos = []
+  while len(abbr)
+    " parse line
+    let match = matchstr(abbr, s:mx)
+    let str = substitute(match, s:mx, '\0', 'ig')
+    let operator = substitute(match, s:mx, '\1', 'ig')
+    let block_start = substitute(match, s:mx, '\2', 'ig')
+    let tag_name = substitute(match, s:mx, '\3', 'ig')
+    let attributes = substitute(match, s:mx, '\4', 'ig')
+    let value = substitute(match, s:mx, '\5', 'ig')
+    let basevalue = substitute(match, s:mx, '\6', 'ig')
+    let multiplier = 0 + substitute(match, s:mx, '\7', 'ig')
+    let block_end = substitute(match, s:mx, '\8', 'ig')
+    let custom = ''
+    let important = 0
+    if len(str) == 0
+      break
+    endif
+    if tag_name =~# '^#'
+      let attributes = tag_name . attributes
+      let tag_name = ''
+    endif
+    if tag_name =~# '[^!]!$'
+      let tag_name = tag_name[:-2]
+      let important = 1
+    endif
+    if tag_name =~# '^\.'
+      let attributes = tag_name . attributes
+      let tag_name = ''
+    endif
+    if tag_name =~# '^\[.*\]$'
+      let attributes = tag_name . attributes
+      let tag_name = ''
+    endif
+
+    for k in keys(custom_expands)
+      if tag_name =~ k
+        let custom = tag_name
+        let tag_name = ''
+        break
+      endif
+    endfor
+
+    if empty(tag_name)
+      let pname = len(parent.child) > 0 ? parent.child[0].name : ''
+      if !empty(pname) && has_key(pmap, pname) && custom == ''
+        let tag_name = pmap[pname]
+      elseif !empty(pname) && index(inlineLevel, pname) > -1
+        let tag_name = 'span'
+      elseif len(custom) == 0
+        let tag_name = 'div'
+      elseif len(custom) != 0 && multiplier > 1	
+        let tag_name = 'div'
+      else
+        let tag_name = custom
+      endif
+    endif
+
+    let basedirect = basevalue[1] ==# '-' ? -1 : 1
+    if basevalue != ''
+      let basevalue = 0 + abs(basevalue[1:])
+    else
+      let basevalue = 1
+    endif
+    if multiplier <= 0 | let multiplier = 1 | endif
+
+    " make default node
+    let current = emmet#newNode()
+
+    let current.name = tag_name
+    let current.important = important
+
+    " aliases
+    let aliases = emmet#getResource(type, 'aliases', {})
+    if has_key(aliases, tag_name)
+      let current.name = aliases[tag_name]
+    endif
+
+    let use_pipe_for_cursor = emmet#getResource(type, 'use_pipe_for_cursor', 1)
+
+    " snippets
+    let snippets = emmet#getResource(type, 'snippets', {})
+    if !empty(snippets)
+      let snippet_name = tag_name
+      if has_key(snippets, snippet_name)
+        let snippet = snippet_name
+        while has_key(snippets, snippet)
+          let snippet = snippets[snippet]
+        endwhile
+        if use_pipe_for_cursor
+          let snippet = substitute(snippet, '|', '${cursor}', 'g')
+        endif
+        " just redirect to expanding
+        if type == 'html' && snippet !~ '^\s*[{\[<]'
+           return emmet#lang#html#parseIntoTree(snippet, a:type)
+        endif
+        let lines = split(snippet, "\n", 1)
+        call map(lines, 'substitute(v:val, "\\(    \\|\\t\\)", escape(indent, "\\\\"), "g")')
+        let current.snippet = join(lines, "\n")
+        let current.name = ''
+      endif
+    endif
+
+    for k in keys(custom_expands)
+      if tag_name =~# k
+        let snippet = '${' . (empty(custom) ? tag_name : custom) . '}'
+        let current.name = ''
+        let current.snippet = snippet
+        break
+      elseif custom =~# k
+        let snippet = '${' . custom . '}'
+        let current.snippet = '${' . custom . '}'
+        if current.name != ''
+          let snode = emmet#newNode()
+          let snode.snippet = snippet
+          let snode.parent = current
+          call add(current.child, snode)
+        else
+          let current.snippet = snippet
+        endif
+        break
+      endif
+    endfor
+
+    " default_attributes
+    let default_attributes = emmet#getResource(type, 'default_attributes', {})
+    if !empty(default_attributes)
+      for pat in [current.name, tag_name]
+        if has_key(default_attributes, pat)
+          if type(default_attributes[pat]) == 4
+            let a = default_attributes[pat]
+            let current.attrs_order += keys(a)
+            if use_pipe_for_cursor
+              for k in keys(a)
+                if type(a[k]) == 7
+                  call remove(current.attr, k)
+                  continue
+                endif
+                let current.attr[k] = len(a[k]) ? substitute(a[k], '|', '${cursor}', 'g') : '${cursor}'
+              endfor
+            else
+              for k in keys(a)
+                if type(a[k]) == 7
+                  call remove(current.attr, k)
+                  continue
+                endif
+                let current.attr[k] = a[k]
+              endfor
+            endif
+          else
+            for a in default_attributes[pat]
+              let current.attrs_order += keys(a)
+              if use_pipe_for_cursor
+                for k in keys(a)
+                  if type(a[k]) == 7
+                    call remove(current.attr, k)
+                    continue
+                  endif
+                  let current.attr[k] = len(a[k]) ? substitute(a[k], '|', '${cursor}', 'g') : '${cursor}'
+                endfor
+              else
+                for k in keys(a)
+                  if type(a[k]) == 7
+                    call remove(current.attr, k)
+                    continue
+                  endif
+                  let current.attr[k] = a[k]
+                endfor
+              endif
+            endfor
+          endif
+          if has_key(settings.html.default_attributes, current.name)
+            let current.name = substitute(current.name, ':.*$', '', '')
+          endif
+          break
+        endif
+      endfor
+    endif
+
+    " parse attributes
+    if len(attributes)
+      let attr = attributes
+      while len(attr)
+        let item = matchstr(attr, '\(\%(\%(#[{}a-zA-Z0-9_\-\$]\+\)\|\%(\[\%(\[[^\]]*\]\|"[^"]*"\|[^"\[\]]*\)\+\]\)\|\%(\.[{}a-zA-Z0-9_\-\$]\+\)*\)\)')
+        if g:emmet_debug > 1
+          echomsg 'attr=' . item
+        endif
+        if len(item) == 0
+          break
+        endif
+        if item[0] ==# '#'
+          let current.attr.id = item[1:]
+          let root['variables']['id'] = current.attr.id
+        endif
+        if item[0] ==# '.'
+          let current.attr.class = substitute(item[1:], '\.', ' ', 'g')
+          let root['variables']['class'] = current.attr.class
+        endif
+        if item[0] ==# '['
+          let atts = item[1:-2]
+          if matchstr(atts, '^\s*\zs[0-9a-zA-Z_\-:]\+\(="[^"]*"\|=''[^'']*''\|=[^ ''"]\+\)') ==# ''
+            let ks = []
+			if has_key(default_attributes, current.name)
+              let dfa = default_attributes[current.name]
+              let ks = type(dfa) == 3 ? len(dfa) > 0 ? keys(dfa[0]) : [] : keys(dfa)
+            endif
+            if len(ks) == 0 && has_key(default_attributes, current.name . ':src')
+              let dfa = default_attributes[current.name . ':src']
+              let ks = type(dfa) == 3 ? len(dfa) > 0 ? keys(dfa[0]) : [] : keys(dfa)
+            endif
+            if len(ks) > 0
+              let current.attr[ks[0]] = atts
+            elseif atts =~# '\.$'
+              let current.attr[atts[:-2]] = function('emmet#types#true')
+            else
+              let current.attr[atts] = ''
+            endif
+          else
+            while len(atts)
+              let amat = matchstr(atts, '^\s*\zs\([0-9a-zA-Z-:]\+\%(={{.\{-}}}\|="[^"]*"\|=''[^'']*''\|=[^ ''"]\+\|[^ ''"\]]*\)\{0,1}\)')
+              if len(amat) == 0
+                break
+              endif
+              let key = split(amat, '=')[0]
+              let Val = amat[len(key)+1:]
+              if key =~# '\.$' && Val ==# ''
+                let key = key[:-2]
+                unlet Val
+                let Val = function('emmet#types#true')
+              elseif Val =~# '^["'']'
+                let Val = Val[1:-2]
+              endif
+              let current.attr[key] = Val
+              if index(current.attrs_order, key) == -1
+                let current.attrs_order += [key]
+              endif
+              let atts = atts[stridx(atts, amat) + len(amat):]
+              unlet Val
+            endwhile
+          endif
+        endif
+        let attr = substitute(strpart(attr, len(item)), '^\s*', '', '')
+      endwhile
+    endif
+
+    " parse text
+    if tag_name =~# '^{.*}$'
+      let current.name = ''
+      let current.value = tag_name
+    else
+      let current.value = value
+    endif
+    let current.basedirect = basedirect
+    let current.basevalue = basevalue
+    let current.multiplier = multiplier
+
+    " parse step inside/outside
+    if !empty(last)
+      if operator =~# '>'
+        unlet! parent
+        let parent = last
+        let current.parent = last
+        let current.pos = last.pos + 1
+      else
+        let current.parent = parent
+        let current.pos = last.pos
+      endif
+    else
+      let current.parent = parent
+      let current.pos = 1
+    endif
+    if operator =~# '[<^]'
+      for c in range(len(operator))
+        let tmp = parent.parent
+        if empty(tmp)
+          break
+        endif
+        let parent = tmp
+        let current.parent = tmp
+      endfor
+    endif
+
+    call add(parent.child, current)
+    let last = current
+
+    " parse block
+    if block_start =~# '('
+      if operator =~# '>'
+        let last.pos += 1
+      endif
+      let last.block = 1
+      for n in range(len(block_start))
+        let pos += [last.pos]
+      endfor
+    endif
+    if block_end =~# ')'
+      for n in split(substitute(substitute(block_end, ' ', '', 'g'), ')', ',),', 'g'), ',')
+        if n ==# ')'
+          if len(pos) > 0 && last.pos >= pos[-1]
+            for c in range(last.pos - pos[-1])
+              let tmp = parent.parent
+              if !has_key(tmp, 'parent')
+                break
+              endif
+              let parent = tmp
+            endfor
+            if len(pos) > 0
+              call remove(pos, -1)
+            endif
+            let last = parent
+            let last.pos += 1
+          endif
+        elseif len(n)
+          let st = 0
+          for nc in range(len(last.child))
+            if last.child[nc].block
+              let st = nc
+              break
+            endif
+          endfor
+          let cl = last.child[st :]
+          let cls = []
+          for c in range(n[1:])
+            for cc in cl
+              if cc.multiplier > 1
+                let cc.basedirect = c + 1
+              else
+                let cc.basevalue = c + 1
+              endif
+            endfor
+            let cls += deepcopy(cl)
+          endfor
+          if st > 0
+            let last.child = last.child[:st-1] + cls
+          else
+            let last.child = cls
+          endif
+        endif
+      endfor
+    endif
+    let abbr = abbr[stridx(abbr, match) + len(match):]
+    if abbr == '/'
+      let current.empty = 1
+    endif
+
+    if g:emmet_debug > 1
+      echomsg 'str='.str
+      echomsg 'block_start='.block_start
+      echomsg 'tag_name='.tag_name
+      echomsg 'operator='.operator
+      echomsg 'attributes='.attributes
+      echomsg 'value='.value
+      echomsg 'basevalue='.basevalue
+      echomsg 'multiplier='.multiplier
+      echomsg 'block_end='.block_end
+      echomsg 'abbr='.abbr
+      echomsg 'pos='.string(pos)
+      echomsg '---'
+    endif
+  endwhile
+  return 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 settings = a:settings
+  let current = a:current
+  let type = a:type
+  let inline = a:inline
+  let filters = a:filters
+  let itemno = a:itemno
+  let indent = a:indent
+  let dollar_expr = emmet#getResource(type, 'dollar_expr', 1)
+  let q = emmet#getResource(type, 'quote_char', '"')
+  let ct = emmet#getResource(type, 'comment_type', 'both')
+  let an = emmet#getResource(type, 'attribute_name', {})
+  let empty_elements = emmet#getResource(type, 'empty_elements', settings.html.empty_elements)
+  let empty_element_suffix = emmet#getResource(type, 'empty_element_suffix', settings.html.empty_element_suffix)
+
+  if emmet#useFilter(filters, 'haml')
+    return emmet#lang#haml#toString(settings, current, type, inline, filters, itemno, indent)
+  endif
+  if emmet#useFilter(filters, 'slim')
+    return emmet#lang#slim#toString(settings, current, type, inline, filters, itemno, indent)
+  endif
+
+  let comment = ''
+  let current_name = current.name
+  if dollar_expr
+    let current_name = substitute(current_name, '\$$', itemno+1, '')
+  endif
+
+  let str = ''
+  if len(current_name) == 0
+    let text = current.value[1:-2]
+    if dollar_expr
+      " TODO: regexp engine specified
+      let nr = itemno + 1
+      if exists('&regexpengine')
+        let text = substitute(text, '\%#=1\%(\\\)\@\<!\(\$\+\)\(@-\?[0-9]\+\)\{0,1}\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d",s:dollar_add(submatch(2)[1:],nr)).submatch(3)', 'g')
+      else
+        let text = substitute(text, '\%(\\\)\@\<!\(\$\+\)\(@-\?[0-9]\+\)\{0,1}\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d",s:dollar_add(submatch(2)[1:],nr).submatch(3)', 'g')
+      endif
+      let text = substitute(text, '\${nr}', "\n", 'g')
+      let text = substitute(text, '\\\$', '$', 'g')
+    endif
+    return text
+  endif
+  if len(current_name) > 0
+    let str .= '<' . current_name
+  endif
+  for attr in emmet#util#unique(current.attrs_order + keys(current.attr))
+    if !has_key(current.attr, attr)
+      continue
+    endif
+    let Val = current.attr[attr]
+    if type(Val) == 2 && Val == function('emmet#types#true')
+      unlet Val
+      let Val = 'true'
+      if g:emmet_html5
+        let str .= ' ' . attr
+      else
+        let str .= ' ' . attr . '=' . q . attr . q
+      endif
+      if emmet#useFilter(filters, 'c')
+        if attr ==# 'id' | let comment .= '#' . Val | endif
+        if attr ==# 'class' | let comment .= '.' . Val | endif
+      endif
+    else
+      if dollar_expr
+        while Val =~# '\$\([^#{]\|$\)'
+          " TODO: regexp engine specified
+          if exists('&regexpengine')
+            let Val = substitute(Val, '\%#=1\(\$\+\)\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d", itemno+1).submatch(2)', 'g')
+          else
+            let Val = substitute(Val, '\(\$\+\)\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d", itemno+1).submatch(2)', 'g')
+          endif
+        endwhile
+        let attr = substitute(attr, '\$$', itemno+1, '')
+      endif
+      if attr ==# 'class' && emmet#useFilter(filters, 'bem')
+        let vals = split(Val, '\s\+')
+        let Val = ''
+        let lead = ''
+        for _val in vals
+          if len(Val) > 0
+            let Val .= ' '
+          endif
+          if _val =~# '^_'
+            if has_key(current.parent.attr, 'class')
+              let lead = current.parent.attr["class"]
+              if _val =~# '^__'
+                let Val .= lead . _val
+              else
+                let Val .= lead . ' ' . lead . _val
+              endif
+            else
+              let lead = split(vals[0], '_')[0]
+              let Val .= lead . _val
+            endif
+          elseif _val =~# '^-'
+            for l in split(_val, '_')
+              if len(Val) > 0
+                let Val .= ' '
+              endif
+              let l = substitute(l, '^-', '__', '')
+              if len(lead) == 0
+                let pattr = current.parent.attr
+                if has_key(pattr, 'class')
+                  let lead = split(pattr['class'], '\s\+')[0]
+                endif
+              endif
+              let Val .= lead . l
+              let lead .= l . '_'
+            endfor
+          else
+            let Val .= _val
+          endif
+        endfor
+      endif
+      if has_key(an, attr)
+        let attr = an[attr]
+      endif
+      if emmet#isExtends(type, 'jsx') && Val =~ '^{.*}$'
+        let str .= ' ' . attr . '=' . Val
+      else
+        let str .= ' ' . attr . '=' . q . Val . q
+      endif
+      if emmet#useFilter(filters, 'c')
+        if attr ==# 'id' | let comment .= '#' . Val | endif
+        if attr ==# 'class' | let comment .= '.' . Val | endif
+      endif
+    endif
+    unlet Val
+  endfor
+  if len(comment) > 0 && ct ==# 'both'
+    let str = '<!-- ' . comment . " -->\n" . str
+  endif
+  if current.empty
+    let str .= ' />'
+  elseif stridx(','.empty_elements.',', ','.current_name.',') != -1
+    let str .= empty_element_suffix
+  else
+    let str .= '>'
+    let text = current.value[1:-2]
+    if dollar_expr
+      " TODO: regexp engine specified
+      let nr = itemno + 1
+      if exists('&regexpengine')
+        let text = substitute(text, '\%#=1\%(\\\)\@\<!\(\$\+\)\(@-\?[0-9]\+\)\{0,1}\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d",s:dollar_add(submatch(2)[1:],nr)).submatch(3)', 'g')
+      else
+        let text = substitute(text, '\%(\\\)\@\<!\(\$\+\)\(@-\?[0-9]\+\)\{0,1}\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d",s:dollar_add(submatch(2)[1:],nr)).submatch(3)', 'g')
+      endif
+      let text = substitute(text, '\${nr}', "\n", 'g')
+      let text = substitute(text, '\\\$', '$', 'g')
+      if text != ''
+        let str = substitute(str, '\("\zs$#\ze"\|\s\zs\$#"\|"\$#\ze\s\)', text, 'g')
+      endif
+    endif
+    let str .= text
+    let nc = len(current.child)
+    let dr = 0
+    if nc > 0
+      for n in range(nc)
+        let child = current.child[n]
+        if child.multiplier > 1 || (child.multiplier == 1 && len(child.child) > 0 && stridx(','.settings.html.inline_elements.',', ','.current_name.',') == -1) || settings.html.block_all_childless
+          let str .= "\n" . indent
+          let dr = 1
+        elseif len(current_name) > 0 && stridx(','.settings.html.inline_elements.',', ','.current_name.',') == -1
+          if nc > 1 || (len(child.name) > 0 && stridx(','.settings.html.inline_elements.',', ','.child.name.',') == -1)
+            let str .= "\n" . indent
+            let dr = 1
+          elseif current.multiplier == 1 && nc == 1 && len(child.name) == 0
+            let str .= "\n" . indent
+            let dr = 1
+          endif
+        endif
+        let inner = emmet#toString(child, type, 0, filters, itemno, indent)
+        let inner = substitute(inner, "^\n", '', 'g')
+        let inner = substitute(inner, "\n", "\n" . escape(indent, '\'), 'g')
+        let inner = substitute(inner, "\n" . escape(indent, '\') . '$', '', 'g')
+        let str .= inner
+      endfor
+    else
+      if settings.html.indent_blockelement && len(current_name) > 0 && stridx(','.settings.html.inline_elements.',', ','.current_name.',') == -1 || settings.html.block_all_childless
+        let str .= "\n" . indent . '${cursor}' . "\n"
+      else
+        let str .= '${cursor}'
+      endif
+    endif
+    if dr
+      let str .= "\n"
+    endif
+    let str .= '</' . current_name . '>'
+  endif
+  if len(comment) > 0
+    if ct ==# 'lastonly'
+      let str .= '<!-- ' . comment . ' -->'
+    else
+      let str .= "\n<!-- /" . comment . ' -->'
+    endif
+  endif
+  if len(current_name) > 0 && current.multiplier > 0 || stridx(','.settings.html.block_elements.',', ','.current_name.',') != -1
+    let str .= "\n"
+  endif
+  return str
+endfunction
+
+function! emmet#lang#html#imageSize() abort
+  let img_region = emmet#util#searchRegion('<img\s', '>')
+  if !emmet#util#regionIsValid(img_region) || !emmet#util#cursorInRegion(img_region)
+    return
+  endif
+  let content = emmet#util#getContent(img_region)
+  if content !~# '^<img[^><]\+>$'
+    return
+  endif
+  let current = emmet#lang#html#parseTag(content)
+  if empty(current) || !has_key(current.attr, 'src')
+    return
+  endif
+  let fn = current.attr.src
+  if fn =~# '^\s*$'
+    return
+  elseif fn !~# '^\(/\|http\)'
+    let fn = simplify(expand('%:h') . '/' . fn)
+  endif
+
+  let [width, height] = emmet#util#getImageSize(fn)
+  if width == -1 && height == -1
+    return
+  endif
+  let current.attr.width = width
+  let current.attr.height = height
+  let current.attrs_order += ['width', 'height']
+  let html = substitute(emmet#toString(current, 'html', 1), '\n', '', '')
+  let html = substitute(html, '\${cursor}', '', '')
+  call emmet#util#setContent(img_region, html)
+endfunction
+
+function! emmet#lang#html#imageEncode() abort
+  let img_region = emmet#util#searchRegion('<img\s', '>')
+  if !emmet#util#regionIsValid(img_region) || !emmet#util#cursorInRegion(img_region)
+    return
+  endif
+  let content = emmet#util#getContent(img_region)
+  if content !~# '^<img[^><]\+>$'
+    return
+  endif
+  let current = emmet#lang#html#parseTag(content)
+  if empty(current) || !has_key(current.attr, 'src')
+    return
+  endif
+  let fn = current.attr.src
+  if fn =~# '^\s*$'
+    return
+  elseif fn !~# '^\(/\|http\)'
+    let fn = simplify(expand('%:h') . '/' . fn)
+  endif
+
+  let encoded = emmet#util#imageEncodeDecode(fn, 0)
+  let current.attr.src = encoded
+  let content = substitute(emmet#toString(current, 'html', 1), '\n', '', '')
+  let content = substitute(content, '\${cursor}', '', '')
+  call emmet#util#setContent(img_region, content)
+endfunction
+
+function! emmet#lang#html#parseTag(tag) abort
+  let current = emmet#newNode()
+  let mx = '<\([a-zA-Z][a-zA-Z0-9]*\)\(\%(\s[a-zA-Z][a-zA-Z0-9]\+=\?\%([^"'' \t]\+\|"[^"]\{-}"\|''[^'']\{-}''\)\s*\)*\)\(/\{0,1}\)>'
+  let match = matchstr(a:tag, mx)
+  let current.name = substitute(match, mx, '\1', 'i')
+  let attrs = substitute(match, mx, '\2', 'i')
+  let mx = '\([a-zA-Z0-9]\+\)\(\(=[^"'' \t]\+\)\|="\([^"]\{-}\)"\|=''\([^'']\{-}\)''\)\?'
+  while len(attrs) > 0
+    let match = matchstr(attrs, mx)
+    if len(match) == 0
+      break
+    endif
+    let attr_match = matchlist(match, mx)
+    let name = attr_match[1]
+    if len(attr_match[2])
+      let Val = len(attr_match[3]) ? attr_match[3] : attr_match[4]
+    else
+      let Val = function('emmet#types#true')
+    endif
+    let current.attr[name] = Val
+    let current.attrs_order += [name]
+    let attrs = attrs[stridx(attrs, match) + len(match):]
+  endwhile
+  return current
+endfunction
+
+function! emmet#lang#html#toggleComment() abort
+  let orgpos = getpos('.')
+  let curpos = getpos('.')
+  let mx = '<\%#[^>]*>'
+  while 1
+    let block = emmet#util#searchRegion('<!--', '-->')
+    if emmet#util#regionIsValid(block)
+      let block[1][1] += 2
+      let content = emmet#util#getContent(block)
+      let content = substitute(content, '^<!--\s\(.*\)\s-->$', '\1', '')
+      call emmet#util#setContent(block, content)
+      silent! call setpos('.', orgpos)
+      return
+    endif
+    let block = emmet#util#searchRegion('<[^>]', '>')
+    if !emmet#util#regionIsValid(block)
+      let pos1 = searchpos('<', 'bcW')
+      if pos1[0] == 0 && pos1[1] == 0
+        return
+      endif
+      let curpos = getpos('.')
+      continue
+    endif
+    let pos1 = block[0]
+    let pos2 = block[1]
+    let content = emmet#util#getContent(block)
+    let tag_name = matchstr(content, '^<\zs/\{0,1}[^ \r\n>]\+')
+    if tag_name[0] ==# '/'
+      call setpos('.', [0, pos1[0], pos1[1], 0])
+      let pos2 = searchpairpos('<'. tag_name[1:] . '\>[^/>]*>', '', '</' . tag_name[1:] . '>', 'bnW')
+      let pos1 = searchpos('>', 'cneW')
+      let block = [pos2, pos1]
+    elseif tag_name =~# '/$'
+      if !emmet#util#pointInRegion(orgpos[1:2], block)
+        " it's broken tree
+        call setpos('.', orgpos)
+        let block = emmet#util#searchRegion('>', '<')
+        let content = '><!-- ' . emmet#util#getContent(block)[1:-2] . ' --><'
+        call emmet#util#setContent(block, content)
+        silent! call setpos('.', orgpos)
+        return
+      endif
+    else
+      call setpos('.', [0, pos2[0], pos2[1], 0])
+      let pos3 = searchpairpos('<'. tag_name . '\>[^/>]*>', '', '</' . tag_name . '>', 'nW')
+      if pos3 == [0, 0]
+        let block = [pos1, pos2]
+      else
+        call setpos('.', [0, pos3[0], pos3[1], 0])
+        let pos2 = searchpos('>', 'neW')
+        let block = [pos1, pos2]
+      endif
+    endif
+    if !emmet#util#regionIsValid(block)
+      silent! call setpos('.', orgpos)
+      return
+    endif
+    if emmet#util#pointInRegion(curpos[1:2], block)
+      let content = '<!-- ' . emmet#util#getContent(block) . ' -->'
+      call emmet#util#setContent(block, content)
+      silent! call setpos('.', orgpos)
+      return
+    endif
+  endwhile
+endfunction
+
+function! emmet#lang#html#balanceTag(flag) range abort
+  let vblock = emmet#util#getVisualBlock()
+  let curpos = emmet#util#getcurpos()
+  let settings = emmet#getSettings()
+
+  if a:flag > 0
+    let mx = '<\([a-zA-Z][a-zA-Z0-9:_\-]*\)[^>]*'
+    let last = curpos[1:2]
+    while 1
+      let pos1 = searchpos(mx, 'bW')
+      let content = matchstr(getline(pos1[0])[pos1[1]-1:], mx)
+      let tag_name = matchstr(content, '^<\zs[a-zA-Z0-9:_\-]*\ze')
+      if stridx(','.settings.html.empty_elements.',', ','.tag_name.',') != -1
+        let pos2 = searchpos('>', 'nW')
+      else
+        let pos2 = searchpairpos('<' . tag_name . '[^>]*>', '', '</'. tag_name . '\zs>', 'nW')
+      endif
+      let block = [pos1, pos2]
+      if pos1 == [0, 0]
+        break
+      endif
+      if emmet#util#pointInRegion(last, block) && emmet#util#regionIsValid(block)
+        call emmet#util#selectRegion(block)
+        return
+      endif
+      if pos1 == last
+        break
+      endif
+      let last = pos1
+    endwhile
+  else
+    let mx = '<\([a-zA-Z][a-zA-Z0-9:_\-]*\)[^>]*>'
+    while 1
+      let pos1 = searchpos(mx, 'W')
+      if pos1 == [0, 0] || pos1 == curpos[1:2]
+        let pos1 = searchpos('>\zs', 'W')
+        let pos2 = searchpos('.\ze<', 'W')
+        let block = [pos1, pos2]
+        if emmet#util#regionIsValid(block)
+          call emmet#util#selectRegion(block)
+          return
+        endif
+      endif
+      let content = matchstr(getline(pos1[0])[pos1[1]-1:], mx)
+      let tag_name = matchstr(content, '^<\zs[a-zA-Z0-9:_\-]*\ze')
+      if stridx(','.settings.html.empty_elements.',', ','.tag_name.',') != -1
+        let pos2 = searchpos('>', 'nW')
+      else
+        let pos2 = searchpairpos('<' . tag_name . '[^>]*>', '', '</'. tag_name . '\zs>', 'nW')
+      endif
+      let block = [pos1, pos2]
+      if pos1 == [0, 0]
+        break
+      endif
+      if emmet#util#regionIsValid(block)
+        call emmet#util#selectRegion(block)
+        return
+      endif
+    endwhile
+  endif
+  call setpos('.', curpos)
+endfunction
+
+function! emmet#lang#html#moveNextPrevItem(flag) abort
+  silent! exe "normal \<esc>"
+  let mx = '\%([0-9a-zA-Z-:]\+\%(="[^"]*"\|=''[^'']*''\|[^ ''">\]]*\)\{0,1}\)'
+  let pos = searchpos('\s'.mx.'\zs', '')
+  if pos != [0,0]
+    call feedkeys('v?\s\zs'.mx."\<cr>", '')
+  endif
+  return ''
+endfunction
+
+function! emmet#lang#html#moveNextPrev(flag) abort
+  let pos = search('\%(</\w\+\)\@<!\zs><\/\|\(""\)\|^\(\s*\)$', a:flag ? 'Wpb' : 'Wp')
+  if pos == 3
+    startinsert!
+  elseif pos != 0
+    silent! normal! l
+    startinsert
+  endif
+  return ''
+endfunction
+
+function! emmet#lang#html#splitJoinTag() abort
+  let curpos = emmet#util#getcurpos()
+  let 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 old = getpos('.')[1:2]
+    let pos1 = searchpos(mx, 'bcnW')
+    let content = matchstr(getline(pos1[0])[pos1[1]-1:], mx)
+    let tag_name = substitute(content, '^<\(/\{0,1}[a-zA-Z][a-zA-Z0-9:_\-]*\).*$', '\1', '')
+    let block = [pos1, [pos1[0], pos1[1] + len(content) - 1]]
+    if content[-2:] ==# '/>' && emmet#util#cursorInRegion(block)
+      let content = substitute(content[:-3], '\s*$', '', '')  . '></' . tag_name . '>'
+      call emmet#util#setContent(block, content)
+      call setpos('.', [0, block[0][0], block[0][1], 0])
+      return
+    endif
+    if tag_name[0] ==# '/'
+      let pos1 = searchpos('<' . tag_name[1:] . '[^a-zA-Z0-9]', 'bcnW')
+      call setpos('.', [0, pos1[0], pos1[1], 0])
+      let pos2 = searchpairpos('<'. tag_name[1:] . '\>[^/>]*>', '', '</' . tag_name[1:] . '>', 'W')
+    else
+      let pos2 = searchpairpos('<'. tag_name . '[^/>]*>', '', '</' . tag_name . '>', 'W')
+    endif
+    if pos2 == [0, 0]
+      return
+    endif
+    let pos2 = searchpos('>', 'neW')
+    let block = [pos1, pos2]
+    if emmet#util#pointInRegion(curpos[1:2], block)
+      let content = matchstr(content, mx)[:-2] . ' />'
+      call emmet#util#setContent(block, content)
+      call setpos('.', [0, block[0][0], block[0][1], 0])
+      return
+    endif
+    if block[0][0] > 0
+      call setpos('.', [0, block[0][0]-1, block[0][1], 0])
+    else
+      call setpos('.', curpos)
+      return
+    endif
+    if pos1 == old
+      call setpos('.', curpos)
+      return
+    endif
+  endwhile
+endfunction
+
+function! emmet#lang#html#removeTag() abort
+  let curpos = emmet#util#getcurpos()
+  let mx = '<\(/\{0,1}[a-zA-Z][-a-zA-Z0-9:_\-]*\)\%(\%(\s[a-zA-Z][a-zA-Z0-9]\+=\%([^"'' \t]\+\|"[^"]\{-}"\|''[^'']\{-}''\)\s*\)*\)\s*\%(/\{0,1}\)>'
+
+  let pos1 = searchpos(mx, 'bcnW')
+  let content = matchstr(getline(pos1[0])[pos1[1]-1:], mx)
+  let tag_name = substitute(content, '^<\(/\{0,1}[a-zA-Z][a-zA-Z0-9:_\-]*\).*$', '\1', '')
+  let block = [pos1, [pos1[0], pos1[1] + len(content) - 1]]
+  if content[-2:] ==# '/>' && emmet#util#cursorInRegion(block)
+    call emmet#util#setContent(block, '')
+    call setpos('.', [0, block[0][0], block[0][1], 0])
+    return
+  endif
+  if tag_name[0] ==# '/'
+    let pos1 = searchpos('<' . tag_name[1:] . '[^a-zA-Z0-9]', 'bcnW')
+    call setpos('.', [0, pos1[0], pos1[1], 0])
+    let pos2 = searchpairpos('<'. tag_name[1:] . '\>[^/>]*>', '', '</' . tag_name[1:] . '>', 'W')
+  else
+    let pos2 = searchpairpos('<'. tag_name . '[^/>]*>', '', '</' . tag_name . '>', 'W')
+  endif
+  if pos2 == [0, 0]
+    return
+  endif
+  let pos2 = searchpos('>', 'neW')
+  let block = [pos1, pos2]
+  if emmet#util#pointInRegion(curpos[1:2], block)
+    call emmet#util#setContent(block, '')
+    call setpos('.', [0, block[0][0], block[0][1], 0])
+    return
+  endif
+  if block[0][0] > 0
+    call setpos('.', [0, block[0][0]-1, block[0][1], 0])
+  else
+    call setpos('.', curpos)
+  endif
+endfunction
+
+function! emmet#lang#html#mergeLines() abort
+  let curpos = emmet#util#getcurpos()
+  let settings = emmet#getSettings()
+
+  let mx = '<\([a-zA-Z][a-zA-Z0-9:_\-]*\)[^>]*>'
+  let last = curpos[1:2]
+  while 1
+    let pos1 = searchpos(mx, 'bcW')
+    let content = matchstr(getline(pos1[0])[pos1[1]-1:], mx)
+	echomsg string(content)
+    let tag_name = matchstr(content, '^<\zs[a-zA-Z0-9:_\-]*\ze')
+    if stridx(','.settings.html.empty_elements.',', ','.tag_name.',') != -1
+      let pos2 = searchpos('>', 'nW')
+    else
+      let pos2 = searchpairpos('<' . tag_name . '[^>]*>', '', '</'. tag_name . '\zs>', 'nW')
+    endif
+    if pos1 == [0, 0] || pos2 == [0, 0]
+      call setpos('.', curpos)
+      return
+    endif
+    let block = [pos1, pos2]
+    if emmet#util#pointInRegion(last, block) && emmet#util#regionIsValid(block)
+      break
+    endif
+    if pos1 == last
+      call setpos('.', curpos)
+      return
+    endif
+    let last = pos1
+  endwhile
+
+  let content = emmet#util#getContent(block)
+  let mx = '<\(/\{0,1}[a-zA-Z][-a-zA-Z0-9:_\-]*\)\%(\%(\s[a-zA-Z][a-zA-Z0-9]\+=\%([^"'' \t]\+\|"[^"]\{-}"\|''[^'']\{-}''\)\s*\)*\)\s*\%(/\{0,1}\)>'
+  let content = join(map(split(content, mx . '\zs\s*'), 'trim(v:val)'), '')
+  call emmet#util#setContent(block, content)
+  if block[0][0] > 0
+    call setpos('.', [0, block[0][0], block[0][1], 0])
+  else
+    call setpos('.', curpos)
+  endif
+endfunction
diff --git a/config/vim/autoload/emmet/lang/jade.vim b/config/vim/autoload/emmet/lang/jade.vim
new file mode 100644
index 0000000..f59f22d
--- /dev/null
+++ b/config/vim/autoload/emmet/lang/jade.vim
@@ -0,0 +1,335 @@
+function! emmet#lang#jade#findTokens(str) abort
+  return emmet#lang#html#findTokens(a:str)
+endfunction
+
+function! emmet#lang#jade#parseIntoTree(abbr, type) abort
+  return emmet#lang#html#parseIntoTree(a:abbr, a:type)
+endfunction
+
+function! emmet#lang#jade#toString(settings, current, type, inline, filters, itemno, indent) abort
+  let settings = a:settings
+  let current = a:current
+  let type = a:type
+  let inline = a:inline
+  let filters = a:filters
+  let itemno = a:itemno
+  let indent = emmet#getIndentation(type)
+  let dollar_expr = emmet#getResource(type, 'dollar_expr', 1)
+  let attribute_style = emmet#getResource('jade', 'attribute_style', 'hash')
+  let str = ''
+
+  let current_name = current.name
+  if dollar_expr
+    let current_name = substitute(current.name, '\$$', itemno+1, '')
+  endif
+  if len(current.name) > 0
+    let str .= '' . current_name
+    let tmp = ''
+    for attr in emmet#util#unique(current.attrs_order + keys(current.attr))
+      if !has_key(current.attr, attr)
+        continue
+      endif
+      let Val = current.attr[attr]
+      if type(Val) == 2 && Val == function('emmet#types#true')
+        if attribute_style ==# 'hash'
+          let tmp .= ' ' . attr . ' = true'
+        elseif attribute_style ==# 'html'
+          let tmp .= attr . '=true'
+        end
+      else
+        if dollar_expr
+          while Val =~# '\$\([^#{]\|$\)'
+            let Val = substitute(Val, '\(\$\+\)\([^{]\|$\)', '\=printf("%0".len(submatch(1))."d", itemno+1).submatch(2)', 'g')
+          endwhile
+          let attr = substitute(attr, '\$$', itemno+1, '')
+        endif
+        let valtmp = substitute(Val, '\${cursor}', '', '')
+        if attr ==# 'id' && len(valtmp) > 0
+          let str .= '#' . Val
+        elseif attr ==# 'class' && len(valtmp) > 0
+          let str .= '.' . substitute(Val, ' ', '.', 'g')
+        else
+          if len(tmp) > 0
+            if attribute_style ==# 'hash'
+              let tmp .= ', '
+            elseif attribute_style ==# 'html'
+              let tmp .= ' '
+            endif
+          endif
+          if attribute_style ==# 'hash'
+            let tmp .= '' . attr . '="' . Val . '"'
+          elseif attribute_style ==# 'html'
+            let tmp .= attr . '="' . Val . '"'
+          end
+        endif
+      endif
+    endfor
+    if len(tmp)
+      if attribute_style ==# 'hash'
+        let str .= '(' . tmp . ')'
+      elseif attribute_style ==# 'html'
+        let str .= '(' . tmp . ')'
+      end
+    endif
+
+    let inner = ''
+    if len(current.value) > 0
+      let text = current.value[1:-2]
+      if dollar_expr
+        let text = substitute(text, '\%(\\\)\@\<!\(\$\+\)\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d", itemno+1).submatch(2)', 'g')
+        let text = substitute(text, '\${nr}', "\n", 'g')
+        let text = substitute(text, '\\\$', '$', 'g')
+        let str = substitute(str, '\$#', text, 'g')
+      endif
+      let lines = split(text, "\n")
+      if len(lines) == 1
+        let str .= ' ' . text
+      else
+        for line in lines
+          let str .= "\n" . indent . line . ' |'
+        endfor
+      endif
+    elseif len(current.child) == 0
+      let str .= '${cursor}'
+    endif
+    if len(current.child) == 1 && len(current.child[0].name) == 0
+      let text = current.child[0].value[1:-2]
+      if dollar_expr
+        let text = substitute(text, '\%(\\\)\@\<!\(\$\+\)\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d", itemno+1).submatch(2)', 'g')
+        let text = substitute(text, '\${nr}', "\n", 'g')
+        let text = substitute(text, '\\\$', '$', 'g')
+      endif
+      let lines = split(text, "\n")
+      if len(lines) == 1
+        let str .= ' ' . text
+      else
+        for line in lines
+          let str .= "\n" . indent . line . ' |'
+        endfor
+      endif
+    elseif len(current.child) > 0
+      for child in current.child
+        let inner .= emmet#toString(child, type, inline, filters, itemno, indent)
+      endfor
+      let inner = substitute(inner, "\n", "\n" . escape(indent, '\'), 'g')
+      let inner = substitute(inner, "\n" . escape(indent, '\') . '$', '', 'g')
+      let str .= "\n" . indent . inner
+    endif
+  else
+    let str = current.value[1:-2]
+    if dollar_expr
+      let str = substitute(str, '\%(\\\)\@\<!\(\$\+\)\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d", itemno+1).submatch(2)', 'g')
+      let str = substitute(str, '\${nr}', "\n", 'g')
+      let str = substitute(str, '\\\$', '$', 'g')
+    endif
+  endif
+  let str .= "\n"
+  return str
+endfunction
+
+function! emmet#lang#jade#imageSize() abort
+  let line = getline('.')
+  let current = emmet#lang#jade#parseTag(line)
+  if empty(current) || !has_key(current.attr, 'src')
+    return
+  endif
+  let fn = current.attr.src
+  if fn =~# '^\s*$'
+    return
+  elseif fn !~# '^\(/\|http\)'
+    let fn = simplify(expand('%:h') . '/' . fn)
+  endif
+
+  let [width, height] = emmet#util#getImageSize(fn)
+  if width == -1 && height == -1
+    return
+  endif
+  let current.attr.width = width
+  let current.attr.height = height
+  let current.attrs_order += ['width', 'height']
+  let jade = emmet#toString(current, 'jade', 1)
+  let jade = substitute(jade, '\${cursor}', '', '')
+  call setline('.', substitute(matchstr(line, '^\s*') . jade, "\n", '', 'g'))
+endfunction
+
+function! emmet#lang#jade#imageEncode() abort
+endfunction
+
+function! emmet#lang#jade#parseTag(tag) abort
+  let current = emmet#newNode()
+  let mx = '%\([a-zA-Z][a-zA-Z0-9]*\)\s*\%({\(.*\)}\)'
+  let match = matchstr(a:tag, mx)
+  let current.name = substitute(match, mx, '\1', '')
+  let attrs = substitute(match, mx, '\2', '')
+  let mx = '\([a-zA-Z0-9]\+\)\s*=>\s*\%(\([^"'' \t]\+\)\|"\([^"]\{-}\)"\|''\([^'']\{-}\)''\)'
+  while len(attrs) > 0
+    let match = matchstr(attrs, mx)
+    if len(match) ==# 0
+      break
+    endif
+    let attr_match = matchlist(match, mx)
+    let name = attr_match[1]
+    let value = len(attr_match[2]) ? attr_match[2] : attr_match[3]
+    let current.attr[name] = value
+    let current.attrs_order += [name]
+    let attrs = attrs[stridx(attrs, match) + len(match):]
+  endwhile
+  return current
+endfunction
+
+function! emmet#lang#jade#toggleComment() abort
+  let line = getline('.')
+  let space = matchstr(line, '^\s*')
+  if line =~# '^\s*-#'
+    call setline('.', space . matchstr(line[len(space)+2:], '^\s*\zs.*'))
+  elseif line =~# '^\s*%[a-z]'
+    call setline('.', space . '-# ' . line[len(space):])
+  endif
+endfunction
+
+function! emmet#lang#jade#balanceTag(flag) range abort
+  let block = emmet#util#getVisualBlock()
+  if a:flag == -2 || a:flag == 2
+    let curpos = [0, line("'<"), col("'<"), 0]
+  else
+    let curpos = emmet#util#getcurpos()
+  endif
+  let n = curpos[1]
+  let ml = len(matchstr(getline(n), '^\s*'))
+
+  if a:flag > 0
+    if a:flag == 1 || !emmet#util#regionIsValid(block)
+      let n = line('.')
+    else
+      while n > 0
+        let l = len(matchstr(getline(n), '^\s*\ze%[a-z]'))
+        if l > 0 && l < ml
+          let ml = l
+          break
+        endif
+        let n -= 1
+      endwhile
+    endif
+    let sn = n
+    if n == 0
+      let ml = 0
+    endif
+    while n < line('$')
+      let l = len(matchstr(getline(n), '^\s*%[a-z]'))
+      if l > 0 && l <= ml
+        let n -= 1
+        break
+      endif
+      let n += 1
+    endwhile
+    call setpos('.', [0, n, 1, 0])
+    normal! V
+    call setpos('.', [0, sn, 1, 0])
+  else
+    while n > 0
+      let l = len(matchstr(getline(n), '^\s*\ze[a-z]'))
+      if l > 0 && l > ml
+        let ml = l
+        break
+      endif
+      let n += 1
+    endwhile
+    let sn = n
+    if n == 0
+      let ml = 0
+    endif
+    while n < line('$')
+      let l = len(matchstr(getline(n), '^\s*%[a-z]'))
+      if l > 0 && l <= ml
+        let n -= 1
+        break
+      endif
+      let n += 1
+    endwhile
+    call setpos('.', [0, n, 1, 0])
+    normal! V
+    call setpos('.', [0, sn, 1, 0])
+  endif
+endfunction
+
+function! emmet#lang#jade#moveNextPrevItem(flag) abort
+  return emmet#lang#jade#moveNextPrev(a:flag)
+endfunction
+
+function! emmet#lang#jade#moveNextPrev(flag) abort
+  let pos = search('""', a:flag ? 'Wb' : 'W')
+  if pos != 0
+    silent! normal! l
+    startinsert
+  endif
+endfunction
+
+function! emmet#lang#jade#splitJoinTag() abort
+  let n = line('.')
+  let sml = len(matchstr(getline(n), '^\s*%[a-z]'))
+  while n > 0
+    if getline(n) =~# '^\s*\ze%[a-z]'
+      if len(matchstr(getline(n), '^\s*%[a-z]')) < sml
+        break
+      endif
+      let line = getline(n)
+      call setline(n, substitute(line, '^\s*%\w\+\%(\s*{[^}]*}\|\s\)\zs.*', '', ''))
+      let sn = n
+      let n += 1
+      let ml = len(matchstr(getline(n), '^\s*%[a-z]'))
+      if len(matchstr(getline(n), '^\s*')) > ml
+        while n <= line('$')
+          let l = len(matchstr(getline(n), '^\s*'))
+          if l <= ml
+            break
+          endif
+          exe n 'delete'
+        endwhile
+        call setpos('.', [0, sn, 1, 0])
+      else
+        let tag = matchstr(getline(sn), '^\s*%\zs\(\w\+\)')
+        let spaces = matchstr(getline(sn), '^\s*')
+        let settings = emmet#getSettings()
+        if stridx(','.settings.html.inline_elements.',', ','.tag.',') == -1
+          call append(sn, spaces . '   ')
+          call setpos('.', [0, sn+1, 1, 0])
+        else
+          call setpos('.', [0, sn, 1, 0])
+        endif
+        startinsert!
+      endif
+      break
+    endif
+    let n -= 1
+  endwhile
+endfunction
+
+function! emmet#lang#jade#removeTag() abort
+  let n = line('.')
+  let ml = 0
+  while n > 0
+    if getline(n) =~# '^\s*\ze[a-z]'
+      let ml = len(matchstr(getline(n), '^\s*%[a-z]'))
+      break
+    endif
+    let n -= 1
+  endwhile
+  let sn = n
+  while n < line('$')
+    let l = len(matchstr(getline(n), '^\s*%[a-z]'))
+    if l > 0 && l <= ml
+      let n -= 1
+      break
+    endif
+    let n += 1
+  endwhile
+  if sn == n
+    exe 'delete'
+  else
+    exe sn ',' (n-1) 'delete'
+  endif
+endfunction
+
+function! emmet#lang#jade#mergeLines() abort
+  " nothing to do
+endfunction
diff --git a/config/vim/autoload/emmet/lang/less.vim b/config/vim/autoload/emmet/lang/less.vim
new file mode 100644
index 0000000..ae956c4
--- /dev/null
+++ b/config/vim/autoload/emmet/lang/less.vim
@@ -0,0 +1,51 @@
+function! emmet#lang#less#findTokens(str) abort
+  return emmet#lang#html#findTokens(a:str)
+endfunction
+
+function! emmet#lang#less#parseIntoTree(abbr, type) abort
+  return emmet#lang#scss#parseIntoTree(a:abbr, a:type)
+endfunction
+
+function! emmet#lang#less#toString(settings, current, type, inline, filters, itemno, indent) abort
+  return emmet#lang#scss#toString(a:settings, a:current, a:type, a:inline, a:filters, a:itemno, a:indent)
+endfunction
+
+function! emmet#lang#less#imageSize() abort
+  call emmet#lang#css#imageSize()
+endfunction
+
+function! emmet#lang#less#imageEncode() abort
+  return emmet#lang#css#imageEncode()
+endfunction
+
+function! emmet#lang#less#parseTag(tag) abort
+  return emmet#lang#css#parseTag(a:tag)
+endfunction
+
+function! emmet#lang#less#toggleComment() abort
+  call emmet#lang#css#toggleComment()
+endfunction
+
+function! emmet#lang#less#balanceTag(flag) range abort
+  call emmet#lang#scss#balanceTag(a:flag)
+endfunction
+
+function! emmet#lang#less#moveNextPrevItem(flag) abort
+  return emmet#lang#less#moveNextPrev(a:flag)
+endfunction
+
+function! emmet#lang#less#moveNextPrev(flag) abort
+  call emmet#lang#scss#moveNextPrev(a:flag)
+endfunction
+
+function! emmet#lang#less#splitJoinTag() abort
+  call emmet#lang#css#splitJoinTag()
+endfunction
+
+function! emmet#lang#less#removeTag() abort
+  call emmet#lang#css#removeTag()
+endfunction
+
+function! emmet#lang#less#mergeLines() abort
+  call emmet#lang#css#mergeLines()
+endfunction
diff --git a/config/vim/autoload/emmet/lang/sass.vim b/config/vim/autoload/emmet/lang/sass.vim
new file mode 100644
index 0000000..3d3fd58
--- /dev/null
+++ b/config/vim/autoload/emmet/lang/sass.vim
@@ -0,0 +1,163 @@
+function! emmet#lang#sass#findTokens(str) abort
+  return emmet#lang#css#findTokens(a:str)
+endfunction
+
+function! emmet#lang#sass#parseIntoTree(abbr, type) abort
+    return emmet#lang#css#parseIntoTree(a:abbr, a:type)
+endfunction
+
+function! emmet#lang#sass#toString(settings, current, type, inline, filters, itemno, indent) abort
+  let settings = a:settings
+  let current = a:current
+  let type = a:type
+  let inline = a:inline
+  let filters = a:filters
+  let itemno = a:itemno
+  let indent = a:indent
+  let str = ''
+
+  let current_name = current.name
+  let current_name = substitute(current.name, '\$$', itemno+1, '')
+  if len(current.name) > 0
+    let str .= current_name
+    let tmp = ''
+    for attr in keys(current.attr)
+      let val = current.attr[attr]
+      while val =~# '\$\([^#{]\|$\)'
+        let val = substitute(val, '\(\$\+\)\([^{]\|$\)', '\=printf("%0".len(submatch(1))."d", itemno+1).submatch(2)', 'g')
+      endwhile
+      let attr = substitute(attr, '\$$', itemno+1, '')
+      if attr ==# 'id'
+        let str .= '#' . val
+      elseif attr ==# 'class'
+        let str .= '.' . val
+      else
+        let tmp .= attr . ': ' . val
+      endif
+    endfor
+    if len(tmp) > 0
+      let str .= "\n"
+      for line in split(tmp, "\n")
+        let str .= indent . line . "\n"
+      endfor
+    else
+      let str .= "\n"
+    endif
+
+    let inner = ''
+    for child in current.child
+      let tmp = emmet#toString(child, type, inline, filters, itemno, indent)
+      let tmp = substitute(tmp, "\n", "\n" . escape(indent, '\'), 'g')
+      let tmp = substitute(tmp, "\n" . escape(indent, '\') . '$', '${cursor}\n', 'g')
+      let inner .= tmp
+    endfor
+    if len(inner) > 0
+      let str .= indent . inner
+    endif
+  else
+    let text = emmet#lang#css#toString(settings, current, type, inline, filters, itemno, indent)
+    let text = substitute(text, '\s*;\ze\(\${[^}]\+}\)\?\(\n\|$\)', '', 'g')
+    return text
+  endif
+  return str
+endfunction
+
+function! emmet#lang#sass#imageSize() abort
+endfunction
+
+function! emmet#lang#sass#imageEncode() abort
+endfunction
+
+function! emmet#lang#sass#parseTag(tag) abort
+endfunction
+
+function! emmet#lang#sass#toggleComment() abort
+endfunction
+
+function! emmet#lang#sass#balanceTag(flag) range abort
+  let block = emmet#util#getVisualBlock()
+  if a:flag == -2 || a:flag == 2
+    let curpos = [0, line("'<"), col("'<"), 0]
+  else
+    let curpos = emmet#util#getcurpos()
+  endif
+  let n = curpos[1]
+  let ml = len(matchstr(getline(n), '^\s*'))
+
+  if a:flag > 0
+    if a:flag == 1 || !emmet#util#regionIsValid(block)
+      let n = line('.')
+    else
+      while n > 0
+        let l = len(matchstr(getline(n), '^\s*\ze[a-z]'))
+        if l > 0 && l < ml
+          let ml = l
+          break
+        endif
+        let n -= 1
+      endwhile
+    endif
+    let sn = n
+    if n == 0
+      let ml = 0
+    endif
+    while n < line('$')
+      let l = len(matchstr(getline(n), '^\s*[a-z]'))
+      if l > 0 && l <= ml
+        let n -= 1
+        break
+      endif
+      let n += 1
+    endwhile
+    call setpos('.', [0, n, 1, 0])
+    normal! V
+    call setpos('.', [0, sn, 1, 0])
+  else
+    while n > 0
+      let l = len(matchstr(getline(n), '^\s*\ze[a-z]'))
+      if l > 0 && l > ml
+        let ml = l
+        break
+      endif
+      let n += 1
+    endwhile
+    let sn = n
+    if n == 0
+      let ml = 0
+    endif
+    while n < line('$')
+      let l = len(matchstr(getline(n), '^\s*[a-z]'))
+      if l > 0 && l <= ml
+        let n -= 1
+        break
+      endif
+      let n += 1
+    endwhile
+    call setpos('.', [0, n, 1, 0])
+    normal! V
+    call setpos('.', [0, sn, 1, 0])
+  endif
+endfunction
+
+function! emmet#lang#sass#moveNextPrevItem(flag) abort
+  return emmet#lang#sass#moveNextPrev(a:flag)
+endfunction
+
+function! emmet#lang#sass#moveNextPrev(flag) abort
+  let pos = search('""\|\(^\s*|\s*\zs\)', a:flag ? 'Wpb' : 'Wp')
+  if pos == 2
+    startinsert!
+  elseif pos != 0
+    silent! normal! l
+    startinsert
+  endif
+endfunction
+
+function! emmet#lang#sass#splitJoinTag() abort
+endfunction
+
+function! emmet#lang#sass#removeTag() abort
+endfunction
+
+function! emmet#lang#sass#mergeLines() abort
+endfunction
diff --git a/config/vim/autoload/emmet/lang/scss.vim b/config/vim/autoload/emmet/lang/scss.vim
new file mode 100644
index 0000000..ae35469
--- /dev/null
+++ b/config/vim/autoload/emmet/lang/scss.vim
@@ -0,0 +1,129 @@
+function! emmet#lang#scss#findTokens(str) abort
+  return emmet#lang#css#findTokens(a:str)
+endfunction
+
+function! emmet#lang#scss#parseIntoTree(abbr, type) abort
+  if a:abbr =~# '>'
+    return emmet#lang#html#parseIntoTree(a:abbr, a:type)
+  else
+    return emmet#lang#css#parseIntoTree(a:abbr, a:type)
+  endif
+endfunction
+
+function! emmet#lang#scss#toString(settings, current, type, inline, filters, itemno, indent) abort
+  let settings = a:settings
+  let current = a:current
+  let type = a:type
+  let inline = a:inline
+  let filters = a:filters
+  let itemno = a:itemno
+  let indent = a:indent
+  let str = ''
+
+  let current_name = substitute(current.name, '\$$', itemno+1, '')
+  if len(current.name) > 0
+    let str .= current_name
+    let tmp = ''
+    for attr in keys(current.attr)
+      let val = current.attr[attr]
+      while val =~# '\$\([^#{]\|$\)'
+        let val = substitute(val, '\(\$\+\)\([^{]\|$\)', '\=printf("%0".len(submatch(1))."d", itemno+1).submatch(2)', 'g')
+      endwhile
+      let attr = substitute(attr, '\$$', itemno+1, '')
+      if attr ==# 'id'
+        let str .= '#' . val
+      elseif attr ==# 'class'
+        let str .= '.' . val
+      else
+        let tmp .= attr . ': ' . val . ';'
+      endif
+    endfor
+    if len(tmp) > 0
+      let str .= " {\n"
+      for line in split(tmp, "\n")
+        let str .= indent . line . "\n"
+      endfor
+    else
+      let str .= " {\n"
+    endif
+
+    let inner = ''
+    for child in current.child
+      let inner .= emmet#toString(child, type, inline, filters, itemno)
+    endfor
+    let inner = substitute(inner, "\n", "\n" . escape(indent, '\'), 'g')
+    let inner = substitute(inner, "\n" . escape(indent, '\') . '$', '', 'g')
+    let str .= indent . inner . "${cursor}\n}\n"
+  else
+    return emmet#lang#css#toString(settings, current, type, inline, filters, itemno, indent)
+  endif
+  return str
+endfunction
+
+function! emmet#lang#scss#imageSize() abort
+  call emmet#lang#css#imageSize()
+endfunction
+
+function! emmet#lang#scss#imageEncode() abort
+  return emmet#lang#css#imageEncode()
+endfunction
+
+function! emmet#lang#scss#parseTag(tag) abort
+  return emmet#lang#css#parseTag(a:tag)
+endfunction
+
+function! emmet#lang#scss#toggleComment() abort
+  call emmet#lang#css#toggleComment()
+endfunction
+
+function! emmet#lang#scss#balanceTag(flag) range abort
+  if a:flag == -2 || a:flag == 2
+    let curpos = [0, line("'<"), col("'<"), 0]
+    call setpos('.', curpos)
+  else
+    let curpos = emmet#util#getcurpos()
+  endif
+  if a:flag < 0
+    let ret = searchpair('}', '', '.\zs{')
+  else
+    let ret = searchpair('{', '', '}', 'bW')
+  endif
+  if ret > 0
+    let pos1 = emmet#util#getcurpos()[1:2]
+    if a:flag < 0
+      let pos2 = searchpairpos('{', '', '}')
+    else
+      let pos2 = searchpairpos('{', '', '}')
+    endif
+    let block = [pos1, pos2]
+    if emmet#util#regionIsValid(block)
+      call emmet#util#selectRegion(block)
+      return
+    endif
+  endif
+  if a:flag == -2 || a:flag == 2
+    silent! exe 'normal! gv'
+  else
+    call setpos('.', curpos)
+  endif
+endfunction
+
+function! emmet#lang#scss#moveNextPrevItem(flag) abort
+  return emmet#lang#scss#moveNextPrev(a:flag)
+endfunction
+
+function! emmet#lang#scss#moveNextPrev(flag) abort
+  call emmet#lang#css#moveNextPrev(a:flag)
+endfunction
+
+function! emmet#lang#scss#splitJoinTag() abort
+  call emmet#lang#css#splitJoinTag()
+endfunction
+
+function! emmet#lang#scss#removeTag() abort
+  call emmet#lang#css#removeTag()
+endfunction
+
+function! emmet#lang#scss#mergeLines() abort
+  call emmet#lang#css#mergeLines()
+endfunction
diff --git a/config/vim/autoload/emmet/lang/slim.vim b/config/vim/autoload/emmet/lang/slim.vim
new file mode 100644
index 0000000..c583c1c
--- /dev/null
+++ b/config/vim/autoload/emmet/lang/slim.vim
@@ -0,0 +1,284 @@
+function! emmet#lang#slim#findTokens(str) abort
+  return emmet#lang#html#findTokens(a:str)
+endfunction
+
+function! emmet#lang#slim#parseIntoTree(abbr, type) abort
+  return emmet#lang#html#parseIntoTree(a:abbr, a:type)
+endfunction
+
+function! emmet#lang#slim#toString(settings, current, type, inline, filters, itemno, indent) abort
+  let current = a:current
+  let type = a:type
+  let inline = a:inline
+  let filters = a:filters
+  let itemno = a:itemno
+  let indent = emmet#getIndentation(type)
+  let dollar_expr = emmet#getResource(type, 'dollar_expr', 1)
+  let str = ''
+
+  let current_name = current.name
+  if dollar_expr
+    let current_name = substitute(current.name, '\$$', itemno+1, '')
+  endif
+  if len(current.name) > 0
+    let str .= current_name
+    for attr in emmet#util#unique(current.attrs_order + keys(current.attr))
+      if !has_key(current.attr, attr)
+        continue
+      endif
+      let Val = current.attr[attr]
+      if type(Val) == 2 && Val == function('emmet#types#true')
+        let str .= ' ' . attr . '=true'
+      else
+        if dollar_expr
+          while Val =~# '\$\([^#{]\|$\)'
+            let Val = substitute(Val, '\(\$\+\)\([^{]\|$\)', '\=printf("%0".len(submatch(1))."d", itemno+1).submatch(2)', 'g')
+          endwhile
+        endif
+        let attr = substitute(attr, '\$$', itemno+1, '')
+        let str .= ' ' . attr . '="' . Val . '"'
+      endif
+    endfor
+
+    let inner = ''
+    if len(current.value) > 0
+      let str .= "\n"
+      let text = current.value[1:-2]
+      if dollar_expr
+        let text = substitute(text, '\%(\\\)\@\<!\(\$\+\)\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d", itemno+1).submatch(2)', 'g')
+        let text = substitute(text, '\${nr}', "\n", 'g')
+        let text = substitute(text, '\\\$', '$', 'g')
+        let str = substitute(str, '\$#', text, 'g')
+      endif
+      for line in split(text, "\n")
+        let str .= indent . '| ' . line . "\n"
+      endfor
+    elseif len(current.child) == 0
+      let str .= '${cursor}'
+    endif
+    if len(current.child) == 1 && len(current.child[0].name) == 0
+      let str .= "\n"
+      let text = current.child[0].value[1:-2]
+      if dollar_expr
+        let text = substitute(text, '\%(\\\)\@\<!\(\$\+\)\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d", itemno+1).submatch(2)', 'g')
+        let text = substitute(text, '\${nr}', "\n", 'g')
+        let text = substitute(text, '\\\$', '$', 'g')
+      endif
+      for line in split(text, "\n")
+        let str .= indent . '| ' . line . "\n"
+      endfor
+    elseif len(current.child) > 0
+      for child in current.child
+        let inner .= emmet#toString(child, type, inline, filters, itemno, indent)
+      endfor
+      let inner = substitute(inner, "\n", "\n" . escape(indent, '\'), 'g')
+      let inner = substitute(inner, "\n" . escape(indent, '\') . '$', '', 'g')
+      let str .= "\n" . indent . inner
+    endif
+  else
+    let str = current.value[1:-2]
+    if dollar_expr
+      let str = substitute(str, '\%(\\\)\@\<!\(\$\+\)\([^{#]\|$\)', '\=printf("%0".len(submatch(1))."d", itemno+1).submatch(2)', 'g')
+      let str = substitute(str, '\${nr}', "\n", 'g')
+      let str = substitute(str, '\\\$', '$', 'g')
+    endif
+  endif
+  if str !~# "\n$"
+    let str .= "\n"
+  endif
+  return str
+endfunction
+
+function! emmet#lang#slim#imageSize() abort
+  let line = getline('.')
+  let current = emmet#lang#slim#parseTag(line)
+  if empty(current) || !has_key(current.attr, 'src')
+    return
+  endif
+  let fn = current.attr.src
+  if fn =~# '^\s*$'
+    return
+  elseif fn !~# '^\(/\|http\)'
+    let fn = simplify(expand('%:h') . '/' . fn)
+  endif
+
+  let [width, height] = emmet#util#getImageSize(fn)
+  if width == -1 && height == -1
+    return
+  endif
+  let current.attr.width = width
+  let current.attr.height = height
+  let current.attrs_order += ['width', 'height']
+  let slim = emmet#toString(current, 'slim', 1)
+  let slim = substitute(slim, '\${cursor}', '', '')
+  call setline('.', substitute(matchstr(line, '^\s*') . slim, "\n", '', 'g'))
+endfunction
+
+function! emmet#lang#slim#imageEncode() abort
+endfunction
+
+function! emmet#lang#slim#parseTag(tag) abort
+  let current = emmet#newNode()
+  let mx = '\([a-zA-Z][a-zA-Z0-9]*\)\s\+\(.*\)'
+  let match = matchstr(a:tag, mx)
+  let current.name = substitute(match, mx, '\1', '')
+  let attrs = substitute(match, mx, '\2', '')
+  let mx = '\([a-zA-Z0-9]\+\)=\%(\([^"'' \t]\+\)\|"\([^"]\{-}\)"\|''\([^'']\{-}\)''\)'
+  while len(attrs) > 0
+    let match = matchstr(attrs, mx)
+    if len(match) == 0
+      break
+    endif
+    let attr_match = matchlist(match, mx)
+    let name = attr_match[1]
+    let value = len(attr_match[2]) ? attr_match[2] : attr_match[3]
+    let current.attr[name] = value
+    let current.attrs_order += [name]
+    let attrs = attrs[stridx(attrs, match) + len(match):]
+  endwhile
+  return current
+endfunction
+
+function! emmet#lang#slim#toggleComment() abort
+  let line = getline('.')
+  let space = matchstr(line, '^\s*')
+  if line =~# '^\s*/'
+    call setline('.', space . line[len(space)+1:])
+  elseif line =~# '^\s*[a-z]'
+    call setline('.', space . '/' . line[len(space):])
+  endif
+endfunction
+
+function! emmet#lang#slim#balanceTag(flag) range abort
+  let block = emmet#util#getVisualBlock()
+  if a:flag == -2 || a:flag == 2
+    let curpos = [0, line("'<"), col("'<"), 0]
+  else
+    let curpos = emmet#util#getcurpos()
+  endif
+  let n = curpos[1]
+  let ml = len(matchstr(getline(n), '^\s*'))
+
+  if a:flag > 0
+    if a:flag == 1 || !emmet#util#regionIsValid(block)
+      let n = line('.')
+    else
+      while n > 0
+        let l = len(matchstr(getline(n), '^\s*\ze[a-z]'))
+        if l > 0 && l < ml
+          let ml = l
+          break
+        endif
+        let n -= 1
+      endwhile
+    endif
+    let sn = n
+    if n == 0
+      let ml = 0
+    endif
+    while n < line('$')
+      let l = len(matchstr(getline(n), '^\s*[a-z]'))
+      if l > 0 && l <= ml
+        let n -= 1
+        break
+      endif
+      let n += 1
+    endwhile
+    call setpos('.', [0, n, 1, 0])
+    normal! V
+    call setpos('.', [0, sn, 1, 0])
+  else
+    while n > 0
+      let l = len(matchstr(getline(n), '^\s*\ze[a-z]'))
+      if l > 0 && l > ml
+        let ml = l
+        break
+      endif
+      let n += 1
+    endwhile
+    let sn = n
+    if n == 0
+      let ml = 0
+    endif
+    while n < line('$')
+      let l = len(matchstr(getline(n), '^\s*[a-z]'))
+      if l > 0 && l <= ml
+        let n -= 1
+        break
+      endif
+      let n += 1
+    endwhile
+    call setpos('.', [0, n, 1, 0])
+    normal! V
+    call setpos('.', [0, sn, 1, 0])
+  endif
+endfunction
+
+function! emmet#lang#slim#moveNextPrevItem(flag) abort
+  return emmet#lang#slim#moveNextPrev(a:flag)
+endfunction
+
+function! emmet#lang#slim#moveNextPrev(flag) abort
+  let pos = search('""\|\(^\s*|\s*\zs\)', a:flag ? 'Wpb' : 'Wp')
+  if pos == 2
+    startinsert!
+  elseif pos != 0
+    silent! normal! l
+    startinsert
+  endif
+endfunction
+
+function! emmet#lang#slim#splitJoinTag() abort
+  let n = line('.')
+  while n > 0
+    if getline(n) =~# '^\s*\ze[a-z]'
+      let sn = n
+      let n += 1
+      if getline(n) =~# '^\s*|'
+        while n <= line('$')
+          if getline(n) !~# '^\s*|'
+            break
+          endif
+          exe n 'delete'
+        endwhile
+        call setpos('.', [0, sn, 1, 0])
+      else
+        let spaces = matchstr(getline(sn), '^\s*')
+        call append(sn, spaces . '  | ')
+        call setpos('.', [0, sn+1, 1, 0])
+        startinsert!
+      endif
+      break
+    endif
+    let n -= 1
+  endwhile
+endfunction
+
+function! emmet#lang#slim#removeTag() abort
+  let n = line('.')
+  let ml = 0
+  while n > 0
+    if getline(n) =~# '^\s*\ze[a-z]'
+      let ml = len(matchstr(getline(n), '^\s*[a-z]'))
+      break
+    endif
+    let n -= 1
+  endwhile
+  let sn = n
+  while n < line('$')
+    let l = len(matchstr(getline(n), '^\s*[a-z]'))
+    if l > 0 && l <= ml
+      let n -= 1
+      break
+    endif
+    let n += 1
+  endwhile
+  if sn == n
+    exe 'delete'
+  else
+    exe sn ',' (n-1) 'delete'
+  endif
+endfunction
+
+function! emmet#lang#slim#mergeLines() abort
+endfunction
diff --git a/config/vim/autoload/emmet/lorem/en.vim b/config/vim/autoload/emmet/lorem/en.vim
new file mode 100644
index 0000000..30713e4
--- /dev/null
+++ b/config/vim/autoload/emmet/lorem/en.vim
@@ -0,0 +1,65 @@
+function! emmet#lorem#en#expand(command) abort
+  let wcount = matchstr(a:command, '\(\d*\)$')
+  let wcount = wcount > 0 ? wcount : 30
+  
+  let common = ['lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur', 'adipisicing', 'elit']
+  let words = ['exercitationem', 'perferendis', 'perspiciatis', 'laborum', 'eveniet',
+  \            'sunt', 'iure', 'nam', 'nobis', 'eum', 'cum', 'officiis', 'excepturi',
+  \            'odio', 'consectetur', 'quasi', 'aut', 'quisquam', 'vel', 'eligendi',
+  \            'itaque', 'non', 'odit', 'tempore', 'quaerat', 'dignissimos',
+  \            'facilis', 'neque', 'nihil', 'expedita', 'vitae', 'vero', 'ipsum',
+  \            'nisi', 'animi', 'cumque', 'pariatur', 'velit', 'modi', 'natus',
+  \            'iusto', 'eaque', 'sequi', 'illo', 'sed', 'ex', 'et', 'voluptatibus',
+  \            'tempora', 'veritatis', 'ratione', 'assumenda', 'incidunt', 'nostrum',
+  \            'placeat', 'aliquid', 'fuga', 'provident', 'praesentium', 'rem',
+  \            'necessitatibus', 'suscipit', 'adipisci', 'quidem', 'possimus',
+  \            'voluptas', 'debitis', 'sint', 'accusantium', 'unde', 'sapiente',
+  \            'voluptate', 'qui', 'aspernatur', 'laudantium', 'soluta', 'amet',
+  \            'quo', 'aliquam', 'saepe', 'culpa', 'libero', 'ipsa', 'dicta',
+  \            'reiciendis', 'nesciunt', 'doloribus', 'autem', 'impedit', 'minima',
+  \            'maiores', 'repudiandae', 'ipsam', 'obcaecati', 'ullam', 'enim',
+  \            'totam', 'delectus', 'ducimus', 'quis', 'voluptates', 'dolores',
+  \            'molestiae', 'harum', 'dolorem', 'quia', 'voluptatem', 'molestias',
+  \            'magni', 'distinctio', 'omnis', 'illum', 'dolorum', 'voluptatum', 'ea',
+  \            'quas', 'quam', 'corporis', 'quae', 'blanditiis', 'atque', 'deserunt',
+  \            'laboriosam', 'earum', 'consequuntur', 'hic', 'cupiditate',
+  \            'quibusdam', 'accusamus', 'ut', 'rerum', 'error', 'minus', 'eius',
+  \            'ab', 'ad', 'nemo', 'fugit', 'officia', 'at', 'in', 'id', 'quos',
+  \            'reprehenderit', 'numquam', 'iste', 'fugiat', 'sit', 'inventore',
+  \            'beatae', 'repellendus', 'magnam', 'recusandae', 'quod', 'explicabo',
+  \            'doloremque', 'aperiam', 'consequatur', 'asperiores', 'commodi',
+  \            'optio', 'dolor', 'labore', 'temporibus', 'repellat', 'veniam',
+  \            'architecto', 'est', 'esse', 'mollitia', 'nulla', 'a', 'similique',
+  \            'eos', 'alias', 'dolore', 'tenetur', 'deleniti', 'porro', 'facere',
+  \            'maxime', 'corrupti']
+  let ret = []
+  let sentence = 0
+  for i in range(wcount)
+    let arr = common
+    if sentence > 0
+      let arr += words
+    endif
+    let r = emmet#util#rand()
+    let word = arr[r % len(arr)]
+    if sentence == 0
+      let word = substitute(word, '^.', '\U&', '')
+    endif
+    let sentence += 1
+    call add(ret, word)
+    if (sentence > 5 && emmet#util#rand() < 10000) || i == wcount - 1
+      if i == wcount - 1
+        let endc = '?!...'[emmet#util#rand() % 5]
+        call add(ret, endc)
+      else
+        let endc = '?!,...'[emmet#util#rand() % 6]
+        call add(ret, endc . ' ')
+      endif
+      if endc !=# ','
+        let sentence = 0
+      endif
+    else
+      call add(ret, ' ')
+    endif
+  endfor
+  return join(ret, '')
+endfunction
diff --git a/config/vim/autoload/emmet/lorem/ja.vim b/config/vim/autoload/emmet/lorem/ja.vim
new file mode 100644
index 0000000..f99d8fa
--- /dev/null
+++ b/config/vim/autoload/emmet/lorem/ja.vim
@@ -0,0 +1,27 @@
+scriptencoding utf-8
+
+function! emmet#lorem#ja#expand(command) abort
+  let wcount = matchstr(a:command, '^\%(lorem\|lipsum\)\(\d*\)}$', '\1', '')
+  let wcount = wcount > 0 ? wcount : 30
+
+  let url = "http://www.aozora.gr.jp/cards/000081/files/470_15407.html"
+  let content = emmet#util#cache(url)
+  if len(content) == 0
+    let content = emmet#util#getContentFromURL(url)
+    let content = matchstr(content, '<div[^>]*>\zs.\{-}</div>')
+    let content = substitute(content, '[ \r]', '', 'g')
+    let content = substitute(content, '<br[^>]*>', "\n", 'g')
+    let content = substitute(content, '<[^>]\+>', '', 'g')
+    let content = join(filter(split(content, "\n"), 'len(v:val)>0'), "\n")
+    call emmet#util#cache(url, content)
+  endif
+  
+  let content = substitute(content, "、\n", "、", "g")
+  let clines = split(content, '\n')
+  let lines = filter(clines, 'len(substitute(v:val,".",".","g"))<=wcount')
+  if len(lines) == 0
+    let lines = clines
+  endif
+  let r = emmet#util#rand()
+  return lines[r % len(lines)]
+endfunction
diff --git a/config/vim/autoload/emmet/util.vim b/config/vim/autoload/emmet/util.vim
new file mode 100644
index 0000000..78960c0
--- /dev/null
+++ b/config/vim/autoload/emmet/util.vim
@@ -0,0 +1,410 @@
+"==============================================================================
+" region utils
+"==============================================================================
+" deleteContent : delete content in region
+"   if region make from between '<foo>' and '</foo>'
+"   --------------------
+"   begin:<foo>
+"   </foo>:end
+"   --------------------
+"   this function make the content as following
+"   --------------------
+"   begin::end
+"   --------------------
+function! emmet#util#deleteContent(region) abort
+  let lines = getline(a:region[0][0], a:region[1][0])
+  call setpos('.', [0, a:region[0][0], a:region[0][1], 0])
+  silent! exe 'delete '.(a:region[1][0] - a:region[0][0])
+  call setline(line('.'), lines[0][:a:region[0][1]-2] . lines[-1][a:region[1][1]])
+endfunction
+
+" change_content : change content in region
+"   if region make from between '<foo>' and '</foo>'
+"   --------------------
+"   begin:<foo>
+"   </foo>:end
+"   --------------------
+"   and content is
+"   --------------------
+"   foo
+"   bar
+"   baz
+"   --------------------
+"   this function make the content as following
+"   --------------------
+"   begin:foo
+"   bar
+"   baz:end
+"   --------------------
+function! emmet#util#setContent(region, content) abort
+  let newlines = split(a:content, '\n', 1)
+  let oldlines = getline(a:region[0][0], a:region[1][0])
+  call setpos('.', [0, a:region[0][0], a:region[0][1], 0])
+  silent! exe 'delete '.(a:region[1][0] - a:region[0][0])
+  if len(newlines) == 0
+    let tmp = ''
+    if a:region[0][1] > 1
+      let tmp = oldlines[0][:a:region[0][1]-2]
+    endif
+    if a:region[1][1] >= 1
+      let tmp .= oldlines[-1][a:region[1][1]:]
+    endif
+    call setline(line('.'), tmp)
+  elseif len(newlines) == 1
+    if a:region[0][1] > 1
+      let newlines[0] = oldlines[0][:a:region[0][1]-2] . newlines[0]
+    endif
+    if a:region[1][1] >= 1
+      let newlines[0] .= oldlines[-1][a:region[1][1]:]
+    endif
+    call setline(line('.'), newlines[0])
+  else
+    if a:region[0][1] > 1
+      let newlines[0] = oldlines[0][:a:region[0][1]-2] . newlines[0]
+    endif
+    if a:region[1][1] >= 1
+      let newlines[-1] .= oldlines[-1][a:region[1][1]:]
+    endif
+    call setline(line('.'), newlines[0])
+    call append(line('.'), newlines[1:])
+  endif
+endfunction
+
+" select_region : select region
+"   this function make a selection of region
+function! emmet#util#selectRegion(region) abort
+  call setpos('.', [0, a:region[1][0], a:region[1][1], 0])
+  normal! v
+  call setpos('.', [0, a:region[0][0], a:region[0][1], 0])
+endfunction
+
+" point_in_region : check point is in the region
+"   this function return 0 or 1
+function! emmet#util#pointInRegion(point, region) abort
+  if !emmet#util#regionIsValid(a:region) | return 0 | endif
+  if a:region[0][0] > a:point[0] | return 0 | endif
+  if a:region[1][0] < a:point[0] | return 0 | endif
+  if a:region[0][0] == a:point[0] && a:region[0][1] > a:point[1] | return 0 | endif
+  if a:region[1][0] == a:point[0] && a:region[1][1] < a:point[1] | return 0 | endif
+  return 1
+endfunction
+
+" cursor_in_region : check cursor is in the region
+"   this function return 0 or 1
+function! emmet#util#cursorInRegion(region) abort
+  if !emmet#util#regionIsValid(a:region) | return 0 | endif
+  let cur = emmet#util#getcurpos()[1:2]
+  return emmet#util#pointInRegion(cur, a:region)
+endfunction
+
+" region_is_valid : check region is valid
+"   this function return 0 or 1
+function! emmet#util#regionIsValid(region) abort
+  if a:region[0][0] == 0 || a:region[1][0] == 0 | return 0 | endif
+  return 1
+endfunction
+
+" search_region : make region from pattern which is composing start/end
+"   this function return array of position
+function! emmet#util#searchRegion(start, end) abort
+  let b = searchpairpos(a:start, '', a:end, 'bcnW')
+  if b == [0, 0]
+    return [searchpairpos(a:start, '', a:end, 'bnW'), searchpairpos(a:start, '\%#', a:end, 'nW')]
+  else
+    return [b, searchpairpos(a:start, '', a:end. '', 'nW')]
+  endif
+endfunction
+
+" get_content : get content in region
+"   this function return string in region
+function! emmet#util#getContent(region) abort
+  if !emmet#util#regionIsValid(a:region)
+    return ''
+  endif
+  let lines = getline(a:region[0][0], a:region[1][0])
+  if a:region[0][0] == a:region[1][0]
+    let lines[0] = lines[0][a:region[0][1]-1:a:region[1][1]-1]
+  else
+    let lines[0] = lines[0][a:region[0][1]-1:]
+    let lines[-1] = lines[-1][:a:region[1][1]-1]
+  endif
+  return join(lines, "\n")
+endfunction
+
+" region_in_region : check region is in the region
+"   this function return 0 or 1
+function! emmet#util#regionInRegion(outer, inner) abort
+  if !emmet#util#regionIsValid(a:inner) || !emmet#util#regionIsValid(a:outer)
+    return 0
+  endif
+  return emmet#util#pointInRegion(a:inner[0], a:outer) && emmet#util#pointInRegion(a:inner[1], a:outer)
+endfunction
+
+" get_visualblock : get region of visual block
+"   this function return region of visual block
+function! emmet#util#getVisualBlock() abort
+  return [[line("'<"), col("'<")], [line("'>"), col("'>")]]
+endfunction
+
+"==============================================================================
+" html utils
+"==============================================================================
+function! emmet#util#getContentFromURL(url) abort
+  let res = system(printf('%s -i %s', g:emmet_curl_command, shellescape(substitute(a:url, '#.*', '', ''))))
+  while res =~# '^HTTP/1.\d 3' || res =~# '^HTTP/1\.\d 200 Connection established' || res =~# '^HTTP/1\.\d 100 Continue'
+    let pos = stridx(res, "\r\n\r\n")
+    if pos != -1
+      let res = strpart(res, pos+4)
+    else
+      let pos = stridx(res, "\n\n")
+      let res = strpart(res, pos+2)
+    endif
+  endwhile
+  let pos = stridx(res, "\r\n\r\n")
+  if pos != -1
+    let content = strpart(res, pos+4)
+  else
+    let pos = stridx(res, "\n\n")
+    let content = strpart(res, pos+2)
+  endif
+  let header = res[:pos-1]
+  let charset = matchstr(content, '<meta[^>]\+content=["''][^;"'']\+;\s*charset=\zs[^;"'']\+\ze["''][^>]*>')
+  if len(charset) == 0
+    let charset = matchstr(content, '<meta\s\+charset=["'']\?\zs[^"'']\+\ze["'']\?[^>]*>')
+  endif
+  if len(charset) == 0
+    let charset = matchstr(header, '\nContent-Type:.* charset=[''"]\?\zs[^''";\n]\+\ze')
+  endif
+  if len(charset) == 0
+    let s1 = len(split(content, '?'))
+    let utf8 = iconv(content, 'utf-8', &encoding)
+    let s2 = len(split(utf8, '?'))
+    return (s2 == s1 || s2 >= s1 * 2) ? utf8 : content
+  endif
+  return iconv(content, charset, &encoding)
+endfunction
+
+function! emmet#util#getTextFromHTML(buf) abort
+  let threshold_len = 100
+  let threshold_per = 0.1
+  let buf = a:buf
+
+  let buf = strpart(buf, stridx(buf, '</head>'))
+  let buf = substitute(buf, '<style[^>]*>.\{-}</style>', '', 'g')
+  let buf = substitute(buf, '<script[^>]*>.\{-}</script>', '', 'g')
+  let res = ''
+  let max = 0
+  let mx = '\(<td[^>]\{-}>\)\|\(<\/td>\)\|\(<div[^>]\{-}>\)\|\(<\/div>\)'
+  let m = split(buf, mx)
+  for str in m
+    let c = split(str, '<[^>]*?>')
+    let str = substitute(str, '<[^>]\{-}>', ' ', 'g')
+    let str = substitute(str, '&gt;', '>', 'g')
+    let str = substitute(str, '&lt;', '<', 'g')
+    let str = substitute(str, '&quot;', '"', 'g')
+    let str = substitute(str, '&apos;', '''', 'g')
+    let str = substitute(str, '&nbsp;', ' ', 'g')
+    let str = substitute(str, '&yen;', '\&#65509;', 'g')
+    let str = substitute(str, '&amp;', '\&', 'g')
+    let str = substitute(str, '^\s*\(.*\)\s*$', '\1', '')
+    let str = substitute(str, '\s\+', ' ', 'g')
+    let l = len(str)
+    if l > threshold_len
+      let per = (l+0.0) / len(c)
+      if max < l && per > threshold_per
+        let max = l
+        let res = str
+      endif
+    endif
+  endfor
+  let res = substitute(res, '^\s*\(.*\)\s*$', '\1', 'g')
+  return res
+endfunction
+
+function! emmet#util#getImageSize(fn) abort
+  let fn = a:fn
+
+  if emmet#util#isImageMagickInstalled()
+    return emmet#util#imageSizeWithImageMagick(fn)
+  endif
+
+  if filereadable(fn)
+    let hex = substitute(system('xxd -p "'.fn.'"'), '\n', '', 'g')
+  else
+    if fn !~# '^\w\+://'
+      let path = fnamemodify(expand('%'), ':p:gs?\\?/?')
+      if has('win32') || has('win64') |
+        let path = tolower(path)
+      endif
+      for k in keys(g:emmet_docroot)
+        let root = fnamemodify(k, ':p:gs?\\?/?')
+        if has('win32') || has('win64') |
+          let root = tolower(root)
+        endif
+        if stridx(path, root) == 0
+          let v = g:emmet_docroot[k]
+          let fn = (len(v) == 0 ? k : v) . fn
+          break
+        endif
+      endfor
+    endif
+    let hex = substitute(system(g:emmet_curl_command.' "'.fn.'" | xxd -p'), '\n', '', 'g')
+  endif
+
+  let [width, height] = [-1, -1]
+  if hex =~# '^89504e470d0a1a0a'
+    let width = eval('0x'.hex[32:39])
+    let height = eval('0x'.hex[40:47])
+  endif
+  if hex =~# '^ffd8'
+    let pos = 4
+    while pos < len(hex)
+      let bs = hex[pos+0:pos+3]
+      let pos += 4
+      if bs ==# 'ffc0' || bs ==# 'ffc2'
+        let pos += 6
+        let height = eval('0x'.hex[pos+0:pos+1])*256 + eval('0x'.hex[pos+2:pos+3])
+        let pos += 4
+        let width = eval('0x'.hex[pos+0:pos+1])*256 + eval('0x'.hex[pos+2:pos+3])
+        break
+      elseif bs =~# 'ffd[9a]'
+        break
+      elseif bs =~# 'ff\(e[0-9a-e]\|fe\|db\|dd\|c4\)'
+        let pos += (eval('0x'.hex[pos+0:pos+1])*256 + eval('0x'.hex[pos+2:pos+3])) * 2
+      endif
+    endwhile
+  endif
+  if hex =~# '^47494638'
+    let width = eval('0x'.hex[14:15].hex[12:13])
+    let height = eval('0x'.hex[18:19].hex[16:17])
+  endif
+
+  return [width, height]
+endfunction
+
+function! emmet#util#imageSizeWithImageMagick(fn) abort
+  let img_info = system('identify -format "%wx%h" "'.a:fn.'"')
+  let img_size = split(substitute(img_info, '\n', '', ''), 'x')
+  if len(img_size) != 2
+    return [-1, -1]
+  endif
+  return img_size
+endfunction
+
+function! emmet#util#isImageMagickInstalled() abort
+  if !get(g:, 'emmet_use_identify', 1)
+    return 0
+  endif
+  return executable('identify')
+endfunction
+
+function! s:b64encode(bytes, table, pad)
+  let b64 = []
+  for i in range(0, len(a:bytes) - 1, 3)
+    let n = a:bytes[i] * 0x10000
+          \ + get(a:bytes, i + 1, 0) * 0x100
+          \ + get(a:bytes, i + 2, 0)
+    call add(b64, a:table[n / 0x40000])
+    call add(b64, a:table[n / 0x1000 % 0x40])
+    call add(b64, a:table[n / 0x40 % 0x40])
+    call add(b64, a:table[n % 0x40])
+  endfor
+  if len(a:bytes) % 3 == 2
+    let b64[-1] = a:pad
+  elseif len(a:bytes) % 3 == 1
+    let b64[-1] = a:pad
+    let b64[-2] = a:pad
+  endif
+  return b64
+endfunction
+
+function! emmet#util#imageEncodeDecode(fn, flag) abort
+  let fn = a:fn
+
+  if filereadable(fn)
+    let hex = substitute(system('xxd -p "'.fn.'"'), '\n', '', 'g')
+  else
+    if fn !~# '^\w\+://'
+      let path = fnamemodify(expand('%'), ':p:gs?\\?/?')
+      if has('win32') || has('win64') |
+        let path = tolower(path)
+      endif
+      for k in keys(g:emmet_docroot)
+        let root = fnamemodify(k, ':p:gs?\\?/?')
+        if has('win32') || has('win64') |
+          let root = tolower(root)
+        endif
+        if stridx(path, root) == 0
+          let v = g:emmet_docroot[k]
+          let fn = (len(v) == 0 ? k : v) . fn
+          break
+        endif
+      endfor
+    endif
+    let hex = substitute(system(g:emmet_curl_command.' "'.fn.'" | xxd -p'), '\n', '', 'g')
+  endif
+
+  let bin = map(split(hex, '..\zs'), 'eval("0x" . v:val)')
+  let table = split('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', '\zs')
+  let ret = 'data:image/'
+  if hex =~# '^89504e470d0a1a0a'
+    let ret .= 'png'
+  elseif hex =~# '^ffd8'
+    let ret .= 'jpeg'
+  elseif hex =~# '^47494638'
+    let ret .= 'gif'
+  else
+    let ret .= 'unknown'
+  endif
+  return ret . ';base64,' . join(s:b64encode(bin, table, '='), '')
+endfunction
+
+function! emmet#util#unique(arr) abort
+  let m = {}
+  let r = []
+  for i in a:arr
+    if !has_key(m, i)
+      let m[i] = 1
+      call add(r, i)
+    endif
+  endfor
+  return r
+endfunction
+
+let s:seed = localtime()
+function! emmet#util#srand(seed) abort
+  let s:seed = a:seed
+endfunction
+
+function! emmet#util#rand() abort
+  let s:seed = s:seed * 214013 + 2531011
+  return (s:seed < 0 ? s:seed - 0x80000000 : s:seed) / 0x10000 % 0x8000
+endfunction
+
+function! emmet#util#cache(name, ...) abort
+  let content = get(a:000, 0, '')
+  let dir = expand('~/.emmet/cache')
+  if !isdirectory(dir)
+    call mkdir(dir, 'p', 0700)
+  endif
+  let file = dir . '/' . substitute(a:name, '\W', '_', 'g')
+  if len(content) == 0
+    if !filereadable(file)
+      return ''
+    endif
+	return join(readfile(file), "\n")
+  endif
+  call writefile(split(content, "\n"), file)
+endfunction
+
+function! emmet#util#getcurpos() abort
+  let pos = getpos('.')
+  if mode(0) ==# 'i' && pos[2] > 0
+    let pos[2] -=1
+  endif
+  return pos
+endfunction
+
+function! emmet#util#closePopup() abort
+  return pumvisible() ? "\<c-e>" : ''
+endfunction
diff --git a/config/vim/autoload/rainbow_parentheses.vim b/config/vim/autoload/rainbow_parentheses.vim
new file mode 100644
index 0000000..87a74ad
--- /dev/null
+++ b/config/vim/autoload/rainbow_parentheses.vim
@@ -0,0 +1,98 @@
+"==============================================================================
+"  Description: Rainbow colors for parentheses, based on rainbow_parenthsis.vim
+"               by Martin Krischik and others.
+"               2011-10-12: Use less code.  Leave room for deeper levels.
+"==============================================================================
+
+let s:pairs = [
+	\ ['brown',       'RoyalBlue3'],
+	\ ['Darkblue',    'SeaGreen3'],
+	\ ['darkgray',    'DarkOrchid3'],
+	\ ['darkgreen',   'firebrick3'],
+	\ ['darkcyan',    'RoyalBlue3'],
+	\ ['darkred',     'SeaGreen3'],
+	\ ['darkmagenta', 'DarkOrchid3'],
+	\ ['brown',       'firebrick3'],
+	\ ['gray',        'RoyalBlue3'],
+	\ ['black',       'SeaGreen3'],
+	\ ['darkmagenta', 'DarkOrchid3'],
+	\ ['Darkblue',    'firebrick3'],
+	\ ['darkgreen',   'RoyalBlue3'],
+	\ ['darkcyan',    'SeaGreen3'],
+	\ ['darkred',     'DarkOrchid3'],
+	\ ['red',         'firebrick3'],
+	\ ]
+let s:pairs = exists('g:rbpt_colorpairs') ? g:rbpt_colorpairs : s:pairs
+let s:max = exists('g:rbpt_max') ? g:rbpt_max : max([len(s:pairs), 16])
+let s:loadtgl = exists('g:rbpt_loadcmd_toggle') ? g:rbpt_loadcmd_toggle : 0
+let s:types = [['(',')'],['\[','\]'],['{','}'],['<','>']]
+
+func! s:extend()
+	if s:max > len(s:pairs)
+		cal extend(s:pairs, s:pairs)
+		cal s:extend()
+	elseif s:max < len(s:pairs)
+		cal remove(s:pairs, s:max, -1)
+	endif
+endfunc
+cal s:extend()
+
+func! rainbow_parentheses#activate()
+	let [id, s:active] = [1, 1]
+	for [ctermfg, guifg] in s:pairs
+		exe 'hi default level'.id.'c ctermfg='.ctermfg.' guifg='.guifg
+		let id += 1
+	endfor
+endfunc
+
+func! rainbow_parentheses#clear()
+	for each in range(1, s:max)
+		exe 'hi clear level'.each.'c'
+	endfor
+	let s:active = 0
+endfunc
+
+func! rainbow_parentheses#toggle()
+	if !exists('s:active')
+		cal rainbow_parentheses#load(0)
+	endif
+	let afunc = exists('s:active') && s:active ? 'clear' : 'activate'
+	cal call('rainbow_parentheses#'.afunc, [])
+endfunc
+
+func! rainbow_parentheses#toggleall()
+	if !exists('s:active')
+		cal rainbow_parentheses#load(0)
+		cal rainbow_parentheses#load(1)
+		cal rainbow_parentheses#load(2)
+	endif
+	if exists('s:active') && s:active
+		cal rainbow_parentheses#clear()
+	else
+		cal rainbow_parentheses#activate()
+	endif
+endfunc
+
+func! s:cluster()
+	let levels = join(map(range(1, s:max), '"level".v:val'), ',')
+	exe 'sy cluster rainbow_parentheses contains=@TOP'.levels.',NoInParens'
+endfunc
+cal s:cluster()
+
+func! rainbow_parentheses#load(...)
+	let [level, grp, type] = ['', '', s:types[a:1]]
+	let alllvls = map(range(1, s:max), '"level".v:val')
+	if !exists('b:loaded')
+		let b:loaded = [0,0,0,0]
+	endif
+	let b:loaded[a:1] = s:loadtgl && b:loaded[a:1] ? 0 : 1
+	for each in range(1, s:max)
+		let region = 'level'. each .(b:loaded[a:1] ? '' : 'none')
+		let grp = b:loaded[a:1] ? 'level'.each.'c' : 'Normal'
+		let cmd = 'sy region %s matchgroup=%s start=/%s/ end=/%s/ contains=TOP,%s,NoInParens'
+		exe printf(cmd, region, grp, type[0], type[1], join(alllvls, ','))
+		cal remove(alllvls, 0)
+	endfor
+endfunc
+
+" vim:ts=2:sw=2:sts=2
diff --git a/config/vim/plugin/colorizer.vim b/config/vim/plugin/colorizer.vim
new file mode 100644
index 0000000..4372234
--- /dev/null
+++ b/config/vim/plugin/colorizer.vim
@@ -0,0 +1,62 @@
+" colorizer.vim	Colorize all text in the form #rrggbb or #rgb; entrance
+" Maintainer:	lilydjwg <lilydjwg@gmail.com>
+" Version:	1.4.1
+" Licence:	Vim license. See ':help license'
+" Derived From: css_color.vim
+" 		http://www.vim.org/scripts/script.php?script_id=2150
+" Thanks To:	Niklas Hofer (Author of css_color.vim), Ingo Karkat, rykka,
+"		KrzysztofUrban, blueyed, shanesmith
+" Usage:
+"
+" This plugin defines three commands:
+"
+" 	ColorHighlight	- start/update highlighting
+" 	ColorClear      - clear all highlights
+" 	ColorToggle     - toggle highlights
+"
+" By default, <leader>tc is mapped to ColorToggle. If you want to use another
+" key map, do like this:
+" 	nmap ,tc <Plug>Colorizer
+"
+" If you want completely not to map it, set the following in your vimrc:
+"	let g:colorizer_nomap = 1
+"
+" To use solid color highlight, set this in your vimrc (later change won't
+" probably take effect unless you use ':ColorHighlight!' to force update):
+"	let g:colorizer_fgcontrast = -1
+" set it to 0 or 1 to use a softened foregroud color.
+"
+" If you don't want to enable colorizer at startup, set the following:
+"	let g:colorizer_startup = 0
+"
+" Note: if you modify a color string in normal mode, if the cursor is still on
+" that line, it'll take 'updatetime' seconds to update. You can use
+" :ColorHighlight (or your key mapping) again to force update.
+"
+" Performace Notice: In terminal, it may take several seconds to highlight 240
+" different colors. GUI version is much quicker.
+
+" Reload guard and 'compatible' handling {{{1
+if exists("loaded_colorizer") || v:version < 700 || !(has("gui_running") || &t_Co == 256)
+  finish
+endif
+let loaded_colorizer = 1
+
+let s:save_cpo = &cpo
+set cpo&vim
+
+"Define commands {{{1
+command! -bar -bang ColorHighlight call colorizer#ColorHighlight(1, "<bang>")
+command! -bar ColorClear call colorizer#ColorClear()
+command! -bar ColorToggle call colorizer#ColorToggle()
+nnoremap <silent> <Plug>Colorizer :ColorToggle<CR>
+if !hasmapto("<Plug>Colorizer") && (!exists("g:colorizer_nomap") || g:colorizer_nomap == 0)
+  nmap <unique> <Leader>tc <Plug>Colorizer
+endif
+if !exists('g:colorizer_startup') || g:colorizer_startup
+  call colorizer#ColorHighlight(0)
+endif
+
+" Cleanup and modelines {{{1
+let &cpo = s:save_cpo
+" vim:ft=vim:fdm=marker:fmr={{{,}}}:
diff --git a/config/vim/plugin/emmet.vim b/config/vim/plugin/emmet.vim
new file mode 100644
index 0000000..dad03a8
--- /dev/null
+++ b/config/vim/plugin/emmet.vim
@@ -0,0 +1,191 @@
+"=============================================================================
+" File: emmet.vim
+" Author: Yasuhiro Matsumoto <mattn.jp@gmail.com>
+" Last Change: 26-Jul-2015.
+" Version: 0.86
+" WebPage: http://github.com/mattn/emmet-vim
+" Description: vim plugins for HTML and CSS hi-speed coding.
+" SeeAlso: http://emmet.io/
+" Usage:
+"
+"   This is vim script support expanding abbreviation like emmet.
+"   ref: http://emmet.io/
+"
+"   Type abbreviation
+"      +-------------------------------------
+"      | html:5_
+"      +-------------------------------------
+"   "_" is a cursor position. and type "<c-y>," (Ctrl+y and Comma)
+"   NOTE: Don't worry about key map. you can change it easily.
+"      +-------------------------------------
+"      | <!DOCTYPE HTML>
+"      | <html lang="en">
+"      | <head>
+"      |     <title></title>
+"      |     <meta charset="UTF-8">
+"      | </head>
+"      | <body>
+"      |      _
+"      | </body>
+"      | </html>
+"      +-------------------------------------
+"   Type following
+"      +-------------------------------------
+"      | div#foo$*2>div.bar
+"      +-------------------------------------
+"   And type "<c-y>,"
+"      +-------------------------------------
+"      |<div id="foo1">
+"      |    <div class="bar">_</div>
+"      |</div>
+"      |<div id="foo2">
+"      |    <div class="bar"></div>
+"      |</div>
+"      +-------------------------------------
+"
+" Tips:
+"
+"   You can customize behavior of expanding with overriding config.
+"   This configuration will be merged at loading plugin.
+"
+"     let g:user_emmet_settings = {
+"     \  'indentation' : '  ',
+"     \  'perl' : {
+"     \    'aliases' : {
+"     \      'req' : 'require '
+"     \    },
+"     \    'snippets' : {
+"     \      'use' : "use strict\nuse warnings\n\n",
+"     \      'warn' : "warn \"|\";",
+"     \    }
+"     \  }
+"     \}
+"
+"   You can set language attribute in html using 'emmet_settings.lang'.
+"
+" GetLatestVimScripts: 2981 1 :AutoInstall: emmet.vim
+" script type: plugin
+
+if &compatible || v:version < 702 || (exists('g:loaded_emmet_vim') && g:loaded_emmet_vim)
+  finish
+endif
+let g:loaded_emmet_vim = 1
+
+let s:save_cpo = &cpoptions
+set cpoptions&vim
+
+if !exists('g:emmet_html5')
+  let g:emmet_html5 = 1
+endif
+
+if !exists('g:emmet_docroot')
+  let g:emmet_docroot = {}
+endif
+
+if !exists('g:emmet_debug')
+  let g:emmet_debug = 0
+endif
+
+if !exists('g:emmet_curl_command')
+  let g:emmet_curl_command = 'curl -s -L -A Mozilla/5.0'
+endif
+
+if !exists('g:user_emmet_leader_key')
+  let g:user_emmet_leader_key = '<c-y>'
+endif
+
+function! s:install_plugin(mode, buffer)
+  let buffer = a:buffer ? '<buffer>' : ''
+  let items = [
+  \ {'mode': 'i', 'var': 'user_emmet_expandabbr_key', 'key': ',', 'plug': 'emmet-expand-abbr', 'func': '<c-r>=emmet#util#closePopup()<cr><c-r>=emmet#expandAbbr(0,"")<cr>'},
+  \ {'mode': 'n', 'var': 'user_emmet_expandabbr_key', 'key': ',', 'plug': 'emmet-expand-abbr', 'func': ':call emmet#expandAbbr(3,"")<cr>'},
+  \ {'mode': 'v', 'var': 'user_emmet_expandabbr_key', 'key': ',', 'plug': 'emmet-expand-abbr', 'func': ':call emmet#expandAbbr(2,"")<cr>'},
+  \ {'mode': 'i', 'var': 'user_emmet_expandword_key', 'key': ';', 'plug': 'emmet-expand-word', 'func': '<c-r>=emmet#util#closePopup()<cr><c-r>=emmet#expandAbbr(1,"")<cr>'},
+  \ {'mode': 'n', 'var': 'user_emmet_expandword_key', 'key': ';', 'plug': 'emmet-expand-word', 'func': ':call emmet#expandAbbr(1,"")<cr>'},
+  \ {'mode': 'i', 'var': 'user_emmet_update_tag', 'key': 'u', 'plug': 'emmet-update-tag', 'func': '<c-r>=emmet#util#closePopup()<cr><c-r>=emmet#updateTag()<cr>'},
+  \ {'mode': 'n', 'var': 'user_emmet_update_tag', 'key': 'u', 'plug': 'emmet-update-tag', 'func': ':call emmet#updateTag()<cr>'},
+  \ {'mode': 'i', 'var': 'user_emmet_balancetaginward_key', 'key': 'd', 'plug': 'emmet-balance-tag-inward', 'func': '<esc>:call emmet#balanceTag(1)<cr>'},
+  \ {'mode': 'n', 'var': 'user_emmet_balancetaginward_key', 'key': 'd', 'plug': 'emmet-balance-tag-inward', 'func': ':call emmet#balanceTag(1)<cr>'},
+  \ {'mode': 'v', 'var': 'user_emmet_balancetaginward_key', 'key': 'd', 'plug': 'emmet-balance-tag-inward', 'func': '<esc>:call emmet#balanceTag(1)<cr>'},
+  \ {'mode': 'i', 'var': 'user_emmet_balancetagoutward_key', 'key': 'D', 'plug': 'emmet-balance-tag-outword', 'func': '<esc>:call emmet#balanceTag(-1)<cr>'},
+  \ {'mode': 'n', 'var': 'user_emmet_balancetagoutward_key', 'key': 'D', 'plug': 'emmet-balance-tag-outword', 'func': ':call emmet#balanceTag(-1)<cr>'},
+  \ {'mode': 'v', 'var': 'user_emmet_balancetagoutward_key', 'key': 'D', 'plug': 'emmet-balance-tag-outword', 'func': '<esc>:call emmet#balanceTag(-1)<cr>'},
+  \ {'mode': 'i', 'var': 'user_emmet_next_key', 'key': 'n', 'plug': 'emmet-move-next', 'func': '<c-r>=emmet#util#closePopup()<cr><c-r>=emmet#moveNextPrev(0)<cr>'},
+  \ {'mode': 'n', 'var': 'user_emmet_next_key', 'key': 'n', 'plug': 'emmet-move-next', 'func': ':call emmet#moveNextPrev(0)<cr>'},
+  \ {'mode': 'i', 'var': 'user_emmet_prev_key', 'key': 'N', 'plug': 'emmet-move-prev', 'func': '<c-r>=emmet#util#closePopup()<cr><c-r>=emmet#moveNextPrev(1)<cr>'},
+  \ {'mode': 'n', 'var': 'user_emmet_prev_key', 'key': 'N', 'plug': 'emmet-move-prev', 'func': ':call emmet#moveNextPrev(1)<cr>'},
+  \ {'mode': 'i', 'var': '', 'key': '', 'plug': 'emmet-move-next-item', 'func': '<esc>:call emmet#moveNextPrevItem(0)<cr>'},
+  \ {'mode': 'n', 'var': '', 'key': '', 'plug': 'emmet-move-next-item', 'func': ':call emmet#moveNextPrevItem(0)<cr>'},
+  \ {'mode': 'i', 'var': '', 'key': '', 'plug': 'emmet-move-prev-item', 'func': '<esc>:call emmet#moveNextPrevItem(1)<cr>'},
+  \ {'mode': 'n', 'var': '', 'key': '', 'plug': 'emmet-move-prev-item', 'func': ':call emmet#moveNextPrevItem(1)<cr>'},
+  \ {'mode': 'i', 'var': 'user_emmet_imagesize_key', 'key': 'i', 'plug': 'emmet-image-size', 'func': '<c-r>=emmet#util#closePopup()<cr><c-r>=emmet#imageSize()<cr>'},
+  \ {'mode': 'n', 'var': 'user_emmet_imagesize_key', 'key': 'i', 'plug': 'emmet-image-size', 'func': ':call emmet#imageSize()<cr>'},
+  \ {'mode': 'i', 'var': 'user_emmet_imageencode_key', 'key': 'I', 'plug': 'emmet-image-encode', 'func': '<c-r>=emmet#util#closePopup()<cr><c-r>=emmet#imageEncode()<cr>'},
+  \ {'mode': 'n', 'var': 'user_emmet_imageencode_key', 'key': 'I', 'plug': 'emmet-image-encode', 'func': ':call emmet#imageEncode()<cr>'},
+  \ {'mode': 'i', 'var': 'user_emmet_togglecomment_key', 'key': '/', 'plug': 'emmet-toggle-comment', 'func': '<c-r>=emmet#util#closePopup()<cr><c-r>=emmet#toggleComment()<cr>'},
+  \ {'mode': 'n', 'var': 'user_emmet_togglecomment_key', 'key': '/', 'plug': 'emmet-toggle-comment', 'func': ':call emmet#toggleComment()<cr>'},
+  \ {'mode': 'i', 'var': 'user_emmet_splitjointag_key', 'key': 'j', 'plug': 'emmet-split-join-tag', 'func': '<esc>:call emmet#splitJoinTag()<cr>'},
+  \ {'mode': 'n', 'var': 'user_emmet_splitjointag_key', 'key': 'j', 'plug': 'emmet-split-join-tag', 'func': ':call emmet#splitJoinTag()<cr>'},
+  \ {'mode': 'i', 'var': 'user_emmet_removetag_key', 'key': 'k', 'plug': 'emmet-remove-tag', 'func': '<c-r>=emmet#util#closePopup()<cr><c-r>=emmet#removeTag()<cr>'},
+  \ {'mode': 'n', 'var': 'user_emmet_removetag_key', 'key': 'k', 'plug': 'emmet-remove-tag', 'func': ':call emmet#removeTag()<cr>'},
+  \ {'mode': 'i', 'var': 'user_emmet_anchorizeurl_key', 'key': 'a', 'plug': 'emmet-anchorize-url', 'func': '<c-r>=emmet#util#closePopup()<cr><c-r>=emmet#anchorizeURL(0)<cr>'},
+  \ {'mode': 'n', 'var': 'user_emmet_anchorizeurl_key', 'key': 'a', 'plug': 'emmet-anchorize-url', 'func': ':call emmet#anchorizeURL(0)<cr>'},
+  \ {'mode': 'i', 'var': 'user_emmet_anchorizesummary_key', 'key': 'A', 'plug': 'emmet-anchorize-summary', 'func': '<c-r>=emmet#util#closePopup()<cr><c-r>=emmet#anchorizeURL(1)<cr>'},
+  \ {'mode': 'n', 'var': 'user_emmet_anchorizesummary_key', 'key': 'A', 'plug': 'emmet-anchorize-summary', 'func': ':call emmet#anchorizeURL(1)<cr>'},
+  \ {'mode': 'i', 'var': 'user_emmet_mergelines_key', 'key': 'm', 'plug': 'emmet-merge-lines', 'func': '<c-r>=emmet#util#closePopup()<cr><c-r>=emmet#mergeLines()<cr>'},
+  \ {'mode': 'n', 'var': 'user_emmet_mergelines_key', 'key': 'm', 'plug': 'emmet-merge-lines', 'func': ':call emmet#mergeLines()<cr>'},
+  \ {'mode': 'v', 'var': 'user_emmet_codepretty_key', 'key': 'c', 'plug': 'emmet-code-pretty', 'func': ':call emmet#codePretty()<cr>'},
+  \]
+
+  let only_plug = get(g:, 'emmet_install_only_plug', 0)
+  for item in items
+    if a:mode !=# 'a' && stridx(a:mode, item.mode) == -1
+      continue
+    endif
+    exe item.mode . 'noremap '. buffer .' <plug>(' . item.plug . ') ' . item.func
+    if item.var != '' && !only_plug
+      if exists('g:' . item.var)
+        let key = eval('g:' . item.var)
+      else
+        let key = g:user_emmet_leader_key . item.key
+      endif
+      if !hasmapto('<plug>(' . item.plug . ')', item.mode) && !len(maparg(key, item.mode))
+        exe item.mode . 'map ' . buffer . ' <unique> ' . key . ' <plug>(' . item.plug . ')'
+      endif
+    endif
+  endfor
+
+  if exists('g:user_emmet_complete_tag') && g:user_emmet_complete_tag
+    if get(g:, 'user_emmet_install_global', 1)
+      set omnifunc=emmet#completeTag
+    else
+      setlocal omnifunc=emmet#completeTag
+    endif
+  endif
+endfunction
+
+command! -nargs=0 -bar EmmetInstall call <SID>install_plugin(get(g:, 'user_emmet_mode', 'a'), 1)
+
+if get(g:, 'user_emmet_install_global', 1)
+  call s:install_plugin(get(g:, 'user_emmet_mode', 'a'), 0)
+endif
+
+if get(g:, 'user_emmet_install_command', 1)
+  command! -nargs=1 Emmet call emmet#expandAbbr(4, <q-args>)
+endif
+
+function! s:setup_styledEmmetAbbreviation() abort
+  if index(['javascript', 'javascriptreact', 'typescript', 'typescriptreact'], &filetype) != -1
+    syntax match styledEmmetAbbreviation "[a-z0-9#+!%]\+" containedin=styledDefinition contained
+  endif
+endfunction
+
+augroup ___emmet_setup___
+  au!
+  autocmd Syntax * call s:setup_styledEmmetAbbreviation()
+augroup END
+
+let &cpoptions = s:save_cpo
+unlet s:save_cpo
+
+" vim:set et:
diff --git a/config/vim/plugin/pickachu.vim b/config/vim/plugin/pickachu.vim
new file mode 100644
index 0000000..259bac7
--- /dev/null
+++ b/config/vim/plugin/pickachu.vim
@@ -0,0 +1,45 @@
+"Script: Pickachu
+"Version: 0.0.1
+"Copyright: Copyright (C) 2018 Doug Beney
+"Licence: 
+"Website: https://dougie.io
+
+if !has('python3')
+	echo "You need Vim Python3 support to use this plugin. If you're using NeoVim, try running `pip3 install neovim` to resolve this issue."
+endif
+
+if !exists('g:pickachu_default_app')
+	let g:pickachu_default_app = "color"
+endif
+
+if !exists("g:pickachu_default_command")
+	let g:pickachu_default_command = "zenity"
+endif
+
+if !exists("g:pickachu_default_date_format")
+	let g:pickachu_default_date_format = "%m/%d/%Y"
+endif
+
+if !exists("g:pickachu_default_color_format")
+	let g:pickachu_default_color_format = "hex"
+endif
+
+function! s:pickachuCompletion(ArgLead, CmdLine, CursorPos)
+	let options = ['color', 'date', 'file']
+	return options
+endfunction
+
+command! -nargs=* -complete=customlist,<SID>pickachuCompletion Pickachu call Pickachu(<f-args>)
+
+python3 import sys
+python3 import vim
+python3 sys.path.append(vim.eval('expand("<sfile>:h")'))
+
+function! Pickachu(...)
+python3 << EOF
+from pickachu.main import MainFunction
+MainFunction()
+EOF
+endfunction
+
+" vim: noexpandtab
diff --git a/config/vim/plugin/pickachu/__init__.py b/config/vim/plugin/pickachu/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/config/vim/plugin/pickachu/__pycache__/__init__.cpython-39.pyc b/config/vim/plugin/pickachu/__pycache__/__init__.cpython-39.pyc
new file mode 100644
index 0000000..c18ad9c
Binary files /dev/null and b/config/vim/plugin/pickachu/__pycache__/__init__.cpython-39.pyc differ
diff --git a/config/vim/plugin/pickachu/__pycache__/apps.cpython-39.pyc b/config/vim/plugin/pickachu/__pycache__/apps.cpython-39.pyc
new file mode 100644
index 0000000..c564bcc
Binary files /dev/null and b/config/vim/plugin/pickachu/__pycache__/apps.cpython-39.pyc differ
diff --git a/config/vim/plugin/pickachu/__pycache__/main.cpython-39.pyc b/config/vim/plugin/pickachu/__pycache__/main.cpython-39.pyc
new file mode 100644
index 0000000..c35190e
Binary files /dev/null and b/config/vim/plugin/pickachu/__pycache__/main.cpython-39.pyc differ
diff --git a/config/vim/plugin/pickachu/__pycache__/processors.cpython-39.pyc b/config/vim/plugin/pickachu/__pycache__/processors.cpython-39.pyc
new file mode 100644
index 0000000..1cf1153
Binary files /dev/null and b/config/vim/plugin/pickachu/__pycache__/processors.cpython-39.pyc differ
diff --git a/config/vim/plugin/pickachu/apps.py b/config/vim/plugin/pickachu/apps.py
new file mode 100644
index 0000000..00a6826
--- /dev/null
+++ b/config/vim/plugin/pickachu/apps.py
@@ -0,0 +1,68 @@
+import vim
+import subprocess
+from . import processors
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# name:        apps.py
+# description: this function contains a dictionary object
+#              where you can easily add new apps with processor
+#              functions to handle their output. Note: a
+#              processor is optional.
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+ZENITY_COMMAND = vim.eval("g:pickachu_default_command")
+# Note: This is not the final date format that displays on
+#       the users' buffer. This is the format we force
+#       Zenity/Qarma to provide us.
+RETURNED_DATE_FORMAT = "%m/%d/%Y"
+if ZENITY_COMMAND == 'qarma':
+	RETURNED_DATE_FORMAT = "MM/dd/yy"
+
+apps = {
+	'date': {
+		'cmd': ZENITY_COMMAND,
+		'processor': processors.dateProcessor,
+		'options': [
+			'--calendar',
+			'--date-format=' + RETURNED_DATE_FORMAT
+		]
+	},
+	'file': {
+		'cmd': ZENITY_COMMAND,
+		'options': [
+            '--file-selection'
+        ]
+	},
+	'color': {
+		'cmd': ZENITY_COMMAND,
+		'options': [
+			'--color-selection'
+    ],
+		'processor': processors.colorProcessor
+	}
+}
+
+def runApp(choosenApp, format=None):
+	app = apps.get(choosenApp, None)
+	if app:
+		output = None
+		try:
+			command_array = [app['cmd']]
+			if app.get('options', False):
+				for option in app['options']:
+					command_array.append(option)
+			# Logging
+			command_array.append('2> /tmp/pickachu_log')
+			output = subprocess.check_output(command_array).decode('utf-8')
+		except:
+			return None
+
+		if app.get('processor', None):
+			if format:
+				return app['processor'](output.rstrip(), format)
+			else:
+				return app['processor'](output.rstrip())
+		else:
+			return output.rstrip()
+	else:
+		print("App does not exist.")
diff --git a/config/vim/plugin/pickachu/main.py b/config/vim/plugin/pickachu/main.py
new file mode 100644
index 0000000..d9a42b3
--- /dev/null
+++ b/config/vim/plugin/pickachu/main.py
@@ -0,0 +1,36 @@
+import vim
+from . import apps
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# name:        main.py
+# description: This file evaluates the command arguments
+#              provided by the user, calls the runApp function,
+#              and inserts valid output to the user's buffer.
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+DEFAULT_APP = vim.eval('g:pickachu_default_app')
+
+
+def MainFunction():
+	# This section is for getting the
+	# arguments from the user's Vim
+	# command.
+	arglength = int(vim.eval('a:0'))
+	CHOOSEN_APP = DEFAULT_APP
+	CHOOSEN_FORMAT = None
+	if arglength > 0:
+		CHOOSEN_APP = vim.eval('a:1')
+	if arglength > 1:
+		CHOOSEN_FORMAT = vim.eval('a:2')
+
+	# We run apps.py's runApp function to get an output.
+	output = apps.runApp(CHOOSEN_APP, CHOOSEN_FORMAT)
+
+	# Now, if runApp gave us an output, we can use the
+	# Vim API to print the output to the user's buffer.
+	if output:
+		pos_y, pos_x = vim.current.window.cursor
+		vim.current.line = vim.current.line[:pos_x+1] + output + vim.current.line[pos_x+1:]
+		vim.current.window.cursor = (pos_y, pos_x + len(output))
+	else:
+		print('Pickachu - Canceled')
diff --git a/config/vim/plugin/pickachu/processors.py b/config/vim/plugin/pickachu/processors.py
new file mode 100644
index 0000000..0fe04c1
--- /dev/null
+++ b/config/vim/plugin/pickachu/processors.py
@@ -0,0 +1,80 @@
+import vim
+from datetime import datetime
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+# name:				 processors.py
+# description: this file contains functions that process data
+#							 from the runapp function (in app.py).
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+DEFAULT_DATE_FORMAT = vim.eval("g:pickachu_default_date_format")
+DEFAULT_COLOR_FORMAT = vim.eval("g:pickachu_default_color_format")
+
+def dateProcessor(input, format=DEFAULT_DATE_FORMAT):
+	try:
+		dateObj = datetime.strptime(input, '%m/%d/%Y')
+	except(ValueError):
+		dateObj = datetime.strptime(input, '%m/%d/%y')
+	return dateObj.strftime(format)
+
+def colorProcessor(input, format=DEFAULT_COLOR_FORMAT):
+	# The system color picker returned an rgba value
+	if 'rgba' in input:
+		strip = input.strip('rgba)(')
+		array = strip.split(',')
+		# Round the alpha value to two decimal placed
+		array[3] = round(float(array[3]), 2)
+		rgba_string = "rgba("
+		values = ",".join(str(x) for x in array)
+		rgba_string += values + ")"
+		return rgba_string
+	# The system color picker returned an rgb value
+	elif 'rgb' in input:
+		# RGB as input
+		if format == 'rgb':
+			return input
+		else:
+			# Strip 'rgb' and parenthesis
+			strip = input.strip('rgb)(')
+			array = strip.split(',')
+
+			if format == 'hex':
+				hex = '#%02x%02x%02x' % (int(array[0]), int(array[1]), int(array[2]))
+				return hex.upper()
+			elif format == 'rgba':
+				rgba_string = "rgba("
+				array.append(1)
+				values = ",".join(str(x) for x in array)
+				rgba_string += values + ")"
+				return rgba_string
+		return array
+	# The system olor picker returned a hex
+	elif '#' in input:
+		# If there is a '#' in input,
+		# they are most likely using Qarma instead of Zenity
+		# or any other program that outputs hex
+		if format == 'hex':
+			return input
+		else:
+			hex = input.lstrip('#')
+			rgb_array = tuple(int(hex[i:i+2], 16) for i in (0, 2 ,4))
+
+			if format == 'rgb':
+				rgb_string = "rgb("
+				for i in range(0, len(rgb_array)):
+					rgb_string += str(rgb_array[i])
+					if i < len(rgb_array) - 1:
+						rgb_string += ", "
+					else:
+						rgb_string += ")"
+				return rgb_string
+			elif format == 'rgba':
+				rgba_string = "rgba("
+				for i in range(0, len(rgb_array)):
+					rgba_string += str(rgb_array[i])
+					if i < len(rgb_array) - 1:
+						rgba_string += ", "
+					else:
+						rgba_string += ", 1)"
+				return rgba_string
+	return None
diff --git a/config/vim/plugin/rainbow_parentheses.vim b/config/vim/plugin/rainbow_parentheses.vim
new file mode 100644
index 0000000..20ce8e5
--- /dev/null
+++ b/config/vim/plugin/rainbow_parentheses.vim
@@ -0,0 +1,13 @@
+"==============================================================================
+"  Description: Rainbow colors for parentheses, based on rainbow_parenthsis.vim
+"               by Martin Krischik and others.
+"==============================================================================
+"  GetLatestVimScripts: 3772 1 :AutoInstall: rainbow_parentheses.zip
+
+com! RainbowParenthesesToggle       cal rainbow_parentheses#toggle()
+com! RainbowParenthesesToggleAll    cal rainbow_parentheses#toggleall()
+com! RainbowParenthesesActivate     cal rainbow_parentheses#activate()
+com! RainbowParenthesesLoadRound    cal rainbow_parentheses#load(0)
+com! RainbowParenthesesLoadSquare   cal rainbow_parentheses#load(1)
+com! RainbowParenthesesLoadBraces   cal rainbow_parentheses#load(2)
+com! RainbowParenthesesLoadChevrons cal rainbow_parentheses#load(3)
diff --git a/config/vim/spell/fr.utf-8.spl b/config/vim/spell/fr.utf-8.spl
new file mode 100644
index 0000000..ff27132
Binary files /dev/null and b/config/vim/spell/fr.utf-8.spl differ
diff --git a/config/vim/spell/fr.utf-8.sug b/config/vim/spell/fr.utf-8.sug
new file mode 100644
index 0000000..df555d2
Binary files /dev/null and b/config/vim/spell/fr.utf-8.sug differ
diff --git a/config/vim/viminfo b/config/vim/viminfo
new file mode 100644
index 0000000..e495b15
Binary files /dev/null and b/config/vim/viminfo differ
diff --git a/config/vim/vimrc b/config/vim/vimrc
new file mode 100644
index 0000000..bddd690
--- /dev/null
+++ b/config/vim/vimrc
@@ -0,0 +1,34 @@
+set viminfo+=n~/.config/vim/viminfo
+set runtimepath+=~/.config/vim,~/.config/vim/after
+set autoindent
+set wrap
+set linebreak
+set mouse=a
+set autowrite
+
+set tabstop=4 softtabstop=0 expandtab shiftwidth=4 smarttab
+
+set nocompatible
+
+set spelllang=en_gb
+
+set number relativenumber
+
+syntax on 
+
+nnoremap <silent> <C-l> :nohl<CR><C-l>
+
+inoremap { {}<ESC>ha
+inoremap [ []<ESC>ha
+inoremap " ""<ESC>ha
+inoremap ( ()<ESC>ha
+
+inoremap <C-space> <C-n>
+
+inoremap <C-down> <C-E>
+inoremap <C-up> <C-Y>
+
+nnoremap <C-J> <C-W><C-J>
+nnoremap <C-K> <C-W><C-K>
+nnoremap <C-L> <C-W><C-L>
+nnoremap <C-H> <C-W><C-H>
-- 
cgit v1.2.1