Refactor JSX indentation code to improve enclosing JSX discovery
Fix a number of bugs reported for JSX indentation (caused by poor JSX
detection):
- https://github.com/mooz/js2-mode/issues/140#issuecomment-
166250016
- https://github.com/mooz/js2-mode/issues/490
- Bug#24896 / https://github.com/mooz/js2-mode/issues/389 (with
respect to comments)
- Bug#26001 /
https://github.com/mooz/js2-mode/issues/389#issuecomment-
271869380
- https://github.com/mooz/js2-mode/issues/411 / Bug#27000 /
https://github.com/mooz/js2-mode/issues/451
Potentially manifest some new bugs (due to false positives with ‘<’
and ‘>’ and SGML detection). Slow down indentation a fair bit.
* list/progmodes/js.el (js-jsx-syntax, js--jsx-start-tag-re)
(js--looking-at-jsx-start-tag-p, js--looking-back-at-jsx-end-tag-p):
New variables and functions.
(js--jsx-find-before-tag, js--jsx-after-tag-re): Deleted.
(js--looking-at-operator-p): Don’t mistake a JSXOpeningElement for the
‘<’ operator.
(js--continued-expression-p): Don’t mistake a JSXClosingElement as a
fragment of a continued expression including the ‘>’ operator.
(js--as-sgml): Simplify. Probably needn’t bind forward-sexp-function
to nil (sgml-mode already does) and probably shouldn’t bind
parse-sexp-lookup-properties to nil either (see Bug#24896).
(js--outermost-enclosing-jsx-tag-pos): Find enclosing JSX more
accurately than js--jsx-find-before-tag. Use sgml-mode’s parsing
logic, rather than unreliable heuristics like paren-wrapping. This
implementation is much slower; the previous implementation was fast,
but at the expense of accuracy. To make up for all the grief we’ve
caused users, we will prefer accuracy over speed from now on. That
said, this can still probably be optimized a lot.
(js--jsx-indented-element-p): Rename to js--jsx-indentation, since it
doesn’t just return a boolean.
(js--jsx-indentation): Refactor js--jsx-indented-element-p to simplify
the implementation as the improved accuracy of other code allows (and
to repent for some awful stylistic choices I made earlier).
(js--expression-in-sgml-indent-line): Rename to
js--indent-line-in-jsx-expression, since it’s a private function and
we can give it a name that reads more like English.
(js--indent-line-in-jsx-expression): Restructure point adjustment
logic more like js-indent-line.
(js--indent-n+1th-jsx-line): New function to complement
js--indent-line-in-jsx-expression.
(js-jsx-indent-line): Refactor. Don’t bind js--continued-expression-p
to ignore any more; instead, rely on the improved accuracy of
js--continued-expression-p.
(js-jsx-mode): Set js-jsx-syntax to t. For now, this will be the flag
we use to determine whether ‘JSX is enabled.’ (Maybe later, we will
refactor the code to use this variable instead of requiring
js-jsx-mode to be enabled, thus rendering the mode obsolete.)