From 9bd3a85ca88515f69d89a6ecadca6e6708dbcd2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Thu, 22 Nov 2018 21:42:29 +0000 Subject: [PATCH 1/2] Really protect against unwanted indentation after undo When I am undoing changes to a region I really want the changes to be undone verbatim, that is, I want the buffer's contents to be like they were before the change that I want to undo occured. This is the very definition of undo. It is probably the rationale for giving undo special treatment in aggressive-indent--internal-dont-indent-if in the first place. It means that the undo command won't immediately cause reindentation. But it doesn't fix the whole problem, because changes performed by undo itself are still recorded into aggressive-indent--changed-list and the very next command, be it a move or an edit somewhere else, will still cause those regions to be indented. Among other things, it's impossible in practice to use `undo' to undo an aggressive indent of a region. The proposed fix checks adds a function to the post-command hook to check for aggressive-indent-protected-commands and clear the change list if the current command is in that list. This is safe if those changes can only have been performed by the command whose auto-indentation effects we want to prevent. * aggressive-indent.el (aggressive-indent--keep-track-of-changes): Check undo-in-progress. * aggressive-indent.el (aggressive-indent--internal-dont-indent-if): Remove check of aggressive-indent-protected-commands and undo-in-progress. (aggressive-indent--post-command): New helper. (aggressive-indent-mode): Put aggressive-indent--post-command in post-command-hook and remove it when exiting minor mode. --- aggressive-indent.el | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/aggressive-indent.el b/aggressive-indent.el index c467db8..b53e10e 100644 --- a/aggressive-indent.el +++ b/aggressive-indent.el @@ -167,11 +167,9 @@ change." ;;; Preventing indentation (defconst aggressive-indent--internal-dont-indent-if - '((memq last-command aggressive-indent-protected-commands) - (memq this-command aggressive-indent-protected-current-commands) + '((memq this-command aggressive-indent-protected-current-commands) (region-active-p) buffer-read-only - undo-in-progress (null (buffer-modified-p)) (and (boundp 'smerge-mode) smerge-mode) (equal (buffer-name) "*ediff-merge*") @@ -471,6 +469,15 @@ If BODY finishes, `while-no-input' returns whatever value BODY produced." (when (timerp aggressive-indent--idle-timer) (cancel-timer aggressive-indent--idle-timer))))) +(defun aggressive-indent--post-command () + "Hook run after every command while in `aggressive-indent-mode'. + +Clears `aggressive-indent--changed-list' iff the current +command (the one that's now finished) lives in +`aggressive-indent-protected-commands'." + (when (memq this-command aggressive-indent-protected-commands) + (setq aggressive-indent--changed-list nil))) + (defun aggressive-indent--keep-track-of-changes (l r &rest _) "Store the limits (L and R) of each change in the buffer." (when aggressive-indent-mode @@ -509,14 +516,15 @@ If BODY finishes, `while-no-input' returns whatever value BODY produced." (aggressive-indent--local-electric t)) (add-hook 'after-change-functions #'aggressive-indent--keep-track-of-changes nil 'local) (add-hook 'after-revert-hook #'aggressive-indent--clear-change-list nil 'local) - (add-hook 'before-save-hook #'aggressive-indent--proccess-changed-list-and-indent nil 'local)) + (add-hook 'before-save-hook #'aggressive-indent--proccess-changed-list-and-indent nil 'local) + (add-hook 'post-command-hook #'aggressive-indent--post-command nil 'local)) ;; Clean the hooks (when (timerp aggressive-indent--idle-timer) (cancel-timer aggressive-indent--idle-timer)) (remove-hook 'after-change-functions #'aggressive-indent--keep-track-of-changes 'local) (remove-hook 'after-revert-hook #'aggressive-indent--clear-change-list 'local) (remove-hook 'before-save-hook #'aggressive-indent--proccess-changed-list-and-indent 'local) - (remove-hook 'post-command-hook #'aggressive-indent--softly-indent-defun 'local))) + (remove-hook 'post-command-hook #'aggressive-indent--post-command 'local))) (defun aggressive-indent--local-electric (on) "Turn variable `electric-indent-mode' on or off locally, as per boolean ON." From 3f3add41ef4e6a0b287d4071a6d55102466a0c99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Thu, 22 Nov 2018 21:58:23 +0000 Subject: [PATCH 2/2] Be slightly more careful before clearing the changes list * aggressive-indent.el (aggressive-indent--pre-command-change-head): New variable. (aggressive-indent--pre-command): New function. (aggressive-indent-mode): Add aggressive-indent--pre-command to pre-command-hook and remove it when exiting minor mode. --- aggressive-indent.el | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/aggressive-indent.el b/aggressive-indent.el index b53e10e..7980d64 100644 --- a/aggressive-indent.el +++ b/aggressive-indent.el @@ -469,6 +469,16 @@ If BODY finishes, `while-no-input' returns whatever value BODY produced." (when (timerp aggressive-indent--idle-timer) (cancel-timer aggressive-indent--idle-timer))))) +(defvar aggressive-indent--pre-command-change-head nil) + +(defun aggressive-indent--pre-command () + "Hook run before every command while in `aggressive-indent-mode'. + +Save the most recent element of +`aggressive-indent--changed-list'." + (setq aggressive-indent--pre-command-change-head + (car aggressive-indent--changed-list))) + (defun aggressive-indent--post-command () "Hook run after every command while in `aggressive-indent-mode'. @@ -476,7 +486,8 @@ Clears `aggressive-indent--changed-list' iff the current command (the one that's now finished) lives in `aggressive-indent-protected-commands'." (when (memq this-command aggressive-indent-protected-commands) - (setq aggressive-indent--changed-list nil))) + (while (not (eq aggressive-indent--pre-command-change-head + (pop aggressive-indent--changed-list)))))) (defun aggressive-indent--keep-track-of-changes (l r &rest _) "Store the limits (L and R) of each change in the buffer." @@ -517,13 +528,15 @@ command (the one that's now finished) lives in (add-hook 'after-change-functions #'aggressive-indent--keep-track-of-changes nil 'local) (add-hook 'after-revert-hook #'aggressive-indent--clear-change-list nil 'local) (add-hook 'before-save-hook #'aggressive-indent--proccess-changed-list-and-indent nil 'local) - (add-hook 'post-command-hook #'aggressive-indent--post-command nil 'local)) + (add-hook 'post-command-hook #'aggressive-indent--post-command nil 'local) + (add-hook 'pre-command-hook #'aggressive-indent--pre-command nil 'local)) ;; Clean the hooks (when (timerp aggressive-indent--idle-timer) (cancel-timer aggressive-indent--idle-timer)) (remove-hook 'after-change-functions #'aggressive-indent--keep-track-of-changes 'local) (remove-hook 'after-revert-hook #'aggressive-indent--clear-change-list 'local) (remove-hook 'before-save-hook #'aggressive-indent--proccess-changed-list-and-indent 'local) + (remove-hook 'pre-command-hook #'aggressive-indent--pre-command 'local) (remove-hook 'post-command-hook #'aggressive-indent--post-command 'local))) (defun aggressive-indent--local-electric (on)