diff --git a/README.md b/README.md index 5d791fe..ca10601 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,5 @@ # vim-vue -Vue plugin for vim + +Vim plugin for `.vue` file syntax and indent. Mainly inspired by [mxw/vim-jsx][1] + +[1]: https://github.com/mxw/vim-jsx "mxw: vim-jsx" diff --git a/after/ftplugin/vue.vim b/after/ftplugin/vue.vim deleted file mode 100644 index aa9c91d..0000000 --- a/after/ftplugin/vue.vim +++ /dev/null @@ -1 +0,0 @@ -setlocal suffixesadd+=.vue diff --git a/after/indent/vue.vim b/after/indent/vue.vim index 5a9a8c5..49c44f0 100644 --- a/after/indent/vue.vim +++ b/after/indent/vue.vim @@ -1,114 +1,81 @@ """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -" Vim indent file +" Vim ftplugin file " -" Language: JSX (JavaScript) -" Maintainer: Max Wang +" Language: Vue (Wepy) +" Maintainer: leafOfTree " """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +se sw=2 ts=2 + " Save the current JavaScript indentexpr. -let b:jsx_js_indentexpr = &indentexpr +let b:vue_js_indentexpr = &indentexpr -" Prologue; load in XML indentation. +" Prologue; load XML indentation. if exists('b:did_indent') let s:did_indent=b:did_indent unlet b:did_indent endif -exe 'runtime! indent/xml.vim' + +runtime! indent/xml.vim + if exists('s:did_indent') let b:did_indent=s:did_indent endif -setlocal indentexpr=GetJsxIndent() - -" JS indentkeys +" JavaScript indentkeys setlocal indentkeys=0{,0},0),0],0\,,!^F,o,O,e " XML indentkeys setlocal indentkeys+=*,<>>,<<>,/ -" Multiline end tag regex (line beginning with '>' or '/>') -let s:endtag = '^\s*\/\?>\s*;\=' +let s:vue_tag = '\v\<\/?(template|script|style)' +let s:end_tag = '^\s*\/\?>\s*;\=' -" Get all syntax types at the beginning of a given line. -fu! SynSOL(lnum) - return map(synstack(a:lnum, 1), 'synIDattr(v:val, "name")') -endfu +setlocal indentexpr=GetVueIndent() -" Get all syntax types at the end of a given line. -fu! SynEOL(lnum) +function! SynsEOL(lnum) let lnum = prevnonblank(a:lnum) let col = strlen(getline(lnum)) return map(synstack(lnum, col), 'synIDattr(v:val, "name")') -endfu +endfunction -" Check if a syntax attribute is XMLish. -fu! SynAttrXMLish(synattr) - return a:synattr =~ "^xml" || a:synattr =~ "^jsx" -endfu +function! SynsHTMLish(syns) + let last_syn = get(a:syns, -1) + return last_syn =~? '\v^(html)' +endfunction -" Check if a synstack is XMLish (i.e., has an XMLish last attribute). -fu! SynXMLish(syns) - return SynAttrXMLish(get(a:syns, -1)) -endfu +function! SynsVueScope(syns) + let first_syn = get(a:syns, 0) + return first_syn =~? '\v^(vueStyle)|(vueTemplate)|(vueScript)' +endfunction -" Check if a synstack denotes the end of a JSX block. -fu! SynJSXBlockEnd(syns) - return get(a:syns, -1) =~ '\%(js\|javascript\)Braces' && - \ SynAttrXMLish(get(a:syns, -2)) -endfu +function! GetVueIndent() + let curline = getline(v:lnum) + let cursyns = SynsEOL(v:lnum) + let prevsyns = SynsEOL(v:lnum - 1) -" Determine how many jsxRegions deep a synstack is. -fu! SynJSXDepth(syns) - return len(filter(copy(a:syns), 'v:val ==# "jsxRegion"')) -endfu - -" Check whether `cursyn' continues the same jsxRegion as `prevsyn'. -fu! SynJSXContinues(cursyn, prevsyn) - let curdepth = SynJSXDepth(a:cursyn) - let prevdepth = SynJSXDepth(a:prevsyn) - - " In most places, we expect the nesting depths to be the same between any - " two consecutive positions within a jsxRegion (e.g., between a parent and - " child node, between two JSX attributes, etc.). The exception is between - " sibling nodes, where after a completed element (with depth N), we return - " to the parent's nesting (depth N - 1). This case is easily detected, - " since it is the only time when the top syntax element in the synstack is - " jsxRegion---specifically, the jsxRegion corresponding to the parent. - return prevdepth == curdepth || - \ (prevdepth == curdepth + 1 && get(a:cursyn, -1) ==# 'jsxRegion') -endfu - -" Cleverly mix JS and XML indentation. -fu! GetJsxIndent() - let cursyn = SynSOL(v:lnum) - let prevsyn = SynEOL(v:lnum - 1) - - " Use XML indenting iff: - " - the syntax at the end of the previous line was either JSX or was the - " closing brace of a jsBlock whose parent syntax was JSX; and - " - the current line continues the same jsxRegion as the previous line. - if (SynXMLish(prevsyn) || SynJSXBlockEnd(prevsyn)) && - \ SynJSXContinues(cursyn, prevsyn) + if SynsHTMLish(prevsyns) let ind = XmlIndentGet(v:lnum, 0) " Align '/>' and '>' with '<' for multiline tags. - if getline(v:lnum) =~? s:endtag + if curline =~? s:end_tag let ind = ind - &sw endif - - " Then correct the indentation of any JSX following '/>' or '>'. - if getline(v:lnum - 1) =~? s:endtag - let ind = ind + &sw - endif else - if len(b:jsx_js_indentexpr) - " Invoke the base JS package's custom indenter. (For vim-javascript, - " e.g., this will be GetJavascriptIndent().) - let ind = eval(b:jsx_js_indentexpr) + if curline =~ s:vue_tag + let ind = 0 else - let ind = cindent(v:lnum) + if len(b:vue_js_indentexpr) + let ind = eval(b:vue_js_indentexpr) + else + let ind = cindent(v:lnum) + endif endif endif + if SynsVueScope(cursyns) && ind == 0 + let ind = &sw + endif + return ind -endfu +endfunction diff --git a/after/syntax/vue.vim b/after/syntax/vue.vim index 6707cec..7a08e07 100644 --- a/after/syntax/vue.vim +++ b/after/syntax/vue.vim @@ -1,4 +1,3 @@ -echom 'vim for vue' """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" " Vim syntax file " @@ -9,40 +8,19 @@ echom 'vim for vue' " CREDITS: Inspired by mxw/vim-jsx. " """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +unlet b:current_syntax +" runtime! syntax/html.vim +syn include @HTMLSyntax syntax/html.vim -" load in XML syntax. -if exists('b:current_syntax') - let s:current_syntax=b:current_syntax - unlet b:current_syntax -endif -syn include @XMLSyntax syntax/xml.vim -if exists('s:current_syntax') - let b:current_syntax=s:current_syntax -endif +unlet! b:current_syntax +syn include @CSSSyntax syntax/css.vim -" load in HTML syntax -if exists('b:current_syntax') - let s:current_syntax=b:current_syntax - unlet b:current_syntax -endif -syn include @HTMLSyntax syntax/css.vim -if exists('s:current_syntax') - let b:current_syntax=s:current_syntax -endif - -" load in CSS syntax -if exists('b:current_syntax') - let s:current_syntax=b:current_syntax - unlet b:current_syntax -endif -syn include @CSSSyntax syntax/javascript.vim -if exists('s:current_syntax') - let b:current_syntax=s:current_syntax -endif +let b:current_syntax='vue' " Find tag + keepend contains=@jsAll,jsImport,jsExport,@XMLSyntax -syn region vueStyle contained start=++ end=++ keepend contains=@CSSSyntax +syn region vueTemplate start=++ end=++ keepend contains=@HTMLSyntax +syn region vueScript start=++ end=++ keepend contains=@jsAll,jsImport,jsExport +syn region vueStyle start=++ end=++ keepend contains=@CSSSyntax " Officially, vim-jsx depends on the pangloss/vim-javascript syntax package " (and is tested against it exclusively). However, in practice, we make some @@ -58,21 +36,3 @@ syn region vueStyle contained start=++ end=++ keepen " Vue attributes should color as JS. Note the trivial end pattern; we let " jsBlock take care of ending the region. syn region xmlString contained start=+{+ end=++ contains=jsBlock,javascriptBlock - -" Note that we prohibit Vue tags from having a < or word character immediately -" preceding it, to avoid conflicts with, respectively, the left shift operator -" and generic Flow type annotations (http://flowtype.org/). -syn region vueRegion - \ contains=@Spell,@XMLSyntax,jsBlock,javascriptBlock,vueScript,vueStyle - \ start=+\%(<\|\w\)\@[:,]\@!\)\([^>]*>(\)\@!+ - \ skip=++ - \ end=++ - \ end=+/>+ - \ keepend - \ extend -" -" Add vueRegion to the lowest-level JS syntax cluster. -syn cluster jsExpression add=vueRegion - -" Allow vueRegion to contain reserved words. -syn cluster javascriptNoReserved add=vueRegion