diff --git a/README.md b/README.md index d23e6f6..5bdf4d2 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,18 @@ Syntax highlighting and indenting for JSX. JSX is a JavaScript syntax transformer which translates inline XML document fragments into JavaScript objects. It was developed by Facebook alongside [React][1]. -This bundle requires pangloss's [vim-javascript][2] syntax highlighting. +vim-jsx is _not_ a JavaScript syntax package, so in order to use it, you will +also need to choose a base JS highlighter. [pangloss/vim-javascript][2] is the +recommended package---it is vim-jsx's "official" dependency, and the only +package against which it is regularly tested. However, vim-jsx makes a best +effort to support other JavaScript syntax packages, including: +- pangloss/vim-javascript +- jelera/vim-javascript-syntax +- othree/yajs + +Notably, the system vim JavaScript syntax is _not_ supported, due to its +over-simplicity. However, the system XML syntax package is an implicit +dependency. Vim support for inline XML in JS is remarkably similar to the same for PHP, which you can find [here][3]. @@ -13,26 +24,25 @@ which you can find [here][3]. Troubleshooting --------------- -If you're experiencing weird highlighting or indenting throughout your JSX -code, please file a GitHub issue which includes the following: +If you're experiencing incorrect highlighting or indenting in your JSX code, +please file a GitHub issue which includes the following: -- A brief affirmation that you've read the README and installed the appropriate - dependencies. +- A brief affirmation that you've read the README and have installed one of the + supported dependencies (and the name of the one you're using). -- A minimal ~/.vimrc which repros the issue you're having, as well as a - screenshot or gif of the issue (a paste is insufficient, since it doesn't - show me the specific highlighting or indenting problem). To obtain a minimal - ~/.vimrc, simply bisect your ~/.vimrc by adding `finish` at various points in - the file. (You can likewise bisect your included plugins by selectively - including only half of them, then a quarter, etc.). +- A minimal ~/.vimrc which repros the issue you're having, as well as both a + paste and a screenshot of the issue (a paste alone is insufficient, since it + doesn't illustrate the specific highlighting or indenting problem). To + obtain a minimal ~/.vimrc, simply bisect your ~/.vimrc by adding `finish` at + various points in the file. (You can likewise bisect your included plugins + by selectively including only half of them, then a quarter, etc.). Most of the issues filed result from failures to install vim-javascript or conflicts with existing JS syntax or indent files---so failing to indicate that -you've ruled those issues out may result in your issue being closed with no -comment. +you've ruled those issues out may result in your issue being closed with +minimal comment. -(Please feel free to disregard all this for feature requests and more -corner-case bugs.) +(Please feel free to disregard all this for feature requests.) Usage ----- @@ -53,8 +63,28 @@ let g:jsx_pragma_required = 1 to your .vimrc or somewhere in your include path. -Please note that this package does not support syntax folding, and has not been -tested with either JavaScript or XML folding enabled. +Frequently Asked Questions +-------------------------- + +- _How come syntax highlighting doesn't work at all?_ + +This is the only question I'll answer with another question---Which do you +think is more likely: (a) this package fails completely and utterly in serving +its most fundamental purpose, or (b) user error? + +- _Why are my end tags colored differently than my start tags?_ + +vim-jsx is basically the glue that holds JavaScript and XML syntax packages +together in blissful harmony. This means that any XML syntax defaults carry +over to the XML portions of vim, and it's common for many colorschemes to +highlight start and end tags differently due to the system XML syntax defaults. + +- _Syntax highlighting seems to work, but breaks highlighting and indenting + further down in the file. What's wrong?_ + +This often results from trying to enable XML folding in one's `~/.vimrc` (i.e., +via `let g:xml_syntax_folding = 1`). vim-jsx does not support syntax folding, +and is not tested with either JavaScript or XML folding enabled. Installation ------------ @@ -63,8 +93,7 @@ Installation The recommended installation method is via [Pathogen][4]. Then simply execute - cd ~/.vim/bundle - git clone https://github.com/mxw/vim-jsx.git + git clone https://github.com/mxw/vim-jsx.git ~/.vim/bundle/vim-jsx (You can install [vim-javascript][2] in an analogous manner.) @@ -105,4 +134,4 @@ or indent files for Javascript, you'll probably want to do something like [2]: https://github.com/pangloss/vim-javascript "pangloss: vim-javascript" [3]: https://github.com/mxw/vim-xhp "mxw: vim-xhp" [4]: https://github.com/tpope/vim-pathogen "tpope: vim-pathogen" -[5]: https://github.com/VundleVim/Vundle "VundleVim: Vundle" +[5]: https://github.com/VundleVim/Vundle.vim "VundleVim: Vundle.vim" diff --git a/after/ftplugin/jsx.vim b/after/ftplugin/jsx.vim index ee64209..6ff94d9 100644 --- a/after/ftplugin/jsx.vim +++ b/after/ftplugin/jsx.vim @@ -3,7 +3,6 @@ " " Language: JSX (JavaScript) " Maintainer: Max Wang -" Depends: pangloss/vim-javascript " """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" @@ -11,7 +10,7 @@ if exists("loaded_matchit") let b:match_ignorecase = 0 let b:match_words = '(:),\[:\],{:},<:>,' . - \ '<\@<=\([^/][^ \t>]*\)[^>]*\%(>\|$\):<\@<=/\1>' + \ '<\@<=\([^/][^ \t>]*\)[^>]*\%(/\@\|$\):<\@<=/\1>' endif setlocal suffixesadd+=.jsx diff --git a/after/indent/jsx.vim b/after/indent/jsx.vim index d9b86d6..9c1a1ac 100644 --- a/after/indent/jsx.vim +++ b/after/indent/jsx.vim @@ -3,10 +3,12 @@ " " Language: JSX (JavaScript) " Maintainer: Max Wang -" Depends: pangloss/vim-javascript " """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +" Save the current JavaScript indentexpr. +let b:jsx_js_indentexpr = &indentexpr + " Prologue; load in XML indentation. if exists('b:did_indent') let s:did_indent=b:did_indent @@ -49,19 +51,31 @@ fu! SynXMLish(syns) return SynAttrXMLish(get(a:syns, -1)) endfu -" Check if a synstack has any XMLish attribute. -fu! SynXMLishAny(syns) - for synattr in a:syns - if SynAttrXMLish(synattr) - return 1 - endif - endfor - return 0 -endfu - " Check if a synstack denotes the end of a JSX block. fu! SynJSXBlockEnd(syns) - return get(a:syns, -1) == 'jsBraces' && SynAttrXMLish(get(a:syns, -2)) + return get(a:syns, -1) =~ '\%(js\|javascript\)Braces' && + \ SynAttrXMLish(get(a:syns, -2)) +endfu + +" Determine how many jsxRegions deep a synstack is. +fu! SynJSXDepth(syns) + return len(filter(copy(a:syns), 'v:val ==# "jsxRegion"')) +endfu + +" Check whether `cursyn' continues the same jsxRegion as `prevsyn'. +fu! SynJSXContinues(cursyn, prevsyn) + let curdepth = SynJSXDepth(a:cursyn) + let prevdepth = SynJSXDepth(a:prevsyn) + + " In most places, we expect the nesting depths to be the same between any + " two consecutive positions within a jsxRegion (e.g., between a parent and + " child node, between two JSX attributes, etc.). The exception is between + " sibling nodes, where after a completed element (with depth N), we return + " to the parent's nesting (depth N - 1). This case is easily detected, + " since it is the only time when the top syntax element in the synstack is + " jsxRegion---specifically, the jsxRegion corresponding to the parent. + return prevdepth == curdepth || + \ (prevdepth == curdepth + 1 && get(a:cursyn, -1) ==# 'jsxRegion') endfu " Cleverly mix JS and XML indentation. @@ -69,9 +83,12 @@ fu! GetJsxIndent() let cursyn = SynSOL(v:lnum) let prevsyn = SynEOL(v:lnum - 1) - " Use XML indenting if the syntax at the end of the previous line was either - " JSX or was the closing brace of a jsBlock whose parent syntax was JSX. - if (SynXMLish(prevsyn) || SynJSXBlockEnd(prevsyn)) && SynXMLishAny(cursyn) + " Use XML indenting iff: + " - the syntax at the end of the previous line was either JSX or was the + " closing brace of a jsBlock whose parent syntax was JSX; and + " - the current line continues the same jsxRegion as the previous line. + if (SynXMLish(prevsyn) || SynJSXBlockEnd(prevsyn)) && + \ SynJSXContinues(cursyn, prevsyn) let ind = XmlIndentGet(v:lnum, 0) " Align '/>' and '>' with '<' for multiline tags. @@ -84,7 +101,13 @@ fu! GetJsxIndent() let ind = ind + &sw endif else - let ind = GetJavascriptIndent() + if len(b:jsx_js_indentexpr) + " Invoke the base JS package's custom indenter. (For vim-javascript, + " e.g., this will be GetJavascriptIndent().) + let ind = eval(b:jsx_js_indentexpr) + else + let ind = cindent(v:lnum) + endif endif return ind diff --git a/after/syntax/jsx.vim b/after/syntax/jsx.vim index 8b209c0..21c68dc 100644 --- a/after/syntax/jsx.vim +++ b/after/syntax/jsx.vim @@ -46,8 +46,8 @@ syn region jsxChild contained start=+{+ end=++ contains=jsBlock,javascriptBlock " preceding it, to avoid conflicts with, respectively, the left shift operator " and generic Flow type annotations (http://flowtype.org/). syn region jsxRegion - \ contains=@XMLSyntax,jsxRegion,jsxChild,jsBlock,javascriptBlock - \ start=+\%(<\|\w\)\@[:,]\@!\)\([^>]*>(\)\@!+ \ skip=++ \ end=++ \ end=+/>+ diff --git a/ftdetect/javascript.vim b/ftdetect/javascript.vim index 84fb5d6..b959bd2 100644 --- a/ftdetect/javascript.vim +++ b/ftdetect/javascript.vim @@ -16,15 +16,16 @@ if !exists('g:jsx_pragma_required') let g:jsx_pragma_required = 0 endif -if g:jsx_pragma_required - " Look for the @jsx pragma. It must be included in a docblock comment before - " anything else in the file (except whitespace). - let s:jsx_pragma_pattern = '\%^\_s*\/\*\*\%(\_.\%(\*\/\)\@!\)*@jsx\_.\{-}\*\/' - let b:jsx_pragma_found = search(s:jsx_pragma_pattern, 'npw') -endif +let s:jsx_pragma_pattern = '\%^\_s*\/\*\*\%(\_.\%(\*\/\)\@!\)*@jsx\_.\{-}\*\/' " Whether to set the JSX filetype on *.js files. fu! EnableJSX() + if g:jsx_pragma_required && !exists('b:jsx_ext_found') + " Look for the @jsx pragma. It must be included in a docblock comment + " before anything else in the file (except whitespace). + let b:jsx_pragma_found = search(s:jsx_pragma_pattern, 'npw') + endif + if g:jsx_pragma_required && !b:jsx_pragma_found | return 0 | endif if g:jsx_ext_required && !exists('b:jsx_ext_found') | return 0 | endif return 1