aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Gutov2013-12-08 18:08:45 +0200
committerDmitry Gutov2013-12-08 18:08:45 +0200
commit47e59c666a7599863725a04b6ed3f74ba01824b3 (patch)
tree2843998028019d76fa883bddc8055dc3e0cb792d
parent36291308801eefe5c04280c32d4b247bf7aa984e (diff)
downloademacs-47e59c666a7599863725a04b6ed3f74ba01824b3.tar.gz
emacs-47e59c666a7599863725a04b6ed3f74ba01824b3.zip
Port indentation code from js2-mode to js-mode
* lisp/progmodes/js.el (js-auto-indent-flag): Remove, was unused. (js-switch-indent-offset): New option. (js--proper-indentation): Use it. And handle the case when "default" is actually a key in an object literal. (js--same-line): New function. (js--multi-line-declaration-indentation): Use it. (js--indent-in-array-comp, js--array-comp-indentation): New functions. (js--proper-indentation): Use them, to handle array comprehension continuations.
-rw-r--r--etc/NEWS11
-rw-r--r--lisp/ChangeLog13
-rw-r--r--lisp/progmodes/js.el108
-rw-r--r--test/indent/js.js45
4 files changed, 152 insertions, 25 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 89fc9583759..8ee102487ae 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -661,6 +661,17 @@ whether it is safe to use Bash's --noediting option. These days
661 661
662*** Add more Ruby file types to `auto-mode-alist'. 662*** Add more Ruby file types to `auto-mode-alist'.
663 663
664** JS Mode
665
666*** Better indentation of multiple-variable declarations.
667If declaration spans several lines, variables on the following lines
668are lined up to the first one.
669
670*** We now recognize and better indent continuations in array
671comprehensions.
672
673*** New option `js-switch-indent-offset`.
674
664 675
665* New Modes and Packages in Emacs 24.4 676* New Modes and Packages in Emacs 24.4
666 677
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 4a18af44e21..7cc7f0b05f1 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,16 @@
12013-12-08 Dmitry Gutov <dgutov@yandex.ru>
2
3 * progmodes/js.el (js-auto-indent-flag): Remove, was unused.
4 (js-switch-indent-offset): New option.
5 (js--proper-indentation): Use it. And handle the case when
6 "default" is actually a key in an object literal.
7 (js--same-line): New function.
8 (js--multi-line-declaration-indentation): Use it.
9 (js--indent-in-array-comp, js--array-comp-indentation): New
10 functions.
11 (js--proper-indentation): Use them, to handle array comprehension
12 continuations.
13
12013-12-08 Leo Liu <sdl.web@gmail.com> 142013-12-08 Leo Liu <sdl.web@gmail.com>
2 15
3 * progmodes/flymake.el (flymake-highlight-line): Re-write. 16 * progmodes/flymake.el (flymake-highlight-line): Re-write.
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index 17c13607d71..572b59ecd9b 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -459,12 +459,13 @@ The value must be no less than minus `js-indent-level'."
459 :group 'js 459 :group 'js
460 :version "24.1") 460 :version "24.1")
461 461
462(defcustom js-auto-indent-flag t 462(defcustom js-switch-indent-offset 0
463 "Whether to automatically indent when typing punctuation characters. 463 "Number of additional spaces for indenting the contents of a switch block.
464If non-nil, the characters {}();,: also indent the current line 464The value must not be negative."
465in Javascript mode." 465 :type 'integer
466 :type 'boolean 466 :safe 'integerp
467 :group 'js) 467 :group 'js
468 :version "24.4")
468 469
469(defcustom js-flat-functions nil 470(defcustom js-flat-functions nil
470 "Treat nested functions as top-level functions in `js-mode'. 471 "Treat nested functions as top-level functions in `js-mode'.
@@ -1766,6 +1767,10 @@ nil."
1766 (list (cons 'c js-comment-lineup-func)))) 1767 (list (cons 'c js-comment-lineup-func))))
1767 (c-get-syntactic-indentation (list (cons symbol anchor))))) 1768 (c-get-syntactic-indentation (list (cons symbol anchor)))))
1768 1769
1770(defun js--same-line (pos)
1771 (and (>= pos (point-at-bol))
1772 (<= pos (point-at-eol))))
1773
1769(defun js--multi-line-declaration-indentation () 1774(defun js--multi-line-declaration-indentation ()
1770 "Helper function for `js--proper-indentation'. 1775 "Helper function for `js--proper-indentation'.
1771Return the proper indentation of the current line if it belongs to a declaration 1776Return the proper indentation of the current line if it belongs to a declaration
@@ -1788,8 +1793,7 @@ statement spanning multiple lines; otherwise, return nil."
1788 (looking-at js--indent-operator-re) 1793 (looking-at js--indent-operator-re)
1789 (js--backward-syntactic-ws)) 1794 (js--backward-syntactic-ws))
1790 (not (eq (char-before) ?\;))) 1795 (not (eq (char-before) ?\;)))
1791 (and (>= pos (point-at-bol)) 1796 (js--same-line pos)))))
1792 (<= pos (point-at-eol)))))))
1793 (condition-case nil 1797 (condition-case nil
1794 (backward-sexp) 1798 (backward-sexp)
1795 (scan-error (setq at-opening-bracket t)))) 1799 (scan-error (setq at-opening-bracket t))))
@@ -1797,23 +1801,68 @@ statement spanning multiple lines; otherwise, return nil."
1797 (goto-char (match-end 0)) 1801 (goto-char (match-end 0))
1798 (1+ (current-column))))))) 1802 (1+ (current-column)))))))
1799 1803
1804(defun js--indent-in-array-comp (bracket)
1805 "Return non-nil if we think we're in an array comprehension.
1806In particular, return the buffer position of the first `for' kwd."
1807 (let ((end (point)))
1808 (save-excursion
1809 (goto-char bracket)
1810 (when (looking-at "\\[")
1811 (forward-char 1)
1812 (js--forward-syntactic-ws)
1813 (if (looking-at "[[{]")
1814 (let (forward-sexp-function) ; Use Lisp version.
1815 (forward-sexp) ; Skip destructuring form.
1816 (js--forward-syntactic-ws)
1817 (if (and (/= (char-after) ?,) ; Regular array.
1818 (looking-at "for"))
1819 (match-beginning 0)))
1820 ;; To skip arbitrary expressions we need the parser,
1821 ;; so we'll just guess at it.
1822 (if (and (> end (point)) ; Not empty literal.
1823 (re-search-forward "[^,]]* \\(for\\) " end t)
1824 ;; Not inside comment or string literal.
1825 (not (nth 8 (parse-partial-sexp bracket (point)))))
1826 (match-beginning 1)))))))
1827
1828(defun js--array-comp-indentation (bracket for-kwd)
1829 (if (js--same-line for-kwd)
1830 ;; First continuation line.
1831 (save-excursion
1832 (goto-char bracket)
1833 (forward-char 1)
1834 (skip-chars-forward " \t")
1835 (current-column))
1836 (save-excursion
1837 (goto-char for-kwd)
1838 (current-column))))
1839
1800(defun js--proper-indentation (parse-status) 1840(defun js--proper-indentation (parse-status)
1801 "Return the proper indentation for the current line." 1841 "Return the proper indentation for the current line."
1802 (save-excursion 1842 (save-excursion
1803 (back-to-indentation) 1843 (back-to-indentation)
1804 (cond ((nth 4 parse-status) 1844 (cond ((nth 4 parse-status) ; inside comment
1805 (js--get-c-offset 'c (nth 8 parse-status))) 1845 (js--get-c-offset 'c (nth 8 parse-status)))
1806 ((nth 8 parse-status) 0) ; inside string 1846 ((nth 3 parse-status) 0) ; inside string
1807 ((js--ctrl-statement-indentation))
1808 ((js--multi-line-declaration-indentation))
1809 ((eq (char-after) ?#) 0) 1847 ((eq (char-after) ?#) 0)
1810 ((save-excursion (js--beginning-of-macro)) 4) 1848 ((save-excursion (js--beginning-of-macro)) 4)
1849 ;; Indent array comprehension continuation lines specially.
1850 ((let ((bracket (nth 1 parse-status))
1851 beg)
1852 (and bracket
1853 (not (js--same-line bracket))
1854 (setq beg (js--indent-in-array-comp bracket))
1855 ;; At or after the first loop?
1856 (>= (point) beg)
1857 (js--array-comp-indentation bracket beg))))
1858 ((js--ctrl-statement-indentation))
1859 ((js--multi-line-declaration-indentation))
1811 ((nth 1 parse-status) 1860 ((nth 1 parse-status)
1812 ;; A single closing paren/bracket should be indented at the 1861 ;; A single closing paren/bracket should be indented at the
1813 ;; same level as the opening statement. Same goes for 1862 ;; same level as the opening statement. Same goes for
1814 ;; "case" and "default". 1863 ;; "case" and "default".
1815 (let ((same-indent-p (looking-at 1864 (let ((same-indent-p (looking-at "[]})]"))
1816 "[]})]\\|\\_<case\\_>\\|\\_<default\\_>")) 1865 (switch-keyword-p (looking-at "default\\_>\\|case\\_>[^:]"))
1817 (continued-expr-p (js--continued-expression-p))) 1866 (continued-expr-p (js--continued-expression-p)))
1818 (goto-char (nth 1 parse-status)) ; go to the opening char 1867 (goto-char (nth 1 parse-status)) ; go to the opening char
1819 (if (looking-at "[({[]\\s-*\\(/[/*]\\|$\\)") 1868 (if (looking-at "[({[]\\s-*\\(/[/*]\\|$\\)")
@@ -1821,17 +1870,26 @@ statement spanning multiple lines; otherwise, return nil."
1821 (skip-syntax-backward " ") 1870 (skip-syntax-backward " ")
1822 (when (eq (char-before) ?\)) (backward-list)) 1871 (when (eq (char-before) ?\)) (backward-list))
1823 (back-to-indentation) 1872 (back-to-indentation)
1824 (cond (same-indent-p 1873 (let* ((in-switch-p (unless same-indent-p
1825 (current-column)) 1874 (looking-at "\\_<switch\\_>")))
1826 (continued-expr-p 1875 (same-indent-p (or same-indent-p
1827 (+ (current-column) (* 2 js-indent-level) 1876 (and switch-keyword-p
1828 js-expr-indent-offset)) 1877 in-switch-p)))
1829 (t 1878 (indent
1830 (+ (current-column) js-indent-level 1879 (cond (same-indent-p
1831 (pcase (char-after (nth 1 parse-status)) 1880 (current-column))
1832 (?\( js-paren-indent-offset) 1881 (continued-expr-p
1833 (?\[ js-square-indent-offset) 1882 (+ (current-column) (* 2 js-indent-level)
1834 (?\{ js-curly-indent-offset)))))) 1883 js-expr-indent-offset))
1884 (t
1885 (+ (current-column) js-indent-level
1886 (pcase (char-after (nth 1 parse-status))
1887 (?\( js-paren-indent-offset)
1888 (?\[ js-square-indent-offset)
1889 (?\{ js-curly-indent-offset)))))))
1890 (if in-switch-p
1891 (+ indent js-switch-indent-offset)
1892 indent)))
1835 ;; If there is something following the opening 1893 ;; If there is something following the opening
1836 ;; paren/bracket, everything else should be indented at 1894 ;; paren/bracket, everything else should be indented at
1837 ;; the same level. 1895 ;; the same level.
diff --git a/test/indent/js.js b/test/indent/js.js
new file mode 100644
index 00000000000..d4167da3e96
--- /dev/null
+++ b/test/indent/js.js
@@ -0,0 +1,45 @@
1var a = 1;
2b = 2;
3
4let c = 1,
5 d = 2;
6
7var e = 100500,
8 + 1;
9
10var f = bar('/protocols/')
11baz();
12
13var h = 100500
141;
15
16const i = 1,
17 j = 2;
18
19var k = 1,
20 l = [
21 1, 2,
22 3, 4
23 ],
24 m = 5;
25
26var n = function() {
27 return 7;
28},
29 o = 8;
30
31foo(bar, function() {
32 return 2;
33});
34
35switch (b) {
36case "a":
37 2;
38default:
39 3;
40}
41
42var ;
43
44var evens = [e for each (e in range(0, 21))
45 if (ed % 2 == 0)];