:group 'js
:version "24.1")
-(defcustom js-auto-indent-flag t
- "Whether to automatically indent when typing punctuation characters.
-If non-nil, the characters {}();,: also indent the current line
-in Javascript mode."
- :type 'boolean
- :group 'js)
+(defcustom js-switch-indent-offset 0
+ "Number of additional spaces for indenting the contents of a switch block.
+The value must not be negative."
+ :type 'integer
+ :safe 'integerp
+ :group 'js
+ :version "24.4")
(defcustom js-flat-functions nil
"Treat nested functions as top-level functions in `js-mode'.
(list (cons 'c js-comment-lineup-func))))
(c-get-syntactic-indentation (list (cons symbol anchor)))))
+(defun js--same-line (pos)
+ (and (>= pos (point-at-bol))
+ (<= pos (point-at-eol))))
+
(defun js--multi-line-declaration-indentation ()
"Helper function for `js--proper-indentation'.
Return the proper indentation of the current line if it belongs to a declaration
(looking-at js--indent-operator-re)
(js--backward-syntactic-ws))
(not (eq (char-before) ?\;)))
- (and (>= pos (point-at-bol))
- (<= pos (point-at-eol)))))))
+ (js--same-line pos)))))
(condition-case nil
(backward-sexp)
(scan-error (setq at-opening-bracket t))))
(goto-char (match-end 0))
(1+ (current-column)))))))
+(defun js--indent-in-array-comp (bracket)
+ "Return non-nil if we think we're in an array comprehension.
+In particular, return the buffer position of the first `for' kwd."
+ (let ((end (point)))
+ (save-excursion
+ (goto-char bracket)
+ (when (looking-at "\\[")
+ (forward-char 1)
+ (js--forward-syntactic-ws)
+ (if (looking-at "[[{]")
+ (let (forward-sexp-function) ; Use Lisp version.
+ (forward-sexp) ; Skip destructuring form.
+ (js--forward-syntactic-ws)
+ (if (and (/= (char-after) ?,) ; Regular array.
+ (looking-at "for"))
+ (match-beginning 0)))
+ ;; To skip arbitrary expressions we need the parser,
+ ;; so we'll just guess at it.
+ (if (and (> end (point)) ; Not empty literal.
+ (re-search-forward "[^,]]* \\(for\\) " end t)
+ ;; Not inside comment or string literal.
+ (not (nth 8 (parse-partial-sexp bracket (point)))))
+ (match-beginning 1)))))))
+
+(defun js--array-comp-indentation (bracket for-kwd)
+ (if (js--same-line for-kwd)
+ ;; First continuation line.
+ (save-excursion
+ (goto-char bracket)
+ (forward-char 1)
+ (skip-chars-forward " \t")
+ (current-column))
+ (save-excursion
+ (goto-char for-kwd)
+ (current-column))))
+
(defun js--proper-indentation (parse-status)
"Return the proper indentation for the current line."
(save-excursion
(back-to-indentation)
- (cond ((nth 4 parse-status)
+ (cond ((nth 4 parse-status) ; inside comment
(js--get-c-offset 'c (nth 8 parse-status)))
- ((nth 8 parse-status) 0) ; inside string
- ((js--ctrl-statement-indentation))
- ((js--multi-line-declaration-indentation))
+ ((nth 3 parse-status) 0) ; inside string
((eq (char-after) ?#) 0)
((save-excursion (js--beginning-of-macro)) 4)
+ ;; Indent array comprehension continuation lines specially.
+ ((let ((bracket (nth 1 parse-status))
+ beg)
+ (and bracket
+ (not (js--same-line bracket))
+ (setq beg (js--indent-in-array-comp bracket))
+ ;; At or after the first loop?
+ (>= (point) beg)
+ (js--array-comp-indentation bracket beg))))
+ ((js--ctrl-statement-indentation))
+ ((js--multi-line-declaration-indentation))
((nth 1 parse-status)
;; A single closing paren/bracket should be indented at the
;; same level as the opening statement. Same goes for
;; "case" and "default".
- (let ((same-indent-p (looking-at
- "[]})]\\|\\_<case\\_>\\|\\_<default\\_>"))
+ (let ((same-indent-p (looking-at "[]})]"))
+ (switch-keyword-p (looking-at "default\\_>\\|case\\_>[^:]"))
(continued-expr-p (js--continued-expression-p)))
(goto-char (nth 1 parse-status)) ; go to the opening char
(if (looking-at "[({[]\\s-*\\(/[/*]\\|$\\)")
(skip-syntax-backward " ")
(when (eq (char-before) ?\)) (backward-list))
(back-to-indentation)
- (cond (same-indent-p
- (current-column))
- (continued-expr-p
- (+ (current-column) (* 2 js-indent-level)
- js-expr-indent-offset))
- (t
- (+ (current-column) js-indent-level
- (pcase (char-after (nth 1 parse-status))
- (?\( js-paren-indent-offset)
- (?\[ js-square-indent-offset)
- (?\{ js-curly-indent-offset))))))
+ (let* ((in-switch-p (unless same-indent-p
+ (looking-at "\\_<switch\\_>")))
+ (same-indent-p (or same-indent-p
+ (and switch-keyword-p
+ in-switch-p)))
+ (indent
+ (cond (same-indent-p
+ (current-column))
+ (continued-expr-p
+ (+ (current-column) (* 2 js-indent-level)
+ js-expr-indent-offset))
+ (t
+ (+ (current-column) js-indent-level
+ (pcase (char-after (nth 1 parse-status))
+ (?\( js-paren-indent-offset)
+ (?\[ js-square-indent-offset)
+ (?\{ js-curly-indent-offset)))))))
+ (if in-switch-p
+ (+ indent js-switch-indent-offset)
+ indent)))
;; If there is something following the opening
;; paren/bracket, everything else should be indented at
;; the same level.