]> git.eshelyaron.com Git - emacs.git/commitdiff
Make call_process call signal_after_change. This fixes bug #38691.
authorAlan Mackenzie <acm@muc.de>
Wed, 22 Jan 2020 19:50:30 +0000 (19:50 +0000)
committerAlan Mackenzie <acm@muc.de>
Wed, 22 Jan 2020 19:50:30 +0000 (19:50 +0000)
Now, functions such as call-proess-region invoke after-change-functions
correctly.

* src/callproc.c (call_process): Call prepare_to_modify_buffer in a single
place, no longer delegating the task to insert_1_both, etc.  Call
signal_after_change in each of two code branches, such that
before-change-functions and after-change-functions are always called in
balanced pairs.

src/callproc.c

index 52b895042055449459f7ebac86f4759c57bcef46..6bd4ae22f6312e1e501e8f423b3fb16206f7e819 100644 (file)
@@ -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,33 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd,
              if (display_on_the_fly)
                break;
            }
+          /* CHANGE FUNCTIONS
+             For each iteration of the enclosing while (1) loop which
+             yields data (i.e. nread > 0), before- and
+             after-change-functions are each invoked exactly once.
+             This is done directly from the current function only, by
+             calling prepare_to_modify_buffer and signal_after_change.
+             It is not done here by directing another function such as
+             insert_1_both to call them.  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, this
+             function removing the newly inserted data.  At this stage
+             prepare_to_modify_buffer has been called, but
+             signal_after_change hasn't.  A continue statement
+             restarts the enclosing while (1) loop.  A second,
+             unwanted, call to `prepare_to_modify_buffer' is inhibited
+             by the test perpared_pos < PT.  The data are inserted
+             again, and this time signal_after_change gets called,
+             balancing the previous call to prepare_to_modify_buffer.  */
+          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 +809,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
@@ -824,6 +854,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd,
 
              TEMP_SET_PT_BOTH (PT + process_coding.produced_char,
                                PT_BYTE + process_coding.produced);
+              signal_after_change (PT, 0, process_coding.produced_char);
              carryover = process_coding.carryover_bytes;
              if (carryover > 0)
                memcpy (buf, process_coding.carryover,