help-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: How to return to the position from where I did tags-query-replace?


From: aklaing
Subject: Re: How to return to the position from where I did tags-query-replace?
Date: Sun, 4 Feb 2018 12:14:36 -0800 (PST)
User-agent: G2/1.0

Thanks Emanuel for taking a look at this.  Your solution works correctly for 
your test case (moving to a random buffer and location) but not as-written for 
tags-query-replace, which has some peculiarities (I just realized).

Looking at the code, the tags-query-replace function uses a function called
user-error for flow control.  Deep in the logic, if it realizes that it has 
finished the job normally, it calls user-error, which is somewhat similar to 
throwing an exception deep in the call stack.  Because this unwinds the stack 
and discards it, the part of the code following (apply fun args) never gets 
evaluated.  This probably also explains why my two initial attempts do not work.

One hacky solution (based on your approach) is to do something similar to 
putting a try/catch around the call to (apply fun args), as follows:

(defun do-tags-query-replace-return (fun &rest args)
  (let ((tmp-point  (point)) 
        (tmp-buffer (current-buffer)))
    (message "DWR Before: %d %s %s" tmp-point tmp-buffer args)
    (condition-case tmp-err
        (apply fun args)
      (user-error
       (let ((err-message (cadr tmp-err)))
         (if (string= err-message "All files processed")
             (message "DWR Trapped: %s" err-message)
           (signal (car tmp-err) (cdr tmp-err))))))
    (message "DWR After: %d %s %s" tmp-point tmp-buffer args)
    (when (bufferp tmp-buffer)
      (switch-to-buffer tmp-buffer)
      (goto-char tmp-point)
      nil)))

Notes: this is similar to putting a try/catch around the
(apply fun args).  I say it is (only) similar because elisp has a notion of 
try/catch which is different from its own notion of error-handling, though
there are similarities.

I like your approach better than my first two attempts because it does not 
require an external package like breadcrumb.  Though (I believe) registers are 
native in emacs, it is better to avoid using persistent state for something 
that should really be on the execution stack.

It should be noted that this solution only works for tags-query-replace, 
because it only traps one very specific type of error, which is the one 
tags-query-replace "throws" when it completes normally.  If tags-query-replace 
exits for any other real error, this will fail -- in the sense that it will not 
return to where it was before it started.  And I think that is a good thing.

One thing that is still not good about this solution is that if etags.el 
changes the string that it uses to indicate completion ("All files processed"), 
this solution will stop working.  That is too fragile.

In the long term, it would probably be better for etags.el to not use 
user-error to indicate normal completion, but that is more elisp than I want to 
do right now.  It requires changes in more than one place.  If the/an author of 
etags.el reads this and you have some time, maybe you can please take a look?

If anyone wants to use the hacky solution above, you might as well remove the 
DWR message calls.

Thanks again for your help, it pushed me to spend more time on it and learn a 
bit more elisp than I already knew.

Thanks,

On Saturday, February 3, 2018 at 11:46:13 PM UTC-5, Emanuel Berg wrote:
> Emanuel Berg wrote:
> 
> > (goto-char (point))
> 
> He he, good one! That should be
> 
>     (goto-char point)
> 
> Any further edits will be in the source
> file [1] only. Modern society does not allow
> this inefficiency.
> 
> [1] http://user.it.uu.se/~embe8573/emacs-init/my-random.el
> 
> -- 
> underground experts united
> http://user.it.uu.se/~embe8573



reply via email to

[Prev in Thread] Current Thread [Next in Thread]