Mercurial > emacs
comparison src/textprop.c @ 22344:2ec50b4767ed
Handle the new convention that `position' values
in a string's intervals start from zero.
(validate_interval_range, interval_of, Fnext_property_change)
(property_change_between_p, Fnext_single_property_change)
(Fprevious_property_change, Fprevious_single_property_change):
(Ftext_property_any, Ftext_property_not_all): Implement that.
Undo previous change.
author | Karl Heuer <kwzh@gnu.org> |
---|---|
date | Wed, 03 Jun 1998 14:45:03 +0000 |
parents | e179bf1418b7 |
children | cf1cbb0e5d5b |
comparison
equal
deleted
inserted
replaced
22343:542ccfb606c3 | 22344:2ec50b4767ed |
---|---|
148 register struct Lisp_String *s = XSTRING (object); | 148 register struct Lisp_String *s = XSTRING (object); |
149 | 149 |
150 if (! (0 <= XINT (*begin) && XINT (*begin) <= XINT (*end) | 150 if (! (0 <= XINT (*begin) && XINT (*begin) <= XINT (*end) |
151 && XINT (*end) <= s->size)) | 151 && XINT (*end) <= s->size)) |
152 args_out_of_range (*begin, *end); | 152 args_out_of_range (*begin, *end); |
153 /* User-level Positions in strings start with 0, | 153 XSETFASTINT (*begin, XFASTINT (*begin)); |
154 but the interval code always wants positions starting with 1. */ | |
155 XSETFASTINT (*begin, XFASTINT (*begin) + 1); | |
156 if (begin != end) | 154 if (begin != end) |
157 XSETFASTINT (*end, XFASTINT (*end) + 1); | 155 XSETFASTINT (*end, XFASTINT (*end)); |
158 i = s->intervals; | 156 i = s->intervals; |
159 | 157 |
160 if (s->size == 0) | 158 if (s->size == 0) |
161 return NULL_INTERVAL; | 159 return NULL_INTERVAL; |
162 | 160 |
477 i->plist = Qnil; | 475 i->plist = Qnil; |
478 return 1; | 476 return 1; |
479 } | 477 } |
480 #endif | 478 #endif |
481 | 479 |
482 /* Returns the interval of the POSITION in OBJECT. | 480 /* Returns the interval of POSITION in OBJECT. |
483 POSITION is BEG-based. */ | 481 POSITION is BEG-based. */ |
484 | 482 |
485 INTERVAL | 483 INTERVAL |
486 interval_of (position, object) | 484 interval_of (position, object) |
487 int position; | 485 int position; |
507 } | 505 } |
508 else | 506 else |
509 { | 507 { |
510 register struct Lisp_String *s = XSTRING (object); | 508 register struct Lisp_String *s = XSTRING (object); |
511 | 509 |
512 /* We expect position to be 1-based. */ | 510 beg = 0; |
513 beg = BEG; | 511 end = s->size; |
514 end = s->size + BEG; | |
515 i = s->intervals; | 512 i = s->intervals; |
516 } | 513 } |
517 | 514 |
518 if (!(beg <= position && position <= end)) | 515 if (!(beg <= position && position <= end)) |
519 args_out_of_range (make_number (position), make_number (position)); | 516 args_out_of_range (make_number (position), make_number (position)); |
714 if (NULL_INTERVAL_P (next)) | 711 if (NULL_INTERVAL_P (next)) |
715 XSETFASTINT (position, (STRINGP (object) | 712 XSETFASTINT (position, (STRINGP (object) |
716 ? XSTRING (object)->size | 713 ? XSTRING (object)->size |
717 : BUF_ZV (XBUFFER (object)))); | 714 : BUF_ZV (XBUFFER (object)))); |
718 else | 715 else |
719 XSETFASTINT (position, next->position - (STRINGP (object))); | 716 XSETFASTINT (position, next->position); |
720 return position; | 717 return position; |
721 } | 718 } |
722 | 719 |
723 if (NULL_INTERVAL_P (i)) | 720 if (NULL_INTERVAL_P (i)) |
724 return limit; | 721 return limit; |
725 | 722 |
726 next = next_interval (i); | 723 next = next_interval (i); |
727 | 724 |
728 while (! NULL_INTERVAL_P (next) && intervals_equal (i, next) | 725 while (! NULL_INTERVAL_P (next) && intervals_equal (i, next) |
729 && (NILP (limit) | 726 && (NILP (limit) || next->position < XFASTINT (limit))) |
730 || next->position - (STRINGP (object)) < XFASTINT (limit))) | |
731 next = next_interval (next); | 727 next = next_interval (next); |
732 | 728 |
733 if (NULL_INTERVAL_P (next)) | 729 if (NULL_INTERVAL_P (next)) |
734 return limit; | 730 return limit; |
735 if (! NILP (limit) | 731 if (! NILP (limit) && !(next->position < XFASTINT (limit))) |
736 && !(next->position - (STRINGP (object)) < XFASTINT (limit))) | |
737 return limit; | 732 return limit; |
738 | 733 |
739 XSETFASTINT (position, next->position - (STRINGP (object))); | 734 XSETFASTINT (position, next->position); |
740 return position; | 735 return position; |
741 } | 736 } |
742 | 737 |
743 /* Return 1 if there's a change in some property between BEG and END. */ | 738 /* Return 1 if there's a change in some property between BEG and END. */ |
744 | 739 |
760 while (! NULL_INTERVAL_P (next) && intervals_equal (i, next)) | 755 while (! NULL_INTERVAL_P (next) && intervals_equal (i, next)) |
761 { | 756 { |
762 next = next_interval (next); | 757 next = next_interval (next); |
763 if (NULL_INTERVAL_P (next)) | 758 if (NULL_INTERVAL_P (next)) |
764 return 0; | 759 return 0; |
765 if (next->position - (STRINGP (object)) >= end) | 760 if (next->position >= end) |
766 return 0; | 761 return 0; |
767 } | 762 } |
768 | 763 |
769 if (NULL_INTERVAL_P (next)) | 764 if (NULL_INTERVAL_P (next)) |
770 return 0; | 765 return 0; |
801 | 796 |
802 here_val = textget (i->plist, prop); | 797 here_val = textget (i->plist, prop); |
803 next = next_interval (i); | 798 next = next_interval (i); |
804 while (! NULL_INTERVAL_P (next) | 799 while (! NULL_INTERVAL_P (next) |
805 && EQ (here_val, textget (next->plist, prop)) | 800 && EQ (here_val, textget (next->plist, prop)) |
806 && (NILP (limit) || next->position - (STRINGP (object)) < XFASTINT (limit))) | 801 && (NILP (limit) || next->position < XFASTINT (limit))) |
807 next = next_interval (next); | 802 next = next_interval (next); |
808 | 803 |
809 if (NULL_INTERVAL_P (next)) | 804 if (NULL_INTERVAL_P (next)) |
810 return limit; | 805 return limit; |
811 if (! NILP (limit) | 806 if (! NILP (limit) && !(next->position < XFASTINT (limit))) |
812 && !(next->position - (STRINGP (object)) < XFASTINT (limit))) | |
813 return limit; | 807 return limit; |
814 | 808 |
815 XSETFASTINT (position, next->position - (STRINGP (object))); | 809 return make_number (next->position); |
816 return position; | |
817 } | 810 } |
818 | 811 |
819 DEFUN ("previous-property-change", Fprevious_property_change, | 812 DEFUN ("previous-property-change", Fprevious_property_change, |
820 Sprevious_property_change, 1, 3, 0, | 813 Sprevious_property_change, 1, 3, 0, |
821 "Return the position of previous property change.\n\ | 814 "Return the position of previous property change.\n\ |
846 i = previous_interval (i); | 839 i = previous_interval (i); |
847 | 840 |
848 previous = previous_interval (i); | 841 previous = previous_interval (i); |
849 while (! NULL_INTERVAL_P (previous) && intervals_equal (previous, i) | 842 while (! NULL_INTERVAL_P (previous) && intervals_equal (previous, i) |
850 && (NILP (limit) | 843 && (NILP (limit) |
851 || (previous->position + LENGTH (previous) - (STRINGP (object)) | 844 || (previous->position + LENGTH (previous) > XFASTINT (limit)))) |
852 > XFASTINT (limit)))) | |
853 previous = previous_interval (previous); | 845 previous = previous_interval (previous); |
854 if (NULL_INTERVAL_P (previous)) | 846 if (NULL_INTERVAL_P (previous)) |
855 return limit; | 847 return limit; |
856 if (!NILP (limit) | 848 if (!NILP (limit) |
857 && !(previous->position + LENGTH (previous) - (STRINGP (object)) | 849 && !(previous->position + LENGTH (previous) > XFASTINT (limit))) |
858 > XFASTINT (limit))) | |
859 return limit; | 850 return limit; |
860 | 851 |
861 XSETFASTINT (position, (previous->position + LENGTH (previous) | 852 return make_number (previous->position + LENGTH (previous)); |
862 - (STRINGP (object)))); | |
863 return position; | |
864 } | 853 } |
865 | 854 |
866 DEFUN ("previous-single-property-change", Fprevious_single_property_change, | 855 DEFUN ("previous-single-property-change", Fprevious_single_property_change, |
867 Sprevious_single_property_change, 2, 4, 0, | 856 Sprevious_single_property_change, 2, 4, 0, |
868 "Return the position of previous property change for a specific property.\n\ | 857 "Return the position of previous property change for a specific property.\n\ |
898 here_val = textget (i->plist, prop); | 887 here_val = textget (i->plist, prop); |
899 previous = previous_interval (i); | 888 previous = previous_interval (i); |
900 while (! NULL_INTERVAL_P (previous) | 889 while (! NULL_INTERVAL_P (previous) |
901 && EQ (here_val, textget (previous->plist, prop)) | 890 && EQ (here_val, textget (previous->plist, prop)) |
902 && (NILP (limit) | 891 && (NILP (limit) |
903 || (previous->position + LENGTH (previous) - (STRINGP (object)) | 892 || (previous->position + LENGTH (previous) > XFASTINT (limit)))) |
904 > XFASTINT (limit)))) | |
905 previous = previous_interval (previous); | 893 previous = previous_interval (previous); |
906 if (NULL_INTERVAL_P (previous)) | 894 if (NULL_INTERVAL_P (previous)) |
907 return limit; | 895 return limit; |
908 if (!NILP (limit) | 896 if (!NILP (limit) |
909 && !(previous->position + LENGTH (previous) - (STRINGP (object)) | 897 && !(previous->position + LENGTH (previous) > XFASTINT (limit))) |
910 > XFASTINT (limit))) | |
911 return limit; | 898 return limit; |
912 | 899 |
913 XSETFASTINT (position, (previous->position + LENGTH (previous) | 900 return make_number (previous->position + LENGTH (previous)); |
914 - (STRINGP (object)))); | |
915 return position; | |
916 } | 901 } |
917 | 902 |
918 /* Callers note, this can GC when OBJECT is a buffer (or nil). */ | 903 /* Callers note, this can GC when OBJECT is a buffer (or nil). */ |
919 | 904 |
920 DEFUN ("add-text-properties", Fadd_text_properties, | 905 DEFUN ("add-text-properties", Fadd_text_properties, |
1292 if (EQ (textget (i->plist, property), value)) | 1277 if (EQ (textget (i->plist, property), value)) |
1293 { | 1278 { |
1294 pos = i->position; | 1279 pos = i->position; |
1295 if (pos < XINT (start)) | 1280 if (pos < XINT (start)) |
1296 pos = XINT (start); | 1281 pos = XINT (start); |
1297 return make_number (pos - (STRINGP (object))); | 1282 return make_number (pos); |
1298 } | 1283 } |
1299 i = next_interval (i); | 1284 i = next_interval (i); |
1300 } | 1285 } |
1301 return Qnil; | 1286 return Qnil; |
1302 } | 1287 } |
1328 break; | 1313 break; |
1329 if (! EQ (textget (i->plist, property), value)) | 1314 if (! EQ (textget (i->plist, property), value)) |
1330 { | 1315 { |
1331 if (i->position > s) | 1316 if (i->position > s) |
1332 s = i->position; | 1317 s = i->position; |
1333 return make_number (s - (STRINGP (object))); | 1318 return make_number (s); |
1334 } | 1319 } |
1335 i = next_interval (i); | 1320 i = next_interval (i); |
1336 } | 1321 } |
1337 return Qnil; | 1322 return Qnil; |
1338 } | 1323 } |
1339 | 1324 |
1340 #if 0 /* You can use set-text-properties for this. */ | |
1341 | |
1342 DEFUN ("erase-text-properties", Ferase_text_properties, | |
1343 Serase_text_properties, 2, 3, 0, | |
1344 "Remove all properties from the text from START to END.\n\ | |
1345 The optional third argument, OBJECT,\n\ | |
1346 is the string or buffer containing the text.") | |
1347 (start, end, object) | |
1348 Lisp_Object start, end, object; | |
1349 { | |
1350 register INTERVAL i; | |
1351 register INTERVAL prev_changed = NULL_INTERVAL; | |
1352 register int s, len, modified; | |
1353 | |
1354 if (NILP (object)) | |
1355 XSETBUFFER (object, current_buffer); | |
1356 | |
1357 i = validate_interval_range (object, &start, &end, soft); | |
1358 if (NULL_INTERVAL_P (i)) | |
1359 return Qnil; | |
1360 | |
1361 s = XINT (start); | |
1362 len = XINT (end) - s; | |
1363 | |
1364 if (i->position != s) | |
1365 { | |
1366 register int got; | |
1367 register INTERVAL unchanged = i; | |
1368 | |
1369 /* If there are properties here, then this text will be modified. */ | |
1370 if (! NILP (i->plist)) | |
1371 { | |
1372 i = split_interval_right (unchanged, s - unchanged->position); | |
1373 i->plist = Qnil; | |
1374 modified++; | |
1375 | |
1376 if (LENGTH (i) > len) | |
1377 { | |
1378 i = split_interval_right (i, len); | |
1379 copy_properties (unchanged, i); | |
1380 return Qt; | |
1381 } | |
1382 | |
1383 if (LENGTH (i) == len) | |
1384 return Qt; | |
1385 | |
1386 got = LENGTH (i); | |
1387 } | |
1388 /* If the text of I is without any properties, and contains | |
1389 LEN or more characters, then we may return without changing | |
1390 anything.*/ | |
1391 else if (LENGTH (i) - (s - i->position) <= len) | |
1392 return Qnil; | |
1393 /* The amount of text to change extends past I, so just note | |
1394 how much we've gotten. */ | |
1395 else | |
1396 got = LENGTH (i) - (s - i->position); | |
1397 | |
1398 len -= got; | |
1399 prev_changed = i; | |
1400 i = next_interval (i); | |
1401 } | |
1402 | |
1403 /* We are starting at the beginning of an interval, I. */ | |
1404 while (len > 0) | |
1405 { | |
1406 if (LENGTH (i) >= len) | |
1407 { | |
1408 /* If I has no properties, simply merge it if possible. */ | |
1409 if (NILP (i->plist)) | |
1410 { | |
1411 if (! NULL_INTERVAL_P (prev_changed)) | |
1412 merge_interval_left (i); | |
1413 | |
1414 return modified ? Qt : Qnil; | |
1415 } | |
1416 | |
1417 if (LENGTH (i) > len) | |
1418 i = split_interval_left (i, len); | |
1419 if (! NULL_INTERVAL_P (prev_changed)) | |
1420 merge_interval_left (i); | |
1421 else | |
1422 i->plist = Qnil; | |
1423 | |
1424 return Qt; | |
1425 } | |
1426 | |
1427 /* Here if we still need to erase past the end of I */ | |
1428 len -= LENGTH (i); | |
1429 if (NULL_INTERVAL_P (prev_changed)) | |
1430 { | |
1431 modified += erase_properties (i); | |
1432 prev_changed = i; | |
1433 } | |
1434 else | |
1435 { | |
1436 modified += ! NILP (i->plist); | |
1437 /* Merging I will give it the properties of PREV_CHANGED. */ | |
1438 prev_changed = i = merge_interval_left (i); | |
1439 } | |
1440 | |
1441 i = next_interval (i); | |
1442 } | |
1443 | |
1444 return modified ? Qt : Qnil; | |
1445 } | |
1446 #endif /* 0 */ | |
1447 | |
1448 /* I don't think this is the right interface to export; how often do you | 1325 /* I don't think this is the right interface to export; how often do you |
1449 want to do something like this, other than when you're copying objects | 1326 want to do something like this, other than when you're copying objects |
1450 around? | 1327 around? |
1451 | 1328 |
1452 I think it would be better to have a pair of functions, one which | 1329 I think it would be better to have a pair of functions, one which |
1458 Optional sixth argument PROP causes only that property to be copied. | 1335 Optional sixth argument PROP causes only that property to be copied. |
1459 Properties are copied to DEST as if by `add-text-properties'. | 1336 Properties are copied to DEST as if by `add-text-properties'. |
1460 Return t if any property value actually changed, nil otherwise. */ | 1337 Return t if any property value actually changed, nil otherwise. */ |
1461 | 1338 |
1462 /* Note this can GC when DEST is a buffer. */ | 1339 /* Note this can GC when DEST is a buffer. */ |
1463 | 1340 |
1464 Lisp_Object | 1341 Lisp_Object |
1465 copy_text_properties (start, end, src, pos, dest, prop) | 1342 copy_text_properties (start, end, src, pos, dest, prop) |
1466 Lisp_Object start, end, src, pos, dest, prop; | 1343 Lisp_Object start, end, src, pos, dest, prop; |
1467 { | 1344 { |
1468 INTERVAL i; | 1345 INTERVAL i; |