]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix counting of nested self-closing JSXOpeningElements
authorJackson Ray Hamilton <jackson@jacksonrayhamilton.com>
Tue, 26 Mar 2019 03:39:48 +0000 (20:39 -0700)
committerJackson Ray Hamilton <jackson@jacksonrayhamilton.com>
Tue, 9 Apr 2019 05:48:23 +0000 (22:48 -0700)
* lisp/progmodes/js.el (js-jsx--matching-close-tag-pos): Fix bug where
self-closing JSXOpeningElements might be missed if one was nested
within another.

* test/manual/indent/jsx-self-closing.jsx: Add test for bug concerning
self-closing JSXOpeningElement counting.

lisp/progmodes/js.el
test/manual/indent/jsx-self-closing.jsx [new file with mode: 0644]

index f8dd72c22bc470cfc9299a00a8467c994302c716..f22c68cff95e89d0da3ea18a3d686a1367af2bb7 100644 (file)
@@ -1934,40 +1934,29 @@ Assuming a JSXOpeningElement or a JSXOpeningFragment is
 immediately before point, find a matching JSXClosingElement or
 JSXClosingFragment, skipping over any nested JSXElements to find
 the match.  Return nil if a match can’t be found."
-  (let ((tag-stack 1) self-closing-pos type)
+  (let ((tag-stack 1) type tag-pos last-pos pos)
     (catch 'stop
       (while (re-search-forward js-jsx--tag-re nil t)
-        (setq type (js-jsx--matched-tag-type))
-        ;; Balance the total of self-closing tags that we subtract
-        ;; from the stack, ignoring those tags which are never added
-        ;; to the stack (see below).
-        (unless (eq type 'self-closing)
-          (when (and self-closing-pos (> (point) self-closing-pos))
+        (setq type (js-jsx--matched-tag-type)
+              tag-pos (match-beginning 0))
+        ;; Clear the stack of any JSXOpeningElements which turned out
+        ;; to be self-closing.
+        (when last-pos
+          (setq pos (point))
+          (goto-char last-pos)
+          (while (re-search-forward js-jsx--self-closing-re pos 'move)
             (setq tag-stack (1- tag-stack))))
         (if (eq type 'close)
             (progn
               (setq tag-stack (1- tag-stack))
               (when (= tag-stack 0)
-                (throw 'stop (match-beginning 0))))
-          ;; Tags that we know are self-closing aren’t added to the
-          ;; stack at all, because we only close the ones that we have
-          ;; anticipated after moving past those anticipated tags’
-          ;; ends, and if a self-closing tag is the first tag we
-          ;; encounter in this loop, then it will never be anticipated
-          ;; (due to an optimization where we sometimes can avoid
-          ;; looking for self-closing tags).
+                (throw 'stop tag-pos)))
+          ;; JSXOpeningElements that we know are self-closing aren’t
+          ;; added to the stack at all (since re-search-forward moves
+          ;; point after their self-closing syntax).
           (unless (eq type 'self-closing)
             (setq tag-stack (1+ tag-stack))))
-        ;; Don’t needlessly recalculate.
-        (unless (and self-closing-pos (<= (point) self-closing-pos))
-          (setq self-closing-pos nil) ; Reset if recalculating.
-          (save-excursion
-            ;; Anticipate a self-closing tag that we should make sure
-            ;; to subtract from the tag stack once we move past its
-            ;; end; we might might miss the end otherwise, due to the
-            ;; regexp-matching method we use to detect tags.
-            (when (re-search-forward js-jsx--self-closing-re nil t)
-              (setq self-closing-pos (match-beginning 0)))))))))
+        (setq last-pos (point))))))
 
 (defun js-jsx--enclosing-curly-pos ()
   "Return position of enclosing “{” in a “{/}” pair about point."
diff --git a/test/manual/indent/jsx-self-closing.jsx b/test/manual/indent/jsx-self-closing.jsx
new file mode 100644 (file)
index 0000000..f8ea7a1
--- /dev/null
@@ -0,0 +1,13 @@
+// Local Variables:
+// indent-tabs-mode: nil
+// js-indent-level: 2
+// End:
+
+// The following test goes below any comments to avoid including
+// misindented comments among the erroring lines.
+
+// Properly parse/indent code with a self-closing tag inside the
+// attribute of another self-closing tag.
+<div>
+  <div attr={() => <div attr="" />} />
+</div>