diff options
| author | Jackson Ray Hamilton | 2019-04-07 00:25:35 -0700 |
|---|---|---|
| committer | Jackson Ray Hamilton | 2019-04-08 22:48:24 -0700 |
| commit | 7b2e3c60d081597adb7feaaabfee8cb8de62289b (patch) | |
| tree | a4bfa97a66d402c69bb25c7889fa4c629376a031 | |
| parent | 462baabed93228a00e5ccadbe5704fb317957cb7 (diff) | |
| download | emacs-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.el | 67 | ||||
| -rw-r--r-- | test/manual/indent/jsx-unclosed-2.jsx | 7 |
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. |
| 1919 | Return `close' for a JSXClosingElement/JSXClosingFragment match, | 1915 | Return `close' for a JSXClosingElement/JSXClosingFragment match, |
| 1920 | return `self-closing' for some self-closing JSXOpeningElements, | 1916 | return `self-closing' for some self-closing JSXOpeningElements, |
| 1921 | else return `other'." | 1917 | else 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 | |||
| 1934 | immediately before point, find a matching JSXClosingElement or | 1931 | immediately before point, find a matching JSXClosingElement or |
| 1935 | JSXClosingFragment, skipping over any nested JSXElements to find | 1932 | JSXClosingFragment, skipping over any nested JSXElements to find |
| 1936 | the match. Return nil if a match can’t be found." | 1933 | the 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. |
| 10 | for (; i < length;) void 0 | 10 | for (; i < length;) void 0 |
| 11 | if (foo > bar) void 0 | 11 | if (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. |
| 14 | if (foo < await bar) void 0 | 19 | if (foo < await bar) void 0 |
| 15 | while (await foo > bar) void 0 | 20 | while (await foo > bar) void 0 |