mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-22 07:09:54 +00:00
Add chained indentation to js-mode
Bug#20896 * lisp/progmodes/js.el (js-chain-indent): New variable. (js--skip-term-backward, js--skip-terms-backward) (js--chained-expression-p): New functions. (js--proper-indentation): Call js--chained-expression-p. * test/manual/indent/js-chain.js: New file. * test/manual/indent/js.js: Add (non-)chained indentation test.
This commit is contained in:
parent
b47f97218e
commit
502390822f
@ -552,6 +552,20 @@ don't indent the first one's initializer; otherwise, indent it.
|
||||
:safe 'symbolp
|
||||
:group 'js)
|
||||
|
||||
(defcustom js-chain-indent nil
|
||||
"Use \"chained\" indentation.
|
||||
Chained indentation applies when the current line starts with \".\".
|
||||
If the previous expression also contains a \".\" at the same level,
|
||||
then the \".\"s will be lined up:
|
||||
|
||||
let x = svg.mumble()
|
||||
.chained;
|
||||
"
|
||||
:version "26.1"
|
||||
:type 'boolean
|
||||
:safe 'booleanp
|
||||
:group 'js)
|
||||
|
||||
;;; KeyMap
|
||||
|
||||
(defvar js-mode-map
|
||||
@ -1808,6 +1822,63 @@ This performs fontification according to `js--class-styles'."
|
||||
(and (progn (backward-char)
|
||||
(not (looking-at "+\\+\\|--\\|/[/*]"))))))))))
|
||||
|
||||
(defun js--skip-term-backward ()
|
||||
"Skip a term before point; return t if a term was skipped."
|
||||
(let ((term-skipped nil))
|
||||
;; Skip backward over balanced parens.
|
||||
(let ((progress t))
|
||||
(while progress
|
||||
(setq progress nil)
|
||||
;; First skip whitespace.
|
||||
(skip-syntax-backward " ")
|
||||
;; Now if we're looking at closing paren, skip to the opener.
|
||||
;; This doesn't strictly follow JS syntax, in that we might
|
||||
;; skip something nonsensical like "()[]{}", but it is enough
|
||||
;; if it works ok for valid input.
|
||||
(when (memq (char-before) '(?\] ?\) ?\}))
|
||||
(setq progress t term-skipped t)
|
||||
(backward-list))))
|
||||
;; Maybe skip over a symbol.
|
||||
(let ((save-point (point)))
|
||||
(if (and (< (skip-syntax-backward "w_") 0)
|
||||
(looking-at js--name-re))
|
||||
;; Skipped.
|
||||
(progn
|
||||
(setq term-skipped t)
|
||||
(skip-syntax-backward " "))
|
||||
;; Did not skip, so restore point.
|
||||
(goto-char save-point)))
|
||||
(when (and term-skipped (> (point) (point-min)))
|
||||
(backward-char)
|
||||
(eq (char-after) ?.))))
|
||||
|
||||
(defun js--skip-terms-backward ()
|
||||
"Skip any number of terms backward.
|
||||
Move point to the earliest \".\" without changing paren levels.
|
||||
Returns t if successful, nil if no term was found."
|
||||
(when (js--skip-term-backward)
|
||||
;; Found at least one.
|
||||
(let ((last-point (point)))
|
||||
(while (js--skip-term-backward)
|
||||
(setq last-point (point)))
|
||||
(goto-char last-point)
|
||||
t)))
|
||||
|
||||
(defun js--chained-expression-p ()
|
||||
"A helper for js--proper-indentation that handles chained expressions.
|
||||
A chained expression is when the current line starts with '.' and the
|
||||
previous line also has a '.' expression.
|
||||
This function returns the indentation for the current line if it is
|
||||
a chained expression line; otherwise nil.
|
||||
This should only be called while point is at the start of the line's content,
|
||||
as determined by `back-to-indentation'."
|
||||
(when js-chain-indent
|
||||
(save-excursion
|
||||
(when (and (eq (char-after) ?.)
|
||||
(js--continued-expression-p)
|
||||
(js--find-newline-backward)
|
||||
(js--skip-terms-backward))
|
||||
(current-column)))))
|
||||
|
||||
(defun js--end-of-do-while-loop-p ()
|
||||
"Return non-nil if point is on the \"while\" of a do-while statement.
|
||||
@ -1984,6 +2055,7 @@ indentation is aligned to that column."
|
||||
;; At or after the first loop?
|
||||
(>= (point) beg)
|
||||
(js--array-comp-indentation bracket beg))))
|
||||
((js--chained-expression-p))
|
||||
((js--ctrl-statement-indentation))
|
||||
((js--multi-line-declaration-indentation))
|
||||
((nth 1 parse-status)
|
||||
|
29
test/manual/indent/js-chain.js
Normal file
29
test/manual/indent/js-chain.js
Normal file
@ -0,0 +1,29 @@
|
||||
// Normal chaining.
|
||||
let x = svg.mumble()
|
||||
.zzz;
|
||||
|
||||
// Chaining with an intervening line comment.
|
||||
let x = svg.mumble() // line comment
|
||||
.zzz;
|
||||
|
||||
// Chaining with multiple dots.
|
||||
let x = svg.selectAll().something()
|
||||
.zzz;
|
||||
|
||||
// Nested chaining.
|
||||
let x = svg.selectAll(d3.svg.something()
|
||||
.zzz);
|
||||
|
||||
// Nothing to chain to.
|
||||
let x = svg()
|
||||
.zzz;
|
||||
|
||||
// Nothing to chain to.
|
||||
let x = svg().mumble.x() + 73
|
||||
.zzz;
|
||||
|
||||
// Local Variables:
|
||||
// indent-tabs-mode: nil
|
||||
// js-chain-indent: t
|
||||
// js-indent-level: 2
|
||||
// End:
|
@ -124,6 +124,10 @@ if (x > 72 &&
|
||||
do_something();
|
||||
}
|
||||
|
||||
// Test that chaining doesn't happen when js-chain-indent is nil.
|
||||
let x = svg.mumble()
|
||||
.zzz;
|
||||
|
||||
// Local Variables:
|
||||
// indent-tabs-mode: nil
|
||||
// js-indent-level: 2
|
||||
|
Loading…
Reference in New Issue
Block a user