[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] feature/jsx 2b4cc70 17/19: Indent expressions in JSXAttri
From: |
Marcin Borkowski |
Subject: |
[Emacs-diffs] feature/jsx 2b4cc70 17/19: Indent expressions in JSXAttributes relative to the attribute’s name |
Date: |
Wed, 27 Mar 2019 05:35:02 -0400 (EDT) |
branch: feature/jsx
commit 2b4cc7028ebb87e733c6036eba149f034064c1fd
Author: Jackson Ray Hamilton <address@hidden>
Commit: Marcin Borkowski <address@hidden>
Indent expressions in JSXAttributes relative to the attribute’s name
* lisp/progmodes/js.el (js-jsx--syntax-propertize-tag): Refer to the
beginning of a JSXExpressionContainer’s associated JSXAttribute (so
line numbers can be calculated later).
(js-jsx--text-properties): Also clear the new text property
js-jsx-expr-attribute.
(js-jsx--indenting): Remove.
(js-jsx--indent-col, js-jsx--indent-attribute-line): New variables.
(js-jsx--indentation): Instead of alternating between two separate
column calculations, neither necessarily correct, bind the JSX column
such that the second call to js--proper-indentation can use it as a
base column.
(js--proper-indentation): Use JSX as the base column for some indents
while indenting JSX.
* test/manual/indent/jsx.jsx: Add more tests for expression indents.
---
lisp/progmodes/js.el | 97 +++++++++++++++++++++++++++-------------------
test/manual/indent/jsx.jsx | 25 ++++++++++++
2 files changed, 83 insertions(+), 39 deletions(-)
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index f22c68c..679633f 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -2081,7 +2081,7 @@ been propertized."
Disambiguate JSX from inequality operators and arrow functions by
testing for syntax only valid as JSX."
(let ((tag-beg (1- (point))) tag-end (type 'open)
- name-beg name-match-data unambiguous
+ name-beg name-match-data expr-attribute-beg unambiguous
forward-sexp-function) ; Use Lisp version.
(catch 'stop
(while (and (< (point) end)
@@ -2096,8 +2096,16 @@ testing for syntax only valid as JSX."
;; JSXExpressionContainer as a JSXAttribute value
;; (“<Foo bar={…}”). Check this early in case continuing a
;; JSXAttribute parse.
- ((and name-beg (= (char-after) ?{))
+ ((or (and name-beg (= (char-after) ?{))
+ (setq expr-attribute-beg nil))
(setq unambiguous t) ; JSXExpressionContainer post tag name ⇒ JSX
+ (when expr-attribute-beg
+ ;; Remember that this JSXExpressionContainer is part of a
+ ;; JSXAttribute, as that can affect its expression’s
+ ;; indentation.
+ (put-text-property
+ (point) (1+ (point)) 'js-jsx-expr-attribute expr-attribute-beg)
+ (setq expr-attribute-beg nil))
(let (expr-end)
(condition-case nil
(save-excursion
@@ -2146,10 +2154,14 @@ testing for syntax only valid as JSX."
;; Skip over strings (if possible). Any
;; JSXExpressionContainer here will be parsed in the
;; next iteration of the loop.
- (when (memq (char-after) '(?\" ?\' ?\`))
- (condition-case nil
- (forward-sexp)
- (scan-error (throw 'stop nil))))))
+ (if (memq (char-after) '(?\" ?\' ?\`))
+ (condition-case nil
+ (forward-sexp)
+ (scan-error (throw 'stop nil)))
+ ;; Save JSXAttribute’s beginning in case we find a
+ ;; JSXExpressionContainer as the JSXAttribute’s value which
+ ;; we should associate with the JSXAttribute.
+ (setq expr-attribute-beg (match-beginning 0)))))
;; There is nothing more to check; this either isn’t JSX, or
;; the tag is incomplete.
(t (throw 'stop nil)))))
@@ -2174,7 +2186,7 @@ testing for syntax only valid as JSX."
(list
'js-jsx-tag-beg nil 'js-jsx-tag-end nil
'js-jsx-tag-name nil 'js-jsx-attribute-name nil
- 'js-jsx-text nil 'js-jsx-expr nil)
+ 'js-jsx-text nil 'js-jsx-expr nil 'js-jsx-expr-attribute nil)
"Plist of text properties added by `js-syntax-propertize'.")
(defun js-syntax-propertize (start end)
@@ -2563,8 +2575,11 @@ current line is the \"=>\" token (of an arrow function)."
(list 'tag (nth 0 enclosing-tag-pos) (nth 1 enclosing-tag-pos)))
(list 'text (nth 0 enclosing-tag-pos) (nth 2 enclosing-tag-pos))))))
-(defvar js-jsx--indenting nil
- "Flag to prevent infinite recursion while indenting JSX.")
+(defvar js-jsx--indent-col nil
+ "Baseline column for JS indentation within JSX.")
+
+(defvar js-jsx--indent-attribute-line nil
+ "Line relative to which indentation uses JSX as a baseline.")
(defun js-jsx--indentation (parse-status)
"Helper function for `js--proper-indentation'.
@@ -2642,25 +2657,22 @@ return nil."
0)))
)))
- ;; When indenting a JSXExpressionContainer expression, use JSX
- ;; indentation as a minimum, and use regular JS indentation if
- ;; it’s deeper.
+ ;; To indent a JSXExpressionContainer’s expression, calculate
+ ;; the JS indentation, possibly using JSX indentation as the
+ ;; base column.
(if expr-p
- (max (+ col
- ;; An expression in a JSXExpressionContainer in a
- ;; JSXAttribute should be indented more, except on
- ;; the ending line of the JSXExpressionContainer.
- (if (and (eq (nth 0 context) 'tag)
- (< current-line
- (save-excursion
- (js-jsx--goto-outermost-enclosing-curly
- (nth 1 context))
- (forward-sexp)
- (line-number-at-pos))))
- js-indent-level
- 0))
- (let ((js-jsx--indenting t)) ; Prevent recursion.
- (js--proper-indentation parse-status)))
+ (let* ((js-jsx--indent-col col)
+ (expr-attribute-pos
+ (save-excursion
+ (goto-char curly-pos) ; Skip first curly.
+ ;; Skip any remaining enclosing curlies up until
+ ;; the contextual JSXElement’s beginning position.
+ (js-jsx--goto-outermost-enclosing-curly (nth 1 context))
+ (get-text-property (point) 'js-jsx-expr-attribute)))
+ (js-jsx--indent-attribute-line
+ (when expr-attribute-pos
+ (line-number-at-pos expr-attribute-pos))))
+ (js--proper-indentation parse-status))
col))))
(defun js--proper-indentation (parse-status)
@@ -2670,7 +2682,7 @@ return nil."
(cond ((nth 4 parse-status) ; inside comment
(js--get-c-offset 'c (nth 8 parse-status)))
((nth 3 parse-status) 0) ; inside string
- ((when (and js-jsx-syntax (not js-jsx--indenting))
+ ((when (and js-jsx-syntax (not js-jsx--indent-col))
(save-excursion (js-jsx--indentation parse-status))))
((eq (char-after) ?#) 0)
((save-excursion (js--beginning-of-macro)) 4)
@@ -2708,17 +2720,24 @@ return nil."
(and switch-keyword-p
in-switch-p)))
(indent
- (cond (same-indent-p
- (current-column))
- (continued-expr-p
- (+ (current-column) (* 2 js-indent-level)
- js-expr-indent-offset))
- (t
- (+ (current-column) js-indent-level
- (pcase (char-after (nth 1 parse-status))
- (?\( js-paren-indent-offset)
- (?\[ js-square-indent-offset)
- (?\{ js-curly-indent-offset)))))))
+ (+
+ (cond
+ ((and js-jsx--indent-attribute-line
+ (eq js-jsx--indent-attribute-line
+ (line-number-at-pos)))
+ js-jsx--indent-col)
+ (t
+ (current-column)))
+ (cond (same-indent-p 0)
+ (continued-expr-p
+ (+ (* 2 js-indent-level)
+ js-expr-indent-offset))
+ (t
+ (+ js-indent-level
+ (pcase (char-after (nth 1 parse-status))
+ (?\( js-paren-indent-offset)
+ (?\[ js-square-indent-offset)
+ (?\{ js-curly-indent-offset))))))))
(if in-switch-p
(+ indent js-switch-indent-offset)
indent)))
diff --git a/test/manual/indent/jsx.jsx b/test/manual/indent/jsx.jsx
index c2351a8..5004d57 100644
--- a/test/manual/indent/jsx.jsx
+++ b/test/manual/indent/jsx.jsx
@@ -68,6 +68,31 @@ return (
</div>
);
+return (
+ <div attribute={{
+ a: 1, // Indent relative to “attribute” column.
+ b: 2
+ } && { // Dedent to “attribute” column.
+ a: 1,
+ b: 2
+ }} /> // Also dedent.
+);
+
+return (
+ <div attribute=
+ { // Indent properly on another line, too.
+ {
+ a: 1,
+ b: 2,
+ } && (
+ // Indent other forms, too.
+ a ? b :
+ c ? d :
+ e
+ )
+ } />
+)
+
// Indent void expressions (no need for contextual parens / commas)
// (https://github.com/mooz/js2-mode/issues/140#issuecomment-166250016).
<div className="class-name">
- [Emacs-diffs] feature/jsx acab35c 19/19: Add tests for miscellaneous JSX parsing feats, (continued)
- [Emacs-diffs] feature/jsx acab35c 19/19: Add tests for miscellaneous JSX parsing feats, Marcin Borkowski, 2019/03/27
- [Emacs-diffs] feature/jsx e196207 15/19: Indent broken arrow function bodies as an N+1th arg, Marcin Borkowski, 2019/03/27
- [Emacs-diffs] feature/jsx 071c134 06/19: Add basic JSX font-locking, Marcin Borkowski, 2019/03/27
- [Emacs-diffs] feature/jsx ec144e9 12/19: Automatically detect JSX in JavaScript files, Marcin Borkowski, 2019/03/27
- [Emacs-diffs] feature/jsx c66bfa6 10/19: Indent JSX as parsed in a JS context, Marcin Borkowski, 2019/03/27
- [Emacs-diffs] feature/jsx f7ac5e4 11/19: Finish replacing SGML-based JSX detection with js-mode’s parsing, Marcin Borkowski, 2019/03/27
- [Emacs-diffs] feature/jsx 79118f8 16/19: Fix counting of nested self-closing JSXOpeningElements, Marcin Borkowski, 2019/03/27
- [Emacs-diffs] feature/jsx 4337acd 14/19: Rename tests to use the “.jsx” file extension, Marcin Borkowski, 2019/03/27
- [Emacs-diffs] feature/jsx 66433fd 13/19: Improve JSX syntax propertization, Marcin Borkowski, 2019/03/27
- [Emacs-diffs] feature/jsx ae0ee9b 18/19: Split JSX indentation calculation into several functions, Marcin Borkowski, 2019/03/27
- [Emacs-diffs] feature/jsx 2b4cc70 17/19: Indent expressions in JSXAttributes relative to the attribute’s name,
Marcin Borkowski <=
- [Emacs-diffs] feature/jsx d5dae48 02/19: Refactor JSX indentation code to improve enclosing JSX discovery, Marcin Borkowski, 2019/03/27
- [Emacs-diffs] feature/jsx 7166bd2 08/19: Propertize and font-lock JSXText and JSXExpressionContainers, Marcin Borkowski, 2019/03/27
- [Emacs-diffs] feature/jsx 85fccaf 04/19: js-syntax-propertize: Disambiguate JS from JSX, fixing some indents, Marcin Borkowski, 2019/03/27