[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] feature/jsx 66433fd 13/19: Improve JSX syntax propertizati
From: |
Marcin Borkowski |
Subject: |
[Emacs-diffs] feature/jsx 66433fd 13/19: Improve JSX syntax propertization |
Date: |
Wed, 27 Mar 2019 05:35:02 -0400 (EDT) |
branch: feature/jsx
commit 66433fd7fd2ba6b2c312dc0cbc8f852e3847641d
Author: Jackson Ray Hamilton <address@hidden>
Commit: Marcin Borkowski <address@hidden>
Improve JSX syntax propertization
* lisp/progmodes/js.el (js-jsx--attribute-name-re): New variable.
(js-jsx--syntax-propertize-tag): Allow “-” in JSXAttribute names. Fix
“out of range” error when typing at the end of a buffer. Fix/improve
future propertization of unfinished JSXBoundaryElements.
* test/manual/indent/js-jsx-unclosed-2.js: Add tests for allowed
characters in JSX.
---
lisp/progmodes/js.el | 74 +++++++++++++++++++--------------
test/manual/indent/js-jsx-unclosed-2.js | 8 ++++
2 files changed, 51 insertions(+), 31 deletions(-)
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index 0bba815..5d87489 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -2083,11 +2083,15 @@ been propertized."
(throw 'stop nil)))
(setq text-beg (point))))))
+(defconst js-jsx--attribute-name-re (concat js--name-start-re
+ "\\(?:\\s_\\|\\sw\\|-\\)*")
+ "Like `js--name-re', but matches “-” as well.")
+
(defun js-jsx--syntax-propertize-tag (end)
"Determine if a JSXBoundaryElement is before END and propertize it.
Disambiguate JSX from inequality operators and arrow functions by
testing for syntax only valid as JSX."
- (let ((tag-beg (1- (point))) (type 'open)
+ (let ((tag-beg (1- (point))) tag-end (type 'open)
name-beg name-match-data unambiguous
forward-sexp-function) ; Use Lisp version.
(catch 'stop
@@ -2127,46 +2131,54 @@ testing for syntax only valid as JSX."
;; figure out what type it actually is.
(if (eq type 'open) (setq type (if name-beg 'self-closing 'close)))
(forward-char))
- ((looking-at js--dotted-name-re)
- (if (not name-beg)
- (progn
- ;; Don’t match code like “if (i < await foo)”
- (if (js--unary-keyword-p (match-string 0)) (throw 'stop nil))
- ;; Save boundaries for later fontification after
- ;; unambiguously determining the code is JSX.
- (setq name-beg (match-beginning 0)
- name-match-data (match-data))
- (goto-char (match-end 0)))
- (setq unambiguous t) ; Non-unary name followed by 2nd name ⇒ JSX
- ;; Save JSXAttribute’s name’s match data for font-locking later.
- (put-text-property (match-beginning 0) (1+ (match-beginning 0))
- 'js-jsx-attribute-name (match-data))
- (goto-char (match-end 0))
+ ((and (not name-beg) (looking-at js--dotted-name-re))
+ ;; Don’t match code like “if (i < await foo)”
+ (if (js--unary-keyword-p (match-string 0)) (throw 'stop nil))
+ ;; Save boundaries for later fontification after
+ ;; unambiguously determining the code is JSX.
+ (setq name-beg (match-beginning 0)
+ name-match-data (match-data))
+ (goto-char (match-end 0)))
+ ((and name-beg (looking-at js-jsx--attribute-name-re))
+ (setq unambiguous t) ; Non-unary name followed by 2nd name ⇒ JSX
+ ;; Save JSXAttribute’s name’s match data for font-locking later.
+ (put-text-property (match-beginning 0) (1+ (match-beginning 0))
+ 'js-jsx-attribute-name (match-data))
+ (goto-char (match-end 0))
+ (if (>= (point) end) (throw 'stop nil))
+ (skip-chars-forward " \t\n" end)
+ (if (>= (point) end) (throw 'stop nil))
+ ;; “=” is optional for null-valued JSXAttributes.
+ (when (= (char-after) ?=)
+ (forward-char)
(if (>= (point) end) (throw 'stop nil))
(skip-chars-forward " \t\n" end)
(if (>= (point) end) (throw 'stop nil))
- ;; “=” is optional for null-valued JSXAttributes.
- (when (= (char-after) ?=)
- (forward-char)
- (if (>= (point) end) (throw 'stop nil))
- (skip-chars-forward " \t\n" end)
- (if (>= (point) end) (throw 'stop nil))
- ;; 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)))))))
+ ;; 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))))))
;; There is nothing more to check; this either isn’t JSX, or
;; the tag is incomplete.
(t (throw 'stop nil)))))
(when unambiguous
;; Save JSXBoundaryElement’s name’s match data for font-locking.
(if name-beg (put-text-property name-beg (1+ name-beg) 'js-jsx-tag-name
name-match-data))
+ ;; Prevent “out of range” errors when typing at the end of a buffer.
+ (setq tag-end (if (eobp) (1- (point)) (point)))
;; Mark beginning and end of tag for font-locking.
- (put-text-property tag-beg (1+ tag-beg) 'js-jsx-tag-beg (cons type
(point)))
- (put-text-property (point) (1+ (point)) 'js-jsx-tag-end tag-beg))
+ (put-text-property tag-beg (1+ tag-beg) 'js-jsx-tag-beg (cons type
tag-end))
+ (put-text-property tag-end (1+ tag-end) 'js-jsx-tag-end tag-beg)
+ ;; Use text properties to extend the syntax-propertize region
+ ;; backward to the beginning of the JSXBoundaryElement in the
+ ;; future. Typically the closing angle bracket could suggest
+ ;; extending backward, but that would also involve more rigorous
+ ;; parsing, and the closing angle bracket may not even exist yet
+ ;; if the JSXBoundaryElement is still being typed.
+ (put-text-property tag-beg (1+ tag-end) 'syntax-multiline t))
(if (js-jsx--at-enclosing-tag-child-p) (js-jsx--syntax-propertize-tag-text
end))))
(defconst js-jsx--text-properties
diff --git a/test/manual/indent/js-jsx-unclosed-2.js
b/test/manual/indent/js-jsx-unclosed-2.js
index 8b6f333..843ef9b 100644
--- a/test/manual/indent/js-jsx-unclosed-2.js
+++ b/test/manual/indent/js-jsx-unclosed-2.js
@@ -29,3 +29,11 @@ while (await foo > bar) void 0
</Baz>
</Bar>
</Foo>
+
+// “-” is not allowed in a JSXBoundaryElement’s name.
+<ABC />
+ <A-B-C /> // Weirdly-indented “continued expression.”
+
+// “-” may be used in a JSXAttribute’s name.
+<Foo a-b-c=""
+ x-y-z="" />
- [Emacs-diffs] feature/jsx 539191c 07/19: Font-lock JSX while editing it by extending regions, (continued)
- [Emacs-diffs] feature/jsx 539191c 07/19: Font-lock JSX while editing it by extending regions, Marcin Borkowski, 2019/03/27
- [Emacs-diffs] feature/jsx 79954c6 05/19: Use js-jsx- prefix for functions and variables, Marcin Borkowski, 2019/03/27
- [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 <=
- [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, 2019/03/27
- [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