branch: externals/transient commit 686b7ebc5f13f869807355da52c06f65a27c1a43 Author: Jonas Bernoulli <jo...@bernoul.li> Commit: Jonas Bernoulli <jo...@bernoul.li>
Fix handling of sub-prefix command that use the minibuffer When a suffix command used the minibuffer, then we have to suspend the transient's hooks and keymaps while doing so and `post-command-hook' is called twice, once before entering the minibuffer and then again when the command is actually done. On the first call we delay work until either the second call or until the minibuffer is exited abnormally. This also applies if the suffix command is itself a prefix command. A prefix command sets up the transient by calling `transient-setup' in its body. If that command uses the minibuffer then it does so before calling `transient-setup'. If the minibuffer is aborted, then the transient state is cleaned up using a function that `transient--delay-post-command' added to `minibuffer-exit-hook'. This case works reasonably but can be improved (see next commit). If the minibuffer is exited normally, then the transient state is adjusted by a function that `transient--delay-post-command' put on `transient--post-command-hook'. But before that happens `transient-setup' is called. That puts the normal function on `post-command-hook'. Then the sub-prefix command finishes and that hook function is called, which calls `transient--post-exit'. But then the hook function that was put on `transient--post-command-hook' is also called and it also calls `transient--post-exit'. If that second call was a noop that wouldn't be a huge deal but it is not. Now it calls `transient--stack-pop', causing a return to the outer prefix. Preventing that is easy. On the pre-minibuffer call to `transient--post-command' we can detect that the suffix is a sub-prefix and in that case we only delay work until the minibuffer is aborted (if it is aborted) but not until the `post-command-hook' is called when the command is actually done. Closes #187. --- lisp/transient.el | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/lisp/transient.el b/lisp/transient.el index 9b50ac86d0..6542ce44f6 100644 --- a/lisp/transient.el +++ b/lisp/transient.el @@ -2106,7 +2106,7 @@ value. Otherwise return CHILDREN as is." (add-hook 'post-command-hook 'transient--post-command-hook) -(defun transient--delay-post-command () +(defun transient--delay-post-command (&optional abort-only) (transient--debug 'delay-post-command) (let ((depth (minibuffer-depth)) (command this-command) @@ -2114,15 +2114,17 @@ value. Otherwise return CHILDREN as is." #'transient--post-exit #'transient--resume-override)) post-command abort-minibuffer) - (setq post-command - (lambda () "@transient--delay-post-command" - (let ((act (and (eq this-command command) - (not (eq (this-command-keys-vector) []))))) - (transient--debug 'post-command-hook "act: %s" act) - (when act - (remove-hook 'transient--post-command-hook post-command) - (remove-hook 'minibuffer-exit-hook abort-minibuffer) - (funcall delayed))))) + (unless abort-only + (setq post-command + (lambda () "@transient--delay-post-command" + (let ((act (and (eq this-command command) + (not (eq (this-command-keys-vector) []))))) + (transient--debug 'post-command-hook "act: %s" act) + (when act + (remove-hook 'transient--post-command-hook post-command) + (remove-hook 'minibuffer-exit-hook abort-minibuffer) + (funcall delayed))))) + (add-hook 'transient--post-command-hook post-command)) (setq abort-minibuffer (lambda () "@transient--delay-post-command" (let ((act (and (or (memq this-command transient--abort-commands) @@ -2135,7 +2137,6 @@ value. Otherwise return CHILDREN as is." (remove-hook 'transient--post-command-hook post-command) (remove-hook 'minibuffer-exit-hook abort-minibuffer) (funcall delayed))))) - (add-hook 'transient--post-command-hook post-command) (add-hook 'minibuffer-exit-hook abort-minibuffer))) (defun transient--post-command () @@ -2146,7 +2147,7 @@ value. Otherwise return CHILDREN as is." (= (minibuffer-depth) (1+ transient--minibuffer-depth))) (transient--suspend-override) - (transient--delay-post-command)) + (transient--delay-post-command (eq transient--exitp 'replace))) (transient--exitp (transient--post-exit)) ((eq this-command (oref transient--prefix command))) @@ -2164,7 +2165,10 @@ value. Otherwise return CHILDREN as is." (unless (and (eq transient--exitp 'replace) (or transient--prefix ;; The current command could act as a prefix, - ;; but decided not to call `transient-setup'. + ;; but decided not to call `transient-setup', + ;; or it is prevented from doing so because it + ;; uses the minibuffer and the user aborted + ;; that. (prog1 nil (transient--stack-zap)))) (remove-hook 'pre-command-hook #'transient--pre-command) (remove-hook 'post-command-hook #'transient--post-command))