From: Alan Mackenzie <acm@muc.de>
To: Eli Zaretskii <eliz@gnu.org>
Cc: emacs-devel@gnu.org
Subject: Re: /* FIXME: Call signal_after_change! */ in callproc.c. Well, why not?
Date: Sun, 29 Dec 2019 13:34:36 +0000 [thread overview]
Message-ID: <20191229133436.GA10699@ACM> (raw)
In-Reply-To: <837e2lwws9.fsf@gnu.org>
Hello, Eli.
I've combined your two recent posts into one, to make it easier to
answer them.
<Post 1>
On Tue, Dec 24, 2019 at 17:47:18 +0200, Eli Zaretskii wrote:
> > Date: Tue, 24 Dec 2019 09:47:24 +0000
> > Cc: emacs-devel@gnu.org
> > From: Alan Mackenzie <acm@muc.de>
> > The point is not to call prepare_to_modify_buffer twice at the same
> > position.
> Why is that a problem? Surely, something like that can happen in real
> life, and any modification hook should be prepared to deal with that?
Well, the more we can issue balanced before- and after- calls, the
better. It is true that the hook functions should be able to handle
unbalanced calls, but we don't know for sure that they can, in all
cases. CC Mode might not be the only casualty (though I intend to fix
CC Mode, here).
Besides, the Elisp manual page "Change Hooks" only describes one
situation for unbalanced calls. This is one large enclosing before-
followed by a sequence of smaller after-s. The situation in callproc.c
is thus technically a bug.
> > > I think you should simply call signal_after_change after the call to
> > > del_range_2 (telling the after-change hooks that actually nothing was
> > > inserted or deleted). Then you won't need the prepared_position
> > > thingy.
> > After thinking it over a couple of days, I can't agree this is a good
> > idea. Calling before/after-change-functions for a non-change would be
> > very unusual in Emacs - I don't know of anywhere where this is currently
> > done - and would surely cause problems somewhere, and would certainly
> > cause some inefficiency. Also we would have to amend the Change Hooks
> > page in the Elisp manual to warn of this possibility.
> Again, I don't see why this could cause any trouble. Inserting an
> empty string is not an outlandish situation, and any modification hook
> must be prepared to (trivially) deal with it.
This may be true, but I wouldn't bet anything on it being true for all
existing hooks. Doing this would necessitate amending the Elisp manual,
and (if we're going to be honest) adding a NEWS item in the incompatible
changes section.
> IOW, jumping through hoops in order to avoid such calls is IMNSHO
> unjustified. It will definitely complicate code, and thus will run
> higher risk of subtle bugs. Why risk that?
We have a real existing bug here, and any fix to it runs the risk of
further bugs. I think introducing no-change change hooks is more likely
to cause trouble than the relatively straightforward patch I'm
proposing. My proposed patch is not complicated. Really, it isn't.
It's the least messy way of fixing the bug we have.
<Post 2>
> > I think the following patch is better. What do you think?
> Frankly, I don't like this, for the reasons I explained in my other
> message. If you insist on jumping through these hoops just to avoid
> an extra call to the modification hooks, please write a comment with
> the detailed description of the logic of these calls and their
> conditions, and how that ensures the paired calls with no extra calls.
OK, I've done this. Writing this comment was actually more difficult
than amending the code. :-) The current state of my proposed patch,
unchanged except for the new comment, follows. Comments?
diff --git a/src/callproc.c b/src/callproc.c
index b51594c2d5..66eebdebb4 100644
--- a/src/callproc.c
+++ b/src/callproc.c
@@ -746,6 +746,8 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd,
int carryover = 0;
bool display_on_the_fly = display_p;
struct coding_system saved_coding = process_coding;
+ ptrdiff_t prepared_pos = 0; /* prepare_to_modify_buffer was last
+ called here. */
while (1)
{
@@ -773,6 +775,27 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd,
if (display_on_the_fly)
break;
}
+ /* CHANGE FUNCTIONS
+ For each typical iteration of the enclosing while (1)
+ loop which yields data (i.e. nread > 0), before- and
+ after-change-functions are invoked exactly once. The
+ call to prepare_to_modify_buffer follows this comment,
+ and there is one call to signal_after_change in each of
+ the branches of the next `else if'.
+
+ Exceptionally, the insertion into the buffer is aborted
+ at the call to del_range_2 ~45 lines further down,
+ without signal_after_change being called. The data are
+ then inserted finally at the next iteration of the
+ while (1) loop. A second, unwanted, call to
+ prepare_to_modify_buffer is inhibited by the test
+ prepared_pos < PT, and signal_after_change is then
+ called normally after the insertion. */
+ if ((prepared_pos < PT) && nread)
+ {
+ prepare_to_modify_buffer (PT, PT, NULL);
+ prepared_pos = PT;
+ }
/* Now NREAD is the total amount of data in the buffer. */
@@ -780,15 +803,16 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd,
;
else if (NILP (BVAR (current_buffer, enable_multibyte_characters))
&& ! CODING_MAY_REQUIRE_DECODING (&process_coding))
- insert_1_both (buf, nread, nread, 0, 1, 0);
+ {
+ insert_1_both (buf, nread, nread, 0, 0, 0);
+ signal_after_change (PT, 0, nread);
+ }
else
{ /* We have to decode the input. */
Lisp_Object curbuf;
ptrdiff_t count1 = SPECPDL_INDEX ();
XSETBUFFER (curbuf, current_buffer);
- /* FIXME: Call signal_after_change! */
- prepare_to_modify_buffer (PT, PT, NULL);
/* We cannot allow after-change-functions be run
during decoding, because that might modify the
buffer, while we rely on process_coding.produced to
@@ -822,6 +846,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd,
continue;
}
+ signal_after_change (PT, 0, process_coding.produced_char);
TEMP_SET_PT_BOTH (PT + process_coding.produced_char,
PT_BYTE + process_coding.produced);
carryover = process_coding.carryover_bytes;
> Thanks.
--
Alan Mackenzie (Nuremberg, Germany).
next prev parent reply other threads:[~2019-12-29 13:34 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-12-21 17:23 /* FIXME: Call signal_after_change! */ in callproc.c. Well, why not? Alan Mackenzie
2019-12-21 18:11 ` Eli Zaretskii
2019-12-21 21:47 ` Alan Mackenzie
2019-12-22 18:38 ` Eli Zaretskii
2019-12-24 9:47 ` Alan Mackenzie
2019-12-24 12:51 ` Alan Mackenzie
2019-12-24 15:58 ` Eli Zaretskii
2019-12-24 15:47 ` Eli Zaretskii
2019-12-29 13:34 ` Alan Mackenzie [this message]
2019-12-29 16:23 ` Stefan Monnier
2020-01-03 8:45 ` Eli Zaretskii
2020-01-04 22:47 ` Alan Mackenzie
2020-01-05 18:17 ` Eli Zaretskii
2020-01-05 18:48 ` Alan Mackenzie
2020-01-21 20:34 ` Alan Mackenzie
2020-01-22 3:27 ` Eli Zaretskii
2020-01-22 20:05 ` Alan Mackenzie
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20191229133436.GA10699@ACM \
--to=acm@muc.de \
--cc=eliz@gnu.org \
--cc=emacs-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).