comparison src/intervals.c @ 2052:48c83a34c005

(verify_interval_modification): Handle insertions specially. For non-insertions, check only the chars being changed. `modification-hooks' property is now a list of functions. (set_point): Ignore chars outside current restriction.
author Richard M. Stallman <rms@gnu.org>
date Sun, 07 Mar 1993 09:34:39 +0000
parents e6c49ff3a53c
children c7e1308a7184
comparison
equal deleted inserted replaced
2051:c1767ea45687 2052:48c83a34c005
1 /* Code for doing intervals. 1 /* Code for doing intervals.
2 Copyright (C) 1991, 1992 Free Software Foundation, Inc. 2 Copyright (C) 1993 Free Software Foundation, Inc.
3 3
4 This file is part of GNU Emacs. 4 This file is part of GNU Emacs.
5 5
6 GNU Emacs is free software; you can redistribute it and/or modify 6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by 7 it under the terms of the GNU General Public License as published by
1069 /* Convert interval SLOT into three intervals. */ 1069 /* Convert interval SLOT into three intervals. */
1070 split_interval_left (slot, start - slot->position + 1); 1070 split_interval_left (slot, start - slot->position + 1);
1071 split_interval_right (slot, length + 1); 1071 split_interval_right (slot, length + 1);
1072 return slot; 1072 return slot;
1073 } 1073 }
1074 1074
1075 /* Insert the intervals of SOURCE into BUFFER at POSITION. 1075 /* Insert the intervals of SOURCE into BUFFER at POSITION.
1076 1076
1077 This is used in insdel.c when inserting Lisp_Strings into 1077 This is used in insdel.c when inserting Lisp_Strings into
1078 the buffer. The text corresponding to SOURCE is already in 1078 the buffer. The text corresponding to SOURCE is already in
1079 the buffer when this is called. The intervals of new tree are 1079 the buffer when this is called. The intervals of new tree are
1223 if (EQ (prop, tem)) 1223 if (EQ (prop, tem))
1224 return Fcar (Fcdr (tail)); 1224 return Fcar (Fcdr (tail));
1225 } 1225 }
1226 return Qnil; 1226 return Qnil;
1227 } 1227 }
1228 1228
1229 /* Set point in BUFFER to POSITION. If the target position is in 1229 /* Set point in BUFFER to POSITION. If the target position is in
1230 after an invisible character which is not displayed with a special glyph, 1230 after an invisible character which is not displayed with a special glyph,
1231 move back to an ok place to display. */ 1231 move back to an ok place to display. */
1232 1232
1233 void 1233 void
1254 /* Perhaps we should just change `position' to the limit. */ 1254 /* Perhaps we should just change `position' to the limit. */
1255 if (position > BUF_Z (buffer) || position < BUF_BEG (buffer)) 1255 if (position > BUF_Z (buffer) || position < BUF_BEG (buffer))
1256 abort (); 1256 abort ();
1257 1257
1258 /* Position Z is really one past the last char in the buffer. */ 1258 /* Position Z is really one past the last char in the buffer. */
1259 if (position == BUF_Z (buffer)) 1259 if (position == BUF_ZV (buffer))
1260 iposition = position - 1; 1260 iposition = position - 1;
1261 1261
1262 /* Set TO to the interval containing the char after POSITION, 1262 /* Set TO to the interval containing the char after POSITION,
1263 and TOPREV to the interval containing the char before POSITION. 1263 and TOPREV to the interval containing the char before POSITION.
1264 Either one may be null. They may be equal. */ 1264 Either one may be null. They may be equal. */
1265 to = find_interval (buffer->intervals, iposition); 1265 to = find_interval (buffer->intervals, iposition);
1266 if (to->position == position) 1266 if (position == BUF_BEGV (buffer))
1267 toprev = 0;
1268 else if (to->position == position)
1267 toprev = previous_interval (to); 1269 toprev = previous_interval (to);
1268 else if (iposition != position) 1270 else if (iposition != position)
1269 toprev = to, to = 0; 1271 toprev = to, to = 0;
1270 else 1272 else
1271 toprev = to; 1273 toprev = to;
1272 1274
1273 buffer_point = (BUF_PT (buffer) == BUF_Z (buffer) 1275 buffer_point = (BUF_PT (buffer) == BUF_ZV (buffer)
1274 ? BUF_Z (buffer) - 1 1276 ? BUF_ZV (buffer) - 1
1275 : BUF_PT (buffer)); 1277 : BUF_PT (buffer));
1276 1278
1277 /* Set FROM to the interval containing the char after PT, 1279 /* Set FROM to the interval containing the char after PT,
1278 and FROMPREV to the interval containing the char before PT. 1280 and FROMPREV to the interval containing the char before PT.
1279 Either one may be null. They may be equal. */ 1281 Either one may be null. They may be equal. */
1280 /* We could cache this and save time. */ 1282 /* We could cache this and save time. */
1281 from = find_interval (buffer->intervals, buffer_point); 1283 from = find_interval (buffer->intervals, buffer_point);
1282 if (from->position == BUF_PT (buffer)) 1284 if (from->position == BUF_BEGV (buffer))
1285 fromprev = 0;
1286 else if (from->position == BUF_PT (buffer))
1283 fromprev = previous_interval (from); 1287 fromprev = previous_interval (from);
1284 else if (buffer_point != BUF_PT (buffer)) 1288 else if (buffer_point != BUF_PT (buffer))
1285 fromprev = from, from = 0; 1289 fromprev = from, from = 0;
1286 else 1290 else
1287 fromprev = from; 1291 fromprev = from;
1351 int position; 1355 int position;
1352 struct buffer *buffer; 1356 struct buffer *buffer;
1353 { 1357 {
1354 buffer->text.pt = position; 1358 buffer->text.pt = position;
1355 } 1359 }
1360
1361 /* Call the modification hook functions in LIST, each with START and END. */
1362
1363 static void
1364 call_mod_hooks (list, start, end)
1365 Lisp_Object list, start, end;
1366 {
1367 struct gcpro gcpro1;
1368 GCPRO1 (list);
1369 while (!NILP (list))
1370 {
1371 call2 (Fcar (list), start, end);
1372 list = Fcdr (list);
1373 }
1374 UNGCPRO;
1375 }
1356 1376
1357 /* Check for read-only intervals and signal an error if we find one. 1377 /* Check for read-only intervals and signal an error if we find one.
1358 Then check for any modification hooks in the range START up to 1378 Then check for any modification hooks in the range START up to
1359 (but not including) TO. Create a list of all these hooks in 1379 (but not including) TO. Create a list of all these hooks in
1360 lexicographic order, eliminating consecutive extra copies of the 1380 lexicographic order, eliminating consecutive extra copies of the
1365 verify_interval_modification (buf, start, end) 1385 verify_interval_modification (buf, start, end)
1366 struct buffer *buf; 1386 struct buffer *buf;
1367 int start, end; 1387 int start, end;
1368 { 1388 {
1369 register INTERVAL intervals = buf->intervals; 1389 register INTERVAL intervals = buf->intervals;
1370 register INTERVAL i; 1390 register INTERVAL i, prev;
1371 Lisp_Object hooks = Qnil; 1391 Lisp_Object hooks;
1372 register prev_mod_hook = Qnil; 1392 register Lisp_Object prev_mod_hooks;
1373 register Lisp_Object mod_hook; 1393 Lisp_Object mod_hooks;
1374 struct gcpro gcpro1; 1394 struct gcpro gcpro1;
1395
1396 hooks = Qnil;
1397 prev_mod_hooks = Qnil;
1398 mod_hooks = Qnil;
1375 1399
1376 if (NULL_INTERVAL_P (intervals)) 1400 if (NULL_INTERVAL_P (intervals))
1377 return; 1401 return;
1378 1402
1379 if (start > end) 1403 if (start > end)
1381 int temp = start; 1405 int temp = start;
1382 start = end; 1406 start = end;
1383 end = temp; 1407 end = temp;
1384 } 1408 }
1385 1409
1386 if (start == BUF_Z (buf)) 1410 /* For an insert operation, check the two chars around the position. */
1387 { 1411 if (start == end)
1388 /* This should not be getting called on empty buffers. */ 1412 {
1389 if (BUF_Z (buf) == 1) 1413 INTERVAL prev;
1390 abort (); 1414 Lisp_Object before, after;
1391 1415
1392 i = find_interval (intervals, start - 1); 1416 /* Set I to the interval containing the char after START,
1393 if (! END_STICKY_P (i)) 1417 and PREV to the interval containing the char before START.
1394 return; 1418 Either one may be null. They may be equal. */
1419 i = find_interval (intervals,
1420 (start == BUF_ZV (buf) ? start - 1 : start));
1421
1422 if (start == BUF_BEGV (buf))
1423 prev = 0;
1424 if (i->position == start)
1425 prev = previous_interval (i);
1426 else if (i->position < start)
1427 prev = i;
1428 if (start == BUF_ZV (buf))
1429 i = 0;
1430
1431 if (NULL_INTERVAL_P (prev))
1432 {
1433 after = textget (i, Qread_only);
1434 if (! NILP (after))
1435 error ("Attempt to insert within read-only text");
1436 }
1437 else if (NULL_INTERVAL_P (i))
1438 {
1439 before = textget (prev, Qread_only);
1440 if (! NILP (before))
1441 error ("Attempt to insert within read-only text");
1442 }
1443 else
1444 {
1445 before = textget (prev, Qread_only);
1446 after = textget (i, Qread_only);
1447 if (! NILP (before) && EQ (before, after))
1448 error ("Attempt to insert within read-only text");
1449 }
1450
1451 /* Run both mod hooks (just once if they're the same). */
1452 if (!NULL_INTERVAL_P (prev))
1453 prev_mod_hooks = textget (prev->plist, Qmodification_hooks);
1454 if (!NULL_INTERVAL_P (i))
1455 mod_hooks = textget (i->plist, Qmodification_hooks);
1456 GCPRO1 (mod_hooks);
1457 if (! NILP (prev_mod_hooks))
1458 call_mod_hooks (prev_mod_hooks, make_number (start),
1459 make_number (end));
1460 UNGCPRO;
1461 if (! NILP (mod_hooks) && ! EQ (mod_hooks, prev_mod_hooks))
1462 call_mod_hooks (mod_hooks, make_number (start), make_number (end));
1395 } 1463 }
1396 else 1464 else
1397 i = find_interval (intervals, start); 1465 {
1398 1466 /* Loop over intervals on or next to START...END,
1399 do 1467 collecting their hooks. */
1400 { 1468
1401 if (! INTERVAL_WRITABLE_P (i)) 1469 i = find_interval (intervals, start);
1402 error ("Attempt to modify read-only text"); 1470 do
1403 1471 {
1404 mod_hook = Fget (Qmodification, i->plist); 1472 if (! INTERVAL_WRITABLE_P (i))
1405 if (! NILP (mod_hook) && ! EQ (mod_hook, prev_mod_hook)) 1473 error ("Attempt to modify read-only text");
1406 { 1474
1407 hooks = Fcons (mod_hook, hooks); 1475 mod_hooks = textget (i->plist, Qmodification_hooks);
1408 prev_mod_hook = mod_hook; 1476 if (! NILP (mod_hooks) && ! EQ (mod_hooks, prev_mod_hooks))
1409 } 1477 {
1410 1478 hooks = Fcons (mod_hooks, hooks);
1411 i = next_interval (i); 1479 prev_mod_hooks = mod_hooks;
1412 } 1480 }
1413 while (! NULL_INTERVAL_P (i) && i->position <= end); 1481
1414 1482 i = next_interval (i);
1415 GCPRO1 (hooks); 1483 }
1416 hooks = Fnreverse (hooks); 1484 /* Keep going thru the interval containing the char before END. */
1417 while (! EQ (hooks, Qnil)) 1485 while (! NULL_INTERVAL_P (i) && i->position < end);
1418 { 1486
1419 call2 (Fcar (hooks), start, end - 1); 1487 GCPRO1 (hooks);
1420 hooks = Fcdr (hooks); 1488 hooks = Fnreverse (hooks);
1421 } 1489 while (! EQ (hooks, Qnil))
1422 UNGCPRO; 1490 {
1491 call_mod_hooks (Fcar (hooks), make_number (start),
1492 make_number (end));
1493 hooks = Fcdr (hooks);
1494 }
1495 UNGCPRO;
1496 }
1423 } 1497 }
1424 1498
1425 /* Balance an interval node if the amount of text in its left and right 1499 /* Balance an interval node if the amount of text in its left and right
1426 subtrees differs by more than the percentage specified by 1500 subtrees differs by more than the percentage specified by
1427 `interval-balance-threshold'. */ 1501 `interval-balance-threshold'. */