From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Juri Linkov Newsgroups: gmane.emacs.bugs Subject: bug#51281: 28.0.60; repeat-mode issues Date: Wed, 20 Oct 2021 20:30:38 +0300 Organization: LINKOV.NET Message-ID: <87y26ny56p.fsf@mail.linkov.net> References: <87tuhdijk3.fsf@mail.linkov.net> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="31929"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (x86_64-pc-linux-gnu) To: 51281@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Wed Oct 20 19:58:01 2021 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mdFqi-00082j-Vl for geb-bug-gnu-emacs@m.gmane-mx.org; Wed, 20 Oct 2021 19:58:01 +0200 Original-Received: from localhost ([::1]:46384 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mdFqh-0007UG-0e for geb-bug-gnu-emacs@m.gmane-mx.org; Wed, 20 Oct 2021 13:57:59 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:38900) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mdFbG-0005Uw-Id for bug-gnu-emacs@gnu.org; Wed, 20 Oct 2021 13:42:04 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:43836) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1mdFbG-00035d-Aa for bug-gnu-emacs@gnu.org; Wed, 20 Oct 2021 13:42:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1mdFbG-0002K1-7T for bug-gnu-emacs@gnu.org; Wed, 20 Oct 2021 13:42:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Juri Linkov Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Wed, 20 Oct 2021 17:42:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51281 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch Original-Received: via spool by 51281-submit@debbugs.gnu.org id=B51281.16347516858844 (code B ref 51281); Wed, 20 Oct 2021 17:42:02 +0000 Original-Received: (at 51281) by debbugs.gnu.org; 20 Oct 2021 17:41:25 +0000 Original-Received: from localhost ([127.0.0.1]:55375 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mdFae-0002Ia-I0 for submit@debbugs.gnu.org; Wed, 20 Oct 2021 13:41:24 -0400 Original-Received: from relay3-d.mail.gandi.net ([217.70.183.195]:32945) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mdFab-0002II-Kc for 51281@debbugs.gnu.org; Wed, 20 Oct 2021 13:41:22 -0400 Original-Received: (Authenticated sender: juri@linkov.net) by relay3-d.mail.gandi.net (Postfix) with ESMTPSA id B8BBE6000C for <51281@debbugs.gnu.org>; Wed, 20 Oct 2021 17:41:14 +0000 (UTC) In-Reply-To: <87tuhdijk3.fsf@mail.linkov.net> (Juri Linkov's message of "Tue, 19 Oct 2021 10:12:20 +0300") X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:217701 Archived-At: --=-=-= Content-Type: text/plain > Currently there is a bug where the prefix arg changed for the repeatable > commands, is applied to the next non-repeatable command. For example: > > C-- C-x o o C-n > or > C-x o C-- o C-n Actually, this too confusing feature that allows changing prefix args during the repeating sequence increases code complexity enormously. For posterity I'll leave here the patch that completely supports it. But this feature will be removed (unless someone will ask to leave it): C-x } } C-1 C-2 } } C-3 C-4 } } Only this will remain: C-x } } C-1 C-2 C-x } } C-3 C-4 C-x } } --=-=-= Content-Type: text/x-diff Content-Disposition: inline; filename=repeat-prefix-arg.patch diff --git a/lisp/repeat.el b/lisp/repeat.el index ee9e14b515..47b080bc6c 100644 --- a/lisp/repeat.el +++ b/lisp/repeat.el @@ -390,7 +390,10 @@ repeat-mode See `describe-repeat-maps' for a list of all repeatable command." :global t :group 'convenience (if (not repeat-mode) - (remove-hook 'post-command-hook 'repeat-post-hook) + (progn + (remove-hook 'pre-command-hook 'repeat-pre-hook) + (remove-hook 'post-command-hook 'repeat-post-hook)) + (add-hook 'pre-command-hook 'repeat-pre-hook) (add-hook 'post-command-hook 'repeat-post-hook) (let* ((keymaps nil) (commands (all-completions @@ -402,51 +405,108 @@ repeat-mode (length commands) (length (delete-dups keymaps)))))) +(defun repeat-map () + "Return a transient map for keys repeatable after the current command." + (let ((rep-map (or repeat-map + (and (symbolp real-this-command) + (get real-this-command 'repeat-map))))) + (when rep-map + (when (and (symbolp rep-map) (boundp rep-map)) + (setq rep-map (symbol-value rep-map))) + rep-map))) + +(defvar repeat-last-prefix-command nil) + +(defun repeat-check-map (map) + "Decides whether MAP can be used for the next command. +Can contain more conditions." + (and map + ;; Avoid using repeatable keys when a minibuffer prompt pops up. + ;; FIXME: Instead of disallowing repeatable keys in the minibuffer, + ;; it would be better to detect when `minibuffer-depth' changes + ;; during a repeatable sequence, but this is impossible to do + ;; when a repeatable command that activates own minibuffer + ;; was called from the minibuffer, e.g. `M-x repeatable-command RET' + ;; where in `exit-minibuffer' (bound to RET) minibuffer-depth is 1, + ;; and if repeatable-command uses the minibuffer, it's also 1. + (zerop (minibuffer-depth)) + (or + ;; Allow prefix commands change `prefix-arg' for next repeatable + ;; commands, i.e. don't disable transient map on such sequence + ;; `C-x } C-1 C-2 }' that changes window enlargement step to 12. + (and repeat-keep-prefix + (or (memq this-command + '(universal-argument universal-argument-more + digit-argument negative-argument)) + prefix-arg)) + ;; Exit when the last char is not among repeatable keys, + ;; so e.g. `C-x u u' repeats undo, whereas `C-/ u' doesn't. + (lookup-key map (vector last-nonmenu-event))))) + +(defun repeat-pre-hook () + "Function run before commands to handle repeatable keys." + ;; Reset prefix-arg before the next non-repeatable command, + ;; e.g. `C-- C-x } } C-n' or `C-x } C-- } C-n', so `C-n' + ;; should not use `prefix-arg' to go in opposite direction. + (when (and repeat-mode repeat-keep-prefix prefix-arg repeat-in-progress) + (if (not (memq this-command + '(universal-argument universal-argument-more + digit-argument negative-argument))) + (let ((map (repeat-map))) + (if (repeat-check-map map) + ;; Optimize to use less logic in the function `repeat-map'. + ;; When called again from `repeat-post-hook' it will use + ;; the variable `repeat-map'. + (setq repeat-map map) + ;; When `repeat-post-hook' will exit the repeatable sequence, + ;; this means the current command is not repeatable, + ;; so reset `prefix-arg' enabled for repeatable commands only. + (setq prefix-arg nil))) + (unless (memq repeat-last-prefix-command + '(universal-argument universal-argument-more + digit-argument negative-argument)) + (setq prefix-arg nil))) + (setq repeat-last-prefix-command this-command))) + (defun repeat-post-hook () "Function run after commands to set transient keymap for repeatable keys." (let ((was-in-progress repeat-in-progress)) (setq repeat-in-progress nil) - (when repeat-mode - (let ((rep-map (or repeat-map - (and (symbolp real-this-command) - (get real-this-command 'repeat-map))))) - (when rep-map - (when (boundp rep-map) - (setq rep-map (symbol-value rep-map))) - (let ((map (copy-keymap rep-map))) - ;; Exit when the last char is not among repeatable keys, - ;; so e.g. `C-x u u' repeats undo, whereas `C-/ u' doesn't. - (when (and (zerop (minibuffer-depth)) ; avoid remapping in prompts - (or (lookup-key map (this-command-keys-vector)) - prefix-arg)) + (let ((map (when repeat-mode (repeat-map)))) + (when (repeat-check-map map) - ;; Messaging - (unless prefix-arg - (funcall repeat-echo-function map)) + ;; Messaging + (unless prefix-arg ;; Don't overwrite prefix arg echo + (funcall repeat-echo-function map)) - ;; Adding an exit key - (when repeat-exit-key - (define-key map repeat-exit-key 'ignore)) + ;; Adding an exit key + (when repeat-exit-key + (setq map (copy-keymap map)) + (define-key map repeat-exit-key 'ignore)) - (when (and repeat-keep-prefix (not prefix-arg)) - (setq prefix-arg current-prefix-arg)) + ;; When the current command is not one of commands + ;; that set `prefix-arg' then keep the current prefix arg + ;; for the next command via `prefix-arg'. + (when (and repeat-keep-prefix + (not prefix-arg)) + (setq prefix-arg current-prefix-arg)) - (setq repeat-in-progress t) - (let ((exitfun (set-transient-map map))) + (setq repeat-in-progress t) + (let ((exitfun (set-transient-map map))) - (when repeat-exit-timer - (cancel-timer repeat-exit-timer) - (setq repeat-exit-timer nil)) + (when repeat-exit-timer + (cancel-timer repeat-exit-timer) + (setq repeat-exit-timer nil)) - (when repeat-exit-timeout - (setq repeat-exit-timer - (run-with-idle-timer - repeat-exit-timeout nil - (lambda () - (setq repeat-in-progress nil) - (funcall exitfun) - (funcall repeat-echo-function nil))))))))))) + (when repeat-exit-timeout + (setq repeat-exit-timer + (run-with-idle-timer + repeat-exit-timeout nil + (lambda () + (setq repeat-in-progress nil) + (funcall exitfun) + (funcall repeat-echo-function nil)))))))) (setq repeat-map nil) (when (and was-in-progress (not repeat-in-progress)) --=-=-=--