From 933e0ab4b0d583b81b8624def414b7895987927b Mon Sep 17 00:00:00 2001 From: Jackson Ray Hamilton Date: Sat, 7 Mar 2015 18:01:05 -0800 Subject: [PATCH] New indentation option for js-mode * lisp/progmodes/js.el (js--proper-indentation): Add new custom option `js-indent-first-initialiser' and a function to utilize it, `js--maybe-goto-declaration-keyword-end'. * test/indent/js.js: Add local variables. * test/indent/js-indent-first-initialiser-t.js: New test for `js-indent-first-initialiser'. * test/indent/js-indent-first-initialiser-dynamic.js: New test for `js-indent-first-initialiser'. --- lisp/ChangeLog | 14 ++++ lisp/progmodes/js.el | 75 +++++++++++++++++++ .../js-indent-first-initialiser-dynamic.js | 30 ++++++++ test/indent/js-indent-first-initialiser-t.js | 21 ++++++ test/indent/js.js | 7 +- 5 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 test/indent/js-indent-first-initialiser-dynamic.js create mode 100644 test/indent/js-indent-first-initialiser-t.js diff --git a/lisp/ChangeLog b/lisp/ChangeLog index c25f4efcdd0..c7cf53df5e0 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,17 @@ +2015-03-10 Jackson Ray Hamilton + + * lisp/progmodes/js.el (js--proper-indentation): Add new custom + option `js-indent-first-initialiser' and a function to utilize it, + `js--maybe-goto-declaration-keyword-end'. + + * test/indent/js.js: Add local variables. + + * test/indent/js-indent-first-initialiser-t.js: New test for + `js-indent-first-initialiser'. + + * test/indent/js-indent-first-initialiser-dynamic.js: New test for + `js-indent-first-initialiser'. + 2015-03-10 Thomas Fitzsimmons * net/ldap.el (ldap-attribute-syntaxes-alist): Add LDAP attributes diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el index d7712e4c49e..27e67bb77c1 100644 --- a/lisp/progmodes/js.el +++ b/lisp/progmodes/js.el @@ -509,6 +509,50 @@ getting timeout messages." :type 'integer :group 'js) +(defcustom js-indent-first-initialiser nil + "Specially indent the first variable declaration's initialiser +in variable statements. + +Normally, the first declaration's initialiser is unindented, and +subsequent declarations have their identifiers lined up against +the first: + + var o = { + foo: 3 + }; + + var o = { + foo: 3 + }, + bar = 2; + +When t, always indent the first declaration's initialiser by an +additional level: + + var o = { + foo: 3 + }; + + var o = { + foo: 3 + }, + bar = 2; + +When `dynamic', if there is only one declaration, don't indent +the first one's initialiser; otherwise, indent it. + + var o = { + foo: 3 + }; + + var o = { + foo: 3 + }, + bar = 2;" + :type 'boolean + :safe 'symbolp + :group 'js) + ;;; KeyMap (defvar js-mode-map @@ -1858,6 +1902,36 @@ In particular, return the buffer position of the first `for' kwd." (goto-char for-kwd) (current-column)))) +(defun js--maybe-goto-declaration-keyword-end (parse-status) + "Helper function for `js--proper-indentation'. +Depending on the value of `js-indent-first-initialiser', move +point to the end of a variable declaration keyword so that +indentation is aligned to that column." + (cond + ((eq js-indent-first-initialiser t) + (when (looking-at js--declaration-keyword-re) + (goto-char (1+ (match-end 0))))) + ((eq js-indent-first-initialiser 'dynamic) + (let ((bracket (nth 1 parse-status)) + declaration-keyword-end + at-closing-bracket-p + comma-p) + (when (looking-at js--declaration-keyword-re) + (setq declaration-keyword-end (match-end 0)) + (save-excursion + (goto-char bracket) + (setq at-closing-bracket-p + (condition-case nil + (progn + (forward-sexp) + t) + (error nil))) + (when at-closing-bracket-p + (while (forward-comment 1)) + (setq comma-p (looking-at-p ",")))) + (when comma-p + (goto-char (1+ declaration-keyword-end)))))))) + (defun js--proper-indentation (parse-status) "Return the proper indentation for the current line." (save-excursion @@ -1891,6 +1965,7 @@ In particular, return the buffer position of the first `for' kwd." (skip-syntax-backward " ") (when (eq (char-before) ?\)) (backward-list)) (back-to-indentation) + (js--maybe-goto-declaration-keyword-end parse-status) (let* ((in-switch-p (unless same-indent-p (looking-at "\\_"))) (same-indent-p (or same-indent-p diff --git a/test/indent/js-indent-first-initialiser-dynamic.js b/test/indent/js-indent-first-initialiser-dynamic.js new file mode 100644 index 00000000000..9c705dbeba9 --- /dev/null +++ b/test/indent/js-indent-first-initialiser-dynamic.js @@ -0,0 +1,30 @@ +var foo = function() { + return 7; +}; + +var foo = function() { + return 7; + }, + bar = 8; + +var foo = function() { + return 7; + }, + bar = function() { + return 8; + }; + +// Local Variables: +// indent-tabs-mode: nil +// js-indent-level: 2 +// js-indent-first-initialiser: dynamic +// End: + +// The following test intentionally produces a scan error and should +// be placed below all other tests to prevent awkward indentation. +// (It still thinks it's within the body of a function.) + +var foo = function() { + return 7; + , + bar = 8; diff --git a/test/indent/js-indent-first-initialiser-t.js b/test/indent/js-indent-first-initialiser-t.js new file mode 100644 index 00000000000..2f08527e5ff --- /dev/null +++ b/test/indent/js-indent-first-initialiser-t.js @@ -0,0 +1,21 @@ +var foo = function() { + return 7; + }; + +var foo = function() { + return 7; + }, + bar = 8; + +var foo = function() { + return 7; + }, + bar = function() { + return 8; + }; + +// Local Variables: +// indent-tabs-mode: nil +// js-indent-level: 2 +// js-indent-first-initialiser: t +// End: diff --git a/test/indent/js.js b/test/indent/js.js index f41849da284..ad7cb56a277 100644 --- a/test/indent/js.js +++ b/test/indent/js.js @@ -1,5 +1,3 @@ -// -*- js-indent-level: 2 -*- - var a = 1; b = 2; @@ -65,3 +63,8 @@ b += baz(`http://foo.bar/${tee}`) .qux(); + +// Local Variables: +// indent-tabs-mode: nil +// js-indent-level: 2 +// End: -- 2.39.2