diff --git a/.gitignore b/.gitignore index e26ebae..6e9b2ec 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ README.html test.vue +.DS_STORE diff --git a/autoload/vue.vim b/autoload/vue.vim index eafb99e..80988d5 100644 --- a/autoload/vue.vim +++ b/autoload/vue.vim @@ -1,22 +1,78 @@ " Since vue#Log and vue#GetConfig are always called " in syntax and indent files, -" this file will be sourced when opening the first vue file -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +" this file will be sourced on opening the first vue file + function! s:GetConfig(name, default) let name = 'g:vim_vue_plugin_'.a:name - return exists(name) ? eval(name) : a:default + let value = exists(name) ? eval(name) : a:default + + if a:name == 'config' + let value = s:MergeDefaultWithConfig(value) + endif + + return value endfunction -let s:name = 'vim-vue-plugin' -let s:load_full_syntax = s:GetConfig("load_full_syntax", 0) -let s:debug = s:GetConfig("debug", 0) +function! s:MergeDefaultWithConfig(user) + let default = { + \'syntax': { + \ 'script': ['javascript'], + \ 'template': ['html'], + \ 'style': ['css'], + \}, + \'attribute': 0, + \'keyword': 0, + \'foldexpr': 0, + \'init_indent': expand('%:e') == 'wpy', + \'full_syntax': [], + \'debug': 0, + \} + + let user = a:user + for key in keys(default) + if has_key(user, key) + let default[key] = user[key] + endif + endfor + return default +endfunction + +function! s:CheckVersion() + if !exists('g:vim_vue_plugin_config') + let message = 'Please check README.md or https://github.com/leafOfTree/vim-vue-plugin' + echom '['.s:name.'] '.message + 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 @@ -39,78 +95,160 @@ if exists('##CursorMoved') && exists('*OnChangeVueSubtype') endfunction endif -function! s:SynsEOL(lnum) - let lnum = prevnonblank(a:lnum) - let cnum = strlen(getline(lnum)) - return map(synstack(lnum, cnum), 'synIDattr(v:val, "name")') +function! s:SyntaxListAtEnd(lnum) + let plnum = prevnonblank(a:lnum) + let col = strlen(getline(plnum)) + return map(synstack(plnum, col), 'synIDattr(v:val, "name")') +endfunction + +function! s:SyntaxAtEnd(lnum) + let syns = s:SyntaxListAtEnd(a:lnum) + return empty(syns) ? '' : get(syns, 0, '') +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 = tolower(matchstr(syntax_name, '\u\U\+\zeBlock')) + 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) == 1 + let name = 'css'.toupper(name[0]).name[1:] + endif + return name +endfunction + +" Remove css prefix +function! s:RecoverSyntax(syntax_name, syntax) + let syntax = a:syntax + if syntax == 'css' + let next_syntax = tolower(matchstr(a:syntax_name, '^\U\+\zs\u\U\+')) + if count(s:style_with_css_prefix, next_syntax) == 1 + let syntax = next_syntax + endif + endif + return syntax +endfunction + +function! s:GetBlockSyntax(lnum) + let syntax_name = s:SyntaxAtEnd(a:lnum) + let syntax = matchstr(syntax_name, '^\U\+') + let syntax = s:RecoverSyntax(syntax_name, syntax) + 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 lnum = line('.') - let cursyns = s:SynsEOL(lnum) - let syn = !empty(cursyns) ? get(cursyns, 0, '') : '' - - let subtype = matchstr(syn, '\w\+\zeVue') - if subtype =~ 'css\w\+' - let subtype = subtype[3:] - endif - let subtype = tolower(subtype) - return subtype + let syntax = vue#GetBlockSyntax(lnum) + return syntax endfunction function! GetVueTag(...) let lnum = a:0 > 0 ? a:1 : line('.') - let cursyns = s:SynsEOL(lnum) - let syn = get(cursyns, 0, '') - - if syn =~ 'VueTemplate' - let tag = 'template' - elseif syn =~ 'VueScript' - let tag = 'script' - elseif syn =~ 'VueStyle' - let tag = 'style' - else - let tag = '' - endif - - return tag + return vue#GetBlockTag(lnum) endfunction -function! vue#LoadSyntax(group, type) - if s:load_full_syntax - call vue#LoadFullSyntax(a:group, a:type) +function! vue#LoadSyntax(group, syntax) + let group = a:group + let syntax = a:syntax + if count(s:full_syntax, syntax) == 1 + call vue#LoadFullSyntax(group, syntax) else - call vue#LoadDefaultSyntax(a:group, a:type) + let loaded = vue#LoadDefaultSyntax(group, syntax) + if !loaded + call vue#LoadFullSyntax(group, syntax) + endif endif endfunction -function! vue#LoadDefaultSyntax(group, type) +function! vue#LoadDefaultSyntax(group, syntax) unlet! b:current_syntax - let syntaxPaths = ['$VIMRUNTIME', '$VIM/vimfiles', '$HOME/.vim'] - for path in syntaxPaths - let file = expand(path).'/syntax/'.a:type.'.vim' + 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.': laod 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, type) - call s:SetCurrentSyntax(a:type) - execute 'syntax include '.a:group.' syntax/'.a:type.'.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' - syntax cluster coffeeJS contains=@htmlJavaScript - - " Avoid overload of `javascript.vim` + " 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 && len(syntax) + 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 + + " Move basic syntaxes to the end of the list, so we can check + " if they are already loaded by other syntax. + " Order matters + for syntax in ['html', 'javascript', 'css'] + let idx = index(syntax_list, syntax) + if idx >= 0 + call remove(syntax_list, idx) + call add(syntax_list, syntax) + endif + endfor + return syntax_list +endfunction + +call s:Main() diff --git a/ftplugin/vue.vim b/ftplugin/vue.vim index 700b5ce..9bb545b 100644 --- a/ftplugin/vue.vim +++ b/ftplugin/vue.vim @@ -17,3 +17,4 @@ endif " indentexpr let b:syng_str = '^\%(.*template\)\@!.*string\|special' let b:syng_strcom = '^\%(.*template\)\@!.*string\|comment\|regex\|special\|doc' + diff --git a/indent/vue-custom-blocks.vim b/indent/vue-custom-blocks.vim deleted file mode 100644 index 703893f..0000000 --- a/indent/vue-custom-blocks.vim +++ /dev/null @@ -1,45 +0,0 @@ -if exists("b:did_indent") - finish -endif - -let s:custom_blocks = vue#GetConfig("custom_blocks", {}) -let s:indent = {} - -function! s:GetSyntaxList() - let syntax_list = [] - for syntax in values(s:custom_blocks) - 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 && len(syntax) - for syn in syntax - if !count(syntax_list, syn) - call add(syntax_list, syn) - endif - endfor - else - echoerr '[vim-vue-plugin] custom_blocks value type' - \.' must be either string or list' - endif - endfor - return syntax_list -endfunction - -function! s:GetIndentExpr(syntax_list) - for syntax in a:syntax_list - unlet! b:did_indent - execute 'runtime indent/'.syntax.'.vim' - let s:indent[syntax] = &l:indentexpr - endfor -endfunction - -function! GetVueCustomBlocksIndent(syn) - let syntax = matchstr(a:syn, '^\l\+') - call vue#Log('custom block syntax: '.syntax) - let ind = eval(s:indent[syntax]) - return ind -endfunction - -call s:GetIndentExpr(s:GetSyntaxList()) diff --git a/indent/vue.vim b/indent/vue.vim index a65754d..aae3339 100644 --- a/indent/vue.vim +++ b/indent/vue.vim @@ -1,293 +1,132 @@ -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -" Vim indent file -" -" Language: Vue -" Maintainer: leafOfTree -" -" CREDITS: Inspired by mxw/vim-jsx. -" -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -if exists("b:did_indent") - finish -endif +if exists('b:did_indent') | finish |endif -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -" -" Config {{{ -" -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -let s:use_pug = vue#GetConfig("use_pug", 0) -let s:use_sass = vue#GetConfig("use_sass", 0) -let s:use_scss = vue#GetConfig("use_scss", 0) -let s:use_stylus = vue#GetConfig("use_stylus", 0) -let s:use_coffee = vue#GetConfig("use_coffee", 0) -let s:use_typescript = vue#GetConfig("use_typescript", 0) -let s:has_init_indent = vue#GetConfig("has_init_indent", - \ expand("%:e") == 'wpy' ? 1 : 0) -let s:custom_blocks = vue#GetConfig("custom_blocks", {}) -let s:use_custom_blocks = !empty(s:custom_blocks) -"}}} +function! s:Init() + """ Configs + let s:config = vue#GetConfig('config', {}) + let s:config_syntax = s:config.syntax + let s:enable_init_indent = s:config.init_indent -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -" -" Variables {{{ -" -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -" Let \ze\n\(^$\n\)*<\(script\|style\)+ - \ keepend contains=@html - -syntax region javascriptVueScript fold - \ start=+]*>+ - \ end=++ - \ keepend contains=@htmlJavaScript,jsImport,jsExport,vueTag - - -syntax region cssVueStyle fold - \ start=+]*>+ - \ end=++ - \ keepend contains=@htmlCss,vueTag - -" Preprocessors syntax -syntax region pugVueTemplate fold - \ start=+]*lang=["']pug["'][^>]*>+ - \ end=++ - \ keepend contains=@PugSyntax,vueTag - -syntax region coffeeVueScript fold - \ start=+]*lang=["']coffee["'][^>]*>+ - \ end=++ - \ keepend contains=@htmlCoffeeScript,jsImport,jsExport,vueTag - -syntax region typescriptVueScript fold - \ start=+]*lang=["']ts["'][^>]*>+ - \ end=++ - \ keepend contains=@TypeScript,vueTag - -syntax region cssLessVueStyle fold - \ start=+]*lang=["']less["'][^>]*>+ - \ end=++ - \ keepend contains=@LessSyntax,vueTag -syntax region sassVueStyle fold - \ start=+]*lang=["']sass["'][^>]*>+ - \ end=++ - \ keepend contains=@SassSyntax,vueTag -syntax region cssScssVueStyle fold - \ start=+]*lang=["']scss["'][^>]*>+ - \ end=++ - \ keepend contains=@ScssSyntax,vueTag - -" Backward compatiable for `use_sass` option -if s:use_sass && !s:use_scss - syntax region cssScssVueStyle fold - \ start=+]*lang=["']scss["'][^>]*>+ - \ end=++ - \ keepend contains=@SassSyntax,vueTag -endif - -syntax region cssStylusVueStyle fold - \ start=+]*lang=["']stylus["'][^>]*>+ - \ end=++ - \ keepend contains=@StylusSyntax,vueTag - -syntax region vueTag fold - \ start=+^<[^/]+ end=+>+ skip=+>+ - \ contains=htmlTagN,htmlString,htmlArg - -highlight default link vueTag htmlTag -highlight default link cssUnitDecorators2 Number -highlight default link cssKeyFrameProp2 Constant -"}}} - -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -" -" Custom blocks {{{ -" -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -runtime syntax/vue-custom-blocks.vim -"}}} - -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -" -" Syntax patch {{{ -" -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -" Patch 7.4.1142 -if has("patch-7.4-1142") - if has("win32") - syntax iskeyword @,48-57,_,128-167,224-235,$,- - else - syntax iskeyword @,48-57,_,192-255,$,- +" Extend group name as +" html defines group @htmlJavaScript and @htmlCss. +" coffee defines group @coffeeJS. +function! s:GetGroupNameForHighlight(syntax) + let syntax = a:syntax + let name = '@'.a:syntax + if syntax == 'javascript' + let name = '@javascript,@htmlJavaScript,@coffeeJS' + elseif syntax == 'css' + let name = '@css,@htmlCss' endif -else - setlocal iskeyword+=- -endif + return name +endfunction -" Style -" Redefine (less|sass|stylus)Definition to highlight