insdel.c 23.3 KB
Newer Older
Jim Blandy's avatar
Jim Blandy committed
1
/* Buffer insertion/deletion and gap motion for GNU Emacs.
Karl Heuer's avatar
Karl Heuer committed
2
   Copyright (C) 1985, 1986, 1993, 1994, 1995 Free Software Foundation, Inc.
Jim Blandy's avatar
Jim Blandy committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

This file is part of GNU Emacs.

GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */


21
#include <config.h>
Jim Blandy's avatar
Jim Blandy committed
22
#include "lisp.h"
23
#include "intervals.h"
Jim Blandy's avatar
Jim Blandy committed
24 25
#include "buffer.h"
#include "window.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
26
#include "blockinput.h"
Jim Blandy's avatar
Jim Blandy committed
27

28
static void insert_from_string_1 ();
29
static void insert_from_buffer_1 ();
Karl Heuer's avatar
Karl Heuer committed
30 31 32
static void gap_left ();
static void gap_right ();
static void adjust_markers ();
Karl Heuer's avatar
Karl Heuer committed
33
static void adjust_point ();
34

Jim Blandy's avatar
Jim Blandy committed
35 36 37
/* Move gap to position `pos'.
   Note that this can quit!  */

38
void
Jim Blandy's avatar
Jim Blandy committed
39 40 41 42 43 44 45 46 47 48 49 50
move_gap (pos)
     int pos;
{
  if (pos < GPT)
    gap_left (pos, 0);
  else if (pos > GPT)
    gap_right (pos);
}

/* Move the gap to POS, which is less than the current GPT.
   If NEWGAP is nonzero, then don't update beg_unchanged and end_unchanged.  */

Karl Heuer's avatar
Karl Heuer committed
51
static void
Jim Blandy's avatar
Jim Blandy committed
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
gap_left (pos, newgap)
     register int pos;
     int newgap;
{
  register unsigned char *to, *from;
  register int i;
  int new_s1;

  pos--;

  if (!newgap)
    {
      if (unchanged_modified == MODIFF)
	{
	  beg_unchanged = pos;
	  end_unchanged = Z - pos - 1;
	}
      else
	{
	  if (Z - GPT < end_unchanged)
	    end_unchanged = Z - GPT;
	  if (pos < beg_unchanged)
	    beg_unchanged = pos;
	}
    }

  i = GPT;
  to = GAP_END_ADDR;
  from = GPT_ADDR;
  new_s1 = GPT - BEG;

  /* Now copy the characters.  To move the gap down,
     copy characters up.  */

  while (1)
    {
      /* I gets number of characters left to copy.  */
      i = new_s1 - pos;
      if (i == 0)
	break;
      /* If a quit is requested, stop copying now.
	 Change POS to be where we have actually moved the gap to.  */
      if (QUITP)
	{
	  pos = new_s1;
	  break;
	}
      /* Move at most 32000 chars before checking again for a quit.  */
      if (i > 32000)
	i = 32000;
#ifdef GAP_USE_BCOPY
      if (i >= 128
	  /* bcopy is safe if the two areas of memory do not overlap
	     or on systems where bcopy is always safe for moving upward.  */
	  && (BCOPY_UPWARD_SAFE
	      || to - from >= 128))
	{
	  /* If overlap is not safe, avoid it by not moving too many
	     characters at once.  */
	  if (!BCOPY_UPWARD_SAFE && i > to - from)
	    i = to - from;
	  new_s1 -= i;
	  from -= i, to -= i;
	  bcopy (from, to, i);
	}
      else
#endif
	{
	  new_s1 -= i;
	  while (--i >= 0)
	    *--to = *--from;
	}
    }

  /* Adjust markers, and buffer data structure, to put the gap at POS.
     POS is where the loop above stopped, which may be what was specified
     or may be where a quit was detected.  */
  adjust_markers (pos + 1, GPT, GAP_SIZE);
  GPT = pos + 1;
  QUIT;
}

Karl Heuer's avatar
Karl Heuer committed
134
static void
Jim Blandy's avatar
Jim Blandy committed
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
gap_right (pos)
     register int pos;
{
  register unsigned char *to, *from;
  register int i;
  int new_s1;

  pos--;

  if (unchanged_modified == MODIFF)
    {
      beg_unchanged = pos;
      end_unchanged = Z - pos - 1;
    }
  else
    {
      if (Z - pos - 1 < end_unchanged)
	end_unchanged = Z - pos - 1;
      if (GPT - BEG < beg_unchanged)
	beg_unchanged = GPT - BEG;
    }

  i = GPT;
  from = GAP_END_ADDR;
  to = GPT_ADDR;
  new_s1 = GPT - 1;

  /* Now copy the characters.  To move the gap up,
     copy characters down.  */

  while (1)
    {
      /* I gets number of characters left to copy.  */
      i = pos - new_s1;
      if (i == 0)
	break;
      /* If a quit is requested, stop copying now.
	 Change POS to be where we have actually moved the gap to.  */
      if (QUITP)
	{
	  pos = new_s1;
	  break;
	}
      /* Move at most 32000 chars before checking again for a quit.  */
      if (i > 32000)
	i = 32000;
#ifdef GAP_USE_BCOPY
      if (i >= 128
	  /* bcopy is safe if the two areas of memory do not overlap
	     or on systems where bcopy is always safe for moving downward.  */
	  && (BCOPY_DOWNWARD_SAFE
	      || from - to >= 128))
	{
	  /* If overlap is not safe, avoid it by not moving too many
	     characters at once.  */
	  if (!BCOPY_DOWNWARD_SAFE && i > from - to)
	    i = from - to;
	  new_s1 += i;
	  bcopy (from, to, i);
	  from += i, to += i;
	}
      else
#endif
	{
	  new_s1 += i;
	  while (--i >= 0)
	    *to++ = *from++;
	}
    }

  adjust_markers (GPT + GAP_SIZE, pos + 1 + GAP_SIZE, - GAP_SIZE);
  GPT = pos + 1;
  QUIT;
}

/* Add `amount' to the position of every marker in the current buffer
   whose current position is between `from' (exclusive) and `to' (inclusive).
   Also, any markers past the outside of that interval, in the direction
   of adjustment, are first moved back to the near end of the interval
   and then adjusted by `amount'.  */

Karl Heuer's avatar
Karl Heuer committed
216
static void
Jim Blandy's avatar
Jim Blandy committed
217 218 219 220 221 222 223
adjust_markers (from, to, amount)
     register int from, to, amount;
{
  Lisp_Object marker;
  register struct Lisp_Marker *m;
  register int mpos;

224
  marker = BUF_MARKERS (current_buffer);
Jim Blandy's avatar
Jim Blandy committed
225

Jim Blandy's avatar
Jim Blandy committed
226
  while (!NILP (marker))
Jim Blandy's avatar
Jim Blandy committed
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
    {
      m = XMARKER (marker);
      mpos = m->bufpos;
      if (amount > 0)
	{
	  if (mpos > to && mpos < to + amount)
	    mpos = to + amount;
	}
      else
	{
	  if (mpos > from + amount && mpos <= from)
	    mpos = from + amount;
	}
      if (mpos > from && mpos <= to)
	mpos += amount;
      m->bufpos = mpos;
      marker = m->chain;
    }
}
Karl Heuer's avatar
Karl Heuer committed
246 247 248 249 250 251 252 253 254 255 256

/* Add the specified amount to point.  This is used only when the value
   of point changes due to an insert or delete; it does not represent
   a conceptual change in point as a marker.  In particular, point is
   not crossing any interval boundaries, so there's no need to use the
   usual SET_PT macro.  In fact it would be incorrect to do so, because
   either the old or the new value of point is out of synch with the
   current set of intervals.  */
static void
adjust_point (amount)
{
257
  BUF_PT (current_buffer) += amount;
Karl Heuer's avatar
Karl Heuer committed
258
}
Jim Blandy's avatar
Jim Blandy committed
259 260 261

/* Make the gap INCREMENT characters longer.  */

262
void
Jim Blandy's avatar
Jim Blandy committed
263 264 265 266 267 268 269 270 271 272 273
make_gap (increment)
     int increment;
{
  unsigned char *result;
  Lisp_Object tem;
  int real_gap_loc;
  int old_gap_size;

  /* If we have to get more space, get enough to last a while.  */
  increment += 2000;

274 275 276 277 278 279 280 281
  /* Don't allow a buffer size that won't fit in an int
     even if it will fit in a Lisp integer.
     That won't work because so many places use `int'.  */
     
  if (VALBITS > INTBITS
      && (Z - BEG + GAP_SIZE + increment) >= ((unsigned) 1 << (INTBITS - 1)))
    error ("Buffer too big");

282
  BLOCK_INPUT;
Jim Blandy's avatar
Jim Blandy committed
283
  result = BUFFER_REALLOC (BEG_ADDR, (Z - BEG + GAP_SIZE + increment));
284

Jim Blandy's avatar
Jim Blandy committed
285
  if (result == 0)
286 287 288 289 290 291
    {
      UNBLOCK_INPUT;
      memory_full ();
    }

  /* We can't unblock until the new address is properly stored.  */
Jim Blandy's avatar
Jim Blandy committed
292
  BEG_ADDR = result;
293
  UNBLOCK_INPUT;
Jim Blandy's avatar
Jim Blandy committed
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317

  /* Prevent quitting in move_gap.  */
  tem = Vinhibit_quit;
  Vinhibit_quit = Qt;

  real_gap_loc = GPT;
  old_gap_size = GAP_SIZE;

  /* Call the newly allocated space a gap at the end of the whole space.  */
  GPT = Z + GAP_SIZE;
  GAP_SIZE = increment;

  /* Move the new gap down to be consecutive with the end of the old one.
     This adjusts the markers properly too.  */
  gap_left (real_gap_loc + old_gap_size, 1);

  /* Now combine the two into one large gap.  */
  GAP_SIZE += old_gap_size;
  GPT = real_gap_loc;

  Vinhibit_quit = tem;
}

/* Insert a string of specified length before point.
318 319
   DO NOT use this for the contents of a Lisp string or a Lisp buffer!
   prepare_to_modify_buffer could relocate the text.  */
Jim Blandy's avatar
Jim Blandy committed
320

321
void
Jim Blandy's avatar
Jim Blandy committed
322 323 324 325
insert (string, length)
     register unsigned char *string;
     register length;
{
326 327
  if (length > 0)
    {
328
      insert_1 (string, length, 0, 1);
329 330 331 332
      signal_after_change (PT-length, 0, length);
    }
}

333
void
334 335 336 337 338 339
insert_and_inherit (string, length)
     register unsigned char *string;
     register length;
{
  if (length > 0)
    {
340
      insert_1 (string, length, 1, 1);
Karl Heuer's avatar
Karl Heuer committed
341
      signal_after_change (PT-length, 0, length);
342 343
    }
}
Jim Blandy's avatar
Jim Blandy committed
344

345 346
void
insert_1 (string, length, inherit, prepare)
347
     register unsigned char *string;
348 349
     register int length;
     int inherit, prepare;
350 351
{
  register Lisp_Object temp;
Jim Blandy's avatar
Jim Blandy committed
352 353

  /* Make sure point-max won't overflow after this insertion.  */
354
  XSETINT (temp, length + Z);
Jim Blandy's avatar
Jim Blandy committed
355 356 357
  if (length + Z != XINT (temp))
    error ("maximum buffer size exceeded");

358 359
  if (prepare)
    prepare_to_modify_buffer (PT, PT);
Jim Blandy's avatar
Jim Blandy committed
360

Karl Heuer's avatar
Karl Heuer committed
361 362
  if (PT != GPT)
    move_gap (PT);
Jim Blandy's avatar
Jim Blandy committed
363 364 365
  if (GAP_SIZE < length)
    make_gap (length - GAP_SIZE);

Karl Heuer's avatar
Karl Heuer committed
366
  record_insert (PT, length);
Jim Blandy's avatar
Jim Blandy committed
367 368 369 370
  MODIFF++;

  bcopy (string, GPT_ADDR, length);

371
#ifdef USE_TEXT_PROPERTIES
372
  if (BUF_INTERVALS (current_buffer) != 0)
373 374 375
    /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES.  */
    offset_intervals (current_buffer, PT, length);
#endif
376

Jim Blandy's avatar
Jim Blandy committed
377 378 379 380
  GAP_SIZE -= length;
  GPT += length;
  ZV += length;
  Z += length;
381
  adjust_overlays_for_insert (PT, length);
Karl Heuer's avatar
Karl Heuer committed
382
  adjust_point (length);
383

384
#ifdef USE_TEXT_PROPERTIES
385
  if (!inherit && BUF_INTERVALS (current_buffer) != 0)
386 387
    Fset_text_properties (make_number (PT - length), make_number (PT),
			  Qnil, Qnil);
388
#endif
Jim Blandy's avatar
Jim Blandy committed
389 390
}

391 392 393 394 395 396
/* Insert the part of the text of STRING, a Lisp object assumed to be
   of type string, consisting of the LENGTH characters starting at
   position POS.  If the text of STRING has properties, they are absorbed
   into the buffer.

   It does not work to use `insert' for this, because a GC could happen
Jim Blandy's avatar
Jim Blandy committed
397 398
   before we bcopy the stuff into the buffer, and relocate the string
   without insert noticing.  */
399

400
void
401
insert_from_string (string, pos, length, inherit)
Jim Blandy's avatar
Jim Blandy committed
402 403
     Lisp_Object string;
     register int pos, length;
404
     int inherit;
405 406 407 408
{
  if (length > 0)
    {
      insert_from_string_1 (string, pos, length, inherit);
Karl Heuer's avatar
Karl Heuer committed
409
      signal_after_change (PT-length, 0, length);
410 411 412 413 414 415 416 417
    }
}

static void
insert_from_string_1 (string, pos, length, inherit)
     Lisp_Object string;
     register int pos, length;
     int inherit;
Jim Blandy's avatar
Jim Blandy committed
418 419 420 421 422
{
  register Lisp_Object temp;
  struct gcpro gcpro1;

  /* Make sure point-max won't overflow after this insertion.  */
423
  XSETINT (temp, length + Z);
Jim Blandy's avatar
Jim Blandy committed
424 425 426 427
  if (length + Z != XINT (temp))
    error ("maximum buffer size exceeded");

  GCPRO1 (string);
Karl Heuer's avatar
Karl Heuer committed
428
  prepare_to_modify_buffer (PT, PT);
Jim Blandy's avatar
Jim Blandy committed
429

Karl Heuer's avatar
Karl Heuer committed
430 431
  if (PT != GPT)
    move_gap (PT);
Jim Blandy's avatar
Jim Blandy committed
432 433 434
  if (GAP_SIZE < length)
    make_gap (length - GAP_SIZE);

Karl Heuer's avatar
Karl Heuer committed
435
  record_insert (PT, length);
Jim Blandy's avatar
Jim Blandy committed
436 437 438 439 440
  MODIFF++;
  UNGCPRO;

  bcopy (XSTRING (string)->data, GPT_ADDR, length);

441
  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
Karl Heuer's avatar
Karl Heuer committed
442
  offset_intervals (current_buffer, PT, length);
443

Jim Blandy's avatar
Jim Blandy committed
444 445 446 447
  GAP_SIZE -= length;
  GPT += length;
  ZV += length;
  Z += length;
448
  adjust_overlays_for_insert (PT, length);
449 450

  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
Karl Heuer's avatar
Karl Heuer committed
451
  graft_intervals_into_buffer (XSTRING (string)->intervals, PT, length,
452
			       current_buffer, inherit);
453

Karl Heuer's avatar
Karl Heuer committed
454
  adjust_point (length);
Jim Blandy's avatar
Jim Blandy committed
455 456
}

457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
/* Insert text from BUF, starting at POS and having length LENGTH, into the
   current buffer.  If the text in BUF has properties, they are absorbed
   into the current buffer.

   It does not work to use `insert' for this, because a malloc could happen
   and relocate BUF's text before the bcopy happens.  */

void
insert_from_buffer (buf, pos, length, inherit)
     struct buffer *buf;
     int pos, length;
     int inherit;
{
  if (length > 0)
    {
      insert_from_buffer_1 (buf, pos, length, inherit);
      signal_after_change (PT-length, 0, length);
    }
}

static void
insert_from_buffer_1 (buf, pos, length, inherit)
     struct buffer *buf;
     int pos, length;
     int inherit;
{
  register Lisp_Object temp;
  int chunk;

  /* Make sure point-max won't overflow after this insertion.  */
  XSETINT (temp, length + Z);
  if (length + Z != XINT (temp))
    error ("maximum buffer size exceeded");

  prepare_to_modify_buffer (PT, PT);

  if (PT != GPT)
    move_gap (PT);
  if (GAP_SIZE < length)
    make_gap (length - GAP_SIZE);

  record_insert (PT, length);
  MODIFF++;

  if (pos < BUF_GPT (buf))
    {
503 504 505
      chunk = BUF_GPT (buf) - pos;
      if (chunk > length)
	chunk = length;
506 507 508 509 510 511 512 513 514
      bcopy (BUF_CHAR_ADDRESS (buf, pos), GPT_ADDR, chunk);
    }
  else
    chunk = 0;
  if (chunk < length)
    bcopy (BUF_CHAR_ADDRESS (buf, pos + chunk),
	   GPT_ADDR + chunk, length - chunk);

#ifdef USE_TEXT_PROPERTIES
515
  if (BUF_INTERVALS (current_buffer) != 0)
516 517 518 519 520 521 522
    offset_intervals (current_buffer, PT, length);
#endif

  GAP_SIZE -= length;
  GPT += length;
  ZV += length;
  Z += length;
523
  adjust_overlays_for_insert (PT, length);
524 525 526
  adjust_point (length);

  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
527 528
  graft_intervals_into_buffer (copy_intervals (BUF_INTERVALS (buf),
					       pos, length),
529 530 531
			       PT - length, length, current_buffer, inherit);
}

Jim Blandy's avatar
Jim Blandy committed
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
/* Insert the character C before point */

void
insert_char (c)
     unsigned char c;
{
  insert (&c, 1);
}

/* Insert the null-terminated string S before point */

void
insert_string (s)
     char *s;
{
  insert (s, strlen (s));
}

/* Like `insert' except that all markers pointing at the place where
   the insertion happens are adjusted to point after it.
   Don't use this function to insert part of a Lisp string,
   since gc could happen and relocate it.  */

555
void
Jim Blandy's avatar
Jim Blandy committed
556 557 558 559
insert_before_markers (string, length)
     unsigned char *string;
     register int length;
{
560 561
  if (length > 0)
    {
Karl Heuer's avatar
Karl Heuer committed
562
      register int opoint = PT;
563
      insert_1 (string, length, 0, 1);
564
      adjust_markers (opoint - 1, opoint, length);
Karl Heuer's avatar
Karl Heuer committed
565
      signal_after_change (PT-length, 0, length);
566
    }
Jim Blandy's avatar
Jim Blandy committed
567 568
}

569
void
570 571 572 573 574 575 576
insert_before_markers_and_inherit (string, length)
     unsigned char *string;
     register int length;
{
  if (length > 0)
    {
      register int opoint = PT;
577
      insert_1 (string, length, 1, 1);
578 579 580 581 582
      adjust_markers (opoint - 1, opoint, length);
      signal_after_change (PT-length, 0, length);
    }
}

Jim Blandy's avatar
Jim Blandy committed
583 584
/* Insert part of a Lisp string, relocating markers after.  */

585
void
586
insert_from_string_before_markers (string, pos, length, inherit)
Jim Blandy's avatar
Jim Blandy committed
587 588
     Lisp_Object string;
     register int pos, length;
589
     int inherit;
Jim Blandy's avatar
Jim Blandy committed
590
{
591 592
  if (length > 0)
    {
Karl Heuer's avatar
Karl Heuer committed
593
      register int opoint = PT;
594 595
      insert_from_string_1 (string, pos, length, inherit);
      adjust_markers (opoint - 1, opoint, length);
Karl Heuer's avatar
Karl Heuer committed
596
      signal_after_change (PT-length, 0, length);
597
    }
Jim Blandy's avatar
Jim Blandy committed
598 599 600 601 602
}

/* Delete characters in current buffer
   from FROM up to (but not including) TO.  */

603
void
Jim Blandy's avatar
Jim Blandy committed
604 605
del_range (from, to)
     register int from, to;
606
{
607
  del_range_1 (from, to, 1);
608 609 610 611
}

/* Like del_range; PREPARE says whether to call prepare_to_modify_buffer.  */

612
void
613 614
del_range_1 (from, to, prepare)
     register int from, to, prepare;
Jim Blandy's avatar
Jim Blandy committed
615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632
{
  register int numdel;

  /* Make args be valid */
  if (from < BEGV)
    from = BEGV;
  if (to > ZV)
    to = ZV;

  if ((numdel = to - from) <= 0)
    return;

  /* Make sure the gap is somewhere in or next to what we are deleting.  */
  if (from > GPT)
    gap_right (from);
  if (to < GPT)
    gap_left (to, 0);

633 634
  if (prepare)
    prepare_to_modify_buffer (from, to);
Jim Blandy's avatar
Jim Blandy committed
635

636 637 638
  record_delete (from, numdel);
  MODIFF++;

Jim Blandy's avatar
Jim Blandy committed
639
  /* Relocate point as if it were a marker.  */
Karl Heuer's avatar
Karl Heuer committed
640
  if (from < PT)
Karl Heuer's avatar
Karl Heuer committed
641
    adjust_point (from - (PT < to ? PT : to));
Jim Blandy's avatar
Jim Blandy committed
642

643
  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
644
  offset_intervals (current_buffer, from, - numdel);
645

Jim Blandy's avatar
Jim Blandy committed
646 647 648 649
  /* Relocate all markers pointing into the new, larger gap
     to point at the end of the text before the gap.  */
  adjust_markers (to + GAP_SIZE, to + GAP_SIZE, - numdel - GAP_SIZE);

650 651 652 653
  /* Adjust the overlay center as needed.  This must be done after
   adjusting the markers that bound the overlays.  */
  adjust_overlays_for_delete (from, numdel);

Jim Blandy's avatar
Jim Blandy committed
654 655 656 657 658 659 660 661 662 663
  GAP_SIZE += numdel;
  ZV -= numdel;
  Z -= numdel;
  GPT = from;

  if (GPT - BEG < beg_unchanged)
    beg_unchanged = GPT - BEG;
  if (Z - GPT < end_unchanged)
    end_unchanged = Z - GPT;

664
  evaporate_overlays (from);
Jim Blandy's avatar
Jim Blandy committed
665 666 667
  signal_after_change (from, numdel, 0);
}

668 669 670 671
/* Call this if you're about to change the region of BUFFER from START
   to END.  This checks the read-only properties of the region, calls
   the necessary modification hooks, and warns the next redisplay that
   it should pay attention to that area.  */
672
void
673 674
modify_region (buffer, start, end)
     struct buffer *buffer;
Jim Blandy's avatar
Jim Blandy committed
675 676
     int start, end;
{
677 678 679 680 681
  struct buffer *old_buffer = current_buffer;

  if (buffer != old_buffer)
    set_buffer_internal (buffer);

Jim Blandy's avatar
Jim Blandy committed
682 683 684 685 686 687 688
  prepare_to_modify_buffer (start, end);

  if (start - 1 < beg_unchanged || unchanged_modified == MODIFF)
    beg_unchanged = start - 1;
  if (Z - end < end_unchanged
      || unchanged_modified == MODIFF)
    end_unchanged = Z - end;
689

690
  if (MODIFF <= SAVE_MODIFF)
691
    record_first_change ();
Jim Blandy's avatar
Jim Blandy committed
692
  MODIFF++;
693

694 695
  buffer->point_before_scroll = Qnil;

696 697
  if (buffer != old_buffer)
    set_buffer_internal (old_buffer);
Jim Blandy's avatar
Jim Blandy committed
698 699 700
}

/* Check that it is okay to modify the buffer between START and END.
701 702 703
   Run the before-change-function, if any.  If intervals are in use,
   verify that the text to be modified is not read-only, and call
   any modification properties the text may have. */
Jim Blandy's avatar
Jim Blandy committed
704

705
void
Jim Blandy's avatar
Jim Blandy committed
706 707 708
prepare_to_modify_buffer (start, end)
     Lisp_Object start, end;
{
Jim Blandy's avatar
Jim Blandy committed
709
  if (!NILP (current_buffer->read_only))
Jim Blandy's avatar
Jim Blandy committed
710 711
    Fbarf_if_buffer_read_only ();

712
  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
713
  if (BUF_INTERVALS (current_buffer) != 0)
714
    verify_interval_modification (current_buffer, start, end);
Jim Blandy's avatar
Jim Blandy committed
715 716

#ifdef CLASH_DETECTION
717
  if (!NILP (current_buffer->file_truename)
718
      && SAVE_MODIFF >= MODIFF)
719
    lock_file (current_buffer->file_truename);
Jim Blandy's avatar
Jim Blandy committed
720 721
#else
  /* At least warn if this file has changed on disk since it was visited.  */
Jim Blandy's avatar
Jim Blandy committed
722
  if (!NILP (current_buffer->filename)
723
      && SAVE_MODIFF >= MODIFF
Jim Blandy's avatar
Jim Blandy committed
724 725
      && NILP (Fverify_visited_file_modtime (Fcurrent_buffer ()))
      && !NILP (Ffile_exists_p (current_buffer->filename)))
Jim Blandy's avatar
Jim Blandy committed
726 727 728 729 730
    call1 (intern ("ask-user-about-supersession-threat"),
	   current_buffer->filename);
#endif /* not CLASH_DETECTION */

  signal_before_change (start, end);
731

732 733 734 735 736 737 738 739 740
  if (current_buffer->newline_cache)
    invalidate_region_cache (current_buffer,
                             current_buffer->newline_cache,
                             start - BEG, Z - end);
  if (current_buffer->width_run_cache)
    invalidate_region_cache (current_buffer,
                             current_buffer->width_run_cache,
                             start - BEG, Z - end);

741
  Vdeactivate_mark = Qt;
Jim Blandy's avatar
Jim Blandy committed
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
}

static Lisp_Object
before_change_function_restore (value)
     Lisp_Object value;
{
  Vbefore_change_function = value;
}

static Lisp_Object
after_change_function_restore (value)
     Lisp_Object value;
{
  Vafter_change_function = value;
}

758 759 760 761 762 763 764 765 766 767 768 769 770 771
static Lisp_Object
before_change_functions_restore (value)
     Lisp_Object value;
{
  Vbefore_change_functions = value;
}

static Lisp_Object
after_change_functions_restore (value)
     Lisp_Object value;
{
  Vafter_change_functions = value;
}

772
/* Signal a change to the buffer immediately before it happens.
Jim Blandy's avatar
Jim Blandy committed
773 774 775
   START and END are the bounds of the text to be changed,
   as Lisp objects.  */

776
void
Jim Blandy's avatar
Jim Blandy committed
777 778 779 780
signal_before_change (start, end)
     Lisp_Object start, end;
{
  /* If buffer is unmodified, run a special hook for that case.  */
781
  if (SAVE_MODIFF >= MODIFF
Jim Blandy's avatar
Jim Blandy committed
782 783 784 785
      && !NILP (Vfirst_change_hook)
      && !NILP (Vrun_hooks))
    call1 (Vrun_hooks, Qfirst_change_hook);

Jim Blandy's avatar
Jim Blandy committed
786
  /* Now in any case run the before-change-function if any.  */
Jim Blandy's avatar
Jim Blandy committed
787
  if (!NILP (Vbefore_change_function))
Jim Blandy's avatar
Jim Blandy committed
788 789 790 791 792
    {
      int count = specpdl_ptr - specpdl;
      Lisp_Object function;

      function = Vbefore_change_function;
793

Jim Blandy's avatar
Jim Blandy committed
794 795 796 797
      record_unwind_protect (after_change_function_restore,
			     Vafter_change_function);
      record_unwind_protect (before_change_function_restore,
			     Vbefore_change_function);
798 799 800 801
      record_unwind_protect (after_change_functions_restore,
			     Vafter_change_functions);
      record_unwind_protect (before_change_functions_restore,
			     Vbefore_change_functions);
Jim Blandy's avatar
Jim Blandy committed
802 803
      Vafter_change_function = Qnil;
      Vbefore_change_function = Qnil;
804 805
      Vafter_change_functions = Qnil;
      Vbefore_change_functions = Qnil;
Jim Blandy's avatar
Jim Blandy committed
806 807 808 809

      call2 (function, start, end);
      unbind_to (count, Qnil);
    }
810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838

  /* Now in any case run the before-change-function if any.  */
  if (!NILP (Vbefore_change_functions))
    {
      int count = specpdl_ptr - specpdl;
      Lisp_Object functions;

      functions = Vbefore_change_functions;

      record_unwind_protect (after_change_function_restore,
			     Vafter_change_function);
      record_unwind_protect (before_change_function_restore,
			     Vbefore_change_function);
      record_unwind_protect (after_change_functions_restore,
			     Vafter_change_functions);
      record_unwind_protect (before_change_functions_restore,
			     Vbefore_change_functions);
      Vafter_change_function = Qnil;
      Vbefore_change_function = Qnil;
      Vafter_change_functions = Qnil;
      Vbefore_change_functions = Qnil;

      while (CONSP (functions))
	{
	  call2 (XCONS (functions)->car, start, end);
	  functions = XCONS (functions)->cdr;
	}
      unbind_to (count, Qnil);
    }
839 840 841

  if (!NILP (current_buffer->overlays_before)
      || !NILP (current_buffer->overlays_after))
842
    report_overlay_modification (start, end, 0, start, end, Qnil);
Jim Blandy's avatar
Jim Blandy committed
843 844
}

845
/* Signal a change immediately after it happens.
Jim Blandy's avatar
Jim Blandy committed
846 847 848
   POS is the address of the start of the changed text.
   LENDEL is the number of characters of the text before the change.
   (Not the whole buffer; just the part that was changed.)
849 850 851
   LENINS is the number of characters in the changed text.

   (Hence POS + LENINS - LENDEL is the position after the changed text.)  */
Jim Blandy's avatar
Jim Blandy committed
852

853
void
Jim Blandy's avatar
Jim Blandy committed
854 855 856
signal_after_change (pos, lendel, lenins)
     int pos, lendel, lenins;
{
Jim Blandy's avatar
Jim Blandy committed
857
  if (!NILP (Vafter_change_function))
Jim Blandy's avatar
Jim Blandy committed
858 859 860 861 862 863 864 865 866
    {
      int count = specpdl_ptr - specpdl;
      Lisp_Object function;
      function = Vafter_change_function;

      record_unwind_protect (after_change_function_restore,
			     Vafter_change_function);
      record_unwind_protect (before_change_function_restore,
			     Vbefore_change_function);
867 868 869 870
      record_unwind_protect (after_change_functions_restore,
			     Vafter_change_functions);
      record_unwind_protect (before_change_functions_restore,
			     Vbefore_change_functions);
Jim Blandy's avatar
Jim Blandy committed
871 872
      Vafter_change_function = Qnil;
      Vbefore_change_function = Qnil;
873 874
      Vafter_change_functions = Qnil;
      Vbefore_change_functions = Qnil;
Jim Blandy's avatar
Jim Blandy committed
875 876 877 878 879

      call3 (function, make_number (pos), make_number (pos + lenins),
	     make_number (lendel));
      unbind_to (count, Qnil);
    }
880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907
  if (!NILP (Vafter_change_functions))
    {
      int count = specpdl_ptr - specpdl;
      Lisp_Object functions;
      functions = Vafter_change_functions;

      record_unwind_protect (after_change_function_restore,
			     Vafter_change_function);
      record_unwind_protect (before_change_function_restore,
			     Vbefore_change_function);
      record_unwind_protect (after_change_functions_restore,
			     Vafter_change_functions);
      record_unwind_protect (before_change_functions_restore,
			     Vbefore_change_functions);
      Vafter_change_function = Qnil;
      Vbefore_change_function = Qnil;
      Vafter_change_functions = Qnil;
      Vbefore_change_functions = Qnil;

      while (CONSP (functions))
	{
	  call3 (XCONS (functions)->car,
		 make_number (pos), make_number (pos + lenins),
		 make_number (lendel));
	  functions = XCONS (functions)->cdr;
	}
      unbind_to (count, Qnil);
    }
908 909 910

  if (!NILP (current_buffer->overlays_before)
      || !NILP (current_buffer->overlays_after))
911
    report_overlay_modification (make_number (pos),
912 913 914 915
				 make_number (pos + lenins - lendel),
				 1,
				 make_number (pos), make_number (pos + lenins),
				 make_number (lendel));
Jim Blandy's avatar
Jim Blandy committed
916
}