aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJackson Ray Hamilton2019-04-07 00:25:35 -0700
committerJackson Ray Hamilton2019-04-08 22:48:24 -0700
commit7b2e3c60d081597adb7feaaabfee8cb8de62289b (patch)
treea4bfa97a66d402c69bb25c7889fa4c629376a031
parent462baabed93228a00e5ccadbe5704fb317957cb7 (diff)
downloademacs-7b2e3c60d081597adb7feaaabfee8cb8de62289b.tar.gz
emacs-7b2e3c60d081597adb7feaaabfee8cb8de62289b.zip
Optimize js-jsx--matching-close-tag-pos
This function’s performance was having a noticeable impact when editing large JSX structures. Improve its performance slightly (elapsed time will be cut in half according to ELP). * lisp/progmodes/js.el (js-jsx--tag-re): Remove. (js-jsx--matched-tag-type): Simplify implementation with respect to the new implementation of js-jsx--matching-close-tag-pos. (js-jsx--self-closing-re): Simplify regexp slightly in sync with a generally simpler matching algorithm. (js-jsx--matching-close-tag-pos): Optimize matching algorithm by using multiple simple regexp searches, rather than one big complex search. * test/manual/indent/jsx-unclosed-2.jsx: Use the term “inequality” and add a test for a possible parsing foible.
-rw-r--r--lisp/progmodes/js.el67
-rw-r--r--test/manual/indent/jsx-unclosed-2.jsx7
2 files changed, 37 insertions, 37 deletions
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index 2d29d4e443a..694a79f0d97 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -1906,26 +1906,23 @@ For use by `syntax-propertize-extend-region-functions'."
1906 (throw 'stop nil))))))) 1906 (throw 'stop nil)))))))
1907 (if new-start (cons new-start end)))) 1907 (if new-start (cons new-start end))))
1908 1908
1909(defconst js-jsx--tag-re 1909(defconst js-jsx--tag-start-re
1910 (concat "<\\s-*\\(" 1910 (concat js--dotted-name-re "\\s-*[" js--name-start-chars "{/>]")
1911 "[/>]" ; JSXClosingElement, or JSXOpeningFragment, or JSXClosingFragment 1911 "Regexp unambiguously matching a JSXOpeningElement.")
1912 "\\|"
1913 js--dotted-name-re "\\s-*[" js--name-start-chars "{/>]" ; JSXOpeningElement
1914 "\\)")
1915 "Regexp unambiguously matching a JSXBoundaryElement.")
1916 1912
1917(defun js-jsx--matched-tag-type () 1913(defun js-jsx--matched-tag-type ()
1918 "Determine the tag type of the last match to `js-jsx--tag-re'. 1914 "Determine if the last “<” was a JSXBoundaryElement and its type.
1919Return `close' for a JSXClosingElement/JSXClosingFragment match, 1915Return `close' for a JSXClosingElement/JSXClosingFragment match,
1920return `self-closing' for some self-closing JSXOpeningElements, 1916return `self-closing' for some self-closing JSXOpeningElements,
1921else return `other'." 1917else return `other'."
1922 (let ((chars (vconcat (match-string 1)))) 1918 (cond
1923 (cond 1919 ((= (char-after) ?/) (forward-char) 'close) ; JSXClosingElement/JSXClosingFragment
1924 ((= (aref chars 0) ?/) 'close) 1920 ((= (char-after) ?>) (forward-char) 'other) ; JSXOpeningFragment
1925 ((= (aref chars (1- (length chars))) ?/) 'self-closing) 1921 ((looking-at js-jsx--tag-start-re) ; JSXOpeningElement
1926 (t 'other)))) 1922 (goto-char (match-end 0))
1923 (if (= (char-before) ?/) 'self-closing 'other))))
1927 1924
1928(defconst js-jsx--self-closing-re "/\\s-*>" 1925(defconst js-jsx--self-closing-re "/>"
1929 "Regexp matching the end of a self-closing JSXOpeningElement.") 1926 "Regexp matching the end of a self-closing JSXOpeningElement.")
1930 1927
1931(defun js-jsx--matching-close-tag-pos () 1928(defun js-jsx--matching-close-tag-pos ()
@@ -1934,29 +1931,27 @@ Assuming a JSXOpeningElement or a JSXOpeningFragment is
1934immediately before point, find a matching JSXClosingElement or 1931immediately before point, find a matching JSXClosingElement or
1935JSXClosingFragment, skipping over any nested JSXElements to find 1932JSXClosingFragment, skipping over any nested JSXElements to find
1936the match. Return nil if a match can’t be found." 1933the match. Return nil if a match can’t be found."
1937 (let ((tag-stack 1) type tag-pos last-pos pos) 1934 (let ((tag-stack 1) tag-pos type last-pos pos)
1938 (catch 'stop 1935 (catch 'stop
1939 (while (re-search-forward js-jsx--tag-re nil t) 1936 (while (and (re-search-forward "<" nil t) (not (eobp)))
1940 (setq type (js-jsx--matched-tag-type) 1937 (when (setq tag-pos (match-beginning 0)
1941 tag-pos (match-beginning 0)) 1938 type (js-jsx--matched-tag-type))
1942 ;; Clear the stack of any JSXOpeningElements which turned out 1939 (when last-pos
1943 ;; to be self-closing. 1940 (setq pos (point))
1944 (when last-pos 1941 (goto-char last-pos)
1945 (setq pos (point)) 1942 (while (re-search-forward js-jsx--self-closing-re pos 'move)
1946 (goto-char last-pos) 1943 (setq tag-stack (1- tag-stack))))
1947 (while (re-search-forward js-jsx--self-closing-re pos 'move) 1944 (if (eq type 'close)
1948 (setq tag-stack (1- tag-stack)))) 1945 (progn
1949 (if (eq type 'close) 1946 (setq tag-stack (1- tag-stack))
1950 (progn 1947 (when (= tag-stack 0)
1951 (setq tag-stack (1- tag-stack)) 1948 (throw 'stop tag-pos)))
1952 (when (= tag-stack 0) 1949 ;; JSXOpeningElements that we know are self-closing aren’t
1953 (throw 'stop tag-pos))) 1950 ;; added to the stack at all (because point is already
1954 ;; JSXOpeningElements that we know are self-closing aren’t 1951 ;; past that syntax).
1955 ;; added to the stack at all (since re-search-forward moves 1952 (unless (eq type 'self-closing)
1956 ;; point after their self-closing syntax). 1953 (setq tag-stack (1+ tag-stack))))
1957 (unless (eq type 'self-closing) 1954 (setq last-pos (point)))))))
1958 (setq tag-stack (1+ tag-stack))))
1959 (setq last-pos (point))))))
1960 1955
1961(defun js-jsx--enclosing-curly-pos () 1956(defun js-jsx--enclosing-curly-pos ()
1962 "Return position of enclosing “{” in a “{/}” pair about point." 1957 "Return position of enclosing “{” in a “{/}” pair about point."
diff --git a/test/manual/indent/jsx-unclosed-2.jsx b/test/manual/indent/jsx-unclosed-2.jsx
index 8db25aa67f1..9d80a2e9ae2 100644
--- a/test/manual/indent/jsx-unclosed-2.jsx
+++ b/test/manual/indent/jsx-unclosed-2.jsx
@@ -6,10 +6,15 @@
6// The following tests go below any comments to avoid including 6// The following tests go below any comments to avoid including
7// misindented comments among the erroring lines. 7// misindented comments among the erroring lines.
8 8
9// Don’t misinterpret equality operators as JSX. 9// Don’t misinterpret inequality operators as JSX.
10for (; i < length;) void 0 10for (; i < length;) void 0
11if (foo > bar) void 0 11if (foo > bar) void 0
12 12
13// Don’t misintrepet inequalities within JSX, either.
14<div>
15 {foo < bar}
16</div>
17
13// Don’t even misinterpret unary operators as JSX. 18// Don’t even misinterpret unary operators as JSX.
14if (foo < await bar) void 0 19if (foo < await bar) void 0
15while (await foo > bar) void 0 20while (await foo > bar) void 0