That can be achieved by changing the
lisp-indent-function for emacs-lisp mode:
(lambda () (setq-local lisp-indent-function #'common-lisp-indent-function)))
lisp-mode.el in emacs source,
(defcustom lisp-indent-function 'lisp-indent-function
"A function to be called by `calculate-lisp-indent'.
It indents the arguments of a Lisp function call. This function
should accept two arguments: the indent-point, and the
`parse-partial-sexp' state at that position. One option for this
function is `common-lisp-indent-function'."
As @wasamasa mentioned in a comment to the question, @Fuco1 (on github.com) has modified the default
lisp-indent-function to fix the indentation of keywords (starting with
Emacs has provided the variable
lisp-indent-function for the user to choose what function to use for indentation in lisp modes.
Instead of overriding the original function definition, we can create our own function and assign the above variable to that function name.
In this example,
- Save the Fuco1 modded function as something like
Fuco1/lisp-indent-function in your emacs setup
- Make use of that function for indentation in
(lambda () (setq-local lisp-indent-function #'Fuco1/lisp-indent-function)))
The modded function is pasted below in the event the source referenced to github is lost.
(defun Fuco1/lisp-indent-function (indent-point state)
"This function is the normal value of the variable `lisp-indent-function'.
The function `calculate-lisp-indent' calls this to determine
if the arguments of a Lisp function call should be indented specially.
INDENT-POINT is the position at which the line being indented begins.
Point is located at the point to indent under (for default indentation);
STATE is the `parse-partial-sexp' state for that position.
If the current line is in a call to a Lisp function that has a non-nil
property `lisp-indent-function' (or the deprecated `lisp-indent-hook'),
it specifies how to indent. The property value can be:
* `defun', meaning indent `defun'-style
\(this is also the case if there is no property and the function
has a name that begins with \"def\", and three or more arguments);
* an integer N, meaning indent the first N arguments specially
(like ordinary function arguments), and then indent any further
arguments like a body;
* a function to call that returns the indentation (or nil).
`lisp-indent-function' calls this function with the same two arguments
that it itself received.
This function returns either the indentation to use, or nil if the
Lisp function does not specify a special indentation."
(let ((normal-indent (current-column))
(goto-char (1+ (elt state 1)))
(parse-partial-sexp (point) calculate-lisp-indent-last-sexp 0 t)
;; car of form doesn't seem to be a symbol, or is a keyword
((and (elt state 2)
(or (not (looking-at "\\sw\\|\\s_"))
(if (not (> (save-excursion (forward-line 1) (point))
(progn (goto-char calculate-lisp-indent-last-sexp)
calculate-lisp-indent-last-sexp 0 t)))
;; Indent under the list or under the first sexp on the same
;; line as calculate-lisp-indent-last-sexp. Note that first
;; thing on that line has to be complete sexp since we are
;; inside the innermost containing sexp.
(skip-syntax-forward " ")
(not (looking-at ":")))
(goto-char (+ 2 (elt state 1)))
(let ((function (buffer-substring (point)
(progn (forward-sexp 1) (point))))
(setq method (or (function-get (intern-soft function)
(get (intern-soft function) 'lisp-indent-hook)))
(cond ((or (eq method 'defun)
(and (null method)
(> (length function) 3)
(string-match "\\`def" function)))
(lisp-indent-defform state indent-point))
(lisp-indent-specform method state
(funcall method indent-point state))))))))