GNU bug report logs - #61549
30.0.50; [PATCH] New keyboard macro counter functions

Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.

Package: emacs; Severity: wishlist; Reported by: Alex Bochannek <alex@HIDDEN>; Keywords: patch; dated Thu, 16 Feb 2023 08:19:02 UTC; Maintainer for emacs is bug-gnu-emacs@HIDDEN.
Severity set to 'wishlist' from 'normal' Request was from Stefan Kangas <stefankangas@HIDDEN> to control <at> debbugs.gnu.org. Full text available.

Message received at 61549 <at> debbugs.gnu.org:


Received: (at 61549) by debbugs.gnu.org; 12 Mar 2023 00:19:24 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Mar 11 19:19:24 2023
Received: from localhost ([127.0.0.1]:58830 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1pb9Qp-0004tZ-VK
	for submit <at> debbugs.gnu.org; Sat, 11 Mar 2023 19:19:24 -0500
Received: from mout.web.de ([212.227.15.4]:60653)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <michael_heerdegen@HIDDEN>) id 1pb9Ql-0004tI-Ju
 for 61549 <at> debbugs.gnu.org; Sat, 11 Mar 2023 19:19:22 -0500
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=web.de; s=s29768273;
 t=1678580347; i=michael_heerdegen@HIDDEN;
 bh=ixchzx4guvpMvqgGghwMM/Ha/YlJtrku5g9b6nWS4nw=;
 h=X-UI-Sender-Class:From:To:Cc:Subject:In-Reply-To:References:Date;
 b=BYFgTWnbXYQvQ7XaSMUwpHTs6rgQpsIgnGFjZhmCjINY9ToZgPZExIL18QJy2vGKZ
 kgUVANf/hstBhETyaylH34VA/FkaMyYlsoGWZoZnOlpjacZUrXCJg91rIUAhOQBrGU
 nBDw5OXTsVbB41bnrtaxzJfDr1bA4x8zQhhX04jrhOP1aEVKtcxUJUr1CbZWrIbaZS
 YiRibB7580GgOX/Lwqdt3jjSj4z8QzKUo+BtRRmYJQmHXfRsM8VRKSLao2ryeeRLbA
 Poy1hoymVrelKevOdtmf5619GJ60agNKAL4Mj6p2O2q1PLpeB9HopwzQD9uxoTj+Ii
 0YBL6DXdqYBjA==
X-UI-Sender-Class: 814a7b36-bfc1-4dae-8640-3722d8ec6cd6
Received: from drachen.dragon ([178.14.74.115]) by smtp.web.de (mrweb005
 [213.165.67.108]) with ESMTPSA (Nemesis) id 1N5CUb-1qZcOk2KZh-011BIz; Sun, 12
 Mar 2023 01:19:07 +0100
From: Michael Heerdegen <michael_heerdegen@HIDDEN>
To: Alex Bochannek <alex@HIDDEN>
Subject: Re: bug#61549: 30.0.50; [PATCH] New keyboard macro counter functions
In-Reply-To: <m2a60qwnwu.fsf@HIDDEN> (Alex Bochannek's message of "Sun, 
 05 Mar 2023 19:37:21 -0800")
References: <m2a61ef2i2.fsf@HIDDEN> <83sff41zgm.fsf@HIDDEN>
 <m2lekuo1os.fsf@HIDDEN> <83fsb2xhzp.fsf@HIDDEN>
 <m2a60qwnwu.fsf@HIDDEN>
Date: Sun, 12 Mar 2023 01:19:01 +0100
Message-ID: <87o7oyizyi.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain
X-Provags-ID: V03:K1:fGYHdUCm2WMBIRkST97Cd1v449JzfTS7l7BDjfsk3hQtMmqbyHI
 UKE18HqwSPNdh2M4a0v9oPTaI8CS+sK6Eil5XtsiHMoCzqcVuL37CgGx7gNVU8wKdNQS1gA
 xBe+KIojoXrlg13a4C7hAuQNgXzoMZOxBgdj2z1uEdkbILsnx995EOblzSqzUNuMPIUaR/p
 pTXxsRSXUw21dBQFmxKlw==
X-Spam-Flag: NO
UI-OutboundReport: notjunk:1;M01:P0:OSXaVCYcGTU=;6rO4UM2Hl5p2K1jm1sQbU6vxAxa
 MCBmnXS03gfU3vzhyNLYzkJiKMorCKlovpdIPxN4pQiVNAfFP7KZKqT3zG5Sw5XSAv0YB3k7S
 BTCkMGFUeHeYkF3cVxaVuvsYagAbP3S7z/z9LyKmT+gFTSMdVZ+PWzXaGbQdmvrDOMW9uacNd
 euA5swPHkjpx3ObD3vvSbH/07gnvjwPWSEYxXZJkbYa/ZozjrjSeGt2Ahsh4pT8EDDA8w7upi
 5ze4+fL3mLH6zBUdkjbyXYkgQDQlCWCh7mtK/6FBlJ0TwkKdhT1PbUMyMFZ2bjR9FlDU0NtG7
 MnynNeYhp/zc9aYNISggaT4xdnY83X3IsqtShMGja+mo5R2WNilvWkJ27L4tQvUqBiANnfoJl
 ho2j8hqu5jOUE/MC9iLJEvObRyGh/8pommKPjfJs7b0ZDHIhc34iDb5RPs8hmZcqpZfYazmX/
 JCMZG/l67QWNCaXOaIA7fv6uikEit+8i+JCvjffrUmnAxtvz3V83fTawSvg012AaWq/AhuC9S
 LJG2RjXAiDUd7QpScIsS2gGgaxUx1Gr/tHuS3qLC8AMJ3UZvpY68YxwWpRyw8h79yom+Fp27u
 TTW4xv7r6xR80yfy6hIVG1CyOdsh+U/CLXxZDhACBPKJonH67xe7dQTtvWrz+3QHygWIBbtYL
 ANMhvJWAygnxgqzM5mh7Mu8icTtDNM0iHf+vO8RvFtb3oxN5FI4vXXoZr+wAFsl9VPtazh7HC
 uipaCP6Ohb4NlLHw39JN2HEov5z8HE4Y1mBUVAPXNxRERmraLCei9EPMyjC3clLv+GO0BWhaK
 Rzr8tXnxkU8377R/U1W7Av4l5iDc5EQ7DhmZzJK7uWJumfGNYjLP4kYiX+LrxkqR1x3y8iRQa
 BVcT68PoDU4ok9lX2oM6jm+szMPUeVa3/zpETNlgJohqmPrWh8VI6wEVythp/RL63dFrBAs+4
 8AjSAovxzHdteAHVssSeN9cUViA=
X-Spam-Score: -0.7 (/)
X-Debbugs-Envelope-To: 61549
Cc: Eli Zaretskii <eliz@HIDDEN>, larsi@HIDDEN, 61549 <at> debbugs.gnu.org,
 monnier@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.7 (-)

Alex Bochannek <alex@HIDDEN> writes:

> diff --git a/doc/emacs/kmacro.texi b/doc/emacs/kmacro.texi

Two small notes from me in addition to Eli's review:

> +(defun kmacro-reg-add-counter-equal (&optional arg)
> +  "Increment `kmacro-counter' by ARG if the counter is equal to a
> +register's value.
> +ARG is the numeric prefix argument that defaults to one."
> +  (interactive "p")
> +  (let
> +      ((register (register-read-with-preview "Compare counter to register: ")))
> +    (kmacro-reg-add-counter '= register arg)))
                               ^^
I think we should function quote here; similar in most of the other
functions.

> +(defun kmacro-quit-counter-equal (&optional arg)
> +  "Quit the keyboard macro if `kmacro-counter' is equal to ARG.
> +ARG is the numeric prefix argument that defaults to zero."
> +  (interactive "P")
> +  (kmacro-quit-counter '= arg))

Is there a reason why the code starts to use the raw prefix here
(capital "P")?


TIA,

Michael.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#61549; Package emacs. Full text available.

Message received at 61549 <at> debbugs.gnu.org:


Received: (at 61549) by debbugs.gnu.org; 11 Mar 2023 08:49:53 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Mar 11 03:49:52 2023
Received: from localhost ([127.0.0.1]:56514 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1pauvI-0006ZM-D7
	for submit <at> debbugs.gnu.org; Sat, 11 Mar 2023 03:49:52 -0500
Received: from eggs.gnu.org ([209.51.188.92]:48704)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <eliz@HIDDEN>) id 1pauvF-0006Z9-Td
 for 61549 <at> debbugs.gnu.org; Sat, 11 Mar 2023 03:49:50 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1pauv9-0005K0-Qw; Sat, 11 Mar 2023 03:49:43 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date:
 mime-version; bh=356889eT8IXMLwUMkGT87udLLQRRjdz6FX8Z0KzZDV8=; b=n4oSl+yPQhTw
 VuWQMTmbNQXbzIbE74ez49h/TZQBUaXwQUOYOcFIFvUOvGgX3M+g9vacOzTfiQ6Po1gVc8rkIiYPP
 GW5laZmos2GwWQQx1XtnJplZwvU2VAFoJ7rb/NYBRFb4FqXWFFanpkr9ys8P+zIHvtLwn/5wK6+qz
 V4cCU69aInupoLMWlFNUfeHnUF9VvTRByDx171vE0a4IKglvZGpZ1ohFtettIXwy/kGnV2nceSEC5
 rFW2lKkQk2Dz9nOUt369CiWsOtKWL9A/dRHFFw/p8smMPUYVLby+pH6O4kTaSQtcMNcmXgof/vtFr
 8DK/3BCr2i19x4evZK7gLQ==;
Received: from [87.69.77.57] (helo=home-c4e4a596f7)
 by fencepost.gnu.org with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1pauv8-0006dZ-Rv; Sat, 11 Mar 2023 03:49:43 -0500
Date: Sat, 11 Mar 2023 10:49:27 +0200
Message-Id: <835yb7y8o8.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: Alex Bochannek <alex@HIDDEN>
In-Reply-To: <m2a60qwnwu.fsf@HIDDEN> (message from Alex Bochannek on
 Sun, 05 Mar 2023 19:37:21 -0800)
Subject: Re: bug#61549: 30.0.50; [PATCH] New keyboard macro counter functions
References: <m2a61ef2i2.fsf@HIDDEN> <83sff41zgm.fsf@HIDDEN>
 <m2lekuo1os.fsf@HIDDEN> <83fsb2xhzp.fsf@HIDDEN>
 <m2a60qwnwu.fsf@HIDDEN>
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 61549
Cc: larsi@HIDDEN, monnier@HIDDEN, 61549 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> From: Alex Bochannek <alex@HIDDEN>
> Cc: monnier@HIDDEN,  larsi@HIDDEN,  61549 <at> debbugs.gnu.org
> Date: Sun, 05 Mar 2023 19:37:21 -0800
> 
> Took me a little bit longer to find time to do this and I now have
> incorporated your feedback in the below patch. Thank you for your
> perspective on prefix, that made a lot of sense and I reworked that part
> of the code to be consistent with how it usually works. I was not aware
> that the interactive code `p' defaults to 1 in the absence of a prefix.
> I couldn't find a place where this is documented and it simplified the
> code.
> 
> I updated the docstrings as you suggested and even though checkdoc
> complained about the lack of a period on the first line, I figured it's
> better to keep below the line length limits.

Thanks, a few more comments below.

> Let me know if you would like to see any other changes, I always
> appreciate constructive feedback!
> 
> I am attaching the changes to:
>   kmacro.texi
>   kmacro.el
>   kmacro-tests.el
> 
> The changelog as well as NEWS and emacs.texi remain the same from my
> original message.

Stefan and Lars didn't respond, and I tend to think there's no need to
describe these functions in the Emacs user manual.  So for the next
iteration (which hopefully will be the last), please submit the patch
without the changes in the manual.  Also, please post all of the
other changes, including NEWS and the commit log message (and mention
the bug number in the latter).

> +(defun kmacro-reg-add-counter-equal (&optional arg)
> +  "Increment `kmacro-counter' by ARG if the counter is equal to a
> +register's value.

The first line of a doc string must be a complete sentence.

> +(defun kmacro-reg-add-counter-less (&optional arg)
> +  "Increment `kmacro-counter' by ARG if the counter is less than a
> +register's value.

Likewise here (and elsewhere in the patch).

> +ARG is the numeric prefix argument that defaults to one."
> +  (interactive "p")
> +  (let
> +      ((register (register-read-with-preview "Compare counter to register: ")))
> +    (kmacro-reg-add-counter '< register arg)))
> +
> +
> +(defun kmacro-reg-add-counter-greater (&optional arg)

I noticed that you always leave 2 empty lines between functions.  Is
that intentional?  We generally leave just one empty line.

> +(defun kmacro-reg-add-counter (pred register arg)
> +  "Increment `kmacro-counter' by ARG if predicate PRED returns
> +non-nil.
> +PRED is called with two arguments: `kmacro-counter' and REGISTER."
> +  (let ((register-val (get-register register)))
> +    (when (apply pred (list kmacro-counter register-val))
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To avoid consing a list here, would it be better to use funcall
instead of apply here?

> +(defun kmacro-quit-counter (pred &optional arg)
> +  "Quit the keyboard macro if predicate PRED returns non-nil.
> +PRED is called with two arguments: `kmacro-counter' and ARG."
> +  (when kmacro-initial-counter-value
> +    (setq kmacro-counter kmacro-initial-counter-value
> +	  kmacro-initial-counter-value nil))
> +  (let ((arg
> +	 (cond ((null arg) 0)
> +	       (t (prefix-numeric-value arg)))))
> +    (when (apply pred (list kmacro-counter arg))
> +      (keyboard-quit))))

Likewise here.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#61549; Package emacs. Full text available.

Message received at 61549 <at> debbugs.gnu.org:


Received: (at 61549) by debbugs.gnu.org; 6 Mar 2023 03:37:31 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sun Mar 05 22:37:31 2023
Received: from localhost ([127.0.0.1]:41061 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1pZ1fG-0004b8-By
	for submit <at> debbugs.gnu.org; Sun, 05 Mar 2023 22:37:31 -0500
Received: from ns.lapseofthought.com ([50.0.39.240]:61400
 helo=mail.lapseofthought.com)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <alex@HIDDEN>) id 1pZ1fC-0004ay-Dx
 for 61549 <at> debbugs.gnu.org; Sun, 05 Mar 2023 22:37:28 -0500
Received: from awb-mbp.local (c-73-92-249-246.hsd1.ca.comcast.net
 [73.92.249.246])
 (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
 (No client certificate requested)
 by mail.lapseofthought.com (Postfix) with ESMTPSA id 4PVPQp3N0Wz3pqNH;
 Sun,  5 Mar 2023 19:37:22 -0800 (PST)
Authentication-Results: ORIGINATING;
 auth=pass smtp.auth=alex smtp.mailfrom=alex@HIDDEN
From: Alex Bochannek <alex@HIDDEN>
To: Eli Zaretskii <eliz@HIDDEN>
Subject: Re: bug#61549: 30.0.50; [PATCH] New keyboard macro counter functions
In-Reply-To: <83fsb2xhzp.fsf@HIDDEN> (Eli Zaretskii's message of "Sun, 19 Feb
 2023 08:54:34 +0200")
References: <m2a61ef2i2.fsf@HIDDEN> <83sff41zgm.fsf@HIDDEN>
 <m2lekuo1os.fsf@HIDDEN> <83fsb2xhzp.fsf@HIDDEN>
Date: Sun, 05 Mar 2023 19:37:21 -0800
Message-ID: <m2a60qwnwu.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 61549
Cc: larsi@HIDDEN, monnier@HIDDEN, 61549 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

--=-=-=
Content-Type: text/plain

Eli,

Took me a little bit longer to find time to do this and I now have
incorporated your feedback in the below patch. Thank you for your
perspective on prefix, that made a lot of sense and I reworked that part
of the code to be consistent with how it usually works. I was not aware
that the interactive code `p' defaults to 1 in the absence of a prefix.
I couldn't find a place where this is documented and it simplified the
code.

I updated the docstrings as you suggested and even though checkdoc
complained about the lack of a period on the first line, I figured it's
better to keep below the line length limits.

Let me know if you would like to see any other changes, I always
appreciate constructive feedback!

I am attaching the changes to:
  kmacro.texi
  kmacro.el
  kmacro-tests.el

The changelog as well as NEWS and emacs.texi remain the same from my
original message.


--=-=-=
Content-Type: text/x-patch
Content-Disposition: inline

diff --git a/doc/emacs/kmacro.texi b/doc/emacs/kmacro.texi
index fc1402b489d..c3d74bb39ed 100644
--- a/doc/emacs/kmacro.texi
+++ b/doc/emacs/kmacro.texi
@@ -35,6 +35,7 @@ Keyboard Macros
 * Basic Keyboard Macro::     Defining and running keyboard macros.
 * Keyboard Macro Ring::      Where previous keyboard macros are saved.
 * Keyboard Macro Counter::   Inserting incrementing numbers in macros.
+* Advanced Macro Counter::   Advanced macro counter commands.
 * Keyboard Macro Query::     Making keyboard macros do different things each
                                time.
 * Save Keyboard Macro::      Giving keyboard macros names; saving them in
@@ -364,6 +365,123 @@ Keyboard Macro Counter
 keyboard macro counter.  @xref{Number Registers}.  For most purposes,
 it is simpler to use a keyboard macro counter.
 
+@node Advanced Macro Counter
+@section Advanced Macro Counter Commands
+
+  The counter associated with a keyboard macro is sufficient in most
+cases.  If additional counters are required for a macro, registers can
+be used and these advanced macro counter commands simplify the
+interaction between the two.  Additional commands are provided to
+terminate a macro after a predefined number of runs.
+
+
+@table @kbd
+@item C-x C-k C-r l
+Load the value of a number register into the macro counter
+(@code{kmacro-reg-load-counter}).
+@item C-x C-k C-r s
+Save the value of the macro counter to a number register
+(@code{kmacro-reg-save-counter}).
+@end table
+
+@table @kbd
+@item C-x C-k C-r a =
+Compare if the macro counter is equal to the value of a register and
+increment the counter if it is (@code{kmacro-reg-add-counter-equal}).
+@item C-x C-k C-r a <
+Compare if the macro counter is less than the value of a register and
+increment the counter if it is (@code{kmacro-reg-add-counter-less}).
+@item C-x C-k C-r a >
+Compare if the macro counter is greater than the value of a register
+and increment the counter if it is
+(@code{kmacro-reg-add-counter-greater}).
+@end table
+
+@table @kbd
+@item C-x C-k C-q =
+Compare if the macro counter is equal to the prefix and terminate the
+macro if it is (@code{kmacro-quit-counter-equal}).
+@item C-x C-k C-q <
+Compare if the macro counter is less than the prefix and terminate the
+macro if it is (@code{kmacro-quit-counter-less}).
+@item C-x C-k C-q >
+Compare if the macro counter is greater than the prefix and terminate
+the macro if it is (@code{kmacro-quit-counter-greater}).
+@end table
+
+@findex kmacro-reg-load-counter
+@kindex C-x C-k C-r l
+@findex kmacro-reg-save-counter
+@kindex C-x C-k C-r s
+  The command @kbd{C-x C-k C-r l} (@code{kmacro-reg-load-counter})
+prompts for the register name from which to load a number into the
+macro counter.  The command @kbd{C-x C-k C-r s}
+(@code{kmacro-reg-save-counter}) prompts for the register name into
+which to save the macro counter's value.  Both @kbd{C-x C-k C-r l}
+(@code{kmacro-reg-load-counter}) and @kbd{C-x C-k C-r s}
+(@code{kmacro-reg-save-counter}) show a preview of the registers by
+default.  @xref{Registers}.  Both commands can be used during or
+outside a keyboard macro definition.
+
+@findex kmacro-reg-add-counter-equal
+@kindex C-x C-k C-r a =
+@findex kmacro-reg-add-counter-less
+@kindex C-x C-k C-r a <
+@findex kmacro-reg-add-counter-greater
+@kindex C-x C-k C-r a >
+  The @kbd{C-x C-k C-r a =} (@code{kmacro-reg-add-counter-equal}),
+@kbd{C-x C-k C-r a <} (@code{kmacro-reg-add-counter-less}), and
+@kbd{C-x C-k C-r a >} (@code{kmacro-reg-add-counter-greater}) commands
+all follow the same pattern.  During keyboard macro definition, the
+command prompts for a register name (with preview by default), the
+contents of which will be compared with the macro counter's value.  If
+the counter is equal to (@code{=}), less than (@code{<}), or greater
+than (@code{>}) the number register's contents, the counter will be
+incremented by the numeric prefix or one if no prefix was given to the
+command.
+
+  For example,
+
+@example
+C-u 2 C-x C-k C-r a > N
+@end example
+
+@noindent
+compares the counter with the contents of register @code{N} and if the
+counter is greater than that, increases it by two.
+
+@findex kmacro-quit-counter-equal
+@kindex C-x C-k C-q =
+@findex kmacro-quit-counter-less
+@kindex C-x C-k C-q <
+@findex kmacro-quit-counter-greater
+@kindex C-x C-k C-q >
+  Finally, the @kbd{C-x C-k C-q =} (@code{kmacro-quit-counter-equal}),
+@kbd{C-x C-k C-q <} (@code{kmacro-quit-counter-less}), and @kbd{C-x
+C-k C-q >} (@code{kmacro-quit-counter-greater}) commands compare the
+macro counter with the prefix given and terminate the execution of the
+macro, if the comparison succeeds.  If no numeric prefix is given, the
+counter will be compared with zero.  The macro is terminated using the
+@code{keyboard-quit} function.  Using this command to exit from a
+macro that has been called by another macro is not supported, the
+entire executing macro is terminated.
+
+  The quit commands can be used to construct the equivalent of a
+@code{while}-loop. This example will stop after ten executions
+assuming the starting value for the macro counter is the default zero.
+
+@example
+C-u 10 C-x C-k C-q = C-x C-k C-i @key{RET}
+@end example
+
+  With the default counter value of zero, the macro called with a
+prefix of @code{C-u C-u} to execute sixteen times, will stop after ten
+iterations.  The counter values that have been inserted will be from 0
+to 9.  If the counter starts out a different value below ten, it will
+still stop at ten, because the counter does not actually count macro
+executions, but is incremented explicitly by the @code{C-x C-k C-i}
+command.
+
 @node Keyboard Macro Query
 @section Executing Macros with Variations
 

--=-=-=
Content-Type: text/x-patch
Content-Disposition: inline

diff --git a/lisp/kmacro.el b/lisp/kmacro.el
index 94d8794bd23..d0630a1998f 100644
--- a/lisp/kmacro.el
+++ b/lisp/kmacro.el
@@ -183,10 +183,18 @@ kmacro-keymap
   "C-l"  #'kmacro-call-ring-2nd-repeat
 
   ;; macro counter
-  "C-f"  #'kmacro-set-format
-  "C-c"  #'kmacro-set-counter
-  "C-i"  #'kmacro-insert-counter
-  "C-a"  #'kmacro-add-counter
+  "C-f"     #'kmacro-set-format
+  "C-c"     #'kmacro-set-counter
+  "C-i"     #'kmacro-insert-counter
+  "C-a"     #'kmacro-add-counter
+  "C-r l"   #'kmacro-reg-load-counter
+  "C-r s"   #'kmacro-reg-save-counter
+  "C-r a =" #'kmacro-reg-add-counter-equal
+  "C-r a <" #'kmacro-reg-add-counter-less
+  "C-r a >" #'kmacro-reg-add-counter-greater
+  "C-q ="   #'kmacro-quit-counter-equal
+  "C-q <"   #'kmacro-quit-counter-less
+  "C-q >"   #'kmacro-quit-counter-greater
 
   ;; macro editing
   "C-e"  #'kmacro-edit-macro-repeat
@@ -347,6 +355,96 @@ kmacro-add-counter
     (kmacro-display-counter)))
 
 
+(defun kmacro-reg-load-counter (register)
+  "Load the value of REGISTER into `kmacro-counter'."
+  (interactive
+   (list (register-read-with-preview "Load register to counter: ")))
+  (let ((register-val (get-register register)))
+    (when (numberp register-val)
+     (setq kmacro-counter register-val))))
+
+
+(defun kmacro-reg-save-counter (register)
+  "Save the value of `kmacro-counter' to REGISTER."
+  (interactive
+   (list (register-read-with-preview "Save counter to register: ")))
+  (set-register register kmacro-counter))
+
+
+(defun kmacro-reg-add-counter-equal (&optional arg)
+  "Increment `kmacro-counter' by ARG if the counter is equal to a
+register's value.
+ARG is the numeric prefix argument that defaults to one."
+  (interactive "p")
+  (let
+      ((register (register-read-with-preview "Compare counter to register: ")))
+    (kmacro-reg-add-counter '= register arg)))
+
+
+(defun kmacro-reg-add-counter-less (&optional arg)
+  "Increment `kmacro-counter' by ARG if the counter is less than a
+register's value.
+ARG is the numeric prefix argument that defaults to one."
+  (interactive "p")
+  (let
+      ((register (register-read-with-preview "Compare counter to register: ")))
+    (kmacro-reg-add-counter '< register arg)))
+
+
+(defun kmacro-reg-add-counter-greater (&optional arg)
+  "Increment `kmacro-counter' by ARG if the counter is greater than
+a register's value.
+ARG is the numeric prefix argument that defaults to one."
+  (interactive "p")
+  (let
+      ((register (register-read-with-preview "Compare counter to register: ")))
+    (kmacro-reg-add-counter '> register arg)))
+
+
+(defun kmacro-reg-add-counter (pred register arg)
+  "Increment `kmacro-counter' by ARG if predicate PRED returns
+non-nil.
+PRED is called with two arguments: `kmacro-counter' and REGISTER."
+  (let ((register-val (get-register register)))
+    (when (apply pred (list kmacro-counter register-val))
+      (setq current-prefix-arg nil)
+      (kmacro-add-counter arg))))
+
+
+(defun kmacro-quit-counter-equal (&optional arg)
+  "Quit the keyboard macro if `kmacro-counter' is equal to ARG.
+ARG is the numeric prefix argument that defaults to zero."
+  (interactive "P")
+  (kmacro-quit-counter '= arg))
+
+
+(defun kmacro-quit-counter-less (&optional arg)
+  "Quit the keyboard macro if `kmacro-counter' is less than ARG.
+ARG is the numeric prefix argument that defaults to zero."
+  (interactive "P")
+  (kmacro-quit-counter '< arg))
+
+
+(defun kmacro-quit-counter-greater (&optional arg)
+  "Quit the keyboard macro if `kmacro-counter' is greater than ARG.
+ARG is the numeric prefix argument that defaults to zero."
+    (interactive "P")
+    (kmacro-quit-counter '> arg))
+
+
+(defun kmacro-quit-counter (pred &optional arg)
+  "Quit the keyboard macro if predicate PRED returns non-nil.
+PRED is called with two arguments: `kmacro-counter' and ARG."
+  (when kmacro-initial-counter-value
+    (setq kmacro-counter kmacro-initial-counter-value
+	  kmacro-initial-counter-value nil))
+  (let ((arg
+	 (cond ((null arg) 0)
+	       (t (prefix-numeric-value arg)))))
+    (when (apply pred (list kmacro-counter arg))
+      (keyboard-quit))))
+
+
 (defun kmacro-loop-setup-function ()
   "Function called prior to each iteration of macro."
   ;; Restore macro counter format to initial format, so it is ok to change

--=-=-=
Content-Type: text/x-patch
Content-Disposition: inline

diff --git a/test/lisp/kmacro-tests.el b/test/lisp/kmacro-tests.el
index 551fd8b60fc..42ada9f4f94 100644
--- a/test/lisp/kmacro-tests.el
+++ b/test/lisp/kmacro-tests.el
@@ -275,6 +275,205 @@ kmacro-tests-start-insert-counter-appends-to-macro
     ;;  Verify that the recording state has changed.
     (should (equal defining-kbd-macro 'append))))
 
+
+(kmacro-tests-deftest kmacro-tests-test-reg-load ()
+  "`kmacro-reg-load-counter' loads the value of register into counter"
+  (set-register ?\C-r 4) ;; Should be safe as a register name
+  (kmacro-tests-simulate-command '(kmacro-set-counter 1))
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and increment counter
+                              "\C-x\C-k\C-i"
+                              "\C-x\C-k\C-i"
+                              ;; Load from register
+                              "\C-x\C-k\C-rl\C-r"
+                              ))
+  (kmacro-tests-should-insert "1245"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 2)))
+    (set-register ?\C-r nil))
+
+(kmacro-tests-deftest kmacro-tests-test-reg-save ()
+  "`kmacro-reg-save-counter' saves counter to register"
+  (set-register ?\C-r nil) ;; Should be safe as a register name
+  (kmacro-tests-simulate-command '(kmacro-set-counter 1))
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and increment counter
+                              "\C-x\C-k\C-i"
+                              ;; Save to register
+                              "\C-x\C-k\C-rs\C-r"
+                              ;; Add to counter
+                              "\C-u2\C-x\C-k\C-a"
+                              ;; Insert and increment counter
+                              "\C-x\C-k\C-i"
+                              ;; Insert register
+                              "\C-xri\C-r"
+                              ))
+  (kmacro-tests-should-insert "142586"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 2)))
+  (set-register ?\C-r nil))
+
+
+(kmacro-tests-deftest kmacro-tests-test-reg-add-counter-equal-01 ()
+  "`kmacro-reg-add-counter-equal' increments counter if equal to register"
+  (set-register ?\C-r 2) ;; Should be safe as a register name
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and increment counter
+                              "\C-x\C-k\C-i"
+                              ;; Increment counter if it matches
+                              "\C-x\C-k\C-ra=\C-r"
+                              ))
+  (kmacro-tests-should-insert "0134"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+  (set-register ?\C-r nil))
+
+(kmacro-tests-deftest kmacro-tests-test-reg-add-counter-equal-02 ()
+  "`kmacro-reg-add-counter-equal' increments counter if equal to register"
+  (set-register ?\C-r 2) ;; Should be safe as a register name
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and increment counter
+                              "\C-x\C-k\C-i"
+                              ;; Add two to counter if it matches
+                              "\C-u2\C-x\C-k\C-ra=\C-r"
+                              ))
+  (kmacro-tests-should-insert "0145"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+  (set-register ?\C-r nil))
+
+(kmacro-tests-deftest kmacro-tests-test-reg-add-counter-equal-03 ()
+  "`kmacro-reg-add-counter-equal' increments counter if equal to register"
+  (set-register ?\C-r 2) ;; Should be safe as a register name
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and increment counter
+                              "\C-x\C-k\C-i"
+                              ;; Add four to counter if it matches
+                              "\C-u\C-x\C-k\C-ra=\C-r"
+                              ))
+  (kmacro-tests-should-insert "0167"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+  (set-register ?\C-r nil))
+
+(kmacro-tests-deftest kmacro-tests-test-reg-add-counter-equal-04 ()
+  "`kmacro-reg-add-counter-equal' increments counter if equal to register"
+  (set-register ?\C-r 2) ;; Should be safe as a register name
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and increment counter
+                              "\C-x\C-k\C-i"
+                              ;; Decrement counter if it matches
+                              "\C-u-\C-x\C-k\C-ra=\C-r"
+                              ))
+  (kmacro-tests-should-insert "0111"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+  (set-register ?\C-r nil))
+
+(kmacro-tests-deftest kmacro-tests-test-reg-add-counter-less ()
+  "`kmacro-reg-add-counter-less' increments counter if less than register"
+  (set-register ?\C-r 6) ;; Should be safe as a register name
+  (kmacro-tests-simulate-command '(kmacro-set-counter 8))
+  (kmacro-tests-define-macro (vconcat
+                              ;; Decrement counter if it's
+                              ;; less than the register
+                              "\C-u-1\C-x\C-k\C-ra<\C-r"
+                              ;; Insert and decrement counter
+                              "\C-u-\C-x\C-k\C-i"
+                              ))
+  (kmacro-tests-should-insert "8764"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+    (set-register ?\C-r nil))
+
+(kmacro-tests-deftest kmacro-tests-test-reg-add-counter-greater ()
+  "`kmacro-reg-add-counter-greater' increments counter if greater than register"
+  (set-register ?\C-r 2) ;; Should be safe as a register name
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and increment counter
+                              "\C-x\C-k\C-i"
+                              ;; Increment counter if it's greater
+                              ;; than the register
+                              "\C-x\C-k\C-ra>\C-r"
+                              ))
+  (kmacro-tests-should-insert "0124"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+  (set-register ?\C-r nil))
+
+
+(kmacro-tests-deftest kmacro-tests-test-quit-counter-equal-01 ()
+  "`kmacro-quit-counter-equal' stops macro if counter is equal to prefix"
+  (kmacro-tests-simulate-command '(kmacro-set-counter 5))
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and decrement counter
+                              "\C-u-\C-x\C-k\C-i"
+                              ;; Stop if the counter is at 0
+                              "\C-x\C-k\C-q="
+                              ))
+  (kmacro-tests-should-insert "5432"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+  (should (condition-case abort
+              (should (= 1 kmacro-counter))
+              (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 1))
+            (quit abort))))
+
+(kmacro-tests-deftest kmacro-tests-test-quit-counter-equal-02 ()
+  "`kmacro-quit-counter-equal' stops macro if counter is equal to prefix"
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and increment counter
+                              "\C-x\C-k\C-i"
+                              ;; Stop if the counter is at 5
+                              "\C-u5\C-x\C-k\C-q="
+                              ))
+  (kmacro-tests-should-insert "0123"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+  (should (condition-case abort
+              (should (= 4 kmacro-counter))
+              (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 1))
+            (quit abort))))
+
+
+(kmacro-tests-deftest kmacro-tests-test-quit-counter-equal-03 ()
+  "`kmacro-quit-counter-equal' stops macro if counter is equal to prefix"
+  (kmacro-tests-simulate-command '(kmacro-set-counter 4))
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and decrement counter
+                              "\C-u-\C-x\C-k\C-i"
+                              ;; Stop if the counter is at -1
+                              "\C-u-\C-x\C-k\C-q="
+                              ))
+  (kmacro-tests-should-insert "4321"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+  (should (condition-case abort
+              (should (= 0 kmacro-counter))
+              (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 1))
+            (quit abort))))
+
+(kmacro-tests-deftest kmacro-tests-test-quit-counter-less ()
+  "`kmacro-quit-counter-less' stops macro if counter is less than prefix"
+  (kmacro-tests-simulate-command '(kmacro-set-counter 8))
+  (kmacro-tests-define-macro (vconcat
+                              ;; Stop if the counter is less than 5
+                              "\C-u5\C-x\C-k\C-q<"
+                              ;; Insert and decrement counter
+                              "\C-u-\C-x\C-k\C-i"
+                              ))
+  (kmacro-tests-should-insert "8765"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+  (should (condition-case abort
+              (should (= 4 kmacro-counter))
+              (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 1))
+            (quit abort))))
+
+(kmacro-tests-deftest kmacro-tests-test-quit-counter-greater ()
+  "`kmacro-quit-counter-greater' stops macro if counter is greater than prefix"
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and increment counter
+                              "\C-x\C-k\C-i"
+                              ;; Stop if the counter is greater than 4
+                              "\C-u4\C-x\C-k\C-q>"
+                              ))
+  (kmacro-tests-should-insert "0123"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+  (should (condition-case abort
+              (should (= 4 kmacro-counter))
+              (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 1))
+            (quit abort))))
+
+
 (kmacro-tests-deftest kmacro-tests-end-call-macro-prefix-args ()
   "kmacro-end-call-macro changes behavior based on prefix arg."
   ;; "Record" two macros.

--=-=-=
Content-Type: text/plain


Thanks!

-- 
Alex.

--=-=-=--




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#61549; Package emacs. Full text available.

Message received at 61549 <at> debbugs.gnu.org:


Received: (at 61549) by debbugs.gnu.org; 19 Feb 2023 06:54:39 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sun Feb 19 01:54:39 2023
Received: from localhost ([127.0.0.1]:45518 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1pTdap-0001Yd-1F
	for submit <at> debbugs.gnu.org; Sun, 19 Feb 2023 01:54:39 -0500
Received: from eggs.gnu.org ([209.51.188.92]:43380)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <eliz@HIDDEN>) id 1pTdam-0001YN-FW
 for 61549 <at> debbugs.gnu.org; Sun, 19 Feb 2023 01:54:37 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1pTdaf-0000WV-Vd; Sun, 19 Feb 2023 01:54:29 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date:
 mime-version; bh=cWYT632w7IWvQ1byClzrfK3niYeArufGQWvxDVkjctA=; b=MUxBmh4VUGjH
 ZX1vOCW2AeOYyAmolLAIqs+d3Uk+rL8c//0XitOrdVlU3dBysAX0+guUCNFrhiO9AtxXsTHsi4khZ
 aiU17ZByIy9J3SQmscopFXN9LRnG5TYMSF/trH1jelWRyhx1ecSGOrCTLFzYyCJLoZK/UjFDJ3oy/
 7rnE16AhLZPce+PYLL0eIlOmHDnwS+L5NqF5dqrXmoXbGxNAr3flEgiY1x+MSST3wv+c24+oLTVoT
 SaZVmHaVMbX1ytx2tX2o4JMlFdMknyVPB72hoOB+WVGx2XJRdnPv36TvSWBEpvHr4wzCnAbHDZc3i
 WbYSlo3AiuHwYyM0mdJ47Q==;
Received: from [87.69.77.57] (helo=home-c4e4a596f7)
 by fencepost.gnu.org with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1pTdaf-0001BG-AH; Sun, 19 Feb 2023 01:54:29 -0500
Date: Sun, 19 Feb 2023 08:54:34 +0200
Message-Id: <83fsb2xhzp.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: Alex Bochannek <alex@HIDDEN>
In-Reply-To: <m2lekuo1os.fsf@HIDDEN> (message from Alex Bochannek on
 Sat, 18 Feb 2023 17:59:15 -0800)
Subject: Re: bug#61549: 30.0.50; [PATCH] New keyboard macro counter functions
References: <m2a61ef2i2.fsf@HIDDEN> <83sff41zgm.fsf@HIDDEN>
 <m2lekuo1os.fsf@HIDDEN>
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 61549
Cc: larsi@HIDDEN, monnier@HIDDEN, 61549 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> From: Alex Bochannek <alex@HIDDEN>
> Cc: Stefan Monnier <monnier@HIDDEN>,  Lars Ingebrigtsen
>  <larsi@HIDDEN>,  61549 <at> debbugs.gnu.org
> Date: Sat, 18 Feb 2023 17:59:15 -0800
> 
> >> +  (let ((arg
> >> +	 (cond ((or (consp arg) (null arg)) 0)
> >> +	       ((eq '- arg) -1)
> >> +	       (t arg))))
> >
> > This seems to imply that ARG has meaning beyond what the above text
> > says.
> 
> I was struggling a bit with this one. On the one hand, I wanted the raw
> prefix because I didn't want `C-u' to turn into 4, on the other hand, I
> still wanted to let `C-u -' be interpreted as -1. Is there a better way
> to do this?

Why do you want C-u to be equivalent to "C-u 0"?  That's inconsistent,
and you already provide an easy way of supplying zero: by using no
prefix argument at all.

In any case, what I meant was that the processing is incompletely
described by the documentation.  And the documentation about the
effect of the prefix argument should be in the doc strings of the
commands, not in the doc string of this function, which is not
intended for interactive use.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#61549; Package emacs. Full text available.

Message received at 61549 <at> debbugs.gnu.org:


Received: (at 61549) by debbugs.gnu.org; 19 Feb 2023 01:59:21 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Feb 18 20:59:21 2023
Received: from localhost ([127.0.0.1]:45275 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1pTYz3-0001oy-EM
	for submit <at> debbugs.gnu.org; Sat, 18 Feb 2023 20:59:21 -0500
Received: from ns.lapseofthought.com ([50.0.39.240]:60085
 helo=mail.lapseofthought.com)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <alex@HIDDEN>) id 1pTYz1-0001op-97
 for 61549 <at> debbugs.gnu.org; Sat, 18 Feb 2023 20:59:20 -0500
Received: from awb-mbp.local (c-73-92-249-246.hsd1.ca.comcast.net
 [73.92.249.246])
 (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
 (No client certificate requested)
 by mail.lapseofthought.com (Postfix) with ESMTPSA id 4PK7yX0sK5z3pdxK;
 Sat, 18 Feb 2023 17:59:16 -0800 (PST)
Authentication-Results: ORIGINATING;
 auth=pass smtp.auth=alex smtp.mailfrom=alex@HIDDEN
From: Alex Bochannek <alex@HIDDEN>
To: Eli Zaretskii <eliz@HIDDEN>
Subject: Re: bug#61549: 30.0.50; [PATCH] New keyboard macro counter functions
In-Reply-To: <83sff41zgm.fsf@HIDDEN> (Eli Zaretskii's message of "Fri, 17 Feb
 2023 10:13:45 +0200")
References: <m2a61ef2i2.fsf@HIDDEN> <83sff41zgm.fsf@HIDDEN>
Date: Sat, 18 Feb 2023 17:59:15 -0800
Message-ID: <m2lekuo1os.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 61549
Cc: Lars Ingebrigtsen <larsi@HIDDEN>,
 Stefan Monnier <monnier@HIDDEN>, 61549 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Eli,

Thanks for all the doc string comments, I was not sure about them and I
don't think I knew about checkdoc. I should spend some more time with
Appendix D of the Elisp manual.

Eli Zaretskii <eliz@HIDDEN> writes:

>> +  (let ((arg
>> +	 (cond ((or (consp arg) (null arg)) 0)
>> +	       ((eq '- arg) -1)
>> +	       (t arg))))
>
> This seems to imply that ARG has meaning beyond what the above text
> says.

I was struggling a bit with this one. On the one hand, I wanted the raw
prefix because I didn't want `C-u' to turn into 4, on the other hand, I
still wanted to let `C-u -' be interpreted as -1. Is there a better way
to do this?

I am updating the doc strings and submit a new version in the next few
days.

Thanks for the review!

-- 
Alex.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#61549; Package emacs. Full text available.

Message received at 61549 <at> debbugs.gnu.org:


Received: (at 61549) by debbugs.gnu.org; 17 Feb 2023 08:14:00 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 17 03:14:00 2023
Received: from localhost ([127.0.0.1]:38394 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1pSvsW-0006TA-3o
	for submit <at> debbugs.gnu.org; Fri, 17 Feb 2023 03:14:00 -0500
Received: from eggs.gnu.org ([209.51.188.92]:40532)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <eliz@HIDDEN>) id 1pSvsR-0006Sr-2A
 for 61549 <at> debbugs.gnu.org; Fri, 17 Feb 2023 03:13:58 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1pSvsK-0000bL-9I; Fri, 17 Feb 2023 03:13:48 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date:
 mime-version; bh=E3Xaz9uvOzWcbscgtVQQQgGrbmwabiY0RFnNH58xOis=; b=BrRn2S5Aeyh5
 B6BZpwms3RC6jnqxFpXMX6yBLB3rlKb4o/tQQ6RD5sBp4ImmoDa3qpvUHZFJAZuZ49BTri1yg+LTq
 jqIBw5elI7gSyMUCfohNlYYHOFAdIDaIlmEQojmV1vVgcKQ0V19vDEy9GVNXqGy2rv1X6eUTG+6DT
 XpBYjvSc8Yy6N5zwf16lBlsPk/Fo7H5iVFvhEIpqAxdGEqYt1tvOE59Yl+zOYaLN0Xl7b9nIVwT4u
 i7Jb8c2Jhw9AkEyga6XjuL5TbRUvYlHCJ1bd6IBMvaQFFF6VfniigQwa+7vT8EsA5Lo8l/hzRd3+X
 en3HcbRC9zEfnak2OUUE0Q==;
Received: from [87.69.77.57] (helo=home-c4e4a596f7)
 by fencepost.gnu.org with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1pSvsJ-0006cK-MH; Fri, 17 Feb 2023 03:13:48 -0500
Date: Fri, 17 Feb 2023 10:13:45 +0200
Message-Id: <83sff41zgm.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: Alex Bochannek <alex@HIDDEN>,
 Stefan Monnier <monnier@HIDDEN>,
 Lars Ingebrigtsen <larsi@HIDDEN>
In-Reply-To: <m2a61ef2i2.fsf@HIDDEN> (message from Alex Bochannek on
 Thu, 16 Feb 2023 00:17:25 -0800)
Subject: Re: bug#61549: 30.0.50; [PATCH] New keyboard macro counter functions
References: <m2a61ef2i2.fsf@HIDDEN>
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 61549
Cc: 61549 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> From: Alex Bochannek <alex@HIDDEN>
> Date: Thu, 16 Feb 2023 00:17:25 -0800
> 
> I have been working on blog posts about keyboard macros and found that
> it would be useful to have comparison functions for the keyboard macro
> counter.

Thanks.

> I implemented two functions to load and save macro counter values from
> and to number registers; three comparison functions of the macro counter
> with a number register that conditionally increment the counter; three
> comparison functions of the macro counter with a prefix that terminate
> the macro execution. This simplifies handling multiple counters and
> conditional macro termination.
> 
> I am attaching the changes to:
>   emacs.texi
>   kmacro.texi
>   NEWS
>   kmacro.el
>   kmacro-tests.el
> 
> I hope this functionality is useful and that I followed the coding and
> style standards.

I wonder whether these commands are important enough to have them in
the manual.  Stefan and Lars, WDYT?  Any other comments to the feature
and its implementation?

> +(defun kmacro-reg-load-counter (register)
> +  "Load the value of a register into `kmacro-counter'"

The first line of a doc string should be a single complete sentence,
ending with a period (here and elsewhere).  You may wish running
checkdoc on your code to reveal any issues.

> +(defun kmacro-reg-add-counter-equal (&optional arg)
> +  "Increment counter by ARG if it is equal to register value"

This doc string is confusing, I think.  Would you like to reword it to
clarify whet the command does?  In particular, the "it" part is
ambiguous.

> +(defun kmacro-reg-add-counter-less (&optional arg)
> +  "Increment counter by ARG if it is less than register value"
> +  (interactive "p")
> +  (let
> +      ((register (register-read-with-preview "Compare counter to register: ")))
> +    (kmacro-reg-add-counter '< register arg)))
> +
> +
> +(defun kmacro-reg-add-counter-greater (&optional arg)
> +  "Increment counter by ARG if it is greater than register value"
> +  (interactive "p")
> +  (let
> +      ((register (register-read-with-preview "Compare counter to register: ")))
> +    (kmacro-reg-add-counter '> register arg)))

Similar problems with the doc strings of these two commands.

> +(defun kmacro-reg-add-counter (func register &optional arg)
> +  "Increment the counter by ARG if (FUNC kmacro-counter REGISTER-VALUE)
> +is true.
> +With no ARG, ARG is set to 1"

Our style is to say "ARG is the numeric prefix argument that defaults
to 1."

> +(defun kmacro-quit-counter-equal (&optional arg)
> +  "Quit the keyboard macro if the counter is equal to ARG"

"when the counter is equal to ARG", I guess?

> +(defun kmacro-quit-counter-less (&optional arg)
> +  "Quit the keyboard macro if the counter is less than ARG"
> +  (interactive "P")
> +  (kmacro-quit-counter '< arg))
> +
> +
> +(defun kmacro-quit-counter-greater (&optional arg)
> +  "Quit the keyboard macro if the counter is greater than ARG"
> +    (interactive "P")
> +    (kmacro-quit-counter '> arg))

Likewise here.

> +(defun kmacro-quit-counter (func &optional arg)
> +  "Quit the keyboard macro if (FUNC kmacro-counter ARG) is true.

Our style is to use PRED instead of FUNC, and document like this:

    Quit the keyboard macro when predicate PRED returns non-nil.
  PRED is called with two arguments: kmacro-counter and ARG.

> +With \\[universal-argument] or no ARG, ARG is set to 0"

  "Arg is the prefix numeric argument and defaults to zero."

> +  (let ((arg
> +	 (cond ((or (consp arg) (null arg)) 0)
> +	       ((eq '- arg) -1)
> +	       (t arg))))

This seems to imply that ARG has meaning beyond what the above text
says.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#61549; Package emacs. Full text available.

Message received at submit <at> debbugs.gnu.org:


Received: (at submit) by debbugs.gnu.org; 16 Feb 2023 08:18:44 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Feb 16 03:18:44 2023
Received: from localhost ([127.0.0.1]:34785 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1pSZTW-0001Dt-Pv
	for submit <at> debbugs.gnu.org; Thu, 16 Feb 2023 03:18:44 -0500
Received: from lists.gnu.org ([209.51.188.17]:46082)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <alex@HIDDEN>) id 1pSZTR-0001Dh-C8
 for submit <at> debbugs.gnu.org; Thu, 16 Feb 2023 03:18:41 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <alex@HIDDEN>)
 id 1pSZTQ-0004nY-Qt
 for bug-gnu-emacs@HIDDEN; Thu, 16 Feb 2023 03:18:36 -0500
Received: from ns.lapseofthought.com ([50.0.39.240]
 helo=mail.lapseofthought.com)
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <alex@HIDDEN>)
 id 1pSZTM-0005b6-Q9
 for bug-gnu-emacs@HIDDEN; Thu, 16 Feb 2023 03:18:36 -0500
Received: from awb-mbp.local (c-73-92-249-246.hsd1.ca.comcast.net
 [73.92.249.246])
 (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
 (No client certificate requested)
 by mail.lapseofthought.com (Postfix) with ESMTPSA id 4PHSVG0nlwz3pf5q
 for <bug-gnu-emacs@HIDDEN>; Thu, 16 Feb 2023 00:17:26 -0800 (PST)
Authentication-Results: ORIGINATING;
 auth=pass smtp.auth=alex smtp.mailfrom=alex@HIDDEN
From: Alex Bochannek <alex@HIDDEN>
To: bug-gnu-emacs@HIDDEN
Subject: 30.0.50; [PATCH] New keyboard macro counter functions
Date: Thu, 16 Feb 2023 00:17:25 -0800
Message-ID: <m2a61ef2i2.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
Received-SPF: pass client-ip=50.0.39.240; envelope-from=alex@HIDDEN;
 helo=mail.lapseofthought.com
X-Spam_score_int: -18
X-Spam_score: -1.9
X-Spam_bar: -
X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001,
 SPF_PASS=-0.001 autolearn=ham autolearn_force=no
X-Spam_action: no action
X-Spam-Score: -1.3 (-)
X-Debbugs-Envelope-To: submit
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -2.3 (--)

--=-=-=
Content-Type: text/plain

Hello!

I have been working on blog posts about keyboard macros and found that
it would be useful to have comparison functions for the keyboard macro
counter.

I implemented two functions to load and save macro counter values from
and to number registers; three comparison functions of the macro counter
with a number register that conditionally increment the counter; three
comparison functions of the macro counter with a prefix that terminate
the macro execution. This simplifies handling multiple counters and
conditional macro termination.

I am attaching the changes to:
  emacs.texi
  kmacro.texi
  NEWS
  kmacro.el
  kmacro-tests.el

I hope this functionality is useful and that I followed the coding and
style standards.

Thanks!

	Advanced keyboard macro counter commands for register
	integration and conditional macro termination

	* doc/emacs/emacs.texi (Top):
	Document advanced keyboard macro counter commands.

	* doc/emacs/kmacro.texi (Keyboard Macros, Keyboard Macro Counter):
	Document advanced keyboard macro counter commands.

	* etc/NEWS:
	Document advanced keyboard macro counter commands.

	* lisp/kmacro.el (kmacro-keymap, kmacro-reg-load-counter)
	(kmacro-reg-save-counter, kmacro-reg-add-counter-equal)
	(kmacro-reg-add-counter-equal, kmacro-reg-add-counter-less)
	(kmacro-reg-add-counter-greater, kmacro-reg-add-counter)
	(kmacro-quit-counter-equal, kmacro-quit-counter-less)
	(kmacro-quit-counter-greater, kmacro-quit-counter):
	Add advanced keyboard macro counter commands to kmacro keymap.
	Implement advanced keyboard macro counter commands.

	* test/lisp/kmacro-tests.el (kmacro-tests-test-reg-load)
	(kmacro-tests-test-reg-save)
	(kmacro-tests-test-reg-add-counter-equal-01)
	(kmacro-tests-test-reg-add-counter-equal-02)
	(kmacro-tests-test-reg-add-counter-equal-03)
	(kmacro-tests-test-reg-add-counter-equal-04)
	(kmacro-tests-test-reg-add-counter-less)
	(kmacro-tests-test-reg-add-counter-greater)
	(kmacro-tests-test-quit-counter-equal-01)
	(kmacro-tests-test-quit-counter-equal-02)
	(kmacro-tests-test-quit-counter-equal-03)
	(kmacro-tests-test-quit-counter-equal-04)
	(kmacro-tests-test-quit-counter-less)
	(kmacro-tests-test-quit-counter-greater):
	Implement unit tests for advanced keyboard macro counter
	commands.

--=-=-=
Content-Type: text/x-patch
Content-Disposition: inline

diff --git a/doc/emacs/emacs.texi b/doc/emacs/emacs.texi
index 7071ea44edd..2584dce8d44 100644
--- a/doc/emacs/emacs.texi
+++ b/doc/emacs/emacs.texi
@@ -434,6 +434,7 @@ Top
 * Basic Keyboard Macro::     Defining and running keyboard macros.
 * Keyboard Macro Ring::      Where previous keyboard macros are saved.
 * Keyboard Macro Counter::   Inserting incrementing numbers in macros.
+* Advanced Macro Counter::   Advanced macro counter commands.
 * Keyboard Macro Query::     Making keyboard macros do different things each
                                 time.
 * Save Keyboard Macro::      Giving keyboard macros names; saving them in

--=-=-=
Content-Type: text/x-patch
Content-Disposition: inline

diff --git a/doc/emacs/kmacro.texi b/doc/emacs/kmacro.texi
index fc1402b489d..27c84c0f96f 100644
--- a/doc/emacs/kmacro.texi
+++ b/doc/emacs/kmacro.texi
@@ -35,6 +35,7 @@ Keyboard Macros
 * Basic Keyboard Macro::     Defining and running keyboard macros.
 * Keyboard Macro Ring::      Where previous keyboard macros are saved.
 * Keyboard Macro Counter::   Inserting incrementing numbers in macros.
+* Advanced Macro Counter::   Advanced macro counter commands.
 * Keyboard Macro Query::     Making keyboard macros do different things each
                                time.
 * Save Keyboard Macro::      Giving keyboard macros names; saving them in
@@ -364,6 +365,123 @@ Keyboard Macro Counter
 keyboard macro counter.  @xref{Number Registers}.  For most purposes,
 it is simpler to use a keyboard macro counter.
 
+@node Advanced Macro Counter
+@section Advanced Macro Counter Commands
+
+  The counter associated with a keyboard macro is sufficient in most
+cases.  If additional counters are required for a macro, registers can
+be used and these advanced macro counter commands simplify the
+interaction between the two.  Additional commands are provided to
+terminate a macro after a predefined number of runs.
+
+
+@table @kbd
+@item C-x C-k C-r l
+Load the value of a number register into the macro counter
+(@code{kmacro-reg-load-counter}).
+@item C-x C-k C-r s
+Save the value of the macro counter to a number register
+(@code{kmacro-reg-save-counter}).
+@end table
+
+@table @kbd
+@item C-x C-k C-r a =
+Compare if the macro counter is equal to the value of a register and
+increment the counter if it is (@code{kmacro-reg-add-counter-equal}).
+@item C-x C-k C-r a <
+Compare if the macro counter is less than the value of a register and
+increment the counter if it is (@code{kmacro-reg-add-counter-less}).
+@item C-x C-k C-r a >
+Compare if the macro counter is greater than the value of a register
+and increment the counter if it is
+(@code{kmacro-reg-add-counter-greater}).
+@end table
+
+@table @kbd
+@item C-x C-k C-q =
+Compare if the macro counter is equal to the prefix and terminate the
+macro if it is (@code{kmacro-quit-counter-equal}).
+@item C-x C-k C-q <
+Compare if the macro counter is less than the prefix and terminate the
+macro if it is (@code{kmacro-quit-counter-less}).
+@item C-x C-k C-q >
+Compare if the macro counter is greater than the prefix and terminate
+the macro if it is (@code{kmacro-quit-counter-greater}).
+@end table
+
+@findex kmacro-reg-load-counter
+@kindex C-x C-k C-r l
+@findex kmacro-reg-save-counter
+@kindex C-x C-k C-r s
+  The command @kbd{C-x C-k C-r l} (@code{kmacro-reg-load-counter})
+prompts for the register name from which to load a number into the
+macro counter.  The command @kbd{C-x C-k C-r s}
+(@code{kmacro-reg-save-counter}) prompts for the register name into
+which to save the macro counter's value.  Both @kbd{C-x C-k C-r l}
+(@code{kmacro-reg-load-counter}) and @kbd{C-x C-k C-r s}
+(@code{kmacro-reg-save-counter}) show a preview of the registers by
+default.  @xref{Registers}.  Both commands can be used during or
+outside a keyboard macro definition.
+
+@findex kmacro-reg-add-counter-equal
+@kindex C-x C-k C-r a =
+@findex kmacro-reg-add-counter-less
+@kindex C-x C-k C-r a <
+@findex kmacro-reg-add-counter-greater
+@kindex C-x C-k C-r a >
+  The @kbd{C-x C-k C-r a =} (@code{kmacro-reg-add-counter-equal}),
+@kbd{C-x C-k C-r a <} (@code{kmacro-reg-add-counter-less}), and
+@kbd{C-x C-k C-r a >} (@code{kmacro-reg-add-counter-greater}) commands
+all follow the same pattern.  During keyboard macro definition, the
+command prompts for a register name (with preview by default), the
+contents of which will be compared with the macro counter's value.  If
+the counter is equal to (@code{=}), less than (@code{<}), or greater
+than (@code{>}) the number register's contents, the counter will be
+incremented by the numeric prefix or one if no prefix was given to the
+command.
+
+  For example,
+
+@example
+C-u 2 C-x C-k C-r a > N
+@end example
+
+@noindent
+compares the counter with the contents of register @code{N} and if the
+counter is greater than that, increases it by two.
+
+@findex kmacro-quit-counter-equal
+@kindex C-x C-k C-q =
+@findex kmacro-quit-counter-less
+@kindex C-x C-k C-q <
+@findex kmacro-quit-counter-greater
+@kindex C-x C-k C-q >
+  Finally, the @kbd{C-x C-k C-q =} (@code{kmacro-quit-counter-equal}),
+@kbd{C-x C-k C-q <} (@code{kmacro-quit-counter-less}), and @kbd{C-x
+C-k C-q >} (@code{kmacro-quit-counter-greater}) commands compare the
+macro counter with the prefix given and terminate the execution of the
+macro, if the comparison succeeds.  If no numeric prefix or only
+@code{C-u} are given, the counter will be compared with zero.  The
+macro is terminated using the @code{keyboard-quit} function.  Using
+this command to exit from a macro that has been called by another
+macro is not supported, the entire executing macro is terminated.
+
+  The quit commands can be used to construct the equivalent of a
+@code{while}-loop. This example will stop after ten executions
+assuming the starting value for the macro counter is the default zero.
+
+@example
+C-u 10 C-x C-k C-q = C-x C-k C-i @key{RET}
+@end example
+
+  With the default counter value of zero, the macro called with a
+prefix of @code{C-u C-u} to execute sixteen times, will stop after ten
+iterations.  The counter values that have been inserted will be from 0
+to 9.  If the counter starts out a different value below ten, it will
+still stop at ten, because the counter does not actually count macro
+executions, but is incremented explicitly by the @code{C-x C-k C-i}
+command.
+
 @node Keyboard Macro Query
 @section Executing Macros with Variations

--=-=-=
Content-Type: text/x-patch
Content-Disposition: inline

diff --git a/etc/NEWS b/etc/NEWS
index 4fbe09e0541..d5a3ebb1df5 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -187,6 +187,25 @@ This command adds a docstring comment to the current defun.  If a
 comment already exists, point is only moved to the comment.  It is
 bound to 'C-c C-d' in 'go-ts-mode'.
 
+** Kmacro
+
++++
+*** New Advanced Macro Counter functions.
+New commands have been added to to implement advanced macro counter
+functions.
+
+The commands 'C-x C-k C-r l' and 'C-x C-k C-r s' load and save the
+macro counter from a to a number register respectively.
+
+The commands 'C-x C-k C-r a =', 'C-x C-k C-r a <', and
+'C-x C-k C-r a >' compare the macro counter with the contents of a
+number register and increment the counter by a prefix if the
+comparison succeeds.
+
+The commands 'C-x C-k C-q =', 'C-x C-k C-q <', and 'C-x C-k C-q >'
+compare the macro counter with a prefix and terminate the macro if the
+comparison succeeds.
+
 
 * New Modes and Packages in Emacs 30.1
 
--=-=-=
Content-Type: text/x-patch
Content-Disposition: inline

diff --git a/lisp/kmacro.el b/lisp/kmacro.el
index 94d8794bd23..e7c3f75efd0 100644
--- a/lisp/kmacro.el
+++ b/lisp/kmacro.el
@@ -183,10 +183,18 @@ kmacro-keymap
   "C-l"  #'kmacro-call-ring-2nd-repeat
 
   ;; macro counter
-  "C-f"  #'kmacro-set-format
-  "C-c"  #'kmacro-set-counter
-  "C-i"  #'kmacro-insert-counter
-  "C-a"  #'kmacro-add-counter
+  "C-f"     #'kmacro-set-format
+  "C-c"     #'kmacro-set-counter
+  "C-i"     #'kmacro-insert-counter
+  "C-a"     #'kmacro-add-counter
+  "C-r l"   #'kmacro-reg-load-counter
+  "C-r s"   #'kmacro-reg-save-counter
+  "C-r a =" #'kmacro-reg-add-counter-equal
+  "C-r a <" #'kmacro-reg-add-counter-less
+  "C-r a >" #'kmacro-reg-add-counter-greater
+  "C-q ="   #'kmacro-quit-counter-equal
+  "C-q <"   #'kmacro-quit-counter-less
+  "C-q >"   #'kmacro-quit-counter-greater
 
   ;; macro editing
   "C-e"  #'kmacro-edit-macro-repeat
@@ -347,6 +355,89 @@ kmacro-add-counter
     (kmacro-display-counter)))
 
 
+(defun kmacro-reg-load-counter (register)
+  "Load the value of a register into `kmacro-counter'"
+  (interactive
+   (list (register-read-with-preview "Load register to counter: ")))
+  (let ((register-val (get-register register)))
+    (when (numberp register-val)
+     (setq kmacro-counter register-val))))
+
+
+(defun kmacro-reg-save-counter (register)
+  "Save the value of `kmacro-counter' to a register"
+  (interactive
+   (list (register-read-with-preview "Save counter to register: ")))
+  (set-register register kmacro-counter))
+
+
+(defun kmacro-reg-add-counter-equal (&optional arg)
+  "Increment counter by ARG if it is equal to register value"
+  (interactive "p")
+  (let
+      ((register (register-read-with-preview "Compare counter to register: ")))
+    (kmacro-reg-add-counter '= register arg)))
+
+
+(defun kmacro-reg-add-counter-less (&optional arg)
+  "Increment counter by ARG if it is less than register value"
+  (interactive "p")
+  (let
+      ((register (register-read-with-preview "Compare counter to register: ")))
+    (kmacro-reg-add-counter '< register arg)))
+
+
+(defun kmacro-reg-add-counter-greater (&optional arg)
+  "Increment counter by ARG if it is greater than register value"
+  (interactive "p")
+  (let
+      ((register (register-read-with-preview "Compare counter to register: ")))
+    (kmacro-reg-add-counter '> register arg)))
+
+
+(defun kmacro-reg-add-counter (func register &optional arg)
+  "Increment the counter by ARG if (FUNC kmacro-counter REGISTER-VALUE)
+is true.
+With no ARG, ARG is set to 1"
+  (let ((register-val (get-register register))
+        (arg (if (null arg) 1 arg)))
+    (when (apply func (list kmacro-counter register-val))
+      (setq current-prefix-arg nil)
+      (kmacro-add-counter arg))))
+
+
+(defun kmacro-quit-counter-equal (&optional arg)
+  "Quit the keyboard macro if the counter is equal to ARG"
+  (interactive "P")
+  (kmacro-quit-counter '= arg))
+
+
+(defun kmacro-quit-counter-less (&optional arg)
+  "Quit the keyboard macro if the counter is less than ARG"
+  (interactive "P")
+  (kmacro-quit-counter '< arg))
+
+
+(defun kmacro-quit-counter-greater (&optional arg)
+  "Quit the keyboard macro if the counter is greater than ARG"
+    (interactive "P")
+    (kmacro-quit-counter '> arg))
+
+
+(defun kmacro-quit-counter (func &optional arg)
+  "Quit the keyboard macro if (FUNC kmacro-counter ARG) is true.
+With \\[universal-argument] or no ARG, ARG is set to 0"
+  (when kmacro-initial-counter-value
+      (setq kmacro-counter kmacro-initial-counter-value
+	    kmacro-initial-counter-value nil))
+  (let ((arg
+	 (cond ((or (consp arg) (null arg)) 0)
+	       ((eq '- arg) -1)
+	       (t arg))))
+    (when (apply func (list kmacro-counter arg))
+      (keyboard-quit))))
+
+
 (defun kmacro-loop-setup-function ()
   "Function called prior to each iteration of macro."
   ;; Restore macro counter format to initial format, so it is ok to change

--=-=-=
Content-Type: text/x-patch
Content-Disposition: inline

diff --git a/test/lisp/kmacro-tests.el b/test/lisp/kmacro-tests.el
index 551fd8b60fc..e30681db539 100644
--- a/test/lisp/kmacro-tests.el
+++ b/test/lisp/kmacro-tests.el
@@ -275,6 +275,220 @@ kmacro-tests-start-insert-counter-appends-to-macro
     ;;  Verify that the recording state has changed.
     (should (equal defining-kbd-macro 'append))))
 
+
+(kmacro-tests-deftest kmacro-tests-test-reg-load ()
+  "`kmacro-reg-load-counter' loads the value of register to into the counter"
+  (set-register ?\C-r 4) ;; Should be safe as a register name
+  (kmacro-tests-simulate-command '(kmacro-set-counter 1))
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and increment counter
+                              "\C-x\C-k\C-i"
+                              "\C-x\C-k\C-i"
+                              ;; Load from register
+                              "\C-x\C-k\C-rl\C-r"
+                              ))
+  (kmacro-tests-should-insert "1245"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 2)))
+    (set-register ?\C-r nil))
+
+(kmacro-tests-deftest kmacro-tests-test-reg-save ()
+  "`kmacro-reg-save-counter' save the counter to a register"
+  (set-register ?\C-r nil) ;; Should be safe as a register name
+  (kmacro-tests-simulate-command '(kmacro-set-counter 1))
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and increment counter
+                              "\C-x\C-k\C-i"
+                              ;; Save to register
+                              "\C-x\C-k\C-rs\C-r"
+                              ;; Add to counter
+                              "\C-u2\C-x\C-k\C-a"
+                              ;; Insert and increment counter
+                              "\C-x\C-k\C-i"
+                              ;; Insert register
+                              "\C-xri\C-r"
+                              ))
+  (kmacro-tests-should-insert "142586"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 2)))
+  (set-register ?\C-r nil))
+
+
+(kmacro-tests-deftest kmacro-tests-test-reg-add-counter-equal-01 ()
+  "`kmacro-reg-add-counter-equal' increments counter if equal to register"
+  (set-register ?\C-r 2) ;; Should be safe as a register name
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and increment counter
+                              "\C-x\C-k\C-i"
+                              ;; Increment counter if it matches
+                              "\C-x\C-k\C-ra=\C-r"
+                              ))
+  (kmacro-tests-should-insert "0134"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+  (set-register ?\C-r nil))
+
+(kmacro-tests-deftest kmacro-tests-test-reg-add-counter-equal-02 ()
+  "`kmacro-reg-add-counter-equal' increments counter if equal to register"
+  (set-register ?\C-r 2) ;; Should be safe as a register name
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and increment counter
+                              "\C-x\C-k\C-i"
+                              ;; Add two to counter if it matches
+                              "\C-u2\C-x\C-k\C-ra=\C-r"
+                              ))
+  (kmacro-tests-should-insert "0145"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+  (set-register ?\C-r nil))
+
+(kmacro-tests-deftest kmacro-tests-test-reg-add-counter-equal-03 ()
+  "`kmacro-reg-add-counter-equal' increments counter if equal to register"
+  (set-register ?\C-r 2) ;; Should be safe as a register name
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and increment counter
+                              "\C-x\C-k\C-i"
+                              ;; Add four to counter if it matches
+                              "\C-u\C-x\C-k\C-ra=\C-r"
+                              ))
+  (kmacro-tests-should-insert "0167"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+  (set-register ?\C-r nil))
+
+(kmacro-tests-deftest kmacro-tests-test-reg-add-counter-equal-04 ()
+  "`kmacro-reg-add-counter-equal' increments counter if equal to register"
+  (set-register ?\C-r 2) ;; Should be safe as a register name
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and increment counter
+                              "\C-x\C-k\C-i"
+                              ;; Decrement counter if it matches
+                              "\C-u-\C-x\C-k\C-ra=\C-r"
+                              ))
+  (kmacro-tests-should-insert "0111"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+  (set-register ?\C-r nil))
+
+(kmacro-tests-deftest kmacro-tests-test-reg-add-counter-less ()
+  "`kmacro-reg-add-counter-less' increments counter if less than register"
+  (set-register ?\C-r 6) ;; Should be safe as a register name
+  (kmacro-tests-simulate-command '(kmacro-set-counter 8))
+  (kmacro-tests-define-macro (vconcat
+                              ;; Decrement counter if it's
+                              ;; less than the register
+                              "\C-u-1\C-x\C-k\C-ra<\C-r"
+                              ;; Insert and decrement counter
+                              "\C-u-\C-x\C-k\C-i"
+                              ))
+  (kmacro-tests-should-insert "8764"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+    (set-register ?\C-r nil))
+
+(kmacro-tests-deftest kmacro-tests-test-reg-add-counter-greater ()
+  "`kmacro-reg-add-counter-greater' increments counter if greater than register"
+  (set-register ?\C-r 2) ;; Should be safe as a register name
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and increment counter
+                              "\C-x\C-k\C-i"
+                              ;; Increment counter if it's greater
+                              ;; than the register
+                              "\C-x\C-k\C-ra>\C-r"
+                              ))
+  (kmacro-tests-should-insert "0124"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+  (set-register ?\C-r nil))
+
+
+(kmacro-tests-deftest kmacro-tests-test-quit-counter-equal-01 ()
+  "`kmacro-quit-counter-equal' stops macro if counter is equal to prefix"
+  (kmacro-tests-simulate-command '(kmacro-set-counter 5))
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and decrement counter
+                              "\C-u-\C-x\C-k\C-i"
+                              ;; Stop if the counter is at 0
+                              "\C-x\C-k\C-q="
+                              ))
+  (kmacro-tests-should-insert "5432"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+  (should (condition-case abort
+              (should (= 1 kmacro-counter))
+              (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 1))
+            (quit abort))))
+
+(kmacro-tests-deftest kmacro-tests-test-quit-counter-equal-02 ()
+  "`kmacro-quit-counter-equal' stops macro if counter is equal to prefix"
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and increment counter
+                              "\C-x\C-k\C-i"
+                              ;; Stop if the counter is at 5
+                              "\C-u5\C-x\C-k\C-q="
+                              ))
+  (kmacro-tests-should-insert "0123"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+  (should (condition-case abort
+              (should (= 4 kmacro-counter))
+              (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 1))
+            (quit abort))))
+
+(kmacro-tests-deftest kmacro-tests-test-quit-counter-equal-03 ()
+  "`kmacro-quit-counter-equal' stops macro if counter is equal to prefix"
+  (kmacro-tests-simulate-command '(kmacro-set-counter 5))
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and decrement counter
+                              "\C-u-\C-x\C-k\C-i"
+                              ;; Stop if the counter is at 0
+                              "\C-u\C-x\C-k\C-q="
+                              ))
+  (kmacro-tests-should-insert "5432"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+  (should (condition-case abort
+              (should (= 1 kmacro-counter))
+              (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 1))
+            (quit abort))))
+
+(kmacro-tests-deftest kmacro-tests-test-quit-counter-equal-04 ()
+  "`kmacro-quit-counter-equal' stops macro if counter is equal to prefix"
+  (kmacro-tests-simulate-command '(kmacro-set-counter 4))
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and decrement counter
+                              "\C-u-\C-x\C-k\C-i"
+                              ;; Stop if the counter is at -1
+                              "\C-u-\C-x\C-k\C-q="
+                              ))
+  (kmacro-tests-should-insert "4321"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+  (should (condition-case abort
+              (should (= 0 kmacro-counter))
+              (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 1))
+            (quit abort))))
+
+(kmacro-tests-deftest kmacro-tests-test-quit-counter-less ()
+  "`kmacro-quit-counter-less' stops macro if counter is less than prefix"
+  (kmacro-tests-simulate-command '(kmacro-set-counter 8))
+  (kmacro-tests-define-macro (vconcat
+                              ;; Stop if the counter is less than 5
+                              "\C-u5\C-x\C-k\C-q<"
+                              ;; Insert and decrement counter
+                              "\C-u-\C-x\C-k\C-i"
+                              ))
+  (kmacro-tests-should-insert "8765"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+  (should (condition-case abort
+              (should (= 4 kmacro-counter))
+              (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 1))
+            (quit abort))))
+
+(kmacro-tests-deftest kmacro-tests-test-quit-counter-greater ()
+  "`kmacro-quit-counter-greater' stops macro if counter is greater than prefix"
+  (kmacro-tests-define-macro (vconcat
+                              ;; Insert and increment counter
+                              "\C-x\C-k\C-i"
+                              ;; Stop if the counter is greater than 4
+                              "\C-u4\C-x\C-k\C-q>"
+                              ))
+  (kmacro-tests-should-insert "0123"
+    (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 4)))
+  (should (condition-case abort
+              (should (= 4 kmacro-counter))
+              (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 1))
+            (quit abort))))
+
+
 (kmacro-tests-deftest kmacro-tests-end-call-macro-prefix-args ()
   "kmacro-end-call-macro changes behavior based on prefix arg."
   ;; "Record" two macros.

--=-=-=
Content-Type: text/plain

-- 
Alex.

--=-=-=--




Acknowledgement sent to Alex Bochannek <alex@HIDDEN>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs@HIDDEN. Full text available.
Report forwarded to bug-gnu-emacs@HIDDEN:
bug#61549; Package emacs. Full text available.
Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.
Last modified: Mon, 4 Sep 2023 09:15:02 UTC

GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997 nCipher Corporation Ltd, 1994-97 Ian Jackson.