Add electric-indent actions to reindent (bug#79371)

* lisp/electric.el (electric-indent-actions)
(electric-indent-function): New user options.
(electric-indent-should-reindent-p, electric-indent--yank-advice)
(electric-indent-save-hook): New functions.
(electric-indent-post-self-insert-function): Use them.
This commit is contained in:
Elías Gabriel Pérez 2025-09-11 19:13:21 -06:00 committed by Stefan Monnier
parent 578aeedbe9
commit 2a782c8d28

View file

@ -192,6 +192,29 @@ Returns nil when we can't find this char."
;;; Electric indentation.
(defcustom electric-indent-actions nil
"List of actions to indent.
The valid elements of this list can be:
- yank: Indent the yanked text only if point is not in a string or
comment and yanked region is longer than 1 line.
- save: Indent the whole buffer before saving it.
The indentation will not happen when the major mode is unable to
reindent code reliably, such as in buffers where indentation is
significant."
:type '(repeat (choice (const :tag "After yanking" yank)
(const :tag "Before saving" before-save)))
:set (lambda (var val)
(set-default var val)
(when electric-indent-mode
(electric-indent-mode -1)
(electric-indent-mode +1)))
:safe (lambda (v)
(and (proper-list-p v)
(null (seq-filter (lambda (e) (not (symbolp e)) ) v))))
:version "31.1")
;; Autoloading variables is generally undesirable, but major modes
;; should usually set this variable by adding elements to the default
;; value, which only works well if the variable is preloaded.
@ -218,6 +241,50 @@ If `indent-line-function' is one of those, then `electric-indent-mode' will
not try to reindent lines. It is normally better to make the major
mode set `electric-indent-inhibit', but this can be used as a workaround.")
(defun electric-indent-can-reindent-p ()
"Return t if `electric-indent-mode' can performs reindentation."
(not (or (memq indent-line-function
electric-indent-functions-without-reindent)
electric-indent-inhibit)))
(defun electric-indent--yank-advice (fn &rest r)
(let ((p (point))
(end (line-beginning-position)))
(apply fn r)
(when (and electric-indent-mode
(memq 'yank electric-indent-actions)
(electric-indent-can-reindent-p)
;; Ensure yanked text is longer than 1 line
(> (point) p)
(not (= end (line-beginning-position))))
(undo-boundary)
(save-excursion
(with-demoted-errors "Error reindenting: %S"
(indent-region p (point)))))))
(defun electric-indent-save-hook ()
(when (and electric-indent-mode
;; Ensure this hook is called interactively
(memq real-this-command '(save-buffer basic-save-buffer))
(memq 'before-save electric-indent-actions)
(not buffer-read-only)
(electric-indent-can-reindent-p))
(save-excursion
(with-demoted-errors "Error reindenting: %S"
(indent-region (point-min) (point-max))))))
(defun electric-indent-toggle-indent-actions (enable)
"Enable the actions specified in `electric-indent-actions'."
(cond
((memq 'yank electric-indent-actions)
(if enable
(advice-add #'yank :around #'electric-indent--yank-advice)
(advice-remove #'yank #'electric-indent--yank-advice)))
((memq 'before-save electric-indent-actions)
(if enable
(add-hook 'before-save-hook #'electric-indent-save-hook)
(remove-hook 'before-save-hook #'electric-indent-save-hook)))))
(defun electric-indent-post-self-insert-function ()
"Function that `electric-indent-mode' adds to `post-self-insert-hook'.
This indents if the hook `electric-indent-functions' returns non-nil,
@ -256,10 +323,7 @@ or comment."
(when at-newline
(let ((before (copy-marker (1- pos) t)))
(save-excursion
(unless
(or (memq indent-line-function
electric-indent-functions-without-reindent)
electric-indent-inhibit)
(when (electric-indent-can-reindent-p)
;; Don't reindent the previous line if the
;; indentation function is not a real one.
(goto-char before)
@ -331,9 +395,13 @@ use `electric-indent-local-mode'."
(if electric-indent-mode (throw 'found t)))))
(remove-hook 'post-self-insert-hook
#'electric-indent-post-self-insert-function))
(add-hook 'post-self-insert-hook
#'electric-indent-post-self-insert-function
60)))
60))
;; Toggle the reindentation on actions
(electric-indent-toggle-indent-actions electric-indent-mode))
;;;###autoload
(define-minor-mode electric-indent-local-mode