Emacs
JavaScript

Emacs js-mode のインデントカスタマイズ

More than 3 years have passed since last update.

Emacs の js-mode はデフォルトではメソッドチェーンや関数合成を多用しているとインデントがやや過剰気味です。

const x = [3, 2, 1]

.map(v => v * 2)
.sort();

test(x,
y,
z);

これを調整して以下のようなインデントになるようにします。

const x = [3, 2, 1]

.map(v => v * 2)
.sort();

test(x,
y,
z);

カスタマイズ変数による調整があまり細かくできないので、インデントの計算を行っている関数 js--proper-indentation を改造します。

(defun js--proper-indentation (parse-status)

"Return the proper indentation for the current line."
(save-excursion
(back-to-indentation)
(cond ((nth 4 parse-status) ; inside comment
(js--get-c-offset 'c (nth 8 parse-status)))
((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 "[]})]"))
(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-*\\(/[/*]\\|$\\)")
(progn ; nothing following the opening paren/bracket
(skip-syntax-backward " ")
(when (eq (char-before) ?\)) (backward-list))
(back-to-indentation)
(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)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; オリジナルの開きカッコを基準にしたインデントから
;; js-indent-level を参照した単純なインデントへ
(back-to-indentation)
(if same-indent-p
(current-column)
(+ (current-column) js-indent-level)))))

((js--continued-expression-p)
(+ js-indent-level js-expr-indent-offset))
(t 0))))