Refactor the whole plugin

This commit is contained in:
leafOfTree
2021-03-23 11:50:46 +08:00
parent b24ce56361
commit 2b050c42c1
17 changed files with 571 additions and 740 deletions

View File

@@ -1,293 +1,132 @@
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Vim indent file
"
" Language: Vue
" Maintainer: leafOfTree <leafvocation@gmail.com>
"
" 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 <template> handled by HTML
let s:vue_tag_start = '\v^\s*\<(script|style)'
let s:vue_tag_end = '\v^\s*\<\/(script|style)'
let s:template_tag = '\v^\s*\<\/?template'
let s:empty_tagname = '(area|base|br|col|embed|hr|input|img|keygen|link|meta|param|source|track|wbr)'
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*\<\/' " </...>
"}}}
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"
" Load indent method {{{
"
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Save shiftwidth
let s:sw = &sw
" Use lib/indent/ files for compatibility
unlet! b:did_indent
runtime lib/indent/xml.vim
unlet! b:did_indent
runtime lib/indent/css.vim
" Use normal indent files
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
runtime! indent/pug.vim
let &formatoptions = s:save_formatoptions
endif
if s:use_sass
unlet! b:did_indent
runtime! indent/sass.vim
endif
if s:use_scss
unlet! b:did_indent
runtime! indent/scss.vim
endif
if s:use_stylus
unlet! b:did_indent
runtime! indent/stylus.vim
endif
if s:use_coffee
unlet! b:did_indent
runtime! indent/coffee.vim
endif
if s:use_typescript
unlet! b:did_indent
runtime! indent/typescript.vim
endif
" Recover shiftwidth
let &sw = s:sw
"}}}
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"
" Settings {{{
"
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" JavaScript indentkeys
setlocal indentkeys=0{,0},0),0],0\,,!^F,o,O,e,:
" XML indentkeys
setlocal indentkeys+=*<Return>,<>>,<<>,/
setlocal indentexpr=GetVueIndent()
"}}}
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"
" Functions {{{
"
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function! GetVueIndent()
let ind = s:GetIndentBySyntax()
let ind = s:AdjustIndent(ind)
call vue#Log('indent: '.ind)
return ind
""" Variables
let s:indent = {}
let s:block_tag = '<\/\?'.join(keys(s:config_syntax), '\|')
" Let <template> handled by HTML
let s:template_tag = '\v^\s*\<\/?template'
let s:vue_tag_start = '\v^\s*\<(script|style)'
let s:vue_tag_end = '\v^\s*\<\/(script|style)'
let s:empty_tagname = '(area|base|br|col|embed|hr|input|img|'
\.'keygen|link|meta|param|source|track|wbr)'
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*\<\/' " </...>
endfunction
function! s:GetIndentBySyntax()
let prevlnum = prevnonblank(v:lnum - 1)
let prevline = getline(prevlnum)
let curline = getline(v:lnum)
let cursyn = get(s:SynsEOL(v:lnum), 0, '')
function! s:SetVueIndent()
""" Settings
" JavaScript indentkeys
setlocal indentkeys=0{,0},0),0],0\,,!^F,o,O,e,:
" XML indentkeys
setlocal indentkeys+=*<Return>,<>>,<<>,/
setlocal indentexpr=GetVueIndent()
endfunction
if s:SynHTML(cursyn)
call vue#Log('syntax: html')
let ind = s:GetHTMLIndent(prevlnum, prevline, curline)
elseif s:SynPug(cursyn)
call vue#Log('syntax: pug')
let ind = GetPugIndent()
elseif s:SynCoffee(cursyn)
call vue#Log('syntax: coffee')
let ind = GetCoffeeIndent(v:lnum)
elseif s:SynTypeScript(cursyn)
call vue#Log('syntax: typescript')
let ind = GetTypescriptIndent()
elseif s:SynSASS(cursyn)
call vue#Log('syntax: sass')
let ind = GetSassIndent()
elseif s:SynSCSS(cursyn)
call vue#Log('syntax: scss')
if exists('*GetSCSSIndent')
call vue#Log('indent: scss')
let ind = GetSCSSIndent()
else
call vue#Log('indent: css')
let ind = GetCSSIndent()
endif
elseif s:SynStylus(cursyn)
call vue#Log('syntax: stylus')
let ind = GetStylusIndent()
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)
function! s:GetIndentFile(syntax)
let syntax = a:syntax
" lib/indent/* files are preversed from previous version vim
if syntax == 'html'
let file = 'lib/indent/xml.vim'
elseif syntax == 'css'
let file = 'lib/indent/css.vim'
else
" Default to JavaScript indent
call vue#Log('syntax: javascript')
if len(b:javascript_indentexpr)
let ind = eval(b:javascript_indentexpr)
else
let ind = cindent(v:lnum)
endif
let file = 'indent/'.syntax.'.vim'
endif
return file
endfunction
function! s:SetIndentExpr(syntax_list)
let saved_shiftwidth = &shiftwidth
let saved_formatoptions = &formatoptions
for syntax in a:syntax_list
unlet! b:did_indent
let &l:indentexpr = ''
execute 'runtime '.s:GetIndentFile(syntax)
let s:indent[syntax] = &l:indentexpr
endfor
let &shiftwidth = saved_shiftwidth
let &formatoptions = saved_formatoptions
endfunction
function! s:GetBlockIndent(syntax)
let syntax = a:syntax
let indentexpr = get(s:indent, syntax)
if !empty(indentexpr)
let ind = eval(indentexpr)
else
call vue#LogWithLnum('indentexpr not found for '.syntax.', use cindent')
let ind = cindent(v:lnum)
endif
return ind
endfunction
function! s:AdjustIndent(ind)
let ind = a:ind
let prevline = getline(prevnonblank(v:lnum - 1))
function! s:GetIndentByContext()
let ind = -1
let prevline = getline(s:PrevNonBlankNonComment(v:lnum))
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')
let ind = 0
elseif s:has_init_indent && ind < 1 && s:SynVueScriptOrStyle(cursyn)
call vue#Log('add initial indent')
let ind = &sw
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')
if curline =~ s:block_tag
let ind = 0
endif
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
if prevline =~ s:block_tag
if prevline !~ s:template_tag
let ind = 0
endif
endif
return ind
endfunction
function! s:SynsEOL(lnum)
let lnum = prevnonblank(a:lnum)
let col = strlen(getline(lnum))
return map(synstack(lnum, col), 'synIDattr(v:val, "name")')
function! s:PrevNonBlankNonComment(lnum)
let lnum = a:lnum - 1
let prevlnum = prevnonblank(lnum)
let prevsyn = vue#SyntaxSecondAtEnd(prevlnum)
while prevsyn =~? 'comment' && lnum > 1
let lnum = lnum - 1
let prevlnum = prevnonblank(lnum)
let prevsyn = vue#SyntaxSecondAtEnd(prevlnum)
endwhile
return prevlnum
endfunction
function! s:SynHTML(syn)
return a:syn ==? 'htmlVueTemplate'
function! s:AdjustBlockIndent(syntax, ind)
let block = a:block
let syntax = a:syntax
let ind = a:ind
if syntax == 'html'
let ind = s:AdjustHTMLIndent(ind)
endif
return ind
endfunction
function! s:SynPug(syn)
return a:syn ==? 'pugVueTemplate'
endfunction
function! s:CheckInitIndent(tag, ind)
let ind = a:ind
let curline = getline(v:lnum)
function! s:SynCoffee(syn)
return a:syn ==? 'coffeeVueScript'
endfunction
function! s:SynTypeScript(syn)
return a:syn ==? 'typescriptVueScript'
endfunction
function! s:SynSASS(syn)
return a:syn ==? 'sassVueStyle'
endfunction
function! s:SynSCSS(syn)
return a:syn ==? 'cssScssVueStyle'
endfunction
function! s:SynStylus(syn)
return a:syn ==? 'cssStylusVueStyle'
endfunction
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)'
let add = s:enable_init_indent
\&& ind == 0
\&& count(['style', 'script'], a:tag) == 1
\&& curline !~ s:block_tag
if add
call vue#LogWithLnum('add initial indent')
let ind = &sw
endif
return ind
endfunction
function! s:PrevMultilineEmptyTag(lnum)
@@ -312,27 +151,59 @@ function! s:PrevMultilineEmptyTag(lnum)
endwhile
endfunction
function! s:PrevNonBlacnkNonComment(lnum)
let curline = getline(a:lnum)
let cursyns = s:SynsEOL(a:lnum)
let cursyn = get(cursyns, 1, '')
if cursyn =~? 'comment' && !empty(curline)
return prevnonblank(a:lnum - 1)
function! s:AdjustHTMLIndent(ind)
let ind = a:ind
let prevlnum = prevnonblank(v:lnum - 1)
let prevline = getline(prevlnum)
let curline = getline(v:lnum)
if prevline =~? s:empty_tag
call vue#LogWithLnum('previous line is an empty tag')
let ind = ind - &sw
endif
let lnum = a:lnum - 1
let prevlnum = prevnonblank(lnum)
let prevsyns = s:SynsEOL(prevlnum)
let prevsyn = get(prevsyns, 1, '')
while prevsyn =~? 'comment' && lnum > 1
let lnum = lnum - 1
let prevlnum = prevnonblank(lnum)
let prevsyns = s:SynsEOL(prevlnum)
let prevsyn = get(prevsyns, 1, '')
endwhile
return prevlnum
endfunction
"}}}
" Align '/>' and '>' with '<'
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
let b:did_indent = 1
" vim: fdm=marker
" Decrease indent if prevlines are a multiline empty tag
let [start, end] = s:PrevMultilineEmptyTag(v:lnum)
if prevlnum == end
call vue#LogWithLnum('previous line is a multiline empty tag')
let ind = indent(v:lnum - 1)
if curline =~? s:full_tag_end
let ind = ind - &sw
endif
endif
endif
return ind
endfunction
function! GetVueIndent()
let ind = s:GetIndentByContext()
if ind == -1
let syntax = vue#GetBlockSyntax(v:lnum)
let ind = s:GetBlockIndent(syntax)
let ind = s:AdjustBlockIndent(syntax, ind)
call vue#LogWithLnum('syntax '.syntax.', ind '.ind)
else
call vue#LogWithLnum('context, ind '.ind)
endif
let tag = vue#GetBlockTag(v:lnum)
let ind = s:CheckInitIndent(tag, ind)
return ind
endfunction
function! s:Main()
call s:Init()
let syntax_list = vue#GetSyntaxList(s:config_syntax)
call s:SetIndentExpr(syntax_list)
call s:SetVueIndent()
endfunction
call s:Main()