Mercurial > emacs
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'. */ |