[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] master bf37078 12/28: Automatically detect JSX in JavaScri
From: |
Jackson Ray Hamilton |
Subject: |
[Emacs-diffs] master bf37078 12/28: Automatically detect JSX in JavaScript files |
Date: |
Tue, 9 Apr 2019 02:00:13 -0400 (EDT) |
branch: master
commit bf37078df2cbea3a44a641ddbe40f11339c135a2
Author: Jackson Ray Hamilton <address@hidden>
Commit: Jackson Ray Hamilton <address@hidden>
Automatically detect JSX in JavaScript files
* lisp/files.el (auto-mode-alist): Simply enable
javascript-mode (js-mode) when opening “.jsx” files, since the “.jsx”
file extension will be used as an indicator of JSX syntax by js-mode,
and more code is likely to work in js-mode than js-jsx-mode, and we
probably want to guide users to use js-mode (with js-jsx-syntax)
instead. Code that used to work exclusively in js-jsx-mode (if anyone
ever wrote any) ought to be updated to work in js-mode too when
js-jsx-syntax is set to t.
* lisp/progmodes/js.el (js-jsx-detect-syntax, js-jsx-regexps)
(js-jsx--detect-and-enable, js-jsx--detect-after-change): New
variables and functions for detecting and enabling JSX.
(js-jsx-syntax): Update docstring with respect to the widened scope of
the effects and use of this variable.
(js-syntactic-mode-name, js--update-mode-name)
(js--idly-update-mode-name, js-jsx-enable): New variable and functions
for indicating when JSX is enabled.
(js-mode): Detect and enable JSX. Print all enabled syntaxes after
the mode name whenever Emacs goes idle; this ensures lately-enabled
syntaxes are evident.
(js-jsx-mode): Update mode name for consistency with the state in
which JSX is enabled in js-mode. Update docstring to suggest
alternative means of using JSX without this mode. Going forward, it
may be best to gently guide users away from js-jsx-mode, since a “one
mode per syntax extension” model would not scale well if more syntax
extensions were to be simultaneously supported (e.g. Facebook’s
“Flow”).
---
lisp/files.el | 3 +-
lisp/progmodes/js.el | 119 ++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 115 insertions(+), 7 deletions(-)
diff --git a/lisp/files.el b/lisp/files.el
index 1dae575..b81550e 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -2705,9 +2705,8 @@
ARC\\|ZIP\\|LZH\\|LHA\\|ZOO\\|[JEW]AR\\|XPI\\|RAR\\|CBR\\|7Z\\)\\'" . archive-mo
("\\.dbk\\'" . xml-mode)
("\\.dtd\\'" . sgml-mode)
("\\.ds\\(ss\\)?l\\'" . dsssl-mode)
- ("\\.jsm?\\'" . javascript-mode)
+ ("\\.js[mx]?\\'" . javascript-mode)
("\\.json\\'" . javascript-mode)
- ("\\.jsx\\'" . js-jsx-mode)
("\\.[ds]?vh?\\'" . verilog-mode)
("\\.by\\'" . bovine-grammar-mode)
("\\.wy\\'" . wisent-grammar-mode)
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index df2c413..0bba815 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -574,10 +574,30 @@ then the \".\"s will be lined up:
:safe 'booleanp
:group 'js)
+(defcustom js-jsx-detect-syntax t
+ "When non-nil, automatically detect whether JavaScript uses JSX.
+`js-jsx-syntax' (which see) may be made buffer-local and set to
+t. The detection strategy can be customized by adding elements
+to `js-jsx-regexps', which see."
+ :version "27.1"
+ :type 'boolean
+ :safe 'booleanp
+ :group 'js)
+
(defcustom js-jsx-syntax nil
"When non-nil, parse JavaScript with consideration for JSX syntax.
-This fixes indentation of JSX code in some cases. It is set to
-be buffer-local when in `js-jsx-mode'."
+
+This enables proper font-locking and indentation of code using
+Facebook’s “JSX” syntax extension for JavaScript, for use with
+Facebook’s “React” library. Font-locking is like sgml-mode.
+Indentation is also like sgml-mode, although some indentation
+behavior may differ slightly to align more closely with the
+conventions of the React developer community.
+
+When `js-mode' is already enabled, you should call
+`js-jsx-enable' to set this variable.
+
+It is set to be buffer-local (and t) when in `js-jsx-mode'."
:version "27.1"
:type 'boolean
:safe 'booleanp
@@ -4223,6 +4243,79 @@ If one hasn't been set, or if it's stale, prompt for a
new one."
(when temp-name
(delete-file temp-name))))))
+;;; Syntax extensions
+
+(defvar js-syntactic-mode-name t
+ "If non-nil, print enabled syntaxes in the mode name.")
+
+(defun js--update-mode-name ()
+ "Print enabled syntaxes if `js-syntactic-mode-name' is t."
+ (when js-syntactic-mode-name
+ (setq mode-name (concat "JavaScript"
+ (if js-jsx-syntax "+JSX" "")))))
+
+(defun js--idly-update-mode-name ()
+ "Update `mode-name' whenever Emacs goes idle.
+In case `js-jsx-syntax' is updated, especially by features of
+Emacs like .dir-locals.el or file variables, this ensures the
+modeline eventually reflects which syntaxes are enabled."
+ (let (timer)
+ (setq timer
+ (run-with-idle-timer
+ 0 t
+ (lambda (buffer)
+ (if (buffer-live-p buffer)
+ (with-current-buffer buffer
+ (js--update-mode-name))
+ (cancel-timer timer)))
+ (current-buffer)))))
+
+(defun js-jsx-enable ()
+ "Enable JSX in the current buffer."
+ (interactive)
+ (setq-local js-jsx-syntax t)
+ (js--update-mode-name))
+
+(defvar js-jsx-regexps
+ (list "\\_<\\(?:var\\|let\\|const\\|import\\)\\_>.*?React")
+ "Regexps for detecting JSX in JavaScript buffers.
+When `js-jsx-detect-syntax' is non-nil and any of these regexps
+match text near the beginning of a JavaScript buffer,
+`js-jsx-syntax' (which see) will be made buffer-local and set to
+t.")
+
+(defun js-jsx--detect-and-enable (&optional arbitrarily)
+ "Detect if JSX is likely to be used, and enable it if so.
+Might make `js-jsx-syntax' buffer-local and set it to t. Matches
+from the beginning of the buffer, unless optional arg ARBITRARILY
+is non-nil. Return t after enabling, nil otherwise."
+ (when (or (and (buffer-file-name)
+ (string-match-p "\\.jsx\\'" (buffer-file-name)))
+ (and js-jsx-detect-syntax
+ (save-excursion
+ (unless arbitrarily
+ (goto-char (point-min)))
+ (catch 'match
+ (mapc
+ (lambda (regexp)
+ (if (re-search-forward regexp 4000 t) (throw 'match
t)))
+ js-jsx-regexps)
+ nil))))
+ (js-jsx-enable)
+ t))
+
+(defun js-jsx--detect-after-change (beg end _len)
+ "Detect if JSX is likely to be used after a change.
+This function is intended for use in `after-change-functions'."
+ (when (<= end 4000)
+ (save-excursion
+ (goto-char beg)
+ (beginning-of-line)
+ (save-restriction
+ (narrow-to-region (point) end)
+ (when (js-jsx--detect-and-enable 'arbitrarily)
+ (remove-hook 'after-change-functions #'js-jsx--detect-after-change
t))))))
+
;;; Main Function
;;;###autoload
@@ -4259,6 +4352,12 @@ If one hasn't been set, or if it's stale, prompt for a
new one."
;; Frameworks
(js--update-quick-match-re)
+ ;; Syntax extensions
+ (unless (js-jsx--detect-and-enable)
+ (add-hook 'after-change-functions #'js-jsx--detect-after-change nil t))
+ (js--update-mode-name) ; If `js-jsx-syntax' was set from outside.
+ (js--idly-update-mode-name)
+
;; Imenu
(setq imenu-case-fold-search nil)
(setq imenu-create-index-function #'js--imenu-create-index)
@@ -4304,10 +4403,20 @@ If one hasn't been set, or if it's stale, prompt for a
new one."
)
;;;###autoload
-(define-derived-mode js-jsx-mode js-mode "JSX"
- "Major mode for editing JSX."
+(define-derived-mode js-jsx-mode js-mode "JavaScript+JSX"
+ "Major mode for editing JavaScript+JSX.
+
+Simply makes `js-jsx-syntax' buffer-local and sets it to t.
+
+`js-mode' may detect and enable support for JSX automatically if
+it appears to be used in a JavaScript file. You could also
+customize `js-jsx-regexps' to improve that detection; or, you
+could set `js-jsx-syntax' to t in your init file, or in a
+.dir-locals.el file, or using file variables; or, you could call
+`js-jsx-enable' in `js-mode-hook'. You may be better served by
+one of the aforementioned options instead of using this mode."
:group 'js
- (setq-local js-jsx-syntax t))
+ (js-jsx-enable))
;;;###autoload (defalias 'javascript-mode 'js-mode)
- [Emacs-diffs] master 8dae742 08/28: Propertize and font-lock JSXText and JSXExpressionContainers, (continued)
- [Emacs-diffs] master 8dae742 08/28: Propertize and font-lock JSXText and JSXExpressionContainers, Jackson Ray Hamilton, 2019/04/09
- [Emacs-diffs] master 3eadf1e 24/28: Identify JSX strings (for js2-mode), Jackson Ray Hamilton, 2019/04/09
- [Emacs-diffs] master 4b305bb 02/28: Refactor JSX indentation code to improve enclosing JSX discovery, Jackson Ray Hamilton, 2019/04/09
- [Emacs-diffs] master 58c77f1 01/28: Add failing tests for JSX indentation bugs, Jackson Ray Hamilton, 2019/04/09
- [Emacs-diffs] master 4d2b5bb 07/28: Font-lock JSX while editing it by extending regions, Jackson Ray Hamilton, 2019/04/09
- [Emacs-diffs] master 462baab 19/28: Add tests for miscellaneous JSX parsing feats, Jackson Ray Hamilton, 2019/04/09
- [Emacs-diffs] master be86ece 04/28: js-syntax-propertize: Disambiguate JS from JSX, fixing some indents, Jackson Ray Hamilton, 2019/04/09
- [Emacs-diffs] master d9d1bb2 14/28: Rename tests to use the “.jsx” file extension, Jackson Ray Hamilton, 2019/04/09
- [Emacs-diffs] master 84b1cfb 15/28: Indent broken arrow function bodies as an N+1th arg, Jackson Ray Hamilton, 2019/04/09
- [Emacs-diffs] master 6f53576 05/28: Use js-jsx- prefix for functions and variables, Jackson Ray Hamilton, 2019/04/09
- [Emacs-diffs] master bf37078 12/28: Automatically detect JSX in JavaScript files,
Jackson Ray Hamilton <=
- [Emacs-diffs] master cf416d9 28/28: Explain reasonings for JSX syntax support design decisions, Jackson Ray Hamilton, 2019/04/09
- [Emacs-diffs] master 9545519 26/28: Add open/close parenthesis syntax to “<” and “>” in JSX, Jackson Ray Hamilton, 2019/04/09
- [Emacs-diffs] master 7c3ffda 27/28: Move curly functions closer to where they’re used, Jackson Ray Hamilton, 2019/04/09
- [Emacs-diffs] master 1a1ef28 10/28: Indent JSX as parsed in a JS context, Jackson Ray Hamilton, 2019/04/09
- [Emacs-diffs] master 55c80d4 17/28: Indent expressions in JSXAttributes relative to the attribute’s name, Jackson Ray Hamilton, 2019/04/09
- [Emacs-diffs] master 18bbfc4 25/28: Permit non-ASCII identifiers in JS, Jackson Ray Hamilton, 2019/04/09
- [Emacs-diffs] master 98e36a3 21/28: Optimize js-jsx--enclosing-tag-pos, Jackson Ray Hamilton, 2019/04/09
- [Emacs-diffs] master 7a9dac5 22/28: Improve whitespace and unary keyword parsing, Jackson Ray Hamilton, 2019/04/09
- [Emacs-diffs] master 8b92719 13/28: Improve JSX syntax propertization, Jackson Ray Hamilton, 2019/04/09
- [Emacs-diffs] master afec451 18/28: Split JSX indentation calculation into several functions, Jackson Ray Hamilton, 2019/04/09