123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- " Since vue#Log and vue#GetConfig are always called
- " in syntax and indent files,
- " this file will be sourced on opening the first vue file
- function! s:GetConfig(name, default)
- let name = 'g:vim_vue_plugin_'.a:name
- let value = exists(name) ? eval(name) : a:default
- if a:name == 'config'
- let value = s:MergeUserConfigIntoDefault(value)
- endif
- return value
- endfunction
- function! s:MergeUserConfigIntoDefault(user)
- let default = {
- \'syntax': {
- \ 'template': ['html'],
- \ 'script': ['javascript'],
- \ 'style': ['css'],
- \},
- \'full_syntax': [],
- \'initial_indent': [],
- \'attribute': 0,
- \'keyword': 0,
- \'foldexpr': 0,
- \'debug': 0,
- \}
- let user = a:user
- for key in keys(default)
- if has_key(user, key)
- let default[key] = user[key]
- endif
- endfor
- " For backwards compatibility with 'init_indent'
- if !has_key(user, 'initial_indent')
- if has_key(user, 'init_indent')
- \ ? user.init_indent
- \ : expand('%:e') == 'wpy'
- let default.initial_indent = ['script', 'style']
- endif
- endif
- return default
- endfunction
- function! s:CheckVersion()
- if !exists('g:vim_vue_plugin_config')
- let prev_configs = [
- \'g:vim_vue_plugin_load_full_syntax',
- \'g:vim_vue_plugin_use_pug',
- \'g:vim_vue_plugin_use_coffee',
- \'g:vim_vue_plugin_use_typescript',
- \'g:vim_vue_plugin_use_less',
- \'g:vim_vue_plugin_use_sass',
- \'g:vim_vue_plugin_use_scss',
- \'g:vim_vue_plugin_use_stylus',
- \'g:vim_vue_plugin_has_init_indent',
- \'g:vim_vue_plugin_highlight_vue_attr',
- \'g:vim_vue_plugin_highlight_vue_keyword',
- \'g:vim_vue_plugin_use_foldexpr',
- \'g:vim_vue_plugin_custom_blocks',
- \'g:vim_vue_plugin_debug',
- \]
- let has_prev_config = 0
- for config in prev_configs
- if exists(config)
- let has_prev_config = 1
- break
- endif
- endfor
- if has_prev_config
- let message = 'Hey, it seems that you just upgraded. Please use `g:vim_vue_plugin_config` to replace previous configs'
- let message2 = 'For details, please check README.md ## Configuration or https://github.com/leafOfTree/vim-vue-plugin'
- echom '['.s:name.'] '.message
- echom '['.s:name.'] '.message2
- endif
- endif
- endfunction
- function! s:Main()
- let s:name = 'vim-vue-plugin'
- let s:config = s:GetConfig('config', {})
- let s:full_syntax = s:config.full_syntax
- let s:debug = s:config.debug
- call s:CheckVersion()
- endfunction
- function! vue#Log(msg)
- if s:debug
- echom '['.s:name.'] '.a:msg
- endif
- endfunction
- function! vue#LogWithLnum(msg)
- if s:debug
- echom '['.s:name.']['.v:lnum.'] '.a:msg
- endif
- endfunction
- function! vue#Warn(msg)
- if s:debug
- echohl WarningMsg
- echom '['.s:name.'] '.a:msg
- echohl None
- endif
- endfunction
- function! vue#GetConfig(name, default)
- return s:GetConfig(a:name, a:default)
- endfunction
- if exists('##CursorMoved') && (exists('*OnChangeVueSyntax') || exists('*OnChangeVueSubtype'))
- augroup vim_vue_plugin
- autocmd!
- autocmd CursorMoved,CursorMovedI,WinEnter *.vue,*.wpy
- \ call s:CheckSyntax()
- augroup END
- if exists('*OnChangeVueSyntax')
- let s:OnChangeListener = function('OnChangeVueSyntax')
- else
- let s:OnChangeListener = function('OnChangeVueSubtype')
- endif
- let s:syntax = ''
- function! s:CheckSyntax()
- let syntax = GetVueSyntax()
- if s:syntax != syntax
- call s:OnChangeListener(syntax)
- let s:syntax = syntax
- endif
- endfunction
- endif
- function! s:SyntaxListAtEnd(lnum)
- let plnum = prevnonblank(a:lnum)
- let pline = getline(plnum)
- " return [] if prevnonblank is an end tag
- if pline =~ '^<\/'
- return []
- endif
- let col = strlen(pline)
- return map(synstack(plnum, col), 'synIDattr(v:val, "name")')
- endfunction
- function! s:SyntaxAtEnd(lnum)
- let syns = s:SyntaxListAtEnd(a:lnum)
- let syntax_name = empty(syns) ? '' : get(syns, 0, '')
- let syntax_name = s:RemoveCssPrefix(syntax_name)
- return syntax_name
- endfunction
- function! vue#SyntaxSecondAtEnd(lnum)
- let syns = s:SyntaxListAtEnd(a:lnum)
- return get(syns, 1, '')
- endfunction
- function! s:GetBlockTag(lnum)
- let syntax_name = s:SyntaxAtEnd(a:lnum)
- let tag = matchstr(syntax_name, '\(\u\U\+\)\+\zeBlock')
- let tag = substitute(tag, '\U\zs\(\u\)', "-\\1", 'g')
- let tag = tolower(tag)
- return tag
- endfunction
- let s:style_with_css_prefix = ['scss', 'less', 'stylus']
- " Adjust syntax name to support emmet-vim by adding css prefix
- function! vue#AlterSyntaxForEmmetVim(name, syntax)
- let name = a:name
- if count(s:style_with_css_prefix, a:syntax)
- let name = 'css'.toupper(name[0]).name[1:]
- endif
- return name
- endfunction
- " Remove css prefix
- function! s:RemoveCssPrefix(syntax_name)
- let syntax_name = a:syntax_name
- let syntax = matchstr(syntax_name, '^\U\+')
- if syntax == 'css'
- let next_syntax = tolower(matchstr(syntax_name, '^\U\+\zs\u\U\+'))
- if count(s:style_with_css_prefix, next_syntax)
- let syntax_name = matchstr(syntax_name, '^\U\+\zs.*')
- let syntax_name = tolower(syntax_name[0]).syntax_name[1:]
- endif
- endif
- return syntax_name
- endfunction
- function! s:GetBlockSyntax(lnum)
- let syntax_name = s:SyntaxAtEnd(a:lnum)
- let syntax = matchstr(syntax_name, '^\U\+')
- return syntax
- endfunction
- function! vue#GetBlockTag(lnum)
- return s:GetBlockTag(a:lnum)
- endfunction
- function! vue#GetBlockSyntax(lnum)
- return s:GetBlockSyntax(a:lnum)
- endfunction
- function! GetVueSubtype()
- let syntax = vue#GetBlockSyntax(line('.'))
- return syntax
- endfunction
- function! GetVueSyntax()
- let syntax = vue#GetBlockSyntax(line('.'))
- return syntax
- endfunction
- function! GetVueTag(...)
- let lnum = a:0 > 0 ? a:1 : line('.')
- return vue#GetBlockTag(lnum)
- endfunction
- function! vue#LoadSyntax(group, syntax)
- let group = a:group
- let syntax = a:syntax
- if s:IncludeOrEqual(s:full_syntax, syntax)
- call vue#LoadFullSyntax(group, syntax)
- else
- let loaded = vue#LoadDefaultSyntax(group, syntax)
- if !loaded
- call vue#LoadFullSyntax(group, syntax)
- endif
- endif
- endfunction
- function! vue#LoadDefaultSyntax(group, syntax)
- unlet! b:current_syntax
- let loaded = 0
- let syntax_paths = ['$VIMRUNTIME', '$VIM/vimfiles', '$HOME/.vim']
- for path in syntax_paths
- let file = expand(path).'/syntax/'.a:syntax.'.vim'
- if filereadable(file)
- let loaded = 1
- execute 'syntax include '.a:group.' '.file
- endif
- endfor
- if loaded
- call vue#Log(a:syntax.': load default')
- else
- call vue#Warn(a:syntax.': syntax not found in '.string(syntax_paths))
- call vue#Warn(a:syntax.': load full instead')
- endif
- return loaded
- endfunction
- " Load all syntax files in 'runtimepath'
- " Useful if there is no default syntax file provided by vim
- function! vue#LoadFullSyntax(group, syntax)
- call vue#Log(a:syntax.': load full')
- call s:SetCurrentSyntax(a:syntax)
- execute 'syntax include '.a:group.' syntax/'.a:syntax.'.vim'
- endfunction
- " Settings to avoid syntax overload
- function! s:SetCurrentSyntax(type)
- if a:type == 'coffee'
- " Avoid `syntax/javascript.vim` in kchmck/vim-coffee-script
- let b:current_syntax = 'vue'
- syntax cluster coffeeJS contains=@javascript,@htmlJavaScript
- else
- unlet! b:current_syntax
- endif
- endfunction
- function! vue#GetSyntaxList(config_syntax)
- let syntax_list = []
- for syntax in values(a:config_syntax)
- let type = type(syntax)
- if type == v:t_string
- if !count(syntax_list, syntax)
- call add(syntax_list, syntax)
- endif
- elseif type == v:t_list
- for syn in syntax
- if !count(syntax_list, syn)
- call add(syntax_list, syn)
- endif
- endfor
- else
- echoerr '[vim-vue-plugin] syntax value type'
- \.' must be either string or list'
- endif
- endfor
- call s:ModifySyntaxOrder(syntax_list)
- return syntax_list
- endfunction
- function! s:IncludeOrEqual(listOrString, item)
- let listOrString = a:listOrString
- let item = a:item
- let type = type(listOrString)
- return (type == v:t_list && count(listOrString, item))
- \ || (type == v:t_string && listOrString == item)
- endfunction
- function! vue#IncludeOrEqual(listOrString, item)
- return s:IncludeOrEqual(a:listOrString, a:item)
- endfunction
- function! s:ModifySyntaxOrder(syntax_list)
- let syntax_list = a:syntax_list
- " Move basic syntax to the end of the list, so we can check
- " if they are already loaded by other syntax.
- " Order matters
- let load_last = ['html', 'javascript', 'css']
- for syntax in load_last
- let idx = index(syntax_list, syntax)
- if idx >= 0
- call remove(syntax_list, idx)
- call add(syntax_list, syntax)
- endif
- endfor
- endfunction
- call s:Main()
|