2

I am writing a piece of lisp code employing the function query-replace. After this function runs, I'd like to know how many replacements were effectively done. At first this seems easy because the return value of query-replace is a list whose elements precisely describe each attempted replacement, including whether or not the user answered y or n when queried.

However, in case a user replies with q or RET, signaling their intention to exit, the return value becomes nil, even if a few replacements were performed before the exit request, so the return value says nothing about the number of replacements.

One solution I found is based on the fact that the number of replacements is shown in the mini-buffer, as well as recorded in the *Messages* buffer, regardless of whether or not the command exits prematurely. So one could parse the last line of the *Messages* buffer in search for the desired number of replacements, but I feel there might be a more elegant alternative. Any ideas?

Ruy
  • 839
  • 5
  • 11

2 Answers2

4

As mentioned by @db48x, indeed, reporting a bug would be a good thing to do, as I guess that docstring should say "DID cancel the call". Also, there might be a small chance that the function could be changed to make it do what you require.

That said. If you are not planning to publish your code, but just want to be pragmatic, then I think there is no problem with parsing the content of the last message, you could simply advise the original function as follows:

(defun query-replace-return-count-advice-function (&rest _)
  (string-to-number (cadr (string-split (current-message)))))

(advice-add 'query-replace :after #'query-replace-return-count-advice-function)

Indeed, I could not come up with a simpler/more elegant solution, e.g. by advising the function in some other way.

dalanicolai
  • 7,795
  • 8
  • 24
  • This is certainly nicer than my idea of parsing the *Messages* buffer. Thanks! As you say, I believe there is no way to obtain the value of a local variable, such as replace-count within perform-replace by means of some mechanism similar to advising a function, right? – Ruy Sep 29 '22 at 19:38
  • At least I don't know of any... – dalanicolai Sep 29 '22 at 21:37
  • 2
    FYI, the bug report has been accepted and the docstring will be fixed in Emacs 29. However, even if some developpers did acknowledge the advantage of changing the output of perform-replace, the fact that the change would have a cascading effect on several other functions, resulted in the decision that no change will be made. See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=58177 – Ruy Oct 02 '22 at 18:27
2

The documentation of perform-replace says:

This function returns nil if and only if there were no matches to
make, or the user didn't cancel the call.

So maybe you have found a bug; probably best to use M-x report-emacs-bug.

That said, parsing the content of the *Messages* buffer should never be your first solution to any problem. Read the source instead to find out how that message is produced. You may find that the source information is readily available.

Drew
  • 77,472
  • 10
  • 114
  • 243
db48x
  • 17,977
  • 1
  • 22
  • 28
  • Thanks for your answer and for suggesting the bug report, which I already did: https://debbugs.gnu.org/58177. I agree that parsing the *Messages* buffer is an awkward solution and this is precisely my reason for asking my question. Regarding the source, I did read it prior to coming here, but couldn't get any inspiration. – Ruy Sep 29 '22 at 18:20
  • It is a rather hard function to read. – db48x Sep 29 '22 at 23:19