Subject: Re: bug#34720: 26.1; Reverting a GPG buffer moves all markers to the end of the file

From: Eli Zaretskii <[email-masked]>
Date: Tue, 27 Aug 2019 11:00:09 +0300

> From: Lars Ingebrigtsen <[email-masked]>
> Cc: [email-masked],  [email-masked]
> Date: Tue, 27 Aug 2019 09:14:22 +0200
> 
> Eli Zaretskii <[email-masked]> writes:
> 
> > IOW, there's no guarantee that markers will be preserved across
> > operations that replace text.
> 
> No, but we have a small handful of functions that do best effort...  but
> they're deep in the C code and not accessible.
> 
> Finsert_file_contents has this:
> 
>   /* Replacement should preserve point as it preserves markers.  */
>   if (!NILP (replace))
>     {
>       window_markers = get_window_points_and_markers ();
>       record_unwind_protect (restore_point_unwind,
> 			     XCAR (XCAR (window_markers)));
>     }
>     ...
>  handled:
> 
>   if (inserted > 0)
>     restore_window_points (window_markers, inserted,
> 			   BYTE_TO_CHAR (same_at_start),
> 			   same_at_end_charpos);

These just restore a single marker: the point marker.  That's a far
cry from restoring all the markers.  I don't think the latter is
possible in all cases without violating the principle of least
astonishment (by placing the markers at locations that have nothing in
comm on with where they have been before the editing operation).

> The problem that this bug report addresses is that Lisp level functions
> that implement special handlers for insert-file-contents (in this case,
> epa-file-insert-file-contents) doesn't have access to the internals
> necessary to give the user the same experience that the built-in version
> gives the user.

That's because markers can only be preserved by operations on the C
level.  If the C-level handling cannot preserve a marker, then it is
unsafe, to say the least, to try to second-guess that by moving the
markers manually from Lisp.

Specifically, if the editing operation deletes the text on both sides
of a marker, there's no reasonable place, in general, to have this
marker after some other text is inserted.  You may think otherwise if
the inserted text happens to be very similar to the one which was
deleted, but that's an illusion.  If some Lisp program wants to
preserve markers during editing, then it must call the likes of
replace-buffer-contents to do the job.

> My suggestion is basically to make DEFUN shims over
> get_window_points_and_markers/restore_window_points, and create a new
> macro `with-saved-markers' that would use that pair to do this cheap,
> best-effort thing that Finsert_file_contents does.

That has come up before.  Giving Lisp programs direct access to
markers is dangerous, because Emacs uses markers internally for
various bookkeeping purposes, such as conversion between character and
byte positions.

But maybe I misunderstand what you want to do, because you didn't
answer my question about restoring markers after replacement.

> >> No wonder this function has gotten one single usage after it was
> >> introduced two years ago.  (Well, one usage to
> >> replace-region-contents, which then calls the function.)  (Unless
> >> I'm grepping wrong.)
> >
> > replace-region-contents is used in json.el.
> 
> Yes, that's the one single usage of this machinery.

It's a rather niche capability, so I'm not surprised it doesn't yet
have a lot of users.