diff options
| author | Jackson Ray Hamilton | 2019-03-25 20:39:48 -0700 |
|---|---|---|
| committer | Jackson Ray Hamilton | 2019-04-08 22:48:23 -0700 |
| commit | 16669d7c5d5a0dfadf672f8359e431ef81044a23 (patch) | |
| tree | 55d370ebbabd90345a34f081772a5a1ef81e7021 | |
| parent | 84b1cfbc2d6b9236913a18ed192798fd530911db (diff) | |
| download | emacs-16669d7c5d5a0dfadf672f8359e431ef81044a23.tar.gz emacs-16669d7c5d5a0dfadf672f8359e431ef81044a23.zip | |
Fix counting of nested self-closing JSXOpeningElements
* 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.
| -rw-r--r-- | lisp/progmodes/js.el | 39 | ||||
| -rw-r--r-- | test/manual/indent/jsx-self-closing.jsx | 13 |
2 files changed, 27 insertions, 25 deletions
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el index f8dd72c22bc..f22c68cff95 100644 --- a/lisp/progmodes/js.el +++ b/lisp/progmodes/js.el | |||
| @@ -1934,40 +1934,29 @@ Assuming a JSXOpeningElement or a JSXOpeningFragment is | |||
| 1934 | immediately before point, find a matching JSXClosingElement or | 1934 | immediately before point, find a matching JSXClosingElement or |
| 1935 | JSXClosingFragment, skipping over any nested JSXElements to find | 1935 | JSXClosingFragment, skipping over any nested JSXElements to find |
| 1936 | the match. Return nil if a match can’t be found." | 1936 | the match. Return nil if a match can’t be found." |
| 1937 | (let ((tag-stack 1) self-closing-pos type) | 1937 | (let ((tag-stack 1) type tag-pos last-pos pos) |
| 1938 | (catch 'stop | 1938 | (catch 'stop |
| 1939 | (while (re-search-forward js-jsx--tag-re nil t) | 1939 | (while (re-search-forward js-jsx--tag-re nil t) |
| 1940 | (setq type (js-jsx--matched-tag-type)) | 1940 | (setq type (js-jsx--matched-tag-type) |
| 1941 | ;; Balance the total of self-closing tags that we subtract | 1941 | tag-pos (match-beginning 0)) |
| 1942 | ;; from the stack, ignoring those tags which are never added | 1942 | ;; Clear the stack of any JSXOpeningElements which turned out |
| 1943 | ;; to the stack (see below). | 1943 | ;; to be self-closing. |
| 1944 | (unless (eq type 'self-closing) | 1944 | (when last-pos |
| 1945 | (when (and self-closing-pos (> (point) self-closing-pos)) | 1945 | (setq pos (point)) |
| 1946 | (goto-char last-pos) | ||
| 1947 | (while (re-search-forward js-jsx--self-closing-re pos 'move) | ||
| 1946 | (setq tag-stack (1- tag-stack)))) | 1948 | (setq tag-stack (1- tag-stack)))) |
| 1947 | (if (eq type 'close) | 1949 | (if (eq type 'close) |
| 1948 | (progn | 1950 | (progn |
| 1949 | (setq tag-stack (1- tag-stack)) | 1951 | (setq tag-stack (1- tag-stack)) |
| 1950 | (when (= tag-stack 0) | 1952 | (when (= tag-stack 0) |
| 1951 | (throw 'stop (match-beginning 0)))) | 1953 | (throw 'stop tag-pos))) |
| 1952 | ;; Tags that we know are self-closing aren’t added to the | 1954 | ;; JSXOpeningElements that we know are self-closing aren’t |
| 1953 | ;; stack at all, because we only close the ones that we have | 1955 | ;; added to the stack at all (since re-search-forward moves |
| 1954 | ;; anticipated after moving past those anticipated tags’ | 1956 | ;; point after their self-closing syntax). |
| 1955 | ;; ends, and if a self-closing tag is the first tag we | ||
| 1956 | ;; encounter in this loop, then it will never be anticipated | ||
| 1957 | ;; (due to an optimization where we sometimes can avoid | ||
| 1958 | ;; looking for self-closing tags). | ||
| 1959 | (unless (eq type 'self-closing) | 1957 | (unless (eq type 'self-closing) |
| 1960 | (setq tag-stack (1+ tag-stack)))) | 1958 | (setq tag-stack (1+ tag-stack)))) |
| 1961 | ;; Don’t needlessly recalculate. | 1959 | (setq last-pos (point)))))) |
| 1962 | (unless (and self-closing-pos (<= (point) self-closing-pos)) | ||
| 1963 | (setq self-closing-pos nil) ; Reset if recalculating. | ||
| 1964 | (save-excursion | ||
| 1965 | ;; Anticipate a self-closing tag that we should make sure | ||
| 1966 | ;; to subtract from the tag stack once we move past its | ||
| 1967 | ;; end; we might might miss the end otherwise, due to the | ||
| 1968 | ;; regexp-matching method we use to detect tags. | ||
| 1969 | (when (re-search-forward js-jsx--self-closing-re nil t) | ||
| 1970 | (setq self-closing-pos (match-beginning 0))))))))) | ||
| 1971 | 1960 | ||
| 1972 | (defun js-jsx--enclosing-curly-pos () | 1961 | (defun js-jsx--enclosing-curly-pos () |
| 1973 | "Return position of enclosing “{” in a “{/}” pair about point." | 1962 | "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 index 00000000000..f8ea7a138ad --- /dev/null +++ b/test/manual/indent/jsx-self-closing.jsx | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | // Local Variables: | ||
| 2 | // indent-tabs-mode: nil | ||
| 3 | // js-indent-level: 2 | ||
| 4 | // End: | ||
| 5 | |||
| 6 | // The following test goes below any comments to avoid including | ||
| 7 | // misindented comments among the erroring lines. | ||
| 8 | |||
| 9 | // Properly parse/indent code with a self-closing tag inside the | ||
| 10 | // attribute of another self-closing tag. | ||
| 11 | <div> | ||
| 12 | <div attr={() => <div attr="" />} /> | ||
| 13 | </div> | ||