diff options
| author | Dmitry Gutov | 2013-12-08 18:08:45 +0200 |
|---|---|---|
| committer | Dmitry Gutov | 2013-12-08 18:08:45 +0200 |
| commit | 47e59c666a7599863725a04b6ed3f74ba01824b3 (patch) | |
| tree | 2843998028019d76fa883bddc8055dc3e0cb792d | |
| parent | 36291308801eefe5c04280c32d4b247bf7aa984e (diff) | |
| download | emacs-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/NEWS | 11 | ||||
| -rw-r--r-- | lisp/ChangeLog | 13 | ||||
| -rw-r--r-- | lisp/progmodes/js.el | 108 | ||||
| -rw-r--r-- | test/indent/js.js | 45 |
4 files changed, 152 insertions, 25 deletions
| @@ -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. | ||
| 667 | If declaration spans several lines, variables on the following lines | ||
| 668 | are lined up to the first one. | ||
| 669 | |||
| 670 | *** We now recognize and better indent continuations in array | ||
| 671 | comprehensions. | ||
| 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 @@ | |||
| 1 | 2013-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 | |||
| 1 | 2013-12-08 Leo Liu <sdl.web@gmail.com> | 14 | 2013-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. |
| 464 | If non-nil, the characters {}();,: also indent the current line | 464 | The value must not be negative." |
| 465 | in 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'. |
| 1771 | Return the proper indentation of the current line if it belongs to a declaration | 1776 | Return 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. | ||
| 1806 | In 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 @@ | |||
| 1 | var a = 1; | ||
| 2 | b = 2; | ||
| 3 | |||
| 4 | let c = 1, | ||
| 5 | d = 2; | ||
| 6 | |||
| 7 | var e = 100500, | ||
| 8 | + 1; | ||
| 9 | |||
| 10 | var f = bar('/protocols/') | ||
| 11 | baz(); | ||
| 12 | |||
| 13 | var h = 100500 | ||
| 14 | 1; | ||
| 15 | |||
| 16 | const i = 1, | ||
| 17 | j = 2; | ||
| 18 | |||
| 19 | var k = 1, | ||
| 20 | l = [ | ||
| 21 | 1, 2, | ||
| 22 | 3, 4 | ||
| 23 | ], | ||
| 24 | m = 5; | ||
| 25 | |||
| 26 | var n = function() { | ||
| 27 | return 7; | ||
| 28 | }, | ||
| 29 | o = 8; | ||
| 30 | |||
| 31 | foo(bar, function() { | ||
| 32 | return 2; | ||
| 33 | }); | ||
| 34 | |||
| 35 | switch (b) { | ||
| 36 | case "a": | ||
| 37 | 2; | ||
| 38 | default: | ||
| 39 | 3; | ||
| 40 | } | ||
| 41 | |||
| 42 | var ; | ||
| 43 | |||
| 44 | var evens = [e for each (e in range(0, 21)) | ||
| 45 | if (ed % 2 == 0)]; | ||