mirror of
https://github.com/sheerun/vim-polyglot.git
synced 2025-11-12 05:23:51 -05:00
Change svelte provider, fixes #700
This commit is contained in:
@@ -2,160 +2,301 @@ if polyglot#init#is_disabled(expand('<sfile>:p'), 'svelte', 'indent/svelte.vim')
|
||||
finish
|
||||
endif
|
||||
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
" Vim indent file
|
||||
" Language: Svelte 3 (HTML/JavaScript)
|
||||
" Author: Evan Lecklider <evan@lecklider.com>
|
||||
" Maintainer: Evan Lecklide <evan@lecklider.com>
|
||||
" URL: https://github.com/evanleck/vim-svelte
|
||||
|
||||
"
|
||||
" Language: Svelte
|
||||
" Maintainer: leafOfTree <leafvocation@gmail.com>
|
||||
"
|
||||
" CREDITS: Inspired by mxw/vim-jsx.
|
||||
"
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
if exists("b:did_indent")
|
||||
finish
|
||||
endif
|
||||
|
||||
if !exists('g:svelte_indent_script')
|
||||
let g:svelte_indent_script = 1
|
||||
endif
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
"
|
||||
" Variables {{{
|
||||
"
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
let s:name = 'vim-svelte-plugin'
|
||||
" Let <template> handled by HTML
|
||||
let s:svelte_tag_start = '\v^\<(script|style)'
|
||||
let s:svelte_tag_end = '\v^\<\/(script|style)'
|
||||
let s:template_tag = '\v^\s*\<\/?template'
|
||||
" https://developer.mozilla.org/en-US/docs/Glossary/Empty_element
|
||||
let s:empty_tagname = '(area|base|br|col|embed|hr|input|img|keygen|link|meta|param|source|track|wbr)'
|
||||
let s:empty_tag = '\v\C\<'.s:empty_tagname.'[^/]*\>'
|
||||
let s:empty_tag_start = '\v\<'.s:empty_tagname.'[^\>]*$'
|
||||
let s:empty_tag_end = '\v^\s*[^\<\>\/]*\>\s*'
|
||||
let s:tag_end = '\v^\s*\/?\>\s*'
|
||||
let s:oneline_block = '^\s*{#.*{/.*}\s*$'
|
||||
"}}}
|
||||
|
||||
if !exists('g:svelte_indent_style')
|
||||
let g:svelte_indent_style = 1
|
||||
endif
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
"
|
||||
" Config {{{
|
||||
"
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
let s:use_pug = svelte#GetConfig('use_pug', 0)
|
||||
let s:use_sass = svelte#GetConfig('use_sass', 0)
|
||||
let s:use_coffee = svelte#GetConfig('use_coffee', 0)
|
||||
let s:use_typescript = svelte#GetConfig('use_typescript', 0)
|
||||
let s:has_init_indent = svelte#GetConfig('has_init_indent', 1)
|
||||
let s:debug = svelte#GetConfig('debug', 0)
|
||||
"}}}
|
||||
|
||||
" Try to mirror Svelte's indent settings so the HTML indenting scripts match.
|
||||
if g:svelte_indent_script
|
||||
let b:html_indent_script1 = "inc"
|
||||
else
|
||||
let b:html_indent_script1 = "zero"
|
||||
endif
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
"
|
||||
" Load indent method {{{
|
||||
"
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
" Save shiftwidth
|
||||
let s:sw = &sw
|
||||
|
||||
if g:svelte_indent_style
|
||||
let b:html_indent_style1 = "inc"
|
||||
else
|
||||
let b:html_indent_style1 = "zero"
|
||||
endif
|
||||
|
||||
runtime! indent/html.vim
|
||||
" Use lib/indent/ files for compatibility
|
||||
unlet! b:did_indent
|
||||
runtime lib/indent/xml.vim
|
||||
|
||||
let s:html_indent = &l:indentexpr
|
||||
let b:did_indent = 1
|
||||
unlet! b:did_indent
|
||||
runtime lib/indent/css.vim
|
||||
|
||||
setlocal indentexpr=GetSvelteIndent()
|
||||
setlocal indentkeys=o,O,*<Return>,<>>,{,},0),0],!^F,;,=:else,=:then,=:catch,=/if,=/each,=/await
|
||||
" Use normal indent files
|
||||
unlet! b:did_indent
|
||||
runtime! indent/javascript.vim
|
||||
let b:javascript_indentexpr = &indentexpr
|
||||
|
||||
" Only define the function once.
|
||||
if exists('*GetSvelteIndent')
|
||||
finish
|
||||
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_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,:,=:else
|
||||
" XML indentkeys
|
||||
setlocal indentkeys+=*<Return>,<>>,<<>,/
|
||||
setlocal indentexpr=GetSvelteIndent()
|
||||
"}}}
|
||||
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
"
|
||||
" Functions {{{
|
||||
"
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
function! GetSvelteIndent()
|
||||
let current_line_number = v:lnum
|
||||
let prevlnum = prevnonblank(v:lnum-1)
|
||||
let prevline = getline(prevlnum)
|
||||
let prevsyns = s:SynsSOL(prevlnum)
|
||||
|
||||
if current_line_number == 0
|
||||
return 0
|
||||
endif
|
||||
let curline = getline(v:lnum)
|
||||
let cursyns = s:SynsSOL(v:lnum)
|
||||
let cursyn = get(cursyns, 0, '')
|
||||
|
||||
let current_line = getline(current_line_number)
|
||||
if s:SynHTML(cursyn)
|
||||
call s:Log('syntax: html')
|
||||
let ind = XmlIndentGet(v:lnum, 0)
|
||||
if prevline =~? s:empty_tag
|
||||
call s:Log('previous line is empty tag')
|
||||
let ind = ind - &sw
|
||||
endif
|
||||
|
||||
" Opening script and style tags should be all the way outdented.
|
||||
if current_line =~ '^\s*</\?\(script\|style\)'
|
||||
return 0
|
||||
endif
|
||||
if s:IsBlockStart(prevsyns) && prevline !~ s:oneline_block
|
||||
call s:Log('increase block indent')
|
||||
let ind = ind + &sw
|
||||
endif
|
||||
|
||||
let previous_line_number = prevnonblank(current_line_number - 1)
|
||||
let previous_line = getline(previous_line_number)
|
||||
let previous_line_indent = indent(previous_line_number)
|
||||
if s:IsBlockEnd(cursyns, curline)
|
||||
call s:Log('decrease block indent')
|
||||
let ind = ind - &sw
|
||||
endif
|
||||
|
||||
" The inside of scripts an styles should be indented unless disabled.
|
||||
if previous_line =~ '^\s*<script'
|
||||
if g:svelte_indent_script
|
||||
return previous_line_indent + shiftwidth()
|
||||
" 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 s:Log('previous line is a multiline empty tag')
|
||||
let ind = indent(v:lnum - 1)
|
||||
endif
|
||||
endif
|
||||
elseif s:SynPug(cursyn)
|
||||
call s:Log('syntax: pug')
|
||||
let ind = GetPugIndent()
|
||||
elseif s:SynCoffee(cursyn)
|
||||
call s:Log('syntax: coffee')
|
||||
let ind = GetCoffeeIndent(v:lnum)
|
||||
elseif s:SynTypeScript(cursyn)
|
||||
call s:Log('syntax: typescript')
|
||||
let ind = GetTypescriptIndent()
|
||||
elseif s:SynSASS(cursyn)
|
||||
call s:Log('syntax: sass')
|
||||
let ind = GetSassIndent()
|
||||
elseif s:SynStyle(cursyn)
|
||||
call s:Log('syntax: style')
|
||||
let ind = GetCSSIndent()
|
||||
else
|
||||
call s:Log('syntax: javascript')
|
||||
if len(b:javascript_indentexpr)
|
||||
let ind = eval(b:javascript_indentexpr)
|
||||
else
|
||||
return previous_line_indent
|
||||
let ind = cindent(v:lnum)
|
||||
endif
|
||||
endif
|
||||
|
||||
if previous_line =~ '^\s*<style'
|
||||
if g:svelte_indent_style
|
||||
return previous_line_indent + shiftwidth()
|
||||
else
|
||||
return previous_line_indent
|
||||
if curline =~? s:svelte_tag_start || curline =~? s:svelte_tag_end
|
||||
\|| prevline =~? s:svelte_tag_end
|
||||
\|| (curline =~ s:template_tag && s:SynPug(cursyn))
|
||||
call s:Log('current line is svelte tag or previous line is svelte tag end')
|
||||
call s:Log('... or current line is pug template tag')
|
||||
let ind = 0
|
||||
elseif s:has_init_indent
|
||||
if s:SynSvelteScriptOrStyle(cursyn) && ind < 1
|
||||
call s:Log('add initial indent')
|
||||
let ind = &sw
|
||||
endif
|
||||
elseif prevline =~? s:svelte_tag_start
|
||||
call s:Log('previous line is svelte tag start')
|
||||
let ind = 0
|
||||
endif
|
||||
|
||||
execute "let indent = " . s:html_indent
|
||||
|
||||
" For some reason, the HTML CSS indentation keeps indenting the next line over
|
||||
" and over after each style declaration.
|
||||
if searchpair('<style>', '', '</style>', 'bW') && previous_line =~ ';$' && current_line !~ '}'
|
||||
return previous_line_indent
|
||||
endif
|
||||
|
||||
" "/await" or ":catch" or ":then"
|
||||
if current_line =~ '^\s*{\s*\/await' || current_line =~ '^\s*{\s*:\(catch\|then\)'
|
||||
let await_start = searchpair('{\s*#await\>', '', '{\s*\/await\>', 'bW')
|
||||
|
||||
if await_start
|
||||
return indent(await_start)
|
||||
endif
|
||||
endif
|
||||
|
||||
" "/each"
|
||||
if current_line =~ '^\s*{\s*\/each'
|
||||
let each_start = searchpair('{\s*#each\>', '', '{\s*\/each\>', 'bW')
|
||||
|
||||
if each_start
|
||||
return indent(each_start)
|
||||
endif
|
||||
endif
|
||||
|
||||
" "/if"
|
||||
if current_line =~ '^\s*{\s*\/if'
|
||||
let if_start = searchpair('{\s*#if\>', '', '{\s*\/if\>', 'bW')
|
||||
|
||||
if if_start
|
||||
return indent(if_start)
|
||||
endif
|
||||
endif
|
||||
|
||||
" ":else" is tricky because it can match an opening "#each" _or_ an opening
|
||||
" "#if", so we try to be smart and look for the closest of the two.
|
||||
if current_line =~ '^\s*{\s*:else'
|
||||
let if_start = searchpair('{\s*#if\>', '', '{\s*\/if\>', 'bW')
|
||||
|
||||
" If it's an "else if" then we know to look for an "#if"
|
||||
if current_line =~ '^\s*{\s*:else if' && if_start
|
||||
return indent(if_start)
|
||||
else
|
||||
" The greater line number will be closer to the cursor position because
|
||||
" we're searching backward.
|
||||
return indent(max([if_start, searchpair('{\s*#each\>', '', '{\s*\/each\>', 'bW')]))
|
||||
endif
|
||||
endif
|
||||
|
||||
" "#if" or "#each"
|
||||
if previous_line =~ '^\s*{\s*#\(if\|each\|await\)'
|
||||
return previous_line_indent + shiftwidth()
|
||||
endif
|
||||
|
||||
" ":else" or ":then"
|
||||
if previous_line =~ '^\s*{\s*:\(else\|catch\|then\)'
|
||||
return previous_line_indent + shiftwidth()
|
||||
endif
|
||||
|
||||
" Custom element juggling for abnormal self-closing tags (<Widget />),
|
||||
" capitalized component tags (<Widget></Widget>), and custom svelte tags
|
||||
" (<svelte:head></svelte:head>).
|
||||
if synID(previous_line_number, match(previous_line, '\S') + 1, 0) == hlID('htmlTag')
|
||||
\ && synID(current_line_number, match(current_line, '\S') + 1, 0) != hlID('htmlEndTag')
|
||||
let indents_match = indent == previous_line_indent
|
||||
let previous_closes = previous_line =~ '/>$'
|
||||
|
||||
if indents_match && !previous_closes && previous_line =~ '<\(\u\|\l\+:\l\+\)'
|
||||
return previous_line_indent + shiftwidth()
|
||||
elseif !indents_match && previous_closes
|
||||
return previous_line_indent
|
||||
endif
|
||||
endif
|
||||
|
||||
return indent
|
||||
call s:Log('indent: '.ind)
|
||||
return ind
|
||||
endfunction
|
||||
|
||||
function! s:IsBlockStart(prevsyns)
|
||||
let prevsyn_second = get(a:prevsyns, 1, '')
|
||||
" Some HTML tags add an extra syntax layer
|
||||
let prevsyn_third = get(a:prevsyns, 2, '')
|
||||
return s:SynBlockBody(prevsyn_second)
|
||||
\ || s:SynBlockStart(prevsyn_second)
|
||||
\ || s:SynBlockBody(prevsyn_third)
|
||||
\ || s:SynBlockStart(prevsyn_third)
|
||||
endfunction
|
||||
|
||||
function! s:IsBlockEnd(cursyns, curline)
|
||||
let cursyn_second = get(a:cursyns, 1, '')
|
||||
" Some HTML tags add an extra syntax layer
|
||||
let cursyn_third = get(a:cursyns, 2, '')
|
||||
return a:curline !~ '^\s*$'
|
||||
\ && (s:SynBlockBody(cursyn_second)
|
||||
\ || s:SynBlockEnd(cursyn_second)
|
||||
\ || s:SynBlockBody(cursyn_third)
|
||||
\ || s:SynBlockEnd(cursyn_third))
|
||||
endfunction
|
||||
|
||||
function! s:SynsEOL(lnum)
|
||||
let lnum = prevnonblank(a:lnum)
|
||||
let col = strlen(getline(lnum))
|
||||
return map(synstack(lnum, col), 'synIDattr(v:val, "name")')
|
||||
endfunction
|
||||
|
||||
function! s:SynsSOL(lnum)
|
||||
let lnum = prevnonblank(a:lnum)
|
||||
let col = match(getline(lnum), '\S') + 1
|
||||
return map(synstack(lnum, col), 'synIDattr(v:val, "name")')
|
||||
endfunction
|
||||
|
||||
function! s:SynHTML(syn)
|
||||
return a:syn ==? 'htmlSvelteTemplate'
|
||||
endfunction
|
||||
|
||||
function! s:SynBlockBody(syn)
|
||||
return a:syn ==? 'svelteBlockBody'
|
||||
endfunction
|
||||
|
||||
function! s:SynBlockStart(syn)
|
||||
return a:syn ==? 'svelteBlockStart'
|
||||
endfunction
|
||||
|
||||
function! s:SynBlockEnd(syn)
|
||||
return a:syn ==? 'svelteBlockEnd'
|
||||
endfunction
|
||||
|
||||
function! s:SynPug(syn)
|
||||
return a:syn ==? 'pugSvelteTemplate'
|
||||
endfunction
|
||||
|
||||
function! s:SynCoffee(syn)
|
||||
return a:syn ==? 'coffeeSvelteScript'
|
||||
endfunction
|
||||
|
||||
function! s:SynTypeScript(syn)
|
||||
return a:syn ==? 'typescriptSvelteScript'
|
||||
endfunction
|
||||
|
||||
function! s:SynSASS(syn)
|
||||
return a:syn ==? 'cssSassSvelteStyle'
|
||||
endfunction
|
||||
|
||||
function! s:SynStyle(syn)
|
||||
return a:syn =~? 'SvelteStyle'
|
||||
endfunction
|
||||
|
||||
function! s:SynSvelteScriptOrStyle(syn)
|
||||
return a:syn =~? '\v(SvelteStyle)|(SvelteScript)'
|
||||
endfunction
|
||||
|
||||
function! s:PrevMultilineEmptyTag(lnum)
|
||||
let lnum = a:lnum - 1
|
||||
let lnums = [0, 0]
|
||||
while lnum > 0
|
||||
let line = getline(lnum)
|
||||
if line =~? s:empty_tag_end
|
||||
let lnums[1] = lnum
|
||||
endif
|
||||
|
||||
if line =~? s:tag_start
|
||||
if line =~? s:empty_tag_start
|
||||
let lnums[0] = lnum
|
||||
return lnums
|
||||
else
|
||||
return [0, 0]
|
||||
endif
|
||||
endif
|
||||
|
||||
let lnum = lnum - 1
|
||||
endwhile
|
||||
endfunction
|
||||
|
||||
function! s:Log(msg)
|
||||
if s:debug
|
||||
echom '['.s:name.']['.v:lnum.'] '.a:msg
|
||||
endif
|
||||
endfunction
|
||||
"}}}
|
||||
|
||||
let b:did_indent = 1
|
||||
" vim: fdm=marker
|
||||
|
||||
Reference in New Issue
Block a user