unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#21799: Requesting review for change to js.el
@ 2015-10-31  9:37 Jackson Hamilton
  2015-10-31 12:36 ` Dmitry Gutov
  0 siblings, 1 reply; 8+ messages in thread
From: Jackson Hamilton @ 2015-10-31  9:37 UTC (permalink / raw)
  To: 21799


[-- Attachment #1.1: Type: text/plain, Size: 61 bytes --]

See attached patch. Adds JSX indentation support to js-mode.

[-- Attachment #1.2: Type: text/html, Size: 82 bytes --]

[-- Attachment #2: jsx.patch --]
[-- Type: text/x-patch, Size: 10594 bytes --]

diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index 5a4f383..c0e5655 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -52,6 +52,7 @@
 (require 'imenu)
 (require 'moz nil t)
 (require 'json nil t)
+(require 'sgml-mode)
 
 (eval-when-compile
   (require 'cl-lib)
@@ -551,6 +552,18 @@ don't indent the first one's initializer; otherwise, indent it.
   :safe 'symbolp
   :group 'js)
 
+(defcustom js-indent-jsx nil
+  "Non-nil to indent JSX elements.
+
+`sgml-basic-offset' and `sgml-attribute-offset' determine the
+indentation level of lines containing JSX.
+
+Enabling this may slow down indentation of entire large files."
+  :version "25.1"
+  :type 'boolean
+  :safe 'booleanp
+  :group 'js)
+
 ;;; KeyMap
 
 (defvar js-mode-map
@@ -1998,9 +2011,195 @@ indentation is aligned to that column."
            (+ js-indent-level js-expr-indent-offset))
           (t 0))))
 
-(defun js-indent-line ()
+;;; JSX Indentation
+
+(defsubst js--jsx-find-before-tag ()
+  "Find where JSX starts.
+
+Assume JSX appears in the following instances:
+- Inside parentheses, when returned or as the first argument
+  to a function, and after a newline
+- When assigned to variables or object properties, but only
+  on a single line
+- As the N+1th argument to a function
+
+This is an optimized version of (re-search-backward \"[(,]\n\"
+nil t), except set point to the end of the match.  This logic
+executes up to the number of lines in the file, so it should be
+really fast to reduce that impact."
+  (let (pos)
+    (while (and (> (point) (point-min))
+                (not (progn
+                       (end-of-line 0)
+                       (when (or (eq (char-before) 40)   ; (
+                                 (eq (char-before) 44))  ; ,
+                         (setq pos (1- (point))))))))
+    pos))
+
+(defconst js--jsx-end-tag-re
+  (concat "</" sgml-name-re ">\\|/>")
+  "Find the end of a JSX element.")
+
+(defconst js--jsx-after-tag-re "[),]"
+  "Find where JSX ends.
+This complements the assumption of where JSX appears from
+`js--jsx-before-tag-re', which see.")
+
+(defun js--jsx-indented-element-p ()
+  "Determine if/how the current line should be indented as JSX.
+
+Return `first' for the first JSXElement on its own line.
+Return `nth' for subsequent lines of the first JSXElement.
+Return `expression' for an embedded JS expression.
+Return `after' for anything after the last JSXElement.
+Return nil for non-JSX lines.
+
+Currently, JSX indentation supports the following styles:
+
+- Single-line elements (indented like normal JS):
+
+  var element = <div></div>;
+
+- Multi-line elements (enclosed in parentheses):
+
+  function () {
+    return (
+      <div>
+        <div></div>
+      </div>
+    );
+ }
+
+- Function arguments:
+
+  React.render(
+    <div></div>,
+    document.querySelector('.root')
+  );"
+  (let ((current-pos (point))
+        (current-line (line-number-at-pos))
+        last-pos
+        before-tag-pos before-tag-line
+        tag-start-pos tag-start-line
+        tag-end-pos tag-end-line
+        after-tag-line
+        parens paren type)
+    (save-excursion
+      (and
+       ;; Determine if we're inside a jsx element
+       (progn
+         (end-of-line)
+         (while (and (not tag-start-pos)
+                     (setq last-pos (js--jsx-find-before-tag)))
+           (while (forward-comment 1))
+           (when (= (char-after) 60) ; <
+             (setq before-tag-pos last-pos
+                   tag-start-pos (point)))
+           (goto-char last-pos))
+         tag-start-pos)
+       (progn
+         (setq before-tag-line (line-number-at-pos before-tag-pos)
+               tag-start-line (line-number-at-pos tag-start-pos))
+         (and
+          ;; A "before" line which also starts an element begins with js, so
+          ;; indent it like js
+          (> current-line before-tag-line)
+          ;; Only indent the jsx lines like jsx
+          (>= current-line tag-start-line)))
+       (cond
+        ;; Analyze bounds if there are any
+        ((progn
+           (while (and (not tag-end-pos)
+                       (setq last-pos (re-search-forward js--jsx-end-tag-re nil t)))
+             (while (forward-comment 1))
+             (when (looking-at js--jsx-after-tag-re)
+               (setq tag-end-pos last-pos)))
+           tag-end-pos)
+         (setq tag-end-line (line-number-at-pos tag-end-pos)
+               after-tag-line (line-number-at-pos after-tag-line))
+         (or (and
+              ;; Ensure we're actually within the bounds of the jsx
+              (<= current-line tag-end-line)
+              ;; An "after" line which does not end an element begins with
+              ;; js, so indent it like js
+              (<= current-line after-tag-line))
+             (and
+              ;; Handle another case where there could be e.g. comments after
+              ;; the element
+              (> current-line tag-end-line)
+              (< current-line after-tag-line)
+              (setq type 'after))))
+        ;; They may not be any bounds (yet)
+        (t))
+       ;; Check if we're inside an embedded multi-line js expression
+       (cond
+        ((not type)
+         (goto-char current-pos)
+         (end-of-line)
+         (setq parens (nth 9 (syntax-ppss)))
+         (while (and parens (not type))
+           (setq paren (car parens))
+           (cond
+            ((and (>= paren tag-start-pos)
+                  ;; Curly bracket indicates the start of an embedded expression
+                  (= (char-after paren) 123) ; {
+                  ;; The first line of the expression is indented like sgml
+                  (> current-line (line-number-at-pos paren))
+                  ;; Check if within a closing curly bracket (if any)
+                  ;; (exclusive, as the closing bracket is indented like sgml)
+                  (cond
+                   ((progn
+                      (goto-char paren)
+                      (ignore-errors (let (forward-sexp-function)
+                                       (forward-sexp))))
+                    (< current-line (line-number-at-pos)))
+                   (t)))
+             ;; Indicate this guy will be indented specially
+             (setq type 'expression))
+            (t (setq parens (cdr parens)))))
+         t)
+        (t))
+       (cond
+        (type)
+        ;; Indent the first jsx thing like js so we can indent future jsx things
+        ;; like sgml relative to the first thing
+        ((= current-line tag-start-line) 'first)
+        ('nth))))))
+
+(defmacro js--as-sgml (&rest body)
+  "Execute BODY as if in sgml-mode."
+  `(with-syntax-table sgml-mode-syntax-table
+     (let (forward-sexp-function
+           parse-sexp-lookup-properties)
+       ,@body)))
+
+(defun js--expression-in-sgml-indent-line ()
+  "Indent the current line as JavaScript or SGML (whichever is farther)."
+  (let* (indent-col
+         (savep (point))
+         ;; Don't whine about errors/warnings when we're indenting.
+         ;; This has to be set before calling parse-partial-sexp below.
+         (inhibit-point-motion-hooks t)
+         (parse-status (save-excursion
+                         (syntax-ppss (point-at-bol)))))
+    ;; Don't touch multiline strings.
+    (unless (nth 3 parse-status)
+      (setq indent-col (save-excursion
+                         (back-to-indentation)
+                         (if (>= (point) savep) (setq savep nil))
+                         (js--as-sgml (sgml-calculate-indent))))
+      (if (null indent-col)
+          'noindent
+        ;; Use whichever indentation column is greater, such that the sgml
+        ;; column is effectively a minimum
+        (setq indent-col (max (js--proper-indentation parse-status)
+                              (+ indent-col js-indent-level)))
+        (if savep
+            (save-excursion (indent-line-to indent-col))
+          (indent-line-to indent-col))))))
+
+(defun js--indent-line-as-js ()
   "Indent the current line as JavaScript."
-  (interactive)
   (let* ((parse-status
           (save-excursion (syntax-ppss (point-at-bol))))
          (offset (- (point) (save-excursion (back-to-indentation) (point)))))
@@ -2008,6 +2207,29 @@ indentation is aligned to that column."
       (indent-line-to (js--proper-indentation parse-status))
       (when (> offset 0) (forward-char offset)))))
 
+(defun js-indent-line ()
+  "Indent the current line as JavaScript or JSX source text.
+If `js-indent-jsx' is non-nil, which see, indent the current line
+as JSX source text."
+  (interactive)
+  (cond
+   (js-indent-jsx
+    (let ((indentation-type (js--jsx-indented-element-p)))
+      (cond
+       ((eq indentation-type 'expression)
+        (js--expression-in-sgml-indent-line))
+       ((or (eq indentation-type 'first)
+            (eq indentation-type 'after))
+        ;; Don't treat this first thing as a continued expression (often a "<" or
+        ;; ">" causes this misinterpretation)
+        (cl-letf (((symbol-function #'js--continued-expression-p) 'ignore))
+          (js--indent-line-as-js)))
+       ((eq indentation-type 'nth)
+        (js--as-sgml (sgml-indent-line)))
+       (t (js--indent-line-as-js)))))
+   (t
+    (js--indent-line-as-js))))
+
 ;;; Filling
 
 (defvar js--filling-paragraph nil)
diff --git a/test/indent/js-indent-jsx.js b/test/indent/js-indent-jsx.js
new file mode 100644
index 0000000..1ea65ed
--- /dev/null
+++ b/test/indent/js-indent-jsx.js
@@ -0,0 +1,84 @@
+var foo = <div></div>;
+
+return (
+  <div>
+  </div>
+  <div>
+    <div></div>
+    <div>
+      <div></div>
+    </div>
+  </div>
+);
+
+React.render(
+  <div>
+    <div></div>
+  </div>,
+  {
+    a: 1
+  },
+  <div>
+    <div></div>
+  </div>
+);
+
+return (
+  // Sneaky!
+  <div></div>
+);
+
+return (
+  <div></div>
+  // Sneaky!
+);
+
+React.render(
+  <input
+    />,
+  {
+    a: 1
+  }
+);
+
+return (
+  <div>
+    {array.map(function () {
+      return {
+        a: 1
+      };
+    })}
+  </div>
+);
+
+return (
+  <div attribute={array.map(function () {
+         return {
+           a: 1
+         };
+
+         return {
+           a: 1
+         };
+
+         return {
+           a: 1
+         };
+       })}>
+  </div>
+);
+
+// Local Variables:
+// indent-tabs-mode: nil
+// js-indent-level: 2
+// js-indent-jsx: t
+// End:
+
+// The following test has intentionally unclosed elements and should
+// be placed below all other tests to prevent awkward indentation.
+
+return (
+  <div>
+    {array.map(function () {
+      return {
+        a: 1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* bug#21799: Requesting review for change to js.el
  2015-10-31  9:37 bug#21799: Requesting review for change to js.el Jackson Hamilton
@ 2015-10-31 12:36 ` Dmitry Gutov
  2015-10-31 16:53   ` Jackson Hamilton
  0 siblings, 1 reply; 8+ messages in thread
From: Dmitry Gutov @ 2015-10-31 12:36 UTC (permalink / raw)
  To: Jackson Hamilton, 21799

On 10/31/2015 11:37 AM, Jackson Hamilton wrote:
> See attached patch. Adds JSX indentation support to js-mode.

Hi Jackson,

JSX files have a different extension, right? Why don't we make it a 
separate major mode?

It can also live in js.el and derive from js-mode. The only thing it'll 
change (for now?) is the indentation function.

And for those who also want the js2-mode AST, we can either tell them to 
use js2-minor-mode, or also create a js2-jsx-mode that would derive from 
js2-mode and use the indentation function defined here.

Then there will be no need for the option js-indent-jsx.





^ permalink raw reply	[flat|nested] 8+ messages in thread

* bug#21799: Requesting review for change to js.el
  2015-10-31 12:36 ` Dmitry Gutov
@ 2015-10-31 16:53   ` Jackson Hamilton
  2015-10-31 17:05     ` Dmitry Gutov
  0 siblings, 1 reply; 8+ messages in thread
From: Jackson Hamilton @ 2015-10-31 16:53 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: 21799

[-- Attachment #1: Type: text/plain, Size: 929 bytes --]

Some use the ".jsx" extension, some just use ".js". One could also do
(add-to-list 'auto-mode-alist '("\\.js\\'" . js-jsx-mode)).

I like the idea of separating the modes as js-jsx-mode and js2-jsx-mode,
I'll make that change.

On Sat, Oct 31, 2015 at 5:36 AM, Dmitry Gutov <dgutov@yandex.ru> wrote:

> On 10/31/2015 11:37 AM, Jackson Hamilton wrote:
>
>> See attached patch. Adds JSX indentation support to js-mode.
>>
>
> Hi Jackson,
>
> JSX files have a different extension, right? Why don't we make it a
> separate major mode?
>
> It can also live in js.el and derive from js-mode. The only thing it'll
> change (for now?) is the indentation function.
>
> And for those who also want the js2-mode AST, we can either tell them to
> use js2-minor-mode, or also create a js2-jsx-mode that would derive from
> js2-mode and use the indentation function defined here.
>
> Then there will be no need for the option js-indent-jsx.
>

[-- Attachment #2: Type: text/html, Size: 1586 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* bug#21799: Requesting review for change to js.el
  2015-10-31 16:53   ` Jackson Hamilton
@ 2015-10-31 17:05     ` Dmitry Gutov
  2015-10-31 17:53       ` Jackson Hamilton
  0 siblings, 1 reply; 8+ messages in thread
From: Dmitry Gutov @ 2015-10-31 17:05 UTC (permalink / raw)
  To: Jackson Hamilton; +Cc: 21799

On 10/31/2015 06:53 PM, Jackson Hamilton wrote:
> Some use the ".jsx" extension, some just use ".js". One could also do
> (add-to-list 'auto-mode-alist '("\\.js\\'" . js-jsx-mode)).

That's a good point.

> I like the idea of separating the modes as js-jsx-mode and js2-jsx-mode,
> I'll make that change.

Thanks.





^ permalink raw reply	[flat|nested] 8+ messages in thread

* bug#21799: Requesting review for change to js.el
  2015-10-31 17:05     ` Dmitry Gutov
@ 2015-10-31 17:53       ` Jackson Hamilton
  2015-10-31 19:20         ` Dmitry Gutov
  2016-02-23  5:15         ` Lars Ingebrigtsen
  0 siblings, 2 replies; 8+ messages in thread
From: Jackson Hamilton @ 2015-10-31 17:53 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: 21799


[-- Attachment #1.1: Type: text/plain, Size: 580 bytes --]

Updated with the addition of js-jsx-mode (attached).

Also, has the ChangeLog maintenance process changed? I don't see a
"current" ChangeLog to which I may add entries.

On Sat, Oct 31, 2015 at 10:05 AM, Dmitry Gutov <dgutov@yandex.ru> wrote:

> On 10/31/2015 06:53 PM, Jackson Hamilton wrote:
>
>> Some use the ".jsx" extension, some just use ".js". One could also do
>> (add-to-list 'auto-mode-alist '("\\.js\\'" . js-jsx-mode)).
>>
>
> That's a good point.
>
> I like the idea of separating the modes as js-jsx-mode and js2-jsx-mode,
>> I'll make that change.
>>
>
> Thanks.
>

[-- Attachment #1.2: Type: text/html, Size: 1261 bytes --]

[-- Attachment #2: jsx.patch --]
[-- Type: text/x-patch, Size: 10496 bytes --]

diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index 5a4f383..3ce1c17 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -52,6 +52,7 @@
 (require 'imenu)
 (require 'moz nil t)
 (require 'json nil t)
+(require 'sgml-mode)
 
 (eval-when-compile
   (require 'cl-lib)
@@ -1998,6 +1999,193 @@ indentation is aligned to that column."
            (+ js-indent-level js-expr-indent-offset))
           (t 0))))
 
+;;; JSX Indentation
+
+(defsubst js--jsx-find-before-tag ()
+  "Find where JSX starts.
+
+Assume JSX appears in the following instances:
+- Inside parentheses, when returned or as the first argument
+  to a function, and after a newline
+- When assigned to variables or object properties, but only
+  on a single line
+- As the N+1th argument to a function
+
+This is an optimized version of (re-search-backward \"[(,]\n\"
+nil t), except set point to the end of the match.  This logic
+executes up to the number of lines in the file, so it should be
+really fast to reduce that impact."
+  (let (pos)
+    (while (and (> (point) (point-min))
+                (not (progn
+                       (end-of-line 0)
+                       (when (or (eq (char-before) 40)   ; (
+                                 (eq (char-before) 44))  ; ,
+                         (setq pos (1- (point))))))))
+    pos))
+
+(defconst js--jsx-end-tag-re
+  (concat "</" sgml-name-re ">\\|/>")
+  "Find the end of a JSX element.")
+
+(defconst js--jsx-after-tag-re "[),]"
+  "Find where JSX ends.
+This complements the assumption of where JSX appears from
+`js--jsx-before-tag-re', which see.")
+
+(defun js--jsx-indented-element-p ()
+  "Determine if/how the current line should be indented as JSX.
+
+Return `first' for the first JSXElement on its own line.
+Return `nth' for subsequent lines of the first JSXElement.
+Return `expression' for an embedded JS expression.
+Return `after' for anything after the last JSXElement.
+Return nil for non-JSX lines.
+
+Currently, JSX indentation supports the following styles:
+
+- Single-line elements (indented like normal JS):
+
+  var element = <div></div>;
+
+- Multi-line elements (enclosed in parentheses):
+
+  function () {
+    return (
+      <div>
+        <div></div>
+      </div>
+    );
+ }
+
+- Function arguments:
+
+  React.render(
+    <div></div>,
+    document.querySelector('.root')
+  );"
+  (let ((current-pos (point))
+        (current-line (line-number-at-pos))
+        last-pos
+        before-tag-pos before-tag-line
+        tag-start-pos tag-start-line
+        tag-end-pos tag-end-line
+        after-tag-line
+        parens paren type)
+    (save-excursion
+      (and
+       ;; Determine if we're inside a jsx element
+       (progn
+         (end-of-line)
+         (while (and (not tag-start-pos)
+                     (setq last-pos (js--jsx-find-before-tag)))
+           (while (forward-comment 1))
+           (when (= (char-after) 60) ; <
+             (setq before-tag-pos last-pos
+                   tag-start-pos (point)))
+           (goto-char last-pos))
+         tag-start-pos)
+       (progn
+         (setq before-tag-line (line-number-at-pos before-tag-pos)
+               tag-start-line (line-number-at-pos tag-start-pos))
+         (and
+          ;; A "before" line which also starts an element begins with js, so
+          ;; indent it like js
+          (> current-line before-tag-line)
+          ;; Only indent the jsx lines like jsx
+          (>= current-line tag-start-line)))
+       (cond
+        ;; Analyze bounds if there are any
+        ((progn
+           (while (and (not tag-end-pos)
+                       (setq last-pos (re-search-forward js--jsx-end-tag-re nil t)))
+             (while (forward-comment 1))
+             (when (looking-at js--jsx-after-tag-re)
+               (setq tag-end-pos last-pos)))
+           tag-end-pos)
+         (setq tag-end-line (line-number-at-pos tag-end-pos)
+               after-tag-line (line-number-at-pos after-tag-line))
+         (or (and
+              ;; Ensure we're actually within the bounds of the jsx
+              (<= current-line tag-end-line)
+              ;; An "after" line which does not end an element begins with
+              ;; js, so indent it like js
+              (<= current-line after-tag-line))
+             (and
+              ;; Handle another case where there could be e.g. comments after
+              ;; the element
+              (> current-line tag-end-line)
+              (< current-line after-tag-line)
+              (setq type 'after))))
+        ;; They may not be any bounds (yet)
+        (t))
+       ;; Check if we're inside an embedded multi-line js expression
+       (cond
+        ((not type)
+         (goto-char current-pos)
+         (end-of-line)
+         (setq parens (nth 9 (syntax-ppss)))
+         (while (and parens (not type))
+           (setq paren (car parens))
+           (cond
+            ((and (>= paren tag-start-pos)
+                  ;; Curly bracket indicates the start of an embedded expression
+                  (= (char-after paren) 123) ; {
+                  ;; The first line of the expression is indented like sgml
+                  (> current-line (line-number-at-pos paren))
+                  ;; Check if within a closing curly bracket (if any)
+                  ;; (exclusive, as the closing bracket is indented like sgml)
+                  (cond
+                   ((progn
+                      (goto-char paren)
+                      (ignore-errors (let (forward-sexp-function)
+                                       (forward-sexp))))
+                    (< current-line (line-number-at-pos)))
+                   (t)))
+             ;; Indicate this guy will be indented specially
+             (setq type 'expression))
+            (t (setq parens (cdr parens)))))
+         t)
+        (t))
+       (cond
+        (type)
+        ;; Indent the first jsx thing like js so we can indent future jsx things
+        ;; like sgml relative to the first thing
+        ((= current-line tag-start-line) 'first)
+        ('nth))))))
+
+(defmacro js--as-sgml (&rest body)
+  "Execute BODY as if in sgml-mode."
+  `(with-syntax-table sgml-mode-syntax-table
+     (let (forward-sexp-function
+           parse-sexp-lookup-properties)
+       ,@body)))
+
+(defun js--expression-in-sgml-indent-line ()
+  "Indent the current line as JavaScript or SGML (whichever is farther)."
+  (let* (indent-col
+         (savep (point))
+         ;; Don't whine about errors/warnings when we're indenting.
+         ;; This has to be set before calling parse-partial-sexp below.
+         (inhibit-point-motion-hooks t)
+         (parse-status (save-excursion
+                         (syntax-ppss (point-at-bol)))))
+    ;; Don't touch multiline strings.
+    (unless (nth 3 parse-status)
+      (setq indent-col (save-excursion
+                         (back-to-indentation)
+                         (if (>= (point) savep) (setq savep nil))
+                         (js--as-sgml (sgml-calculate-indent))))
+      (if (null indent-col)
+          'noindent
+        ;; Use whichever indentation column is greater, such that the sgml
+        ;; column is effectively a minimum
+        (setq indent-col (max (js--proper-indentation parse-status)
+                              (+ indent-col js-indent-level)))
+        (if savep
+            (save-excursion (indent-line-to indent-col))
+          (indent-line-to indent-col))))))
+
 (defun js-indent-line ()
   "Indent the current line as JavaScript."
   (interactive)
@@ -2008,6 +2196,25 @@ indentation is aligned to that column."
       (indent-line-to (js--proper-indentation parse-status))
       (when (> offset 0) (forward-char offset)))))
 
+(defun js-jsx-indent-line ()
+  "Indent the current line as JSX (with SGML offsets).
+i.e., customize JSX element indentation with `sgml-basic-offset',
+`sgml-attribute-offset' et al."
+  (interactive)
+  (let ((indentation-type (js--jsx-indented-element-p)))
+    (cond
+     ((eq indentation-type 'expression)
+      (js--expression-in-sgml-indent-line))
+     ((or (eq indentation-type 'first)
+          (eq indentation-type 'after))
+      ;; Don't treat this first thing as a continued expression (often a "<" or
+      ;; ">" causes this misinterpretation)
+      (cl-letf (((symbol-function #'js--continued-expression-p) 'ignore))
+        (js-indent-line)))
+     ((eq indentation-type 'nth)
+      (js--as-sgml (sgml-indent-line)))
+     (t (js-indent-line)))))
+
 ;;; Filling
 
 (defvar js--filling-paragraph nil)
@@ -3566,6 +3773,20 @@ If one hasn't been set, or if it's stale, prompt for a new one."
   ;;(syntax-propertize (point-max))
   )
 
+;;;###autoload
+(define-derived-mode js-jsx-mode js-mode "JSX"
+  "Major mode for editing JSX.
+
+To customize the indentation for this mode, set the SGML offset
+variables (`sgml-basic-offset', `sgml-attribute-offset' et al)
+locally, like so:
+
+  (defun set-jsx-indentation ()
+    (setq-local sgml-basic-offset js-indent-level))
+  (add-hook 'js-jsx-mode-hook #'set-jsx-indentation)"
+  :group 'js
+  (setq-local indent-line-function #'js-jsx-indent-line))
+
 ;;;###autoload (defalias 'javascript-mode 'js-mode)
 
 (eval-after-load 'folding
diff --git a/test/indent/js-jsx.js b/test/indent/js-jsx.js
new file mode 100644
index 0000000..7401939
--- /dev/null
+++ b/test/indent/js-jsx.js
@@ -0,0 +1,85 @@
+// -*- mode: js-jsx; -*-
+
+var foo = <div></div>;
+
+return (
+  <div>
+  </div>
+  <div>
+    <div></div>
+    <div>
+      <div></div>
+    </div>
+  </div>
+);
+
+React.render(
+  <div>
+    <div></div>
+  </div>,
+  {
+    a: 1
+  },
+  <div>
+    <div></div>
+  </div>
+);
+
+return (
+  // Sneaky!
+  <div></div>
+);
+
+return (
+  <div></div>
+  // Sneaky!
+);
+
+React.render(
+  <input
+    />,
+  {
+    a: 1
+  }
+);
+
+return (
+  <div>
+    {array.map(function () {
+      return {
+        a: 1
+      };
+    })}
+  </div>
+);
+
+return (
+  <div attribute={array.map(function () {
+         return {
+           a: 1
+         };
+
+         return {
+           a: 1
+         };
+
+         return {
+           a: 1
+         };
+       })}>
+  </div>
+);
+
+// Local Variables:
+// indent-tabs-mode: nil
+// js-indent-level: 2
+// End:
+
+// The following test has intentionally unclosed elements and should
+// be placed below all other tests to prevent awkward indentation.
+
+return (
+  <div>
+    {array.map(function () {
+      return {
+        a: 1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* bug#21799: Requesting review for change to js.el
  2015-10-31 17:53       ` Jackson Hamilton
@ 2015-10-31 19:20         ` Dmitry Gutov
  2016-02-23  5:15         ` Lars Ingebrigtsen
  1 sibling, 0 replies; 8+ messages in thread
From: Dmitry Gutov @ 2015-10-31 19:20 UTC (permalink / raw)
  To: Jackson Hamilton; +Cc: 21799

On 10/31/2015 07:53 PM, Jackson Hamilton wrote:

> Also, has the ChangeLog maintenance process changed? I don't see a
> "current" ChangeLog to which I may add entries.

Now we put ChangeLog entries into the commit messages.

See CONTRIBUTE, "Generating ChangeLog entries", second part.





^ permalink raw reply	[flat|nested] 8+ messages in thread

* bug#21799: Requesting review for change to js.el
  2015-10-31 17:53       ` Jackson Hamilton
  2015-10-31 19:20         ` Dmitry Gutov
@ 2016-02-23  5:15         ` Lars Ingebrigtsen
  2016-02-23 10:14           ` Dmitry Gutov
  1 sibling, 1 reply; 8+ messages in thread
From: Lars Ingebrigtsen @ 2016-02-23  5:15 UTC (permalink / raw)
  To: Jackson Hamilton; +Cc: 21799, Dmitry Gutov

Jackson Hamilton <jackson@jacksonrayhamilton.com> writes:

> Updated with the addition of js-jsx-mode (attached).

Looks good to me, I think, but I think it should probably be separated
out into its own file: jsx-mode.el.

Also, I can't find your name in the Emacs copyright assignment file.
Would you be willing to sign FSF copyright assignment papers?

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 8+ messages in thread

* bug#21799: Requesting review for change to js.el
  2016-02-23  5:15         ` Lars Ingebrigtsen
@ 2016-02-23 10:14           ` Dmitry Gutov
  0 siblings, 0 replies; 8+ messages in thread
From: Dmitry Gutov @ 2016-02-23 10:14 UTC (permalink / raw)
  To: Lars Ingebrigtsen, Jackson Hamilton; +Cc: 21799-done

On 02/23/2016 07:15 AM, Lars Ingebrigtsen wrote:

> Looks good to me, I think, but I think it should probably be separated
> out into its own file: jsx-mode.el.

Sorry, we've already applied it and forgot to close the bug.

Calling it jsx-mode.el might be suboptimal due to the conflict: 
https://github.com/jsx/jsx-mode.el (and that one's for a different JSX).

> Also, I can't find your name in the Emacs copyright assignment file.

It's there, as "Jackson Ray Hamilton".





^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2016-02-23 10:14 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-10-31  9:37 bug#21799: Requesting review for change to js.el Jackson Hamilton
2015-10-31 12:36 ` Dmitry Gutov
2015-10-31 16:53   ` Jackson Hamilton
2015-10-31 17:05     ` Dmitry Gutov
2015-10-31 17:53       ` Jackson Hamilton
2015-10-31 19:20         ` Dmitry Gutov
2016-02-23  5:15         ` Lars Ingebrigtsen
2016-02-23 10:14           ` Dmitry Gutov

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).