mirror of
https://github.com/leafOfTree/vim-vue-plugin.git
synced 2026-11-02 10:27:34 +08:00
A syntax in the config without a syntax file, like postcss, showed E484 on opening a file. Skip loading it, with a warning in debug. A syntax without an indent file used cindent, which broke indent of languages like pug, stylus without their plugins, or toml. Keep the indent instead. Lines outside blocks still use cindent.
340 lines
8.9 KiB
VimL
340 lines
8.9 KiB
VimL
" 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, e.g. for blank lines between
|
|
" blocks, but not for the end tag line itself
|
|
if plnum != a:lnum && 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)
|
|
if empty(globpath(&runtimepath, 'syntax/'.a:syntax.'.vim'))
|
|
call vue#Warn(a:syntax.': syntax not found in runtimepath')
|
|
return
|
|
endif
|
|
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()
|