insdel.c 22.7 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

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
Karl Heuer's avatar
Karl Heuer committed
8
the Free Software Foundation; either version 2, or (at your option)
Jim Blandy's avatar
Jim Blandy committed
9 10 11 12 13 14 15 16 17 18 19 20
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 29
#define min(x, y) ((x) < (y) ? (x) : (y))

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

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

40
void
Jim Blandy's avatar
Jim Blandy committed
41 42 43 44 45 46 47 48 49 50 51 52
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
53
static void
Jim Blandy's avatar
Jim Blandy committed
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 134 135
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
136
static void
Jim Blandy's avatar
Jim Blandy committed
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 216 217
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
218
static void
Jim Blandy's avatar
Jim Blandy committed
219 220 221 222 223 224 225
adjust_markers (from, to, amount)
     register int from, to, amount;
{
  Lisp_Object marker;
  register struct Lisp_Marker *m;
  register int mpos;

226
  marker = BUF_MARKERS (current_buffer);
Jim Blandy's avatar
Jim Blandy committed
227

Jim Blandy's avatar
Jim Blandy committed
228
  while (!NILP (marker))
Jim Blandy's avatar
Jim Blandy committed
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
    {
      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
248

249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
/* Adjust markers whose insertion-type is t
   for an insertion of AMOUNT characters at POS.  */

static void
adjust_markers_for_insert (pos, amount)
     register int pos, amount;
{
  Lisp_Object marker;

  marker = BUF_MARKERS (current_buffer);

  while (!NILP (marker))
    {
      register struct Lisp_Marker *m = XMARKER (marker);
      if (m->insertion_type && m->bufpos == pos)
	m->bufpos += amount;
      marker = m->chain;
    }
}

Karl Heuer's avatar
Karl Heuer committed
269 270 271 272 273 274 275 276 277
/* 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)
278
     int amount;
Karl Heuer's avatar
Karl Heuer committed
279
{
280
  BUF_PT (current_buffer) += amount;
Karl Heuer's avatar
Karl Heuer committed
281
}
Jim Blandy's avatar
Jim Blandy committed
282 283 284

/* Make the gap INCREMENT characters longer.  */

285
void
Jim Blandy's avatar
Jim Blandy committed
286 287 288 289 290 291 292 293 294 295 296
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;

297 298 299 300
  /* 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'.  */
     
301 302 303
  if (Z - BEG + GAP_SIZE + increment
      >= ((unsigned) 1 << (min (INTBITS, VALBITS) - 1)))
    error ("Buffer exceeds maximum size");
304

305
  BLOCK_INPUT;
Jim Blandy's avatar
Jim Blandy committed
306
  result = BUFFER_REALLOC (BEG_ADDR, (Z - BEG + GAP_SIZE + increment));
307

Jim Blandy's avatar
Jim Blandy committed
308
  if (result == 0)
309 310 311 312 313 314
    {
      UNBLOCK_INPUT;
      memory_full ();
    }

  /* We can't unblock until the new address is properly stored.  */
Jim Blandy's avatar
Jim Blandy committed
315
  BEG_ADDR = result;
316
  UNBLOCK_INPUT;
Jim Blandy's avatar
Jim Blandy committed
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340

  /* 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.
341 342
   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
343

344
void
Jim Blandy's avatar
Jim Blandy committed
345 346 347 348
insert (string, length)
     register unsigned char *string;
     register length;
{
349 350
  if (length > 0)
    {
351
      insert_1 (string, length, 0, 1);
352 353 354 355
      signal_after_change (PT-length, 0, length);
    }
}

356
void
357 358 359 360 361 362
insert_and_inherit (string, length)
     register unsigned char *string;
     register length;
{
  if (length > 0)
    {
363
      insert_1 (string, length, 1, 1);
Karl Heuer's avatar
Karl Heuer committed
364
      signal_after_change (PT-length, 0, length);
365 366
    }
}
Jim Blandy's avatar
Jim Blandy committed
367

368 369
void
insert_1 (string, length, inherit, prepare)
370
     register unsigned char *string;
371 372
     register int length;
     int inherit, prepare;
373 374
{
  register Lisp_Object temp;
Jim Blandy's avatar
Jim Blandy committed
375

376 377
  if (prepare)
    prepare_to_modify_buffer (PT, PT);
Jim Blandy's avatar
Jim Blandy committed
378

Karl Heuer's avatar
Karl Heuer committed
379 380
  if (PT != GPT)
    move_gap (PT);
Jim Blandy's avatar
Jim Blandy committed
381 382 383
  if (GAP_SIZE < length)
    make_gap (length - GAP_SIZE);

Karl Heuer's avatar
Karl Heuer committed
384
  record_insert (PT, length);
Jim Blandy's avatar
Jim Blandy committed
385 386 387 388
  MODIFF++;

  bcopy (string, GPT_ADDR, length);

389
#ifdef USE_TEXT_PROPERTIES
390
  if (BUF_INTERVALS (current_buffer) != 0)
391 392 393
    /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES.  */
    offset_intervals (current_buffer, PT, length);
#endif
394

Jim Blandy's avatar
Jim Blandy committed
395 396 397 398
  GAP_SIZE -= length;
  GPT += length;
  ZV += length;
  Z += length;
399
  adjust_overlays_for_insert (PT, length);
400
  adjust_markers_for_insert (PT, length);
Karl Heuer's avatar
Karl Heuer committed
401
  adjust_point (length);
402

403
#ifdef USE_TEXT_PROPERTIES
404
  if (!inherit && BUF_INTERVALS (current_buffer) != 0)
405 406
    Fset_text_properties (make_number (PT - length), make_number (PT),
			  Qnil, Qnil);
407
#endif
Jim Blandy's avatar
Jim Blandy committed
408 409
}

410 411 412 413 414 415
/* 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
416 417
   before we bcopy the stuff into the buffer, and relocate the string
   without insert noticing.  */
418

419
void
420
insert_from_string (string, pos, length, inherit)
Jim Blandy's avatar
Jim Blandy committed
421 422
     Lisp_Object string;
     register int pos, length;
423
     int inherit;
424 425 426 427
{
  if (length > 0)
    {
      insert_from_string_1 (string, pos, length, inherit);
Karl Heuer's avatar
Karl Heuer committed
428
      signal_after_change (PT-length, 0, length);
429 430 431 432 433 434 435 436
    }
}

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
437 438 439 440 441
{
  register Lisp_Object temp;
  struct gcpro gcpro1;

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

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

Karl Heuer's avatar
Karl Heuer committed
449 450
  if (PT != GPT)
    move_gap (PT);
Jim Blandy's avatar
Jim Blandy committed
451 452 453
  if (GAP_SIZE < length)
    make_gap (length - GAP_SIZE);

Karl Heuer's avatar
Karl Heuer committed
454
  record_insert (PT, length);
Jim Blandy's avatar
Jim Blandy committed
455 456 457 458 459
  MODIFF++;
  UNGCPRO;

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

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

Jim Blandy's avatar
Jim Blandy committed
463 464 465 466
  GAP_SIZE -= length;
  GPT += length;
  ZV += length;
  Z += length;
467
  adjust_overlays_for_insert (PT, length);
468
  adjust_markers_for_insert (PT, length);
469 470

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

Karl Heuer's avatar
Karl Heuer committed
474
  adjust_point (length);
Jim Blandy's avatar
Jim Blandy committed
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 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
/* 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))
    {
523 524 525
      chunk = BUF_GPT (buf) - pos;
      if (chunk > length)
	chunk = length;
526 527 528 529 530 531 532 533 534
      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
535
  if (BUF_INTERVALS (current_buffer) != 0)
536 537 538 539 540 541 542
    offset_intervals (current_buffer, PT, length);
#endif

  GAP_SIZE -= length;
  GPT += length;
  ZV += length;
  Z += length;
543
  adjust_overlays_for_insert (PT, length);
544
  adjust_markers_for_insert (PT, length);
545 546 547
  adjust_point (length);

  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
548 549
  graft_intervals_into_buffer (copy_intervals (BUF_INTERVALS (buf),
					       pos, length),
550 551 552
			       PT - length, length, current_buffer, inherit);
}

Jim Blandy's avatar
Jim Blandy committed
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
/* 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.  */

576
void
Jim Blandy's avatar
Jim Blandy committed
577 578 579 580
insert_before_markers (string, length)
     unsigned char *string;
     register int length;
{
581 582
  if (length > 0)
    {
Karl Heuer's avatar
Karl Heuer committed
583
      register int opoint = PT;
584
      insert_1 (string, length, 0, 1);
585
      adjust_markers (opoint - 1, opoint, length);
Karl Heuer's avatar
Karl Heuer committed
586
      signal_after_change (PT-length, 0, length);
587
    }
Jim Blandy's avatar
Jim Blandy committed
588 589
}

590
void
591 592 593 594 595 596 597
insert_before_markers_and_inherit (string, length)
     unsigned char *string;
     register int length;
{
  if (length > 0)
    {
      register int opoint = PT;
598
      insert_1 (string, length, 1, 1);
599 600 601 602 603
      adjust_markers (opoint - 1, opoint, length);
      signal_after_change (PT-length, 0, length);
    }
}

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

606
void
607
insert_from_string_before_markers (string, pos, length, inherit)
Jim Blandy's avatar
Jim Blandy committed
608 609
     Lisp_Object string;
     register int pos, length;
610
     int inherit;
Jim Blandy's avatar
Jim Blandy committed
611
{
612 613
  if (length > 0)
    {
Karl Heuer's avatar
Karl Heuer committed
614
      register int opoint = PT;
615 616
      insert_from_string_1 (string, pos, length, inherit);
      adjust_markers (opoint - 1, opoint, length);
Karl Heuer's avatar
Karl Heuer committed
617
      signal_after_change (PT-length, 0, length);
618
    }
Jim Blandy's avatar
Jim Blandy committed
619 620 621 622 623
}

/* Delete characters in current buffer
   from FROM up to (but not including) TO.  */

624
void
Jim Blandy's avatar
Jim Blandy committed
625 626
del_range (from, to)
     register int from, to;
627
{
628
  del_range_1 (from, to, 1);
629 630 631 632
}

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

633
void
634 635
del_range_1 (from, to, prepare)
     register int from, to, prepare;
Jim Blandy's avatar
Jim Blandy committed
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
{
  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);

654 655
  if (prepare)
    prepare_to_modify_buffer (from, to);
Jim Blandy's avatar
Jim Blandy committed
656

657 658 659
  record_delete (from, numdel);
  MODIFF++;

Jim Blandy's avatar
Jim Blandy committed
660
  /* Relocate point as if it were a marker.  */
Karl Heuer's avatar
Karl Heuer committed
661
  if (from < PT)
Karl Heuer's avatar
Karl Heuer committed
662
    adjust_point (from - (PT < to ? PT : to));
Jim Blandy's avatar
Jim Blandy committed
663

664
  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
665
  offset_intervals (current_buffer, from, - numdel);
666

Jim Blandy's avatar
Jim Blandy committed
667 668 669 670
  /* 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);

671
  /* Adjust the overlay center as needed.  This must be done after
Karl Heuer's avatar
Karl Heuer committed
672
     adjusting the markers that bound the overlays.  */
673 674
  adjust_overlays_for_delete (from, numdel);

Jim Blandy's avatar
Jim Blandy committed
675 676 677 678 679 680 681 682 683 684
  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;

685
  evaporate_overlays (from);
Jim Blandy's avatar
Jim Blandy committed
686 687 688
  signal_after_change (from, numdel, 0);
}

689 690 691 692
/* 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.  */
693
void
694 695
modify_region (buffer, start, end)
     struct buffer *buffer;
Jim Blandy's avatar
Jim Blandy committed
696 697
     int start, end;
{
698 699 700 701 702
  struct buffer *old_buffer = current_buffer;

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

Jim Blandy's avatar
Jim Blandy committed
703 704 705 706 707 708 709
  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;
710

711
  if (MODIFF <= SAVE_MODIFF)
712
    record_first_change ();
Jim Blandy's avatar
Jim Blandy committed
713
  MODIFF++;
714

715 716
  buffer->point_before_scroll = Qnil;

717 718
  if (buffer != old_buffer)
    set_buffer_internal (old_buffer);
Jim Blandy's avatar
Jim Blandy committed
719 720 721
}

/* Check that it is okay to modify the buffer between START and END.
722 723 724
   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
725

726
void
Jim Blandy's avatar
Jim Blandy committed
727 728 729
prepare_to_modify_buffer (start, end)
     Lisp_Object start, end;
{
Jim Blandy's avatar
Jim Blandy committed
730
  if (!NILP (current_buffer->read_only))
Jim Blandy's avatar
Jim Blandy committed
731 732
    Fbarf_if_buffer_read_only ();

733
  /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
734
  if (BUF_INTERVALS (current_buffer) != 0)
735
    verify_interval_modification (current_buffer, start, end);
Jim Blandy's avatar
Jim Blandy committed
736 737

#ifdef CLASH_DETECTION
738
  if (!NILP (current_buffer->file_truename)
739 740
      /* Make binding buffer-file-name to nil effective.  */
      && !NILP (current_buffer->filename)
741
      && SAVE_MODIFF >= MODIFF)
742
    lock_file (current_buffer->file_truename);
Jim Blandy's avatar
Jim Blandy committed
743 744
#else
  /* At least warn if this file has changed on disk since it was visited.  */
Jim Blandy's avatar
Jim Blandy committed
745
  if (!NILP (current_buffer->filename)
746
      && SAVE_MODIFF >= MODIFF
Jim Blandy's avatar
Jim Blandy committed
747 748
      && NILP (Fverify_visited_file_modtime (Fcurrent_buffer ()))
      && !NILP (Ffile_exists_p (current_buffer->filename)))
Jim Blandy's avatar
Jim Blandy committed
749 750 751 752 753
    call1 (intern ("ask-user-about-supersession-threat"),
	   current_buffer->filename);
#endif /* not CLASH_DETECTION */

  signal_before_change (start, end);
754

755 756 757 758 759 760 761 762 763
  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);

764
  Vdeactivate_mark = Qt;
Jim Blandy's avatar
Jim Blandy committed
765 766
}

767
/* Signal a change to the buffer immediately before it happens.
Jim Blandy's avatar
Jim Blandy committed
768 769 770
   START and END are the bounds of the text to be changed,
   as Lisp objects.  */

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

781 782 783
  /* Run the before-change-function if any.
     We don't bother "binding" this variable to nil
     because it is obsolete anyway and new code should not use it.  */
Jim Blandy's avatar
Jim Blandy committed
784
  if (!NILP (Vbefore_change_function))
785
    call2 (Vbefore_change_function, start, end);
786

787
  /* Now run the before-change-functions if any.  */
788 789
  if (!NILP (Vbefore_change_functions))
    {
790 791 792 793 794 795 796 797 798 799
      Lisp_Object args[3];
      Lisp_Object before_change_functions;
      Lisp_Object after_change_functions;
      struct gcpro gcpro1, gcpro2;

      /* "Bind" before-change-functions and after-change-functions
	 to nil--but in a way that errors don't know about.
	 That way, if there's an error in them, they will stay nil.  */
      before_change_functions = Vbefore_change_functions;
      after_change_functions = Vafter_change_functions;
800 801
      Vbefore_change_functions = Qnil;
      Vafter_change_functions = Qnil;
802 803 804 805 806 807 808 809 810 811 812 813
      GCPRO2 (before_change_functions, after_change_functions);

      /* Actually run the hook functions.  */
      args[0] = Qbefore_change_functions;
      args[1] = start;
      args[2] = end;
      run_hook_list_with_args (before_change_functions, 3, args);

      /* "Unbind" the variables we "bound" to nil.  */
      Vbefore_change_functions = before_change_functions;
      Vafter_change_functions = after_change_functions;
      UNGCPRO;
814
    }
815 816 817

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

821
/* Signal a change immediately after it happens.
Jim Blandy's avatar
Jim Blandy committed
822 823 824
   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.)
825 826 827
   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
828

829
void
Jim Blandy's avatar
Jim Blandy committed
830 831 832
signal_after_change (pos, lendel, lenins)
     int pos, lendel, lenins;
{
833 834 835
  /* Run the after-change-function if any.
     We don't bother "binding" this variable to nil
     because it is obsolete anyway and new code should not use it.  */
Jim Blandy's avatar
Jim Blandy committed
836
  if (!NILP (Vafter_change_function))
837 838 839
    call3 (Vafter_change_function,
	   make_number (pos), make_number (pos + lenins),
	   make_number (lendel));
Jim Blandy's avatar
Jim Blandy committed
840

841 842
  if (!NILP (Vafter_change_functions))
    {
843 844 845 846 847 848 849 850 851 852
      Lisp_Object args[4];
      Lisp_Object before_change_functions;
      Lisp_Object after_change_functions;
      struct gcpro gcpro1, gcpro2;

      /* "Bind" before-change-functions and after-change-functions
	 to nil--but in a way that errors don't know about.
	 That way, if there's an error in them, they will stay nil.  */
      before_change_functions = Vbefore_change_functions;
      after_change_functions = Vafter_change_functions;
853 854
      Vbefore_change_functions = Qnil;
      Vafter_change_functions = Qnil;
855 856 857 858 859 860 861 862 863 864 865 866 867 868
      GCPRO2 (before_change_functions, after_change_functions);

      /* Actually run the hook functions.  */
      args[0] = Qafter_change_functions;
      XSETFASTINT (args[1], pos);
      XSETFASTINT (args[2], pos + lenins);
      XSETFASTINT (args[3], lendel);
      run_hook_list_with_args (after_change_functions,
			       4, args);

      /* "Unbind" the variables we "bound" to nil.  */
      Vbefore_change_functions = before_change_functions;
      Vafter_change_functions = after_change_functions;
      UNGCPRO;
869
    }
870 871 872

  if (!NILP (current_buffer->overlays_before)
      || !NILP (current_buffer->overlays_after))
873
    report_overlay_modification (make_number (pos),
874 875 876 877
				 make_number (pos + lenins - lendel),
				 1,
				 make_number (pos), make_number (pos + lenins),
				 make_number (lendel));
Jim Blandy's avatar
Jim Blandy committed
878
}