Files
vim-vue-plugin/autoload/vue.vim
T
leafOfTree de9fbec1ad Handle syntax without syntax or indent files
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.
2026-10-21 13:51:38 +00:00

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()