1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-23 07:00:04 +08:00

Improve tsx support (#3993)

This commit is contained in:
Wang Shidong 2020-12-02 23:28:17 +08:00 committed by GitHub
parent 03a2ab8afe
commit 6e25213d3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 463 additions and 2 deletions

View File

@ -25,8 +25,8 @@
function! SpaceVim#layers#lang#typescript#plugins() abort
let plugins = []
call add(plugins, ['leafgarland/typescript-vim'])
call add(plugins, ['peitalin/vim-jsx-typescript'])
call add(plugins, ['leafgarland/typescript-vim', {'merged' : 0}])
call add(plugins, [g:_spacevim_root_dir . 'bundle/vim-jsx-typescript', {'merged' : 0}])
call add(plugins, ['heavenshell/vim-jsdoc', { 'on_cmd': 'JsDoc' }])
if !SpaceVim#layers#lsp#check_filetype('typescript')
if has('nvim')

View File

@ -0,0 +1,16 @@
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Vim ftplugin file
"
" Language: TSX (TypeScript)
"
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" modified from html.vim
if exists("loaded_matchit")
let b:match_ignorecase = 0
let b:match_words = '(:),\[:\],{:},<:>,' .
\ '<\@<=\([^/][^ \t>]*\)[^>]*\%(>\|$\):<\@<=/\1>'
endif
setlocal suffixesadd+=.tsx
setlocal commentstring={/*\ %s\ */}

View File

@ -0,0 +1,183 @@
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" " Vim indent file
"
" Language: typescriptreact (TypeScript)
" from:
" https://github.com/peitalin/vim-jsx-typescript/issues/4#issuecomment-564519091
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
runtime! indent/typescript.vim
let b:did_indent = 1
if !exists('*GetTypescriptIndent') | finish | endif
setlocal indentexpr=GetTsxIndent()
setlocal indentkeys=0{,0},0),0],0\,,!^F,o,O,e,*<Return>,<>>,<<>,/
if exists('*shiftwidth')
function! s:sw()
return shiftwidth()
endfunction
else
function! s:sw()
return &sw
endfunction
endif
let s:real_endtag = '\s*<\/\+[A-Za-z]*>'
let s:return_block = '\s*return\s\+('
function! s:SynSOL(lnum)
return map(synstack(a:lnum, 1), 'synIDattr(v:val, "name")')
endfunction
function! s:SynEOL(lnum)
let lnum = prevnonblank(a:lnum)
let col = strlen(getline(lnum))
return map(synstack(lnum, col), 'synIDattr(v:val, "name")')
endfunction
function! s:SynAttrJSX(synattr)
return a:synattr =~ "^tsx"
endfunction
function! s:SynXMLish(syns)
return s:SynAttrJSX(get(a:syns, -1))
endfunction
function! s:SynJSXDepth(syns)
return len(filter(copy(a:syns), 'v:val ==# "tsxRegion"'))
endfunction
function! s:SynJSXCloseTag(syns)
return len(filter(copy(a:syns), 'v:val ==# "tsxCloseTag"'))
endfunction
function! s:SynJsxEscapeJs(syns)
return len(filter(copy(a:syns), 'v:val ==# "tsxJsBlock"'))
endfunction
function! s:SynJSXContinues(cursyn, prevsyn)
let curdepth = s:SynJSXDepth(a:cursyn)
let prevdepth = s:SynJSXDepth(a:prevsyn)
return prevdepth == curdepth ||
\ (prevdepth == curdepth + 1 && get(a:cursyn, -1) ==# 'tsxRegion')
endfunction
function! GetTsxIndent()
let cursyn = s:SynSOL(v:lnum)
let prevsyn = s:SynEOL(v:lnum - 1)
let nextsyn = s:SynEOL(v:lnum + 1)
let currline = getline(v:lnum)
if ((s:SynXMLish(prevsyn) && s:SynJSXContinues(cursyn, prevsyn)) || currline =~# '\v^\s*\<')
let preline = getline(v:lnum - 1)
if currline =~# '\v^\s*\/?\>' " /> >
return preline =~# '\v^\s*\<' ? indent(v:lnum - 1) : indent(v:lnum - 1) - s:sw()
endif
if preline =~# '\v\{\s*$' && preline !~# '\v^\s*\<'
return currline =~# '\v^\s*\}' ? indent(v:lnum - 1) : indent(v:lnum - 1) + s:sw()
endif
" return ( | return ( | return (
" <div></div> | <div | <div
" {} | style={ | style={
" <div></div> | } | }
" ) | foo="bar"| ></div>
if preline =~# '\v\}\s*$'
if currline =~# '\v^\s*\<\/'
return indent(v:lnum - 1) - s:sw()
endif
let ind = indent(v:lnum - 1)
if preline =~# '\v^\s*\<'
let ind = ind + s:sw()
endif
if currline =~# '\v^\s*\/?\>'
let ind = ind - s:sw()
endif
return ind
endif
" return ( | return (
" <div> | <div>
" </div> | </div>
" ##); | );
if preline =~# '\v(\s?|\k?)\($' || preline =~# '\v^\s*\<\>'
return indent(v:lnum - 1) + s:sw()
endif
let ind = s:XmlIndentGet(v:lnum)
" <div | <div
" hoge={ | hoge={
" <div></div> | ##<div></div>
if s:SynJsxEscapeJs(prevsyn) && preline =~# '\v\{\s*$'
let ind = ind + s:sw()
endif
" />
if preline =~# '\v^\s*\/?\>$' || currline =~# '\v^\s*\<\/\>'
"let ind = currline =~# '\v^\s*\<\/' ? ind : ind + s:sw()
let ind = ind + s:sw()
" }> or }}\> or }}>
elseif preline =~# '\v^\s*\}?\}\s*\/?\>$'
let ind = ind + s:sw()
" ></a
elseif preline =~# '\v^\s*\>\<\/\a'
let ind = ind + s:sw()
elseif preline =~# '\v^\s*}}.+\<\/\k+\>$'
let ind = ind + s:sw()
endif
" <div | <div
" hoge={ | hoge={
" <div></div> | <div></div>
" } | }##
if currline =~# '}$' && !(currline =~# '\v\{')
let ind = ind - s:sw()
endif
if currline =~# '^\s*)' && s:SynJSXCloseTag(prevsyn)
let ind = ind - s:sw()
endif
else
let ind = GetTypescriptIndent()
endif
return ind
endfunction
let b:xml_indent_open = '.\{-}<\a'
let b:xml_indent_close = '.\{-}</'
function! s:XmlIndentWithPattern(line, pat)
let s = substitute('x'.a:line, a:pat, "\1", 'g')
return strlen(substitute(s, "[^\1].*$", '', ''))
endfunction
" [-- return the sum of indents of a:lnum --]
function! s:XmlIndentSum(lnum, style, add)
let line = getline(a:lnum)
if a:style == match(line, '^\s*</')
return (&sw *
\ (s:XmlIndentWithPattern(line, b:xml_indent_open)
\ - s:XmlIndentWithPattern(line, b:xml_indent_close)
\ - s:XmlIndentWithPattern(line, '.\{-}/>'))) + a:add
else
return a:add
endif
endfunction
function! s:XmlIndentGet(lnum)
" Find a non-empty line above the current line.
let lnum = prevnonblank(a:lnum - 1)
" Hit the start of the file, use zero indent.
if lnum == 0 | return 0 | endif
let ind = s:XmlIndentSum(lnum, -1, indent(lnum))
let ind = s:XmlIndentSum(a:lnum, 0, ind)
return ind
endfunction

View File

@ -0,0 +1,256 @@
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Vim syntax file
"
" Language: TSX (TypeScript)
"
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" These are the plugin-to-syntax-element correspondences:
" - leafgarland/typescript-vim: typescriptFuncBlock
let s:tsx_cpo = &cpo
set cpo&vim
syntax case match
if exists('b:current_syntax')
let s:current_syntax = b:current_syntax
unlet b:current_syntax
endif
syn include @HTMLSyntax syntax/html.vim
set syntax=typescript
if exists('s:current_syntax')
let b:current_syntax = s:current_syntax
endif
"""""" Vim Syntax Help """"""
" `keepend` and `extend` docs:
" https://github.com/othree/til/blob/master/vim/syntax-keepend-extend.md
" \@<= positive lookbehind
" \@<! negative lookbehind
" \@= positive lookahead
" \@! negative lookahead
syntax case match
" <tag></tag>
" s~~~~~~~~~~~e
syntax region tsxRegion
\ start=+\(\([a-zA-Z]\)\@<!<>\|\(\s\|[(]\s*\)\@<=\z(<[/a-zA-Z],\@!\([a-zA-Z0-9:\-],\@!\)*\)\)+
\ skip=+<!--\_.\{-}-->+
\ end=+</\_.\{-}>+
\ end=+[a-zA-Z0-9.]*[/]*>\s*\n*\s*\n*\s*[});,]\@=+
\ contains=tsxTag,tsxCloseTag,tsxComment,Comment,@Spell,tsxColon,tsxIfOperator,tsxElseOperator,jsBlock
\ extend
\ keepend
" Negative lookbacks for:
" <> preceeded by [a-zA-Z]
" <<Tag...
" [a-zA-Z]<Tag
" end 1): handle </NormalClosingTag>
" end 2): handle <SelfClosingTags/>\s*\n*\s*\n*\s*)
" \s => spaces/tabs
" \n => end-of-line => \n only match end of line in the buffer.
" \s*\n*\s*\n*\s* => handles arbitrary spacing between closing tsxTag </tag>
" and the ending brace for the scope: `}` or `)`
"
" \z( pattern \) Braces can be used to make a pattern into an atom.
" <tag>{content}</tag>
" s~~~~~~~e
syn region jsBlock
\ start=+{+
\ end=+}+
\ contained
\ contains=TOP
" \@<= positive lookbehind
" \@<! negative lookbehind
" \@= positive lookahead
" \@! negative lookahead
" RULE: capture expression, then apply rule AFTER
" e.g foo\(bar\)\@!
" match all `foo` which is not followed by `bar`
" https://jbodah.github.io/blog/2016/11/01/positivenegative-lookaheadlookbehind-vim/
" <tag key={this.props.key}>
" s~~~~~~~~~~~~~~e
syntax region tsxJsBlock
\ matchgroup=tsxAttributeBraces start=+\([=]\|\s\)\@<={+
\ matchgroup=tsxAttributeBraces end=+}\(\s*}\|)\)\@!+
\ contained
\ keepend
\ extend
\ contains=TOP
" <tag id="sample">
" s~~~~~~~~~~~~~~~e
syntax region tsxTag
\ start=+<[^ /!?<"'=:]\@=+
\ end=+[/]\{0,1}>+
\ contained
\ contains=tsxTagName,tsxAttrib,tsxEqual,tsxString,tsxJsBlock,tsxAttributeComment,tsxGenerics
syntax region tsxGenerics
\ matchgroup=tsxTypeBraces start=+\([<][_\-\.:a-zA-Z0-9]*\|[<][_\-\.:a-zA-Z0-9]*\)\@<=\s*[<]+
\ matchgroup=tsxTypeBraces end=+>+
\ contains=tsxTypes,tsxGenerics
\ contained
\ extend
syntax match tsxTypes /[_\.a-zA-Z0-9]/
\ contained
" \@<! negative lookbehind
" <T1, T2>
" s~~~~~~~e
" For Generics outside of tsxRegion
" Must come after tsxRegion in this file
syntax region tsGenerics
\ start=+<\([\[A-Z]\|typeof\)\([a-zA-Z0-9,{}\[\]'".=>():]\|\s\)*>\(\s*\n*\s*[()]\|\s*[=]\)+
\ end=+\([=]\)\@<!>+
\ contains=tsxTypes,tsxGenerics
\ extend
" </tag>
" ~~~~~~
syntax region tsxCloseTag
\ start=+</[^ /!?<"'=:]\@=+
\ end=+>+
" matches tsx Comments: {/* ..... /*}
syn region Comment contained start=+{/\*+ end=+\*/}+ contains=Comment
\ extend
syn region tsxAttributeComment contained start=+//+ end=+\n+ contains=Comment
\ extend
syntax match tsxCloseString
\ +\w\++
\ contained
syntax match tsxColon
\ +[;]+
\ contained
" <!-- -->
" ~~~~~~~~
syntax match tsxComment /<!--\_.\{-}-->/ display
syntax match tsxEntity "&[^; \t]*;" contains=tsxEntityPunct
syntax match tsxEntityPunct contained "[&.;]"
" <MyComponent ...>
" ~~~~~~~~~~~
" NOT
" <someCamel ...>
" ~~~~~
syntax match tsxComponentName
\ +\<[_$]\?[A-Z][-_$A-Za-z0-9]*\>+
\ contained
\ display
syntax match tsxCloseComponentName
\ +[</]\?[A-Z][-_$A-Za-z0-9]*\>+
\ contained
\ display
" <tag key={this.props.key}>
" ~~~
syntax match tsxTagName
\ +[<]\@<=[^ /!?<>"']\++
\ contained
\ contains=tsxComponentName
\ display
" </tag>
" ~~~
syntax match tsxCloseTagName
\ +[</]\@<=[^ /!?<>"']\++
\ containedin=tsxCloseTag
\ contains=tsxCloseComponentName
\ display
" <tag key={this.props.key}>
" ~~~
syntax match tsxAttrib
\ +[-'"<]\@<!\<[a-zA-Z:_][-.0-9a-zA-Z0-9:_]*[/]\{0,1}\>\(['"]\@!\|$\)+
\ contained
\ keepend
\ contains=tsxAttribPunct,tsxAttribHook
\ display
syntax match tsxAttribPunct +[:.]+ contained display
" <tag id="sample">
" ~
syntax match tsxEqual +=+ contained display
" <tag id="sample">
" s~~~~~~e
syntax region tsxString contained start=+"+ end=+"+ contains=tsxEntity,@Spell display
" <tag id=`sample${var}`>
syntax region tsxString contained start=+`+ end=+`+ contains=tsxEntity,@Spell display
" <tag id='sample'>
" s~~~~~~e
syntax region tsxString contained start=+'+ end=+'+ contains=tsxEntity,@Spell display
syntax match tsxIfOperator +?+
syntax match tsxNotOperator +!+
syntax match tsxElseOperator +:+
" highlight def link tsxTagName htmlTagName
highlight def link tsxTagName xmlTagName
highlight def link tsxComponentName xmlTagName
highlight def link tsxCloseComponentName xmlTagName
highlight def link tsxTag htmlTag
highlight def link tsxCloseTag xmlEndTag
highlight def link tsxCloseTagName xmlTagName
highlight def link tsxRegionEnd xmlEndTag
highlight def link tsxEqual htmlTag
highlight def link tsxString String
highlight def link tsxNameSpace Function
highlight def link tsxComment Error
highlight def link tsxAttrib htmlArg
highlight def link tsxCloseString htmlTagName
highlight def link tsxAttributeBraces htmlTag
highlight def link tsxAttributeComment Comment
highlight def link tsxColon typescriptEndColons
highlight def link tsxGenerics typescriptEndColons
highlight def link tsGenerics tsxTypeBraces
highlight def link tsxIfOperator typescriptEndColons
highlight def link tsxNotOperator typescriptEndColons
highlight def link tsxElseOperator typescriptEndColons
highlight def link tsxTypeBraces htmlTag
highlight def link tsxTypes typescriptEndColons
" Custom React Highlights
syn keyword ReactState state nextState prevState setState
" Then EITHER (define your own colour scheme):
" OR (make the colour scheme match an existing one):
" hi link ReactKeywords typescriptRComponent
syn keyword ReactProps props defaultProps ownProps nextProps prevProps
syn keyword Events e event target value
syn keyword ReduxKeywords dispatch payload
syn keyword ReduxHooksKeywords useState useEffect useMemo useCallback
syn keyword WebBrowser window localStorage
syn keyword ReactLifeCycleMethods componentWillMount shouldComponentUpdate componentWillUpdate componentDidUpdate componentWillReceiveProps componentWillUnmount componentDidMount
let b:current_syntax = 'typescriptreact'
let &cpo = s:tsx_cpo
unlet s:tsx_cpo

View File

@ -0,0 +1,6 @@
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Vim ftdetect file
" Language: TSX (Typescript)
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
autocmd BufNewFile,BufRead *.tsx setf typescriptreact