diff options
| author | Richard M. Stallman | 1995-09-12 17:37:32 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1995-09-12 17:37:32 +0000 |
| commit | 318d2fa869105827f75e615fcf04605283ba8b14 (patch) | |
| tree | 62fe22647724bb76c6588313767c76e52be7bc59 /src | |
| parent | c5ca07864e26c10e538a810888f3c74dde1ebec3 (diff) | |
| download | emacs-318d2fa869105827f75e615fcf04605283ba8b14.tar.gz emacs-318d2fa869105827f75e615fcf04605283ba8b14.zip | |
(call_mod_hooks): Moved from intevals.c
(verify_interval_modification): Moved from intervals.c.
(interval_insert_behind_hooks, interval_insert_in_front_hooks): New variables.
(report_interval_modification): New function.
Diffstat (limited to 'src')
| -rw-r--r-- | src/textprop.c | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/src/textprop.c b/src/textprop.c index c41757388c7..ad41534c3ef 100644 --- a/src/textprop.c +++ b/src/textprop.c | |||
| @@ -26,6 +26,11 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |||
| 26 | #ifndef NULL | 26 | #ifndef NULL |
| 27 | #define NULL (void *)0 | 27 | #define NULL (void *)0 |
| 28 | #endif | 28 | #endif |
| 29 | |||
| 30 | /* Test for membership, allowing for t (actually any non-cons) to mean the | ||
| 31 | universal set. */ | ||
| 32 | |||
| 33 | #define TMEM(sym, set) (CONSP (set) ? ! NILP (Fmemq (sym, set)) : ! NILP (set)) | ||
| 29 | 34 | ||
| 30 | 35 | ||
| 31 | /* NOTES: previous- and next- property change will have to skip | 36 | /* NOTES: previous- and next- property change will have to skip |
| @@ -66,6 +71,10 @@ Lisp_Object Qfront_sticky, Qrear_nonsticky; | |||
| 66 | Lisp_Object Vinhibit_point_motion_hooks; | 71 | Lisp_Object Vinhibit_point_motion_hooks; |
| 67 | Lisp_Object Vdefault_text_properties; | 72 | Lisp_Object Vdefault_text_properties; |
| 68 | 73 | ||
| 74 | /* verify_interval_modification saves insertion hooks here | ||
| 75 | to be run later by report_interval_modification. */ | ||
| 76 | Lisp_Object interval_insert_behind_hooks; | ||
| 77 | Lisp_Object interval_insert_in_front_hooks; | ||
| 69 | 78 | ||
| 70 | /* Extract the interval at the position pointed to by BEGIN from | 79 | /* Extract the interval at the position pointed to by BEGIN from |
| 71 | OBJECT, a string or buffer. Additionally, check that the positions | 80 | OBJECT, a string or buffer. Additionally, check that the positions |
| @@ -1394,8 +1403,219 @@ copy_text_properties (start, end, src, pos, dest, prop) | |||
| 1394 | 1403 | ||
| 1395 | return modified ? Qt : Qnil; | 1404 | return modified ? Qt : Qnil; |
| 1396 | } | 1405 | } |
| 1406 | |||
| 1407 | /* Call the modification hook functions in LIST, each with START and END. */ | ||
| 1408 | |||
| 1409 | static void | ||
| 1410 | call_mod_hooks (list, start, end) | ||
| 1411 | Lisp_Object list, start, end; | ||
| 1412 | { | ||
| 1413 | struct gcpro gcpro1; | ||
| 1414 | GCPRO1 (list); | ||
| 1415 | while (!NILP (list)) | ||
| 1416 | { | ||
| 1417 | call2 (Fcar (list), start, end); | ||
| 1418 | list = Fcdr (list); | ||
| 1419 | } | ||
| 1420 | UNGCPRO; | ||
| 1421 | } | ||
| 1422 | |||
| 1423 | /* Check for read-only intervals and signal an error if we find one. | ||
| 1424 | Then check for any modification hooks in the range START up to | ||
| 1425 | (but not including) END. Create a list of all these hooks in | ||
| 1426 | lexicographic order, eliminating consecutive extra copies of the | ||
| 1427 | same hook. Then call those hooks in order, with START and END - 1 | ||
| 1428 | as arguments. */ | ||
| 1397 | 1429 | ||
| 1398 | void | 1430 | void |
| 1431 | verify_interval_modification (buf, start, end) | ||
| 1432 | struct buffer *buf; | ||
| 1433 | int start, end; | ||
| 1434 | { | ||
| 1435 | register INTERVAL intervals = BUF_INTERVALS (buf); | ||
| 1436 | register INTERVAL i, prev; | ||
| 1437 | Lisp_Object hooks; | ||
| 1438 | register Lisp_Object prev_mod_hooks; | ||
| 1439 | Lisp_Object mod_hooks; | ||
| 1440 | struct gcpro gcpro1; | ||
| 1441 | |||
| 1442 | hooks = Qnil; | ||
| 1443 | prev_mod_hooks = Qnil; | ||
| 1444 | mod_hooks = Qnil; | ||
| 1445 | |||
| 1446 | interval_insert_behind_hooks = Qnil; | ||
| 1447 | interval_insert_in_front_hooks = Qnil; | ||
| 1448 | |||
| 1449 | if (NULL_INTERVAL_P (intervals)) | ||
| 1450 | return; | ||
| 1451 | |||
| 1452 | if (start > end) | ||
| 1453 | { | ||
| 1454 | int temp = start; | ||
| 1455 | start = end; | ||
| 1456 | end = temp; | ||
| 1457 | } | ||
| 1458 | |||
| 1459 | /* For an insert operation, check the two chars around the position. */ | ||
| 1460 | if (start == end) | ||
| 1461 | { | ||
| 1462 | INTERVAL prev; | ||
| 1463 | Lisp_Object before, after; | ||
| 1464 | |||
| 1465 | /* Set I to the interval containing the char after START, | ||
| 1466 | and PREV to the interval containing the char before START. | ||
| 1467 | Either one may be null. They may be equal. */ | ||
| 1468 | i = find_interval (intervals, start); | ||
| 1469 | |||
| 1470 | if (start == BUF_BEGV (buf)) | ||
| 1471 | prev = 0; | ||
| 1472 | else if (i->position == start) | ||
| 1473 | prev = previous_interval (i); | ||
| 1474 | else if (i->position < start) | ||
| 1475 | prev = i; | ||
| 1476 | if (start == BUF_ZV (buf)) | ||
| 1477 | i = 0; | ||
| 1478 | |||
| 1479 | /* If Vinhibit_read_only is set and is not a list, we can | ||
| 1480 | skip the read_only checks. */ | ||
| 1481 | if (NILP (Vinhibit_read_only) || CONSP (Vinhibit_read_only)) | ||
| 1482 | { | ||
| 1483 | /* If I and PREV differ we need to check for the read-only | ||
| 1484 | property together with its stickyness. If either I or | ||
| 1485 | PREV are 0, this check is all we need. | ||
| 1486 | We have to take special care, since read-only may be | ||
| 1487 | indirectly defined via the category property. */ | ||
| 1488 | if (i != prev) | ||
| 1489 | { | ||
| 1490 | if (! NULL_INTERVAL_P (i)) | ||
| 1491 | { | ||
| 1492 | after = textget (i->plist, Qread_only); | ||
| 1493 | |||
| 1494 | /* If interval I is read-only and read-only is | ||
| 1495 | front-sticky, inhibit insertion. | ||
| 1496 | Check for read-only as well as category. */ | ||
| 1497 | if (! NILP (after) | ||
| 1498 | && NILP (Fmemq (after, Vinhibit_read_only))) | ||
| 1499 | { | ||
| 1500 | Lisp_Object tem; | ||
| 1501 | |||
| 1502 | tem = textget (i->plist, Qfront_sticky); | ||
| 1503 | if (TMEM (Qread_only, tem) | ||
| 1504 | || (NILP (Fplist_get (i->plist, Qread_only)) | ||
| 1505 | && TMEM (Qcategory, tem))) | ||
| 1506 | error ("Attempt to insert within read-only text"); | ||
| 1507 | } | ||
| 1508 | } | ||
| 1509 | |||
| 1510 | if (! NULL_INTERVAL_P (prev)) | ||
| 1511 | { | ||
| 1512 | before = textget (prev->plist, Qread_only); | ||
| 1513 | |||
| 1514 | /* If interval PREV is read-only and read-only isn't | ||
| 1515 | rear-nonsticky, inhibit insertion. | ||
| 1516 | Check for read-only as well as category. */ | ||
| 1517 | if (! NILP (before) | ||
| 1518 | && NILP (Fmemq (before, Vinhibit_read_only))) | ||
| 1519 | { | ||
| 1520 | Lisp_Object tem; | ||
| 1521 | |||
| 1522 | tem = textget (prev->plist, Qrear_nonsticky); | ||
| 1523 | if (! TMEM (Qread_only, tem) | ||
| 1524 | && (! NILP (Fplist_get (prev->plist,Qread_only)) | ||
| 1525 | || ! TMEM (Qcategory, tem))) | ||
| 1526 | error ("Attempt to insert within read-only text"); | ||
| 1527 | } | ||
| 1528 | } | ||
| 1529 | } | ||
| 1530 | else if (! NULL_INTERVAL_P (i)) | ||
| 1531 | { | ||
| 1532 | after = textget (i->plist, Qread_only); | ||
| 1533 | |||
| 1534 | /* If interval I is read-only and read-only is | ||
| 1535 | front-sticky, inhibit insertion. | ||
| 1536 | Check for read-only as well as category. */ | ||
| 1537 | if (! NILP (after) && NILP (Fmemq (after, Vinhibit_read_only))) | ||
| 1538 | { | ||
| 1539 | Lisp_Object tem; | ||
| 1540 | |||
| 1541 | tem = textget (i->plist, Qfront_sticky); | ||
| 1542 | if (TMEM (Qread_only, tem) | ||
| 1543 | || (NILP (Fplist_get (i->plist, Qread_only)) | ||
| 1544 | && TMEM (Qcategory, tem))) | ||
| 1545 | error ("Attempt to insert within read-only text"); | ||
| 1546 | |||
| 1547 | tem = textget (prev->plist, Qrear_nonsticky); | ||
| 1548 | if (! TMEM (Qread_only, tem) | ||
| 1549 | && (! NILP (Fplist_get (prev->plist, Qread_only)) | ||
| 1550 | || ! TMEM (Qcategory, tem))) | ||
| 1551 | error ("Attempt to insert within read-only text"); | ||
| 1552 | } | ||
| 1553 | } | ||
| 1554 | } | ||
| 1555 | |||
| 1556 | /* Run both insert hooks (just once if they're the same). */ | ||
| 1557 | if (!NULL_INTERVAL_P (prev)) | ||
| 1558 | interval_insert_behind_hooks | ||
| 1559 | = textget (prev->plist, Qinsert_behind_hooks); | ||
| 1560 | if (!NULL_INTERVAL_P (i)) | ||
| 1561 | interval_insert_in_front_hooks | ||
| 1562 | = textget (i->plist, Qinsert_in_front_hooks); | ||
| 1563 | } | ||
| 1564 | else | ||
| 1565 | { | ||
| 1566 | /* Loop over intervals on or next to START...END, | ||
| 1567 | collecting their hooks. */ | ||
| 1568 | |||
| 1569 | i = find_interval (intervals, start); | ||
| 1570 | do | ||
| 1571 | { | ||
| 1572 | if (! INTERVAL_WRITABLE_P (i)) | ||
| 1573 | error ("Attempt to modify read-only text"); | ||
| 1574 | |||
| 1575 | mod_hooks = textget (i->plist, Qmodification_hooks); | ||
| 1576 | if (! NILP (mod_hooks) && ! EQ (mod_hooks, prev_mod_hooks)) | ||
| 1577 | { | ||
| 1578 | hooks = Fcons (mod_hooks, hooks); | ||
| 1579 | prev_mod_hooks = mod_hooks; | ||
| 1580 | } | ||
| 1581 | |||
| 1582 | i = next_interval (i); | ||
| 1583 | } | ||
| 1584 | /* Keep going thru the interval containing the char before END. */ | ||
| 1585 | while (! NULL_INTERVAL_P (i) && i->position < end); | ||
| 1586 | |||
| 1587 | GCPRO1 (hooks); | ||
| 1588 | hooks = Fnreverse (hooks); | ||
| 1589 | while (! EQ (hooks, Qnil)) | ||
| 1590 | { | ||
| 1591 | call_mod_hooks (Fcar (hooks), make_number (start), | ||
| 1592 | make_number (end)); | ||
| 1593 | hooks = Fcdr (hooks); | ||
| 1594 | } | ||
| 1595 | UNGCPRO; | ||
| 1596 | } | ||
| 1597 | } | ||
| 1598 | |||
| 1599 | /* Run the interval hooks for an insertion. | ||
| 1600 | verify_interval_modification chose which hooks to run; | ||
| 1601 | this function is called after the insertion happens | ||
| 1602 | so it can indicate the range of inserted text. */ | ||
| 1603 | |||
| 1604 | void | ||
| 1605 | report_interval_modification (start, end) | ||
| 1606 | Lisp_Object start, end; | ||
| 1607 | { | ||
| 1608 | if (! NILP (interval_insert_behind_hooks)) | ||
| 1609 | call_mod_hooks (interval_insert_behind_hooks, | ||
| 1610 | make_number (start), make_number (end)); | ||
| 1611 | if (! NILP (interval_insert_in_front_hooks) | ||
| 1612 | && ! EQ (interval_insert_in_front_hooks, | ||
| 1613 | interval_insert_behind_hooks)) | ||
| 1614 | call_mod_hooks (interval_insert_in_front_hooks, | ||
| 1615 | make_number (start), make_number (end)); | ||
| 1616 | } | ||
| 1617 | |||
| 1618 | void | ||
| 1399 | syms_of_textprop () | 1619 | syms_of_textprop () |
| 1400 | { | 1620 | { |
| 1401 | DEFVAR_LISP ("default-text-properties", &Vdefault_text_properties, | 1621 | DEFVAR_LISP ("default-text-properties", &Vdefault_text_properties, |
| @@ -1408,6 +1628,12 @@ character that does not have its own value for that property."); | |||
| 1408 | "If non-nil, don't run `point-left' and `point-entered' text properties.\n\ | 1628 | "If non-nil, don't run `point-left' and `point-entered' text properties.\n\ |
| 1409 | This also inhibits the use of the `intangible' text property."); | 1629 | This also inhibits the use of the `intangible' text property."); |
| 1410 | Vinhibit_point_motion_hooks = Qnil; | 1630 | Vinhibit_point_motion_hooks = Qnil; |
| 1631 | |||
| 1632 | staticpro (&interval_insert_behind_hooks); | ||
| 1633 | staticpro (&interval_insert_in_front_hooks); | ||
| 1634 | interval_insert_behind_hooks = Qnil; | ||
| 1635 | interval_insert_in_front_hooks = Qnil; | ||
| 1636 | |||
| 1411 | 1637 | ||
| 1412 | /* Common attributes one might give text */ | 1638 | /* Common attributes one might give text */ |
| 1413 | 1639 | ||