aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJackson Ray Hamilton2019-02-17 21:16:13 -0800
committerJackson Ray Hamilton2019-04-08 22:48:21 -0700
commit4d2b5bbfebc040ca477f1156b44989b4e19bbc3e (patch)
treebaf41c198d666df2175fa13b74060860d1d95d7c
parent52a3113b9beae6672c4bc981ee0c7bcc84ee58b5 (diff)
downloademacs-4d2b5bbfebc040ca477f1156b44989b4e19bbc3e.tar.gz
emacs-4d2b5bbfebc040ca477f1156b44989b4e19bbc3e.zip
Font-lock JSX while editing it by extending regions
* lisp/progmodes/js.el (js-jsx--font-lock-keywords): Call tag beginning and end matchers. (js-jsx--match-tag-beg, js-jsx--match-tag-end): New functions. (js-jsx--syntax-propertize-tag): Record buffer positions of JSXElement beginning and end for font-locking. (js--syntax-propertize-extend-region) (js-jsx--syntax-propertize-extend-region): New functions for extending the syntax-propertize region backwards to the start of a JSXElement so its JSXAttribute children on its n+1th lines can be parsed as such while editing those lines. (js-mode): Add js--syntax-propertize-extend-region to syntax-propertize-extend-region-functions.
-rw-r--r--lisp/progmodes/js.el81
1 files changed, 74 insertions, 7 deletions
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index 1319fa19394..7fb4bcc808a 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -1496,8 +1496,10 @@ point of view of font-lock. It applies highlighting directly with
1496 1496
1497(defconst js-jsx--font-lock-keywords 1497(defconst js-jsx--font-lock-keywords
1498 `((js-jsx--match-tag-name 0 font-lock-function-name-face t) 1498 `((js-jsx--match-tag-name 0 font-lock-function-name-face t)
1499 (js-jsx--match-attribute-name 0 font-lock-variable-name-face t)) 1499 (js-jsx--match-attribute-name 0 font-lock-variable-name-face t)
1500 "JSX font lock faces.") 1500 (js-jsx--match-tag-beg)
1501 (js-jsx--match-tag-end))
1502 "JSX font lock faces and multiline text properties.")
1501 1503
1502(defun js-jsx--match-tag-name (limit) 1504(defun js-jsx--match-tag-name (limit)
1503 "Match JSXBoundaryElement names, until LIMIT." 1505 "Match JSXBoundaryElement names, until LIMIT."
@@ -1521,6 +1523,28 @@ point of view of font-lock. It applies highlighting directly with
1521 (progn (set-match-data value) t)) 1523 (progn (set-match-data value) t))
1522 (js-jsx--match-attribute-name limit)))))) 1524 (js-jsx--match-attribute-name limit))))))
1523 1525
1526(defun js-jsx--match-tag-beg (limit)
1527 "Match JSXBoundaryElements from start, until LIMIT."
1528 (when js-jsx-syntax
1529 (let ((pos (next-single-char-property-change (point) 'js-jsx-tag-beg nil limit))
1530 value)
1531 (when (and pos (> pos (point)))
1532 (goto-char pos)
1533 (or (and (setq value (get-text-property pos 'js-jsx-tag-beg))
1534 (progn (put-text-property pos (cdr value) 'font-lock-multiline t) t))
1535 (js-jsx--match-tag-beg limit))))))
1536
1537(defun js-jsx--match-tag-end (limit)
1538 "Match JSXBoundaryElements from end, until LIMIT."
1539 (when js-jsx-syntax
1540 (let ((pos (next-single-char-property-change (point) 'js-jsx-tag-end nil limit))
1541 value)
1542 (when (and pos (> pos (point)))
1543 (goto-char pos)
1544 (or (and (setq value (get-text-property pos 'js-jsx-tag-end))
1545 (progn (put-text-property value pos 'font-lock-multiline t) t))
1546 (js-jsx--match-tag-end limit))))))
1547
1524(defconst js--font-lock-keywords-3 1548(defconst js--font-lock-keywords-3
1525 `( 1549 `(
1526 ;; This goes before keywords-2 so it gets used preferentially 1550 ;; This goes before keywords-2 so it gets used preferentially
@@ -1769,11 +1793,53 @@ This performs fontification according to `js--class-styles'."
1769 "Check if STRING is a unary operator keyword in JavaScript." 1793 "Check if STRING is a unary operator keyword in JavaScript."
1770 (string-match-p js--unary-keyword-re string)) 1794 (string-match-p js--unary-keyword-re string))
1771 1795
1796(defun js--syntax-propertize-extend-region (start end)
1797 "Extend the START-END region for propertization, if necessary.
1798For use by `syntax-propertize-extend-region-functions'."
1799 (if js-jsx-syntax (js-jsx--syntax-propertize-extend-region start end)))
1800
1801(defun js-jsx--syntax-propertize-extend-region (start end)
1802 "Extend the START-END region for propertization, if necessary.
1803If any “>” in the region appears to be the end of a tag starting
1804before the start of the region, extend region backwards to the
1805start of that tag so parsing may proceed from that point.
1806For use by `syntax-propertize-extend-region-functions'."
1807 (let (new-start
1808 forward-sexp-function ; Use the Lisp version.
1809 parse-sexp-lookup-properties) ; Fix backward-sexp error here.
1810 (catch 'stop
1811 (goto-char start)
1812 (while (re-search-forward ">" end t)
1813 (catch 'continue
1814 ;; Check if this is really a right shift bitwise operator
1815 ;; (“>>” or “>>>”).
1816 (unless (or (eq (char-before (1- (point))) ?>)
1817 (eq (char-after) ?>))
1818 (save-excursion
1819 (backward-char)
1820 (while (progn (if (= (point) (point-min)) (throw 'continue nil))
1821 (/= (char-before) ?<))
1822 (skip-chars-backward " \t\n")
1823 (if (= (point) (point-min)) (throw 'continue nil))
1824 (cond
1825 ((memq (char-before) '(?\" ?\' ?\` ?\}))
1826 (condition-case nil
1827 (backward-sexp)
1828 (scan-error (throw 'continue nil))))
1829 ((memq (char-before) '(?\/ ?\=)) (backward-char))
1830 ((looking-back js--dotted-name-re (line-beginning-position) t)
1831 (goto-char (match-beginning 0)))
1832 (t (throw 'continue nil))))
1833 (when (< (point) start)
1834 (setq new-start (1- (point)))
1835 (throw 'stop nil)))))))
1836 (if new-start (cons new-start end))))
1837
1772(defun js-jsx--syntax-propertize-tag (end) 1838(defun js-jsx--syntax-propertize-tag (end)
1773 "Determine if a JSXBoundaryElement is before END and propertize it. 1839 "Determine if a JSXBoundaryElement is before END and propertize it.
1774Disambiguate JSX from inequality operators and arrow functions by 1840Disambiguate JSX from inequality operators and arrow functions by
1775testing for syntax only valid as JSX." 1841testing for syntax only valid as JSX."
1776 (let ((tag-beg (1- (point))) tag-end (type 'open) 1842 (let ((tag-beg (1- (point))) (type 'open)
1777 name-beg name-match-data unambiguous 1843 name-beg name-match-data unambiguous
1778 forward-sexp-function) ; Use Lisp version. 1844 forward-sexp-function) ; Use Lisp version.
1779 (catch 'stop 1845 (catch 'stop
@@ -1783,8 +1849,7 @@ testing for syntax only valid as JSX."
1783 (cond 1849 (cond
1784 ((= (char-after) ?>) 1850 ((= (char-after) ?>)
1785 (forward-char) 1851 (forward-char)
1786 (setq unambiguous t 1852 (setq unambiguous t)
1787 tag-end (point))
1788 (throw 'stop nil)) 1853 (throw 'stop nil))
1789 ;; Handle a JSXSpreadChild (“<Foo {...bar}”) or a 1854 ;; Handle a JSXSpreadChild (“<Foo {...bar}”) or a
1790 ;; JSXExpressionContainer as a JSXAttribute value 1855 ;; JSXExpressionContainer as a JSXAttribute value
@@ -1852,8 +1917,8 @@ testing for syntax only valid as JSX."
1852 ;; Save JSXBoundaryElement’s name’s match data for font-locking. 1917 ;; Save JSXBoundaryElement’s name’s match data for font-locking.
1853 (if name-beg (put-text-property name-beg (1+ name-beg) 'js-jsx-tag-name name-match-data)) 1918 (if name-beg (put-text-property name-beg (1+ name-beg) 'js-jsx-tag-name name-match-data))
1854 ;; Mark beginning and end of tag for features like indentation. 1919 ;; Mark beginning and end of tag for features like indentation.
1855 (put-text-property tag-beg (1+ tag-beg) 'js-jsx-tag-beg type) 1920 (put-text-property tag-beg (1+ tag-beg) 'js-jsx-tag-beg (cons type (point)))
1856 (if tag-end (put-text-property (1- tag-end) tag-end 'js-jsx-tag-end tag-beg))))) 1921 (put-text-property (point) (1+ (point)) 'js-jsx-tag-end tag-beg))))
1857 1922
1858(defconst js-jsx--text-properties 1923(defconst js-jsx--text-properties
1859 '(js-jsx-tag-beg nil js-jsx-tag-end nil js-jsx-tag-name nil js-jsx-attribute-name nil) 1924 '(js-jsx-tag-beg nil js-jsx-tag-end nil js-jsx-tag-name nil js-jsx-attribute-name nil)
@@ -3945,6 +4010,8 @@ If one hasn't been set, or if it's stale, prompt for a new one."
3945 '(font-lock-syntactic-face-function 4010 '(font-lock-syntactic-face-function
3946 . js-font-lock-syntactic-face-function))) 4011 . js-font-lock-syntactic-face-function)))
3947 (setq-local syntax-propertize-function #'js-syntax-propertize) 4012 (setq-local syntax-propertize-function #'js-syntax-propertize)
4013 (add-hook 'syntax-propertize-extend-region-functions
4014 #'js--syntax-propertize-extend-region 'append 'local)
3948 (setq-local prettify-symbols-alist js--prettify-symbols-alist) 4015 (setq-local prettify-symbols-alist js--prettify-symbols-alist)
3949 4016
3950 (setq-local parse-sexp-ignore-comments t) 4017 (setq-local parse-sexp-ignore-comments t)