diff --git a/README.md b/README.md
index bf039a8..45b2a2b 100644
--- a/README.md
+++ b/README.md
@@ -76,6 +76,7 @@ let g:vim_vue_plugin_load_full_syntax = 1
| `g:vim_vue_plugin_highlight_vue_attr` | Highlight vue attribute value as expression instead of string. | 0 |
| `g:vim_vue_plugin_highlight_vue_keyword` | Highlight vue keyword like `data`, `methods`, ... | 0 |
| `g:vim_vue_plugin_use_foldexpr`\# | Enable builtin `foldexpr` foldmethod. | 0 |
+| `g:vim_vue_plugin_custom_blocks` | Highlight custom blocks. Check the exmple bleow. | {} |
| `g:vim_vue_plugin_debug` | Echo debug messages in `messages` list. Useful to debug if unexpected indents occur. | 0 |
\*: Vim may be slow if the feature is enabled. Find a balance between syntax highlight and speed. By the way, custom syntax can be added in `~/.vim/syntax` or `$VIM/vimfiles/syntax`.
@@ -89,6 +90,32 @@ let g:vim_vue_plugin_load_full_syntax = 1
- `g:vim_vue_plugin_load_full_syntax` applies to other `HTML/Sass/Less` plugins.
- `filetype` is set to `vue` so autocmds and other settings for `javascript` have to be manually enabled for `vue`.
+## Custom blocks
+
+You could enable syntax highlighting in a custom block by setting `g:vim_vue_plugin_custom_blocks`.
+
+Its structure is `{ block: filetype }` or `{ block: filetype[] }`. When providing a filetype list, you need to add `lang="..."` in the tag. Otherwise, the first one will be used.
+
+```vim
+let g:vim_vue_plugin_custom_blocks = {
+ \'docs': 'markdown',
+ \'i18n': ['json', 'yaml', 'json5'],
+ \}
+```
+
+```vue
+
+# This is the documentation for component.
+
+
+
+en:
+ hello: "Hello World!"
+ja:
+ hello: "こんにちは、世界!"
+
+```
+
## Context based behavior
As there are more than one language in `.vue` file, the different behaviors like mapping or completion and local options, may be required under different tags or subtypes(current language type).
diff --git a/autoload/vue.vim b/autoload/vue.vim
index a516725..eafb99e 100644
--- a/autoload/vue.vim
+++ b/autoload/vue.vim
@@ -1,6 +1,15 @@
+" 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
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+function! s:GetConfig(name, default)
+ let name = 'g:vim_vue_plugin_'.a:name
+ return exists(name) ? eval(name) : a:default
+endfunction
+
let s:name = 'vim-vue-plugin'
-let s:debug = exists("g:vim_vue_plugin_debug")
- \ && g:vim_vue_plugin_debug == 1
+let s:load_full_syntax = s:GetConfig("load_full_syntax", 0)
+let s:debug = s:GetConfig("debug", 0)
function! vue#Log(msg)
if s:debug
@@ -9,13 +18,9 @@ function! vue#Log(msg)
endfunction
function! vue#GetConfig(name, default)
- let name = 'g:vim_vue_plugin_'.a:name
- return exists(name) ? eval(name) : a:default
+ return s:GetConfig(a:name, a:default)
endfunction
-" 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
if exists('##CursorMoved') && exists('*OnChangeVueSubtype')
augroup vim_vue_plugin
autocmd!
@@ -70,3 +75,42 @@ function! GetVueTag(...)
return tag
endfunction
+
+function! vue#LoadSyntax(group, type)
+ if s:load_full_syntax
+ call vue#LoadFullSyntax(a:group, a:type)
+ else
+ call vue#LoadDefaultSyntax(a:group, a:type)
+ endif
+endfunction
+
+function! vue#LoadDefaultSyntax(group, type)
+ unlet! b:current_syntax
+ let syntaxPaths = ['$VIMRUNTIME', '$VIM/vimfiles', '$HOME/.vim']
+ for path in syntaxPaths
+ let file = expand(path).'/syntax/'.a:type.'.vim'
+ if filereadable(file)
+ execute 'syntax include '.a:group.' '.file
+ endif
+ endfor
+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'
+endfunction
+
+" Settings to avoid syntax overload
+function! s:SetCurrentSyntax(type)
+ if a:type == 'coffee'
+ syntax cluster coffeeJS contains=@htmlJavaScript
+
+ " Avoid overload of `javascript.vim`
+ let b:current_syntax = 'vue'
+ else
+ unlet! b:current_syntax
+ endif
+endfunction
+"}}}
diff --git a/indent/vue-custom-blocks.vim b/indent/vue-custom-blocks.vim
new file mode 100644
index 0000000..703893f
--- /dev/null
+++ b/indent/vue-custom-blocks.vim
@@ -0,0 +1,45 @@
+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 ba72598..a65754d 100644
--- a/indent/vue.vim
+++ b/indent/vue.vim
@@ -11,6 +11,23 @@ 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)
+"}}}
+
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"
" Variables {{{
@@ -25,23 +42,9 @@ let s:empty_tag = '\v\<'.s:empty_tagname.'[^/]*\>'
let s:empty_tag_start = '\v\<'.s:empty_tagname.'[^\>]*$'
let s:empty_tag_end = '\v^\s*[^\<\>\/]*\/?\>\s*'
let s:tag_start = '\v^\s*\<\w*'
-let s:tag_end = '\v^\s*\/?\>\s*'
-let s:full_tag_end = '\v^\s*\<\/'
-"}}}
+let s:tag_end = '\v^\s*\/?\>\s*' " />
+let s:full_tag_end = '\v^\s*\<\/' "
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-"
-" 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)
"}}}
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
@@ -64,6 +67,12 @@ unlet! b:did_indent
runtime! indent/javascript.vim
let b:javascript_indentexpr = &indentexpr
+if s:use_custom_blocks
+ unlet! b:did_indent
+ runtime indent/vue-custom-blocks.vim
+ let s:vue_custom_blocks_tag = '<\/\?'.join(keys(s:custom_blocks), '\|')
+endif
+
if s:use_pug
unlet! b:did_indent
let s:save_formatoptions = &formatoptions
@@ -118,42 +127,21 @@ setlocal indentexpr=GetVueIndent()
"
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function! GetVueIndent()
+ let ind = s:GetIndentBySyntax()
+ let ind = s:AdjustIndent(ind)
+ call vue#Log('indent: '.ind)
+ return ind
+endfunction
+
+function! s:GetIndentBySyntax()
let prevlnum = prevnonblank(v:lnum - 1)
let prevline = getline(prevlnum)
- let prevsyns = s:SynsEOL(prevlnum)
- let prevsyn = get(prevsyns, 0, '')
-
let curline = getline(v:lnum)
- let cursyns = s:SynsEOL(v:lnum)
- let cursyn = get(cursyns, 0, '')
+ let cursyn = get(s:SynsEOL(v:lnum), 0, '')
if s:SynHTML(cursyn)
call vue#Log('syntax: html')
- let ind = XmlIndentGet(v:lnum, 0)
- if prevline =~? s:empty_tag
- call vue#Log('previous line is an empty tag')
- let ind = ind - &sw
- endif
-
- " Align '/>' and '>' with '<' for multiline tags.
- if curline =~? s:tag_end
- let ind = ind - &sw
- endif
- " Then correct the indentation of any element following '/>' or '>'.
- if prevline =~? s:tag_end
- let ind = ind + &sw
-
- " Decrease indent if prevlines are a multiline empty tag
- let [start, end] = s:PrevMultilineEmptyTag(v:lnum)
- if end == prevlnum
- call vue#Log('previous line is a multiline empty tag')
- if curline =~? s:full_tag_end
- let ind = indent(v:lnum - 1) - &sw
- else
- let ind = indent(v:lnum - 1)
- endif
- endif
- endif
+ let ind = s:GetHTMLIndent(prevlnum, prevline, curline)
elseif s:SynPug(cursyn)
call vue#Log('syntax: pug')
let ind = GetPugIndent()
@@ -181,7 +169,11 @@ function! GetVueIndent()
elseif s:SynStyle(cursyn)
call vue#Log('syntax: css')
let ind = GetCSSIndent()
+ elseif s:use_custom_blocks && s:SynCustomBlocks(cursyn)
+ call vue#Log('syntax: custom blocks')
+ let ind = GetVueCustomBlocksIndent(cursyn)
else
+ " Default to JavaScript indent
call vue#Log('syntax: javascript')
if len(b:javascript_indentexpr)
let ind = eval(b:javascript_indentexpr)
@@ -189,28 +181,66 @@ function! GetVueIndent()
let ind = cindent(v:lnum)
endif
endif
+ return ind
+endfunction
- if curline =~? s:vue_tag_start || curline =~? s:vue_tag_end
- \|| prevline =~? s:vue_tag_end
- \|| (curline =~ s:template_tag && s:SynPug(cursyn))
+function! s:AdjustIndent(ind)
+ let ind = a:ind
+ let prevline = getline(prevnonblank(v:lnum - 1))
+ let curline = getline(v:lnum)
+ let cursyn = get(s:SynsEOL(v:lnum), 0, '')
+
+ if curline =~? s:vue_tag_start
+ \ || curline =~? s:vue_tag_end
+ \ || prevline =~? s:vue_tag_end
+ \ || (curline =~ s:template_tag && s:SynPug(cursyn))
call vue#Log('current line is vue tag or previous line is vue end tag')
- call vue#Log('... or current line is pug template tag')
+ call vue#Log(', or current line is pug template tag')
let ind = 0
- elseif s:has_init_indent
- if s:SynVueScriptOrStyle(cursyn) && ind < 1
+ elseif s:has_init_indent && ind < 1 && s:SynVueScriptOrStyle(cursyn)
call vue#Log('add initial indent')
let ind = &sw
- endif
- else
- let prevlnum_noncomment = s:PrevNonBlacnkNonComment(v:lnum)
- let prevline_noncomment = getline(prevlnum_noncomment)
- if prevline_noncomment =~? s:vue_tag_start
- call vue#Log('previous line is vue tag start')
- let ind = 0
- endif
+ elseif getline(s:PrevNonBlacnkNonComment(v:lnum)) =~? s:vue_tag_start
+ call vue#Log('previous line is vue tag start')
+ let ind = 0
+ elseif s:use_custom_blocks && curline =~ s:vue_custom_blocks_tag
+ call vue#Log('current line is vue custom blocks tag')
+ let ind = 0
endif
- call vue#Log('indent: '.ind)
+ return ind
+endfunction
+
+function! s:GetHTMLIndent(prevlnum, prevline, curline)
+ let prevlnum = a:prevlnum
+ let prevline = a:prevline
+ let curline = a:curline
+
+ let ind = XmlIndentGet(v:lnum, 0)
+ if prevline =~? s:empty_tag
+ call vue#Log('previous line is an empty tag')
+ let ind = ind - &sw
+ endif
+
+ " Align '/>' and '>' with '<' for multiline tags.
+ if curline =~? s:tag_end
+ let ind = ind - &sw
+ endif
+ " Then correct the indentation of any element following '/>' or '>'.
+ if prevline =~? s:tag_end
+ let ind = ind + &sw
+
+ " Decrease indent if prevlines are a multiline empty tag
+ let [start, end] = s:PrevMultilineEmptyTag(v:lnum)
+ if end == prevlnum
+ call vue#Log('previous line is a multiline empty tag')
+ if curline =~? s:full_tag_end
+ let ind = indent(v:lnum - 1) - &sw
+ else
+ let ind = indent(v:lnum - 1)
+ endif
+ endif
+ endif
return ind
endfunction
@@ -252,6 +282,10 @@ function! s:SynStyle(syn)
return a:syn =~? 'VueStyle'
endfunction
+function! s:SynCustomBlocks(syn)
+ return a:syn =~? 'Block'
+endfunction
+
function! s:SynVueScriptOrStyle(syn)
return a:syn =~? '\v(VueStyle)|(VueScript)'
endfunction
diff --git a/syntax/vue-custom-blocks.vim b/syntax/vue-custom-blocks.vim
new file mode 100644
index 0000000..cc761ce
--- /dev/null
+++ b/syntax/vue-custom-blocks.vim
@@ -0,0 +1,64 @@
+let s:custom_blocks = vue#GetConfig("custom_blocks", {})
+
+if empty(s:custom_blocks)
+ finish
+endif
+
+function! s:LoadSyntax()
+ 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
+ for syntax in syntax_list
+ let syntaxGroup = '@'.syntax
+ call vue#LoadFullSyntax(syntaxGroup, syntax)
+ endfor
+endfunction
+
+function! s:SetSyntax(block, syntax, lang = 0)
+ let block = a:block
+ let syntax = a:syntax
+ let lang = a:lang
+
+ let region_name = syntax.toupper(block[0]).block[1:].'Block'
+ let syntax_lang = lang ? 'lang=["'']'.syntax.'["''][^>]*' : ''
+ let start = '<'.block.'[^>]*'.syntax_lang.'>'
+ let end = ''.block.'>'
+ let syntaxGroup = '@'.syntax
+
+ execute 'syntax region '.region_name.' fold matchgroup=vueTag'
+ \.' start=+'.start.'+'
+ \.' end=+'.end.'+'
+ \.' keepend contains='.syntaxGroup
+endfunction
+
+function! s:Highlight()
+ for [block, syntax] in items(s:custom_blocks)
+ let type = type(syntax)
+ if type == v:t_string
+ call s:SetSyntax(block, syntax)
+ elseif type == v:t_list && len(syntax)
+ call s:SetSyntax(block, syntax[0])
+ for syn in syntax
+ call s:SetSyntax(block, syn, 1)
+ endfor
+ endif
+ endfor
+endfunction
+
+call s:LoadSyntax()
+call s:Highlight()
diff --git a/syntax/vue.vim b/syntax/vue.vim
index d50bc4e..b5801f6 100644
--- a/syntax/vue.vim
+++ b/syntax/vue.vim
@@ -18,7 +18,6 @@ let b:current_loading_main_syntax = 'vue'
" Config {{{
"
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-let s:load_full_syntax = vue#GetConfig("load_full_syntax", 0)
let s:use_pug = vue#GetConfig("use_pug", 0)
let s:use_less = vue#GetConfig("use_less", 0)
let s:use_sass = vue#GetConfig("use_sass", 0)
@@ -28,50 +27,6 @@ let s:use_coffee = vue#GetConfig("use_coffee", 0)
let s:use_typescript = vue#GetConfig("use_typescript", 0)
"}}}
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-"
-" Functions {{{
-"
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
-function! s:LoadSyntax(group, type)
- if s:load_full_syntax
- call s:LoadFullSyntax(a:group, a:type)
- else
- call s:LoadDefaultSyntax(a:group, a:type)
- endif
-endfunction
-
-function! s:LoadDefaultSyntax(group, type)
- unlet! b:current_syntax
- let syntaxPaths = ['$VIMRUNTIME', '$VIM/vimfiles', '$HOME/.vim']
- for path in syntaxPaths
- let file = expand(path).'/syntax/'.a:type.'.vim'
- if filereadable(file)
- execute 'syntax include '.a:group.' '.file
- endif
- endfor
-endfunction
-
-" Load all syntax files in 'runtimepath'
-" Useful if there is no default syntax file provided by vim
-function! s:LoadFullSyntax(group, type)
- call s:SetCurrentSyntax(a:type)
- execute 'syntax include '.a:group.' syntax/'.a:type.'.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`
- let b:current_syntax = 'vue'
- else
- unlet! b:current_syntax
- endif
-endfunction
-"}}}
-
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"
" Load main syntax {{{
@@ -80,17 +35,17 @@ endfunction
" Load syntax/html.vim to syntax group, which loads full JavaScript and CSS
" syntax. It defines group @html, @htmlJavaScript, and @htmlCss.
-call s:LoadSyntax('@html', 'html')
+call vue#LoadSyntax('@html', 'html')
" Avoid overload
if !hlexists('cssTagName')
- call s:LoadSyntax('@htmlCss', 'css')
+ call vue#LoadSyntax('@htmlCss', 'css')
endif
" Avoid overload
if !hlexists('javaScriptComment')
call vue#Log('load javascript cluster')
- call s:LoadSyntax('@htmlJavaScript', 'javascript')
+ call vue#LoadSyntax('@htmlJavaScript', 'javascript')
endif
" Load vue-html syntax
@@ -107,43 +62,43 @@ runtime syntax/vue-javascript.vim
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" If pug is enabled, load vim-pug syntax
if s:use_pug
- call s:LoadFullSyntax('@PugSyntax', 'pug')
+ call vue#LoadFullSyntax('@PugSyntax', 'pug')
syn cluster htmlJavascript remove=javascriptParenthesisBlock
endif
" If less is enabled, load less syntax
if s:use_less
- call s:LoadSyntax('@LessSyntax', 'less')
+ call vue#LoadSyntax('@LessSyntax', 'less')
runtime! after/syntax/less.vim
endif
" If sass is enabled, load sass syntax
if s:use_sass
- call s:LoadSyntax('@SassSyntax', 'sass')
+ call vue#LoadSyntax('@SassSyntax', 'sass')
runtime! after/syntax/sass.vim
endif
" If scss is enabled, load sass syntax
if s:use_scss
- call s:LoadSyntax('@ScssSyntax', 'scss')
+ call vue#LoadSyntax('@ScssSyntax', 'scss')
runtime! after/syntax/scss.vim
endif
" If stylus is enabled, load stylus syntax
if s:use_stylus
- call s:LoadFullSyntax('@StylusSyntax', 'stylus')
+ call vue#LoadFullSyntax('@StylusSyntax', 'stylus')
runtime! after/syntax/stylus.vim
endif
" If CoffeeScript is enabled, load the syntax. Keep name consistent with
" vim-coffee-script/after/html.vim
if s:use_coffee
- call s:LoadFullSyntax('@htmlCoffeeScript', 'coffee')
+ call vue#LoadFullSyntax('@htmlCoffeeScript', 'coffee')
endif
" If TypeScript is enabled, load the syntax.
if s:use_typescript
- call s:LoadFullSyntax('@TypeScript', 'typescript')
+ call vue#LoadFullSyntax('@TypeScript', 'typescript')
endif
"}}}
@@ -226,7 +181,14 @@ syntax region vueTag
highlight default link vueTag htmlTag
highlight default link cssUnitDecorators2 Number
highlight default link cssKeyFrameProp2 Constant
+"}}}
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+"
+" Custom blocks {{{
+"
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+runtime syntax/vue-custom-blocks.vim
"}}}
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""