Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use JSX highlighting and indentation added in Emacs 27 #523

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,26 @@ The stable versions are hosted at [GNU ELPA](http://elpa.gnu.org/)
You can also install the latest development version from
[MELPA](https://melpa.org/#/getting-started).

JSX
===

Full support for highlighting and indenting of JSX is available in Emacs 27.
Eventually it can be downloaded [here](https://www.gnu.org/software/emacs/);
until it’s available there, you can install a snapshot of the Emacs master
branch:

```
git clone https://git.savannah.gnu.org/git/emacs.git
cd emacs
./autogen.sh
./configure
make
make install
```

Otherwise, in Emacs 26 and earlier, you can use `js2-jsx-mode` for rudimentary
JSX indentation support (only).

Emacs 22 and 23
===============

Expand Down
90 changes: 78 additions & 12 deletions js2-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
;;
;; To install it as your major mode for JavaScript editing:

;; (add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))
;; (add-to-list 'auto-mode-alist '("\\.jsx?\\'" . js2-mode))

;; Alternatively, to install it as a minor mode just for JavaScript linting,
;; you must add it to the appropriate major-mode hook. Normally this would be:
Expand All @@ -60,8 +60,10 @@

;; (add-to-list 'interpreter-mode-alist '("node" . js2-mode))

;; Support for JSX is available via the derived mode `js2-jsx-mode'. If you
;; also want JSX support, use that mode instead:
;; Support for JSX is also available. In Emacs 27, support for the syntax will
;; be automatically enabled in buffers using it and in ".jsx" files. For Emacs
;; versions prior to 27, support is only available via the derived mode
;; `js2-jsx-mode'; if you want JSX support in Emacs <27, use that mode instead:

;; (add-to-list 'auto-mode-alist '("\\.jsx?\\'" . js2-jsx-mode))
;; (add-to-list 'interpreter-mode-alist '("node" . js2-jsx-mode))
Expand Down Expand Up @@ -11703,14 +11705,45 @@ Selecting an error will jump it to the corresponding source-buffer error.
(goto-char pos)
(message msg))))))

;; In Emacs >=27, this is needed for JSX indentation and highlighting.
(defun js2-syntax-propertize (start end)
"Apply syntax properties from START to END."
(goto-char start)
(when (and
(boundp 'js-jsx--text-properties)
(bound-and-true-p js-jsx-syntax))
(remove-text-properties start end js-jsx--text-properties))
(funcall
(syntax-propertize-rules
("<" (0 (ignore (when (and
(fboundp 'js-jsx--syntax-propertize-tag)
(bound-and-true-p js-jsx-syntax))
(js-jsx--syntax-propertize-tag end))))))
(point) end))

;; In Emacs >=27, this is needed for JSX highlighting.
(defconst js2--font-lock-keywords
`(,@(bound-and-true-p js-jsx--font-lock-keywords))
"Font lock keywords for `js2-mode'; see `font-lock-keywords'.")

(defun js2-font-lock-syntactic-face-function (state)
"Return syntactic face given STATE."
;; This mode parses and colors JS strings using its AST, but it does neither
;; of those things for JSX strings. Until it does, fontify such strings in
;; the typical `font-lock-syntactic-face-function' manner.
(when (and (nth 3 state)
(get-text-property (nth 8 state) 'js-jsx-string))
font-lock-string-face))

;;;###autoload
(define-derived-mode js2-mode js-mode "Javascript-IDE"
(define-derived-mode js2-mode js-mode "JavaScript-IDE"
"Major mode for editing JavaScript code."
(set (make-local-variable 'max-lisp-eval-depth)
(max max-lisp-eval-depth 3000))
(set (make-local-variable 'indent-line-function) #'js2-indent-line)
(set (make-local-variable 'indent-region-function) #'js2-indent-region)
(set (make-local-variable 'syntax-propertize-function) nil)
(set (make-local-variable 'syntax-propertize-function)
(if (boundp 'js-jsx-syntax) #'js2-syntax-propertize nil))
(set (make-local-variable 'comment-line-break-function) #'js2-line-break)
(set (make-local-variable 'beginning-of-defun-function) #'js2-beginning-of-defun)
(set (make-local-variable 'end-of-defun-function) #'js2-end-of-defun)
Expand All @@ -11722,7 +11755,20 @@ Selecting an error will jump it to the corresponding source-buffer error.
;; needed for M-x rgrep, among other things
(put 'js2-mode 'find-tag-default-function #'js2-mode-find-tag)

(setq font-lock-defaults '(nil t))
(setq font-lock-defaults
(if (boundp 'js-jsx-syntax)
;; JSX fontification in Emacs 27 is provided by syntactic
;; font-locking, so we want to turn that on. We still only want to
;; fontify JS strings and comments using the AST, but since JSX
;; strings aren’t fontified by the AST yet, we fontify (only) those
;; in `js2-font-lock-syntactic-face-function'.
(list js2--font-lock-keywords nil nil nil nil
'(font-lock-syntactic-face-function
. js2-font-lock-syntactic-face-function))
;; Unless new Emacs >=27 JSX support is available, we don’t want to
;; fontify syntactically at all; strings and comments are only ever
;; fontified using the AST.
(list nil t)))

;; Experiment: make reparse-delay longer for longer files.
(when (cl-plusp js2-dynamic-idle-timer-adjust)
Expand Down Expand Up @@ -11750,25 +11796,45 @@ Selecting an error will jump it to the corresponding source-buffer error.
(when js2-include-jslint-declaration-externs
(add-hook 'js2-post-parse-callbacks 'js2-apply-jslint-declaration-externs nil t))

;; In Emacs >=27, in order to see enabled syntaxes (like “[JSX]”) in the
;; modeline, we need to first call this function.
(when (fboundp 'js-use-syntactic-mode-name)
(js-use-syntactic-mode-name))

;; We remove syntax-table text properties in js2-reparse, but since we
;; actually still do care about the JSX ones, refer to an alternative text
;; property for syntax-table provided by js-mode (which it provides for
;; precisely this purpose).
(push '(syntax-table js-jsx-syntax-table) char-property-alias-alist)

(run-hooks 'js2-init-hook)

(let ((js2-idle-timer-delay 0))
;; Schedule parsing for after when the mode hooks run.
(js2-mode-reset-timer)))

;; We may eventually want js2-jsx-mode to derive from js-jsx-mode, but that'd be
;; a bit more complicated and it doesn't net us much yet.
;;;###autoload
(define-derived-mode js2-jsx-mode js2-mode "JSX-IDE"
"Major mode for editing JSX code.
"Major mode for editing JavaScript+JSX code.

This is like `js-jsx-mode', which see.

To customize the indentation for this mode, set the SGML offset
variables (`sgml-basic-offset' et al) locally, like so:
In Emacs versions prior to 27, customize indentation by setting
`sgml-basic-offset' locally, like so:

(defun set-jsx-indentation ()
(setq-local sgml-basic-offset js2-basic-offset))
(add-hook \\='js2-jsx-mode-hook #\\='set-jsx-indentation)"
(set (make-local-variable 'indent-line-function) #'js2-jsx-indent-line))
(if (and (fboundp 'js-jsx-enable)
(fboundp 'js-use-syntactic-mode-name))
(progn
(js-jsx-enable)
;; Use the standard name because a syntactic part will be appended.
(setq mode-name "JavaScript-IDE")
(js-use-syntactic-mode-name))
;; Unless new Emacs >=27 JSX support is available, the old way to provide
;; JSX support (indentation only) is thus:
(set (make-local-variable 'indent-line-function) #'js2-jsx-indent-line)))

(defun js2-mode-exit ()
"Exit `js2-mode' and clean up."
Expand Down