diff options
| author | Richard M. Stallman | 1993-03-07 09:34:39 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1993-03-07 09:34:39 +0000 |
| commit | 294efdbeb87b67c641e2eb6188aa120543c15953 (patch) | |
| tree | 99c45abf0e9774377c3e32f31c35acd8d826b983 /src | |
| parent | 83ec8b67da4885ccc1c7f7d9236091e603f039dd (diff) | |
| download | emacs-294efdbeb87b67c641e2eb6188aa120543c15953.tar.gz emacs-294efdbeb87b67c641e2eb6188aa120543c15953.zip | |
(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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/intervals.c | 152 |
1 files changed, 113 insertions, 39 deletions
diff --git a/src/intervals.c b/src/intervals.c index b9b4c5f838e..ce682b9adbf 100644 --- a/src/intervals.c +++ b/src/intervals.c | |||
| @@ -1,5 +1,5 @@ | |||
| 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 | ||
| @@ -1071,7 +1071,7 @@ make_new_interval (intervals, start, length) | |||
| 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 |
| @@ -1225,7 +1225,7 @@ textget (plist, prop) | |||
| 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. */ |
| @@ -1256,22 +1256,24 @@ set_point (position, 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, |
| @@ -1279,7 +1281,9 @@ set_point (position, buffer) | |||
| 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; |
| @@ -1353,6 +1357,22 @@ temp_set_point (position, 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 |
| @@ -1367,12 +1387,16 @@ verify_interval_modification (buf, start, end) | |||
| 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; |
| 1375 | 1395 | ||
| 1396 | hooks = Qnil; | ||
| 1397 | prev_mod_hooks = Qnil; | ||
| 1398 | mod_hooks = Qnil; | ||
| 1399 | |||
| 1376 | if (NULL_INTERVAL_P (intervals)) | 1400 | if (NULL_INTERVAL_P (intervals)) |
| 1377 | return; | 1401 | return; |
| 1378 | 1402 | ||
| @@ -1383,43 +1407,93 @@ verify_interval_modification (buf, 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. */ |
| 1411 | if (start == end) | ||
| 1387 | { | 1412 | { |
| 1388 | /* This should not be getting called on empty buffers. */ | 1413 | INTERVAL prev; |
| 1389 | if (BUF_Z (buf) == 1) | 1414 | Lisp_Object before, after; |
| 1390 | abort (); | ||
| 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); | ||
| 1398 | |||
| 1399 | do | ||
| 1400 | { | 1465 | { |
| 1401 | if (! INTERVAL_WRITABLE_P (i)) | 1466 | /* Loop over intervals on or next to START...END, |
| 1402 | error ("Attempt to modify read-only text"); | 1467 | collecting their hooks. */ |
| 1403 | 1468 | ||
| 1404 | mod_hook = Fget (Qmodification, i->plist); | 1469 | i = find_interval (intervals, start); |
| 1405 | if (! NILP (mod_hook) && ! EQ (mod_hook, prev_mod_hook)) | 1470 | do |
| 1406 | { | 1471 | { |
| 1407 | hooks = Fcons (mod_hook, hooks); | 1472 | if (! INTERVAL_WRITABLE_P (i)) |
| 1408 | prev_mod_hook = mod_hook; | 1473 | error ("Attempt to modify read-only text"); |
| 1409 | } | ||
| 1410 | 1474 | ||
| 1411 | i = next_interval (i); | 1475 | mod_hooks = textget (i->plist, Qmodification_hooks); |
| 1412 | } | 1476 | if (! NILP (mod_hooks) && ! EQ (mod_hooks, prev_mod_hooks)) |
| 1413 | while (! NULL_INTERVAL_P (i) && i->position <= end); | 1477 | { |
| 1478 | hooks = Fcons (mod_hooks, hooks); | ||
| 1479 | prev_mod_hooks = mod_hooks; | ||
| 1480 | } | ||
| 1414 | 1481 | ||
| 1415 | GCPRO1 (hooks); | 1482 | i = next_interval (i); |
| 1416 | hooks = Fnreverse (hooks); | 1483 | } |
| 1417 | while (! EQ (hooks, Qnil)) | 1484 | /* Keep going thru the interval containing the char before END. */ |
| 1418 | { | 1485 | while (! NULL_INTERVAL_P (i) && i->position < end); |
| 1419 | call2 (Fcar (hooks), start, end - 1); | 1486 | |
| 1420 | hooks = Fcdr (hooks); | 1487 | GCPRO1 (hooks); |
| 1488 | hooks = Fnreverse (hooks); | ||
| 1489 | while (! EQ (hooks, Qnil)) | ||
| 1490 | { | ||
| 1491 | call_mod_hooks (Fcar (hooks), make_number (start), | ||
| 1492 | make_number (end)); | ||
| 1493 | hooks = Fcdr (hooks); | ||
| 1494 | } | ||
| 1495 | UNGCPRO; | ||
| 1421 | } | 1496 | } |
| 1422 | UNGCPRO; | ||
| 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 |