diff options
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 | 
