diff options
author | Adam Stankiewicz <sheerun@sher.pl> | 2019-06-08 13:25:41 +0200 |
---|---|---|
committer | Adam Stankiewicz <sheerun@sher.pl> | 2019-06-08 13:25:41 +0200 |
commit | 26c678b08d88b658ec6069eb2ada2b2ba21c5d39 (patch) | |
tree | ebf7500bafee56b195bf52ced286fe29e5b3f485 /autoload/jsx_pretty | |
parent | 17ecfbdabcfdf294dae27c506fb68b58175199b5 (diff) | |
download | vim-polyglot-26c678b08d88b658ec6069eb2ada2b2ba21c5d39.tar.gz vim-polyglot-26c678b08d88b658ec6069eb2ada2b2ba21c5d39.zip |
Change jsx/tsx provider, closes #400
Diffstat (limited to 'autoload/jsx_pretty')
-rw-r--r-- | autoload/jsx_pretty/comment.vim | 41 | ||||
-rw-r--r-- | autoload/jsx_pretty/indent.vim | 204 | ||||
-rw-r--r-- | autoload/jsx_pretty/syntax.vim | 218 |
3 files changed, 463 insertions, 0 deletions
diff --git a/autoload/jsx_pretty/comment.vim b/autoload/jsx_pretty/comment.vim new file mode 100644 index 00000000..d5d58f5d --- /dev/null +++ b/autoload/jsx_pretty/comment.vim @@ -0,0 +1,41 @@ +if exists('g:polyglot_disabled') && index(g:polyglot_disabled, 'jsx') != -1 + finish +endif + +function! jsx_pretty#comment#update_commentstring(original) + let syn_current = s:syn_name(line('.'), col('.')) + let syn_start = s:syn_name(line('.'), 1) + let save_cursor = getcurpos() + + if syn_start =~ '^jsx' + let line = getline(".") + let start = len(matchstr(line, '^\s*')) + let syn_name = s:syn_name(line('.'), start + 1) + + if line =~ '^\s*//' + let &l:commentstring = '// %s' + elseif s:syn_contains(line('.'), col('.'), 'jsxTaggedRegion') + let &l:commentstring = '<!-- %s -->' + elseif syn_name =~ '^jsxAttrib' + let &l:commentstring = '// %s' + else + let &l:commentstring = '{/* %s */}' + endif + else + let &l:commentstring = a:original + endif + + " Restore the cursor position + call setpos('.', save_cursor) +endfunction + +function! s:syn_name(lnum, cnum) + let syn_id = get(synstack(a:lnum, a:cnum), -1) + return synIDattr(syn_id, "name") +endfunction + +function! s:syn_contains(lnum, cnum, syn_name) + let stack = synstack(a:lnum, a:cnum) + let syn_names = map(stack, 'synIDattr(v:val, "name")') + return index(syn_names, a:syn_name) >= 0 +endfunction diff --git a/autoload/jsx_pretty/indent.vim b/autoload/jsx_pretty/indent.vim new file mode 100644 index 00000000..a4e7a839 --- /dev/null +++ b/autoload/jsx_pretty/indent.vim @@ -0,0 +1,204 @@ +if exists('g:polyglot_disabled') && index(g:polyglot_disabled, 'jsx') != -1 + finish +endif + +if exists('*shiftwidth') + function! s:sw() + return shiftwidth() + endfunction +else + function! s:sw() + return &sw + endfunction +endif + +" Get the syntax group of start of line +function! s:syn_sol(lnum) + let line = getline(a:lnum) + let sol = matchstr(line, '^\s*') + return map(synstack(a:lnum, len(sol) + 1), 'synIDattr(v:val, "name")') +endfunction + +" Get the syntax group of end of line +function! s:syn_eol(lnum) + let lnum = prevnonblank(a:lnum) + let col = strlen(getline(lnum)) + return map(synstack(lnum, col), 'synIDattr(v:val, "name")') +endfunction + +function! s:prev_indent(lnum) + let lnum = prevnonblank(a:lnum - 1) + return indent(lnum) +endfunction + +function! s:prev_line(lnum) + let lnum = prevnonblank(a:lnum - 1) + return substitute(getline(lnum), '^\s*\|\s*$', '', 'g') +endfunction + +function! s:syn_attr_jsx(synattr) + return a:synattr =~ "^jsx" +endfunction + +function! s:syn_xmlish(syns) + return s:syn_attr_jsx(get(a:syns, -1)) +endfunction + +function! s:syn_jsx_element(syns) + return get(a:syns, -1) =~ 'jsxElement' +endfunction + +function! s:syn_js_comment(syns) + return get(a:syns, -1) =~ 'Comment$' +endfunction + +function! s:syn_jsx_escapejs(syns) + return get(a:syns, -1) =~ '\(\(js\(Template\)\?\|javaScript\(Embed\)\?\|typescript\)Braces\|javascriptTemplateSB\|typescriptInterpolationDelimiter\)' && + \ (get(a:syns, -2) =~ 'jsxEscapeJs' || + \ get(a:syns, -3) =~ 'jsxEscapeJs') +endfunction + +function! s:syn_jsx_attrib(syns) + return len(filter(copy(a:syns), 'v:val =~ "jsxAttrib"')) +endfunction + +let s:start_tag = '<\s*\([-:_\.\$0-9A-Za-z]\+\|>\)' +" match `/end_tag>` and `//>` +let s:end_tag = '/\%(\s*[-:_\.\$0-9A-Za-z]*\s*\|/\)>' +let s:opfirst = '^' . get(g:,'javascript_opfirst', + \ '\C\%([<>=,.?^%|/&]\|\([-:+]\)\1\@!\|\*\+\|!=\|in\%(stanceof\)\=\>\)') + +function! jsx_pretty#indent#get(js_indent) + let lnum = v:lnum + let line = substitute(getline(lnum), '^\s*\|\s*$', '', 'g') + let current_syn = s:syn_sol(lnum) + let current_syn_eol = s:syn_eol(lnum) + let prev_syn_sol = s:syn_sol(lnum - 1) + let prev_syn_eol = s:syn_eol(lnum - 1) + let prev_line = s:prev_line(lnum) + let prev_ind = s:prev_indent(lnum) + + if s:syn_xmlish(current_syn) + + " { + " <div></div> + " ##} <-- + if s:syn_jsx_element(current_syn) && line =~ '}$' + let pair_line = searchpair('{', '', '}', 'b') + return indent(pair_line) + elseif line =~ '^-->$' + if prev_line =~ '^<!--' + return prev_ind + else + return prev_ind - s:sw() + endif + elseif prev_line =~ '-->$' + return prev_ind + " close tag </tag> or /> including </> + elseif prev_line =~ s:end_tag . '$' + if line =~ '^<\s*' . s:end_tag + return prev_ind - s:sw() + elseif s:syn_jsx_attrib(prev_syn_sol) + return prev_ind - s:sw() + else + return prev_ind + endif + elseif line =~ '^\(>\|/\s*>\)' + if prev_line =~ '^<' + return prev_ind + else + return prev_ind - s:sw() + endif + elseif prev_line =~ '^\(<\|>\)' && + \ (s:syn_xmlish(prev_syn_eol) || s:syn_js_comment(prev_syn_eol)) + if line =~ '^<\s*' . s:end_tag + return prev_ind + else + return prev_ind + s:sw() + endif + elseif line =~ '^<\s*' . s:end_tag + if !s:syn_xmlish(prev_syn_sol) + if s:syn_jsx_escapejs(prev_syn_eol) + \ || s:syn_jsx_escapejs(prev_syn_sol) + return prev_ind - s:sw() + else + return prev_ind + endif + else + return prev_ind - s:sw() + endif + elseif !s:syn_xmlish(prev_syn_eol) + if prev_line =~ '\(&&\|||\|=>\|[([{]\|`\)$' + " <div> + " { + " } + " </div> + if line =~ '^[)\]}]' + return prev_ind + else + return prev_ind + s:sw() + endif + else + return prev_ind + endif + elseif !s:syn_xmlish(prev_syn_sol) + if prev_line =~ '^\<\(return\|default\|await\|yield\)' + if line !~ '^/\s*>' || line !~ '^<\s*' . s:end_tag + return prev_ind + s:sw() + else + return prev_ind + endif + else + return prev_ind + endif + else + return prev_ind + endif + elseif s:syn_jsx_escapejs(current_syn) + if line =~ '^}' + let char = getline('.')[col('.') - 1] + " When pressing enter after the }, keep the indent + if char != '}' && search('}', 'b', lnum) + return indent(lnum) + else + let pair_line = searchpair('{', '', '}', 'bW') + return indent(pair_line) + endif + elseif line =~ '^{' || line =~ '^\${' + if s:syn_jsx_escapejs(prev_syn_eol) + \ || s:syn_jsx_attrib(prev_syn_sol) + return prev_ind + elseif s:syn_xmlish(prev_syn_eol) && (prev_line =~ s:end_tag || prev_line =~ '-->$') + return prev_ind + else + return prev_ind + s:sw() + endif + endif + elseif s:syn_jsx_escapejs(current_syn_eol) + let pair_line = searchpair('{', '', '}', 'bW') + return indent(pair_line) + elseif line =~ '^/[/*]' " js comment in jsx tag + if get(prev_syn_sol, -1) =~ 'Punct' + return prev_ind + s:sw() + elseif synIDattr(synID(lnum - 1, 1, 1), 'name') =~ 'jsxTag' + return prev_ind + else + return a:js_indent() + endif + else + let ind = a:js_indent() + + " If current syntax is not a jsx syntax group + if s:syn_xmlish(prev_syn_eol) && line !~ '^[)\]}]' + let sol = matchstr(line, s:opfirst) + if sol is '' + " Fix javascript continue indent + return ind - s:sw() + else + return ind + endif + endif + return ind + endif + +endfunction diff --git a/autoload/jsx_pretty/syntax.vim b/autoload/jsx_pretty/syntax.vim new file mode 100644 index 00000000..eac1f92a --- /dev/null +++ b/autoload/jsx_pretty/syntax.vim @@ -0,0 +1,218 @@ +if exists('g:polyglot_disabled') && index(g:polyglot_disabled, 'jsx') != -1 + finish +endif + +function! jsx_pretty#syntax#highlight() + + let s:highlight_close_tag = get(g:, 'vim_jsx_pretty_highlight_close_tag', 0) + + " <tag id="sample"> + " ~~~~~~~~~~~~~~~~~ + " and self close tag + " <tag id="sample" /> + " ~~~~~~~~~~~~~~~~~~~ + syntax region jsxTag + \ start=+<+ + \ matchgroup=jsxOpenPunct + \ end=+>+ + \ matchgroup=NONE + \ end=+\(/\_s*>\)\@=+ + \ contained + \ contains=jsxOpenTag,jsxEscapeJs,jsxAttrib,jsComment,@javascriptComments,javaScriptLineComment,javaScriptComment,typescriptLineComment,typescriptComment,jsxSpreadOperator + \ keepend + \ extend + + " <tag></tag> + " ~~~~~~~~~~~ + " and fragment + " <></> + " ~~~~~ + " and self close tag + " <tag /> + " ~~~~~~~ + syntax region jsxElement + \ start=+<\_s*\(>\|\${\|\z(\<[-:_\.\$0-9A-Za-z]\+\>\)\)+ + \ end=+/\_s*>+ + \ end=+<\_s*/\_s*\z1\_s*>+ + \ contains=jsxElement,jsxEscapeJs,jsxTag,jsxComment,jsxCloseString,jsxCloseTag,@Spell + \ keepend + \ extend + \ contained + \ fold + + " detect jsx region + syntax region jsxRegion + \ start=+\(\(\_[([,?:=+\-*/<>{}]\|&&\|||\|=>\|\<return\|\<default\|\<await\|\<yield\)\_s*\)\@<=<\_s*\(>\|\z(\(script\)\@!\<[_\$A-Za-z][-:_\.\$0-9A-Za-z]*\>\)\(\_s*\([-+*)\]}&|?]\|/\([/*]\|\_s*>\)\@!\)\)\@!\)+ + \ end=++ + \ contains=jsxElement + + " <tag key={this.props.key}> + " ~~~~~~~~~~~~~~~~ + syntax region jsxEscapeJs + \ start=+{+ + \ end=++ + \ extend + \ contained + \ contains=jsBlock,javascriptBlock,javaScriptBlockBuildIn,typescriptBlock + + " <tag key={this.props.key}> + " ~~~~ + " and fragment start tag + " <> + " ~~ + exe 'syntax region jsxOpenTag + \ matchgroup=jsxOpenPunct + \ start=+<+ + \ end=+>+ + \ matchgroup=NONE + \ end=+\>+ + \ contained + \ contains=jsxTagName + \ nextgroup=jsxAttrib + \ skipwhite + \ skipempty ' .(s:highlight_close_tag ? 'transparent' : '') + + " <foo.bar> + " ~ + syntax match jsxDot +\.+ contained display + + " <foo:bar> + " ~ + syntax match jsxNamespace +:+ contained display + + " <tag id="sample"> + " ~ + syntax match jsxEqual +=+ contained display nextgroup=jsxString,jsxEscapeJs,jsxRegion skipwhite + + " <tag /> + " ~~ + syntax match jsxCloseString +/\_s*>+ contained + + " </tag> + " ~~~~~~ + " and fragment close tag + " </> + " ~~~ + syntax region jsxCloseTag + \ matchgroup=jsxClosePunct + \ start=+<\_s*/+ + \ end=+>+ + \ contained + \ contains=jsxTagName + + " <tag key={this.props.key}> + " ~~~ + syntax match jsxAttrib + \ +\<[-A-Za-z_][-:_\$0-9A-Za-z]*\>+ + \ contained + \ nextgroup=jsxEqual + \ skipwhite + \ skipempty + \ contains=jsxAttribKeyword + \ display + + " <MyComponent ...> + " ~~~~~~~~~~~ + " NOT + " <someCamel ...> + " ~~~~~ + exe 'syntax match jsxComponentName + \ +\<[A-Z][\$0-9A-Za-z]\+\>+ + \ contained + \ display ' .(s:highlight_close_tag ? 'transparent' : '') + + " <tag key={this.props.key}> + " ~~~ + exe 'syntax match jsxTagName + \ +\<[-:_\.\$0-9A-Za-z]\+\>+ + \ contained + \ contains=jsxComponentName,jsxDot,jsxNamespace + \ nextgroup=jsxAttrib + \ skipempty + \ skipwhite + \ display ' .(s:highlight_close_tag ? 'transparent' : '') + + " <tag id="sample"> + " ~~~~~~~~ + " and + " <tag id='sample'> + " ~~~~~~~~ + syntax region jsxString start=+\z(["']\)+ skip=+\\\%(\z1\|$\)+ end=+\z1+ contained contains=@Spell display + + let s:tags = get(g:, 'vim_jsx_pretty_template_tags', ['html', 'raw']) + let s:enable_tagged_jsx = !empty(s:tags) + + " add support to JSX inside the tagged template string + " https://github.com/developit/htm + if s:enable_tagged_jsx + exe 'syntax region jsxTaggedRegion + \ start=+\%('. join(s:tags, '\|') .'\)\@<=`+ms=s+1 + \ end=+`+me=e-1 + \ extend + \ contained + \ containedin=jsTemplateString,javascriptTemplate,javaScriptStringT,typescriptStringB + \ contains=jsxElement' + + syntax region jsxEscapeJs + \ start=+\${+ + \ end=++ + \ extend + \ contained + \ contains=jsTemplateExpression,javascriptTemplateSubstitution,javaScriptEmbed,typescriptInterpolation + + syntax region jsxOpenTag + \ matchgroup=jsxOpenPunct + \ start=+<\%(\${\)\@=+ + \ matchgroup=NONE + \ end=++ + \ contained + \ contains=jsxEscapeJs + \ nextgroup=jsxAttrib,jsxSpreadOperator + \ skipwhite + \ skipempty + + syntax keyword jsxAttribKeyword class contained display + + syntax match jsxSpreadOperator +\.\.\.+ contained display nextgroup=jsxEscapeJs skipwhite + + syntax match jsxCloseTag +<//>+ display + + syntax match jsxComment +<!--\_.\{-}-->+ display + endif + + " Highlight the tag name + highlight def link jsxTag Function + highlight def link jsxTagName Identifier + highlight def link jsxComponentName Function + + highlight def link jsxAttrib Type + highlight def link jsxAttribKeyword jsxAttrib + highlight def link jsxEqual Operator + highlight def link jsxString String + highlight def link jsxDot Operator + highlight def link jsxNamespace Operator + + " Highlight the jsxCloseString (i.e. />), jsxPunct (i.e. <,>) and jsxCloseTag (i.e. <//>) + highlight def link jsxCloseString Comment + highlight def link jsxPunct jsxCloseString + highlight def link jsxOpenPunct jsxPunct + highlight def link jsxClosePunct jsxPunct + highlight def link jsxCloseTag jsxCloseString + + highlight def link jsxComment Comment + highlight def link jsxSpreadOperator Operator + + if s:highlight_close_tag + highlight! def link jsxOpenPunct jsxTag + highlight! def link jsxCloseString Identifier + endif + + let s:vim_jsx_pretty_colorful_config = get(g:, 'vim_jsx_pretty_colorful_config', 0) + + if s:vim_jsx_pretty_colorful_config == 1 + highlight def link jsObjectKey Label + highlight def link jsArrowFuncArgs Type + highlight def link jsFuncArgs Type + endif + +endfunction |