diff options
| author | Joseph Arceneaux | 1992-09-24 01:29:22 +0000 |
|---|---|---|
| committer | Joseph Arceneaux | 1992-09-24 01:29:22 +0000 |
| commit | 9c79dd1b203d66a6a3f2227c22667a5ab5dbb290 (patch) | |
| tree | 657e7e93f609382a0ad058c2c56f9925e5c16e43 /src | |
| parent | ff462f26fd1dcf45c26cf0cdc5345dc04b52daf8 (diff) | |
| download | emacs-9c79dd1b203d66a6a3f2227c22667a5ab5dbb290.tar.gz emacs-9c79dd1b203d66a6a3f2227c22667a5ab5dbb290.zip | |
See ChangeLog
Diffstat (limited to 'src')
| -rw-r--r-- | src/intervals.c | 411 | ||||
| -rw-r--r-- | src/intervals.h | 6 | ||||
| -rw-r--r-- | src/textprop.c | 89 |
3 files changed, 260 insertions, 246 deletions
diff --git a/src/intervals.c b/src/intervals.c index 94970e6848b..fc725b5fac8 100644 --- a/src/intervals.c +++ b/src/intervals.c | |||
| @@ -368,9 +368,6 @@ split_interval_right (interval, offset) | |||
| 368 | 368 | ||
| 369 | new->position = position + offset - 1; | 369 | new->position = position + offset - 1; |
| 370 | new->parent = interval; | 370 | new->parent = interval; |
| 371 | #if 0 | ||
| 372 | copy_properties (interval, new); | ||
| 373 | #endif | ||
| 374 | 371 | ||
| 375 | if (LEAF_INTERVAL_P (interval) || NULL_RIGHT_CHILD (interval)) | 372 | if (LEAF_INTERVAL_P (interval) || NULL_RIGHT_CHILD (interval)) |
| 376 | { | 373 | { |
| @@ -411,12 +408,7 @@ split_interval_left (interval, offset) | |||
| 411 | int position = interval->position; | 408 | int position = interval->position; |
| 412 | int new_length = offset - 1; | 409 | int new_length = offset - 1; |
| 413 | 410 | ||
| 414 | #if 0 | ||
| 415 | copy_properties (interval, new); | ||
| 416 | #endif | ||
| 417 | |||
| 418 | new->position = interval->position; | 411 | new->position = interval->position; |
| 419 | |||
| 420 | interval->position = interval->position + offset - 1; | 412 | interval->position = interval->position + offset - 1; |
| 421 | new->parent = interval; | 413 | new->parent = interval; |
| 422 | 414 | ||
| @@ -674,92 +666,6 @@ adjust_intervals_for_insertion (tree, position, length) | |||
| 674 | return tree; | 666 | return tree; |
| 675 | } | 667 | } |
| 676 | 668 | ||
| 677 | /* Merge interval I with its lexicographic successor. Note that | ||
| 678 | this does not deal with the properties, or delete I. */ | ||
| 679 | |||
| 680 | INTERVAL | ||
| 681 | merge_interval_right (i) | ||
| 682 | register INTERVAL i; | ||
| 683 | { | ||
| 684 | register int absorb = LENGTH (i); | ||
| 685 | |||
| 686 | /* Zero out this interval. */ | ||
| 687 | i->total_length -= absorb; | ||
| 688 | |||
| 689 | /* Find the succeeding interval. */ | ||
| 690 | if (! NULL_RIGHT_CHILD (i)) /* It's below us. Add absorb | ||
| 691 | as we descend. */ | ||
| 692 | { | ||
| 693 | i = i->right; | ||
| 694 | while (! NULL_LEFT_CHILD (i)) | ||
| 695 | { | ||
| 696 | i->total_length += absorb; | ||
| 697 | i = i->left; | ||
| 698 | } | ||
| 699 | |||
| 700 | i->total_length += absorb; | ||
| 701 | return i; | ||
| 702 | } | ||
| 703 | |||
| 704 | while (! NULL_PARENT (i)) /* It's above us. Subtract as | ||
| 705 | we ascend. */ | ||
| 706 | { | ||
| 707 | if (AM_LEFT_CHILD (i)) | ||
| 708 | { | ||
| 709 | i = i->parent; | ||
| 710 | return i; | ||
| 711 | } | ||
| 712 | |||
| 713 | i = i->parent; | ||
| 714 | i->total_length -= absorb; | ||
| 715 | } | ||
| 716 | |||
| 717 | return NULL_INTERVAL; | ||
| 718 | } | ||
| 719 | |||
| 720 | /* Merge interval I with its lexicographic predecessor. Note that | ||
| 721 | this does not deal with the properties, or delete I.*/ | ||
| 722 | |||
| 723 | INTERVAL | ||
| 724 | merge_interval_left (i) | ||
| 725 | register INTERVAL i; | ||
| 726 | { | ||
| 727 | register int absorb = LENGTH (i); | ||
| 728 | |||
| 729 | /* Zero out this interval. */ | ||
| 730 | i->total_length -= absorb; | ||
| 731 | |||
| 732 | /* Find the preceding interval. */ | ||
| 733 | if (! NULL_LEFT_CHILD (i)) /* It's below us. Go down, | ||
| 734 | adding ABSORB as we go. */ | ||
| 735 | { | ||
| 736 | i = i->left; | ||
| 737 | while (! NULL_RIGHT_CHILD (i)) | ||
| 738 | { | ||
| 739 | i->total_length += absorb; | ||
| 740 | i = i->right; | ||
| 741 | } | ||
| 742 | |||
| 743 | i->total_length += absorb; | ||
| 744 | return i; | ||
| 745 | } | ||
| 746 | |||
| 747 | while (! NULL_PARENT (i)) /* It's above us. Go up, | ||
| 748 | subtracting ABSORB. */ | ||
| 749 | { | ||
| 750 | if (AM_RIGHT_CHILD (i)) | ||
| 751 | { | ||
| 752 | i = i->parent; | ||
| 753 | return i; | ||
| 754 | } | ||
| 755 | |||
| 756 | i = i->parent; | ||
| 757 | i->total_length -= absorb; | ||
| 758 | } | ||
| 759 | |||
| 760 | return NULL_INTERVAL; | ||
| 761 | } | ||
| 762 | |||
| 763 | /* Delete an node I from its interval tree by merging its subtrees | 669 | /* Delete an node I from its interval tree by merging its subtrees |
| 764 | into one subtree which is then returned. Caller is responsible for | 670 | into one subtree which is then returned. Caller is responsible for |
| 765 | storing the resulting subtree into its parent. */ | 671 | storing the resulting subtree into its parent. */ |
| @@ -992,7 +898,115 @@ offset_intervals (buffer, start, length) | |||
| 992 | else | 898 | else |
| 993 | adjust_intervals_for_deletion (buffer, start, -length); | 899 | adjust_intervals_for_deletion (buffer, start, -length); |
| 994 | } | 900 | } |
| 901 | |||
| 902 | /* Merge interval I with its lexicographic successor. The resulting | ||
| 903 | interval is returned, and has the properties of the original | ||
| 904 | successor. The properties of I are lost. I is removed from the | ||
| 905 | interval tree. | ||
| 906 | |||
| 907 | IMPORTANT: | ||
| 908 | The caller must verify that this is not the last (rightmost) | ||
| 909 | interval. */ | ||
| 910 | |||
| 911 | INTERVAL | ||
| 912 | merge_interval_right (i) | ||
| 913 | register INTERVAL i; | ||
| 914 | { | ||
| 915 | register int absorb = LENGTH (i); | ||
| 916 | register INTERVAL successor; | ||
| 917 | |||
| 918 | /* Zero out this interval. */ | ||
| 919 | i->total_length -= absorb; | ||
| 920 | |||
| 921 | /* Find the succeeding interval. */ | ||
| 922 | if (! NULL_RIGHT_CHILD (i)) /* It's below us. Add absorb | ||
| 923 | as we descend. */ | ||
| 924 | { | ||
| 925 | successor = i->right; | ||
| 926 | while (! NULL_LEFT_CHILD (successor)) | ||
| 927 | { | ||
| 928 | successor->total_length += absorb; | ||
| 929 | successor = successor->left; | ||
| 930 | } | ||
| 931 | |||
| 932 | successor->total_length += absorb; | ||
| 933 | delete_interval (i); | ||
| 934 | return successor; | ||
| 935 | } | ||
| 936 | |||
| 937 | successor = i; | ||
| 938 | while (! NULL_PARENT (successor)) /* It's above us. Subtract as | ||
| 939 | we ascend. */ | ||
| 940 | { | ||
| 941 | if (AM_LEFT_CHILD (successor)) | ||
| 942 | { | ||
| 943 | successor = successor->parent; | ||
| 944 | delete_interval (i); | ||
| 945 | return successor; | ||
| 946 | } | ||
| 947 | |||
| 948 | successor = successor->parent; | ||
| 949 | successor->total_length -= absorb; | ||
| 950 | } | ||
| 951 | |||
| 952 | /* This must be the rightmost or last interval and cannot | ||
| 953 | be merged right. The caller should have known. */ | ||
| 954 | abort (); | ||
| 955 | } | ||
| 956 | |||
| 957 | /* Merge interval I with its lexicographic predecessor. The resulting | ||
| 958 | interval is returned, and has the properties of the original predecessor. | ||
| 959 | The properties of I are lost. Interval node I is removed from the tree. | ||
| 960 | |||
| 961 | IMPORTANT: | ||
| 962 | The caller must verify that this is not the first (leftmost) interval. */ | ||
| 963 | |||
| 964 | INTERVAL | ||
| 965 | merge_interval_left (i) | ||
| 966 | register INTERVAL i; | ||
| 967 | { | ||
| 968 | register int absorb = LENGTH (i); | ||
| 969 | register INTERVAL predecessor; | ||
| 970 | |||
| 971 | /* Zero out this interval. */ | ||
| 972 | i->total_length -= absorb; | ||
| 973 | |||
| 974 | /* Find the preceding interval. */ | ||
| 975 | if (! NULL_LEFT_CHILD (i)) /* It's below us. Go down, | ||
| 976 | adding ABSORB as we go. */ | ||
| 977 | { | ||
| 978 | predecessor = i->left; | ||
| 979 | while (! NULL_RIGHT_CHILD (predecessor)) | ||
| 980 | { | ||
| 981 | predecessor->total_length += absorb; | ||
| 982 | predecessor = predecessor->right; | ||
| 983 | } | ||
| 984 | |||
| 985 | predecessor->total_length += absorb; | ||
| 986 | delete_interval (i); | ||
| 987 | return predecessor; | ||
| 988 | } | ||
| 989 | |||
| 990 | predecessor = i; | ||
| 991 | while (! NULL_PARENT (predecessor)) /* It's above us. Go up, | ||
| 992 | subtracting ABSORB. */ | ||
| 993 | { | ||
| 994 | if (AM_RIGHT_CHILD (predecessor)) | ||
| 995 | { | ||
| 996 | predecessor = predecessor->parent; | ||
| 997 | delete_interval (i); | ||
| 998 | return predecessor; | ||
| 999 | } | ||
| 1000 | |||
| 1001 | predecessor = predecessor->parent; | ||
| 1002 | predecessor->total_length -= absorb; | ||
| 1003 | } | ||
| 995 | 1004 | ||
| 1005 | /* This must be the leftmost or first interval and cannot | ||
| 1006 | be merged left. The caller should have known. */ | ||
| 1007 | abort (); | ||
| 1008 | } | ||
| 1009 | |||
| 996 | /* Make an exact copy of interval tree SOURCE which descends from | 1010 | /* Make an exact copy of interval tree SOURCE which descends from |
| 997 | PARENT. This is done by recursing through SOURCE, copying | 1011 | PARENT. This is done by recursing through SOURCE, copying |
| 998 | the current interval and its properties, and then adjusting | 1012 | the current interval and its properties, and then adjusting |
| @@ -1056,33 +1070,10 @@ make_new_interval (intervals, start, length) | |||
| 1056 | return slot; | 1070 | return slot; |
| 1057 | } | 1071 | } |
| 1058 | 1072 | ||
| 1059 | void | 1073 | /* Insert the intervals of SOURCE into BUFFER at POSITION. |
| 1060 | map_intervals (source, destination, position) | ||
| 1061 | INTERVAL source, destination; | ||
| 1062 | int position; | ||
| 1063 | { | ||
| 1064 | register INTERVAL i, t; | ||
| 1065 | |||
| 1066 | if (NULL_INTERVAL_P (source)) | ||
| 1067 | return; | ||
| 1068 | i = find_interval (destination, position); | ||
| 1069 | if (NULL_INTERVAL_P (i)) | ||
| 1070 | return; | ||
| 1071 | |||
| 1072 | t = find_interval (source, 1); | ||
| 1073 | while (! NULL_INTERVAL_P (t)) | ||
| 1074 | { | ||
| 1075 | i = make_new_interval (destination, position, LENGTH (t)); | ||
| 1076 | position += LENGTH (t); | ||
| 1077 | copy_properties (t, i); | ||
| 1078 | t = next_interval (t); | ||
| 1079 | } | ||
| 1080 | } | ||
| 1081 | |||
| 1082 | /* Insert the intervals of NEW_TREE into BUFFER at POSITION. | ||
| 1083 | 1074 | ||
| 1084 | This is used in insdel.c when inserting Lisp_Strings into | 1075 | This is used in insdel.c when inserting Lisp_Strings into |
| 1085 | the buffer. The text corresponding to NEW_TREE is already in | 1076 | the buffer. The text corresponding to SOURCE is already in |
| 1086 | the buffer when this is called. The intervals of new tree are | 1077 | the buffer when this is called. The intervals of new tree are |
| 1087 | those belonging to the string being inserted; a copy is not made. | 1078 | those belonging to the string being inserted; a copy is not made. |
| 1088 | 1079 | ||
| @@ -1111,17 +1102,17 @@ map_intervals (source, destination, position) | |||
| 1111 | text... */ | 1102 | text... */ |
| 1112 | 1103 | ||
| 1113 | void | 1104 | void |
| 1114 | graft_intervals_into_buffer (new_tree, position, b) | 1105 | graft_intervals_into_buffer (source, position, buffer) |
| 1115 | INTERVAL new_tree; | 1106 | INTERVAL source; |
| 1116 | int position; | 1107 | int position; |
| 1117 | struct buffer *b; | 1108 | struct buffer *buffer; |
| 1118 | { | 1109 | { |
| 1119 | register INTERVAL under, over, this; | 1110 | register INTERVAL under, over, this; |
| 1120 | register INTERVAL tree = b->intervals; | 1111 | register INTERVAL tree = buffer->intervals; |
| 1121 | 1112 | ||
| 1122 | /* If the new text has no properties, it becomes part of whatever | 1113 | /* If the new text has no properties, it becomes part of whatever |
| 1123 | interval it was inserted into. */ | 1114 | interval it was inserted into. */ |
| 1124 | if (NULL_INTERVAL_P (new_tree)) | 1115 | if (NULL_INTERVAL_P (source)) |
| 1125 | return; | 1116 | return; |
| 1126 | 1117 | ||
| 1127 | /* Paranoia -- the text has already been added, so this buffer | 1118 | /* Paranoia -- the text has already been added, so this buffer |
| @@ -1133,9 +1124,9 @@ graft_intervals_into_buffer (new_tree, position, b) | |||
| 1133 | { | 1124 | { |
| 1134 | /* The inserted text constitutes the whole buffer, so | 1125 | /* The inserted text constitutes the whole buffer, so |
| 1135 | simply copy over the interval structure. */ | 1126 | simply copy over the interval structure. */ |
| 1136 | if (BUF_Z (b) == TOTAL_LENGTH (new_tree)) | 1127 | if (BUF_Z (b) == TOTAL_LENGTH (source)) |
| 1137 | { | 1128 | { |
| 1138 | b->intervals = reproduce_tree (new_tree, tree->parent); | 1129 | buffer->intervals = reproduce_tree (source, tree->parent); |
| 1139 | /* Explicitly free the old tree here. */ | 1130 | /* Explicitly free the old tree here. */ |
| 1140 | 1131 | ||
| 1141 | return; | 1132 | return; |
| @@ -1150,14 +1141,14 @@ graft_intervals_into_buffer (new_tree, position, b) | |||
| 1150 | } | 1141 | } |
| 1151 | } | 1142 | } |
| 1152 | else | 1143 | else |
| 1153 | if (TOTAL_LENGTH (tree) == TOTAL_LENGTH (new_tree)) | 1144 | if (TOTAL_LENGTH (tree) == TOTAL_LENGTH (source)) |
| 1154 | 1145 | ||
| 1155 | /* If the buffer contains only the new string, but | 1146 | /* If the buffer contains only the new string, but |
| 1156 | there was already some interval tree there, then it may be | 1147 | there was already some interval tree there, then it may be |
| 1157 | some zero length intervals. Eventually, do something clever | 1148 | some zero length intervals. Eventually, do something clever |
| 1158 | about inserting properly. For now, just waste the old intervals. */ | 1149 | about inserting properly. For now, just waste the old intervals. */ |
| 1159 | { | 1150 | { |
| 1160 | b->intervals = reproduce_tree (new_tree, tree->parent); | 1151 | buffer->intervals = reproduce_tree (source, tree->parent); |
| 1161 | /* Explicitly free the old tree here. */ | 1152 | /* Explicitly free the old tree here. */ |
| 1162 | 1153 | ||
| 1163 | return; | 1154 | return; |
| @@ -1166,7 +1157,7 @@ graft_intervals_into_buffer (new_tree, position, b) | |||
| 1166 | this = under = find_interval (tree, position); | 1157 | this = under = find_interval (tree, position); |
| 1167 | if (NULL_INTERVAL_P (under)) /* Paranoia */ | 1158 | if (NULL_INTERVAL_P (under)) /* Paranoia */ |
| 1168 | abort (); | 1159 | abort (); |
| 1169 | over = find_interval (new_tree, 1); | 1160 | over = find_interval (source, 1); |
| 1170 | 1161 | ||
| 1171 | /* Insertion between intervals */ | 1162 | /* Insertion between intervals */ |
| 1172 | if (position == under->position) | 1163 | if (position == under->position) |
| @@ -1184,7 +1175,8 @@ graft_intervals_into_buffer (new_tree, position, b) | |||
| 1184 | over = next_interval (over); | 1175 | over = next_interval (over); |
| 1185 | } | 1176 | } |
| 1186 | else | 1177 | else |
| 1187 | /* This string sticks to under */ | 1178 | /* This string "sticks" to the first interval, `under', |
| 1179 | which means it gets those properties. */ | ||
| 1188 | while (! NULL_INTERVAL_P (over)) | 1180 | while (! NULL_INTERVAL_P (over)) |
| 1189 | { | 1181 | { |
| 1190 | position = LENGTH (over) + 1; | 1182 | position = LENGTH (over) + 1; |
| @@ -1229,7 +1221,8 @@ graft_intervals_into_buffer (new_tree, position, b) | |||
| 1229 | else | 1221 | else |
| 1230 | { | 1222 | { |
| 1231 | if (FRONT_STICKY (under)) | 1223 | if (FRONT_STICKY (under)) |
| 1232 | /* The intervals stick to under */ | 1224 | /* The inserted text "sticks" to the interval `under', |
| 1225 | which means it gets those properties. */ | ||
| 1233 | while (! NULL_INTERVAL_P (over)) | 1226 | while (! NULL_INTERVAL_P (over)) |
| 1234 | { | 1227 | { |
| 1235 | position = LENGTH (over) + 1; | 1228 | position = LENGTH (over) + 1; |
| @@ -1251,16 +1244,16 @@ graft_intervals_into_buffer (new_tree, position, b) | |||
| 1251 | } | 1244 | } |
| 1252 | } | 1245 | } |
| 1253 | 1246 | ||
| 1254 | b->intervals = balance_intervals (b->intervals); | 1247 | buffer->intervals = balance_intervals (buffer->intervals); |
| 1255 | return; | 1248 | return; |
| 1256 | } | 1249 | } |
| 1257 | 1250 | ||
| 1258 | /* Here for insertion in the middle of an interval. */ | 1251 | /* Here for insertion in the middle of an interval. */ |
| 1259 | 1252 | ||
| 1260 | if (TOTAL_LENGTH (new_tree) < LENGTH (this)) | 1253 | if (TOTAL_LENGTH (source) < LENGTH (this)) |
| 1261 | { | 1254 | { |
| 1262 | INTERVAL end_unchanged | 1255 | INTERVAL end_unchanged |
| 1263 | = split_interval_right (this, TOTAL_LENGTH (new_tree) + 1); | 1256 | = split_interval_right (this, TOTAL_LENGTH (source) + 1); |
| 1264 | copy_properties (under, end_unchanged); | 1257 | copy_properties (under, end_unchanged); |
| 1265 | } | 1258 | } |
| 1266 | 1259 | ||
| @@ -1276,39 +1269,10 @@ graft_intervals_into_buffer (new_tree, position, b) | |||
| 1276 | over = next_interval (over); | 1269 | over = next_interval (over); |
| 1277 | } | 1270 | } |
| 1278 | 1271 | ||
| 1279 | b->intervals = balance_intervals (b->intervals); | 1272 | buffer->intervals = balance_intervals (buffer->intervals); |
| 1280 | return; | 1273 | return; |
| 1281 | } | 1274 | } |
| 1282 | 1275 | ||
| 1283 | /* Intervals can have properties which are hooks to call. Look for | ||
| 1284 | the property HOOK on interval I, and if found, call its value as | ||
| 1285 | a function.*/ | ||
| 1286 | |||
| 1287 | void | ||
| 1288 | run_hooks (i, hook) | ||
| 1289 | INTERVAL i; | ||
| 1290 | Lisp_Object hook; | ||
| 1291 | { | ||
| 1292 | register Lisp_Object tail = i->plist; | ||
| 1293 | register Lisp_Object sym, val; | ||
| 1294 | |||
| 1295 | while (! NILP (tail)) | ||
| 1296 | { | ||
| 1297 | sym = Fcar (tail); | ||
| 1298 | if (EQ (sym, hook)) | ||
| 1299 | { | ||
| 1300 | Lisp_Object begin, end; | ||
| 1301 | XFASTINT (begin) = i->position; | ||
| 1302 | XFASTINT (end) = i->position + LENGTH (i) - 1; | ||
| 1303 | val = Fcar (Fcdr (tail)); | ||
| 1304 | call2 (val, begin, end); | ||
| 1305 | return; | ||
| 1306 | } | ||
| 1307 | |||
| 1308 | tail = Fcdr (Fcdr (tail)); | ||
| 1309 | } | ||
| 1310 | } | ||
| 1311 | |||
| 1312 | /* Set point in BUFFER to POSITION. If the target position is in | 1276 | /* Set point in BUFFER to POSITION. If the target position is in |
| 1313 | an invisible interval which is not displayed with a special glyph, | 1277 | an invisible interval which is not displayed with a special glyph, |
| 1314 | skip intervals until we find one. Point may be at the first | 1278 | skip intervals until we find one. Point may be at the first |
| @@ -1327,6 +1291,7 @@ set_point (position, buffer) | |||
| 1327 | int buffer_point; | 1291 | int buffer_point; |
| 1328 | register Lisp_Object obj; | 1292 | register Lisp_Object obj; |
| 1329 | int backwards = (position < BUF_PT (buffer)) ? 1 : 0; | 1293 | int backwards = (position < BUF_PT (buffer)) ? 1 : 0; |
| 1294 | int old_position = buffer->text.pt; | ||
| 1330 | 1295 | ||
| 1331 | if (position == buffer->text.pt) | 1296 | if (position == buffer->text.pt) |
| 1332 | return; | 1297 | return; |
| @@ -1349,7 +1314,10 @@ set_point (position, buffer) | |||
| 1349 | buffer_point =(BUF_PT (buffer) == BUF_Z (buffer) | 1314 | buffer_point =(BUF_PT (buffer) == BUF_Z (buffer) |
| 1350 | ? BUF_Z (buffer) - 1 | 1315 | ? BUF_Z (buffer) - 1 |
| 1351 | : BUF_PT (buffer)); | 1316 | : BUF_PT (buffer)); |
| 1317 | |||
| 1318 | /* We could cache this and save time. */ | ||
| 1352 | from = find_interval (buffer->intervals, buffer_point); | 1319 | from = find_interval (buffer->intervals, buffer_point); |
| 1320 | |||
| 1353 | if (NULL_INTERVAL_P (to) || NULL_INTERVAL_P (from)) | 1321 | if (NULL_INTERVAL_P (to) || NULL_INTERVAL_P (from)) |
| 1354 | abort (); /* Paranoia */ | 1322 | abort (); /* Paranoia */ |
| 1355 | 1323 | ||
| @@ -1386,14 +1354,36 @@ set_point (position, buffer) | |||
| 1386 | 1354 | ||
| 1387 | /* We should run point-left and point-entered hooks here, iff the | 1355 | /* We should run point-left and point-entered hooks here, iff the |
| 1388 | two intervals are not equivalent. */ | 1356 | two intervals are not equivalent. */ |
| 1357 | if (! intervals_equal (from, to)) | ||
| 1358 | { | ||
| 1359 | Lisp_Object val; | ||
| 1360 | |||
| 1361 | val = Fget (Qpoint_left, from->plist); | ||
| 1362 | if (! NILP (val)) | ||
| 1363 | call2 (val, old_position, position); | ||
| 1364 | |||
| 1365 | val = Fget (Qpoint_entered, to->plist); | ||
| 1366 | if (! NILP (val)) | ||
| 1367 | call2 (val, old_position, position); | ||
| 1368 | } | ||
| 1389 | } | 1369 | } |
| 1390 | 1370 | ||
| 1391 | /* Check for read-only intervals. Call the modification hooks if any. | 1371 | /* Set point temporarily, without checking any text properties. */ |
| 1392 | Check for the range START up to (but not including) TO. | ||
| 1393 | 1372 | ||
| 1394 | First all intervals of the region are checked that they are | 1373 | INLINE void |
| 1395 | modifiable, then all the modification hooks are called in | 1374 | temp_set_point (position, buffer) |
| 1396 | lexicographic order. */ | 1375 | int position; |
| 1376 | struct buffer *buffer; | ||
| 1377 | { | ||
| 1378 | buffer->text.pt = position; | ||
| 1379 | } | ||
| 1380 | |||
| 1381 | /* Check for read-only intervals and signal an error if we find one. | ||
| 1382 | Then check for any modification hooks in the range START up to | ||
| 1383 | (but not including) TO. Create a list of all these hooks in | ||
| 1384 | lexicographic order, eliminating consecutive extra copies of the | ||
| 1385 | same hook. Then call those hooks in order, with START and END - 1 | ||
| 1386 | as arguments. */ | ||
| 1397 | 1387 | ||
| 1398 | void | 1388 | void |
| 1399 | verify_interval_modification (buf, start, end) | 1389 | verify_interval_modification (buf, start, end) |
| @@ -1403,6 +1393,9 @@ verify_interval_modification (buf, start, end) | |||
| 1403 | register INTERVAL intervals = buf->intervals; | 1393 | register INTERVAL intervals = buf->intervals; |
| 1404 | register INTERVAL i; | 1394 | register INTERVAL i; |
| 1405 | register Lisp_Object hooks = Qnil; | 1395 | register Lisp_Object hooks = Qnil; |
| 1396 | register prev_mod_hook = Qnil; | ||
| 1397 | register Lisp_Object mod_hook; | ||
| 1398 | struct gcpro gcpro1; | ||
| 1406 | 1399 | ||
| 1407 | if (NULL_INTERVAL_P (intervals)) | 1400 | if (NULL_INTERVAL_P (intervals)) |
| 1408 | return; | 1401 | return; |
| @@ -1416,6 +1409,7 @@ verify_interval_modification (buf, start, end) | |||
| 1416 | 1409 | ||
| 1417 | if (start == BUF_Z (buf)) | 1410 | if (start == BUF_Z (buf)) |
| 1418 | { | 1411 | { |
| 1412 | /* This should not be getting called on empty buffers. */ | ||
| 1419 | if (BUF_Z (buf) == 1) | 1413 | if (BUF_Z (buf) == 1) |
| 1420 | abort (); | 1414 | abort (); |
| 1421 | 1415 | ||
| @@ -1428,19 +1422,28 @@ verify_interval_modification (buf, start, end) | |||
| 1428 | 1422 | ||
| 1429 | do | 1423 | do |
| 1430 | { | 1424 | { |
| 1431 | register Lisp_Object mod_hook; | ||
| 1432 | if (! INTERVAL_WRITABLE_P (i)) | 1425 | if (! INTERVAL_WRITABLE_P (i)) |
| 1433 | error ("Attempt to write in a protected interval"); | 1426 | error ("Attempt to modify read-only text"); |
| 1427 | |||
| 1434 | mod_hook = Fget (Qmodification, i->plist); | 1428 | mod_hook = Fget (Qmodification, i->plist); |
| 1435 | if (! EQ (mod_hook, Qnil)) | 1429 | if (! NILP (mod_hook) && ! EQ (mod_hook, prev_mod_hook)) |
| 1436 | hooks = Fcons (mod_hook, hooks); | 1430 | { |
| 1431 | hooks = Fcons (mod_hook, hooks); | ||
| 1432 | prev_mod_hook = mod_hook; | ||
| 1433 | } | ||
| 1434 | |||
| 1437 | i = next_interval (i); | 1435 | i = next_interval (i); |
| 1438 | } | 1436 | } |
| 1439 | while (! NULL_INTERVAL_P (i) && i->position <= end); | 1437 | while (! NULL_INTERVAL_P (i) && i->position <= end); |
| 1440 | 1438 | ||
| 1439 | GCPRO1 (hooks); | ||
| 1441 | hooks = Fnreverse (hooks); | 1440 | hooks = Fnreverse (hooks); |
| 1442 | while (! EQ (hooks, Qnil)) | 1441 | while (! EQ (hooks, Qnil)) |
| 1443 | call2 (Fcar (hooks), i->position, i->position + LENGTH (i) - 1); | 1442 | { |
| 1443 | call2 (Fcar (hooks), start, end - 1); | ||
| 1444 | hooks = Fcdr (hooks); | ||
| 1445 | } | ||
| 1446 | UNGCPRO; | ||
| 1444 | } | 1447 | } |
| 1445 | 1448 | ||
| 1446 | /* Balance an interval node if the amount of text in its left and right | 1449 | /* Balance an interval node if the amount of text in its left and right |
| @@ -1500,7 +1503,7 @@ balance_intervals (tree) | |||
| 1500 | return new_tree; | 1503 | return new_tree; |
| 1501 | } | 1504 | } |
| 1502 | 1505 | ||
| 1503 | /* Produce an interval tree reflecting the interval structure in | 1506 | /* Produce an interval tree reflecting the intervals in |
| 1504 | TREE from START to START + LENGTH. */ | 1507 | TREE from START to START + LENGTH. */ |
| 1505 | 1508 | ||
| 1506 | static INTERVAL | 1509 | static INTERVAL |
| @@ -1526,19 +1529,14 @@ copy_intervals (tree, start, length) | |||
| 1526 | new = make_interval (); | 1529 | new = make_interval (); |
| 1527 | new->position = 1; | 1530 | new->position = 1; |
| 1528 | got = (LENGTH (i) - (start - i->position)); | 1531 | got = (LENGTH (i) - (start - i->position)); |
| 1529 | new->total_length = got; | 1532 | new->total_length = length; |
| 1530 | copy_properties (i, new); | 1533 | copy_properties (i, new); |
| 1531 | 1534 | ||
| 1532 | t = new; | 1535 | t = new; |
| 1533 | while (got < length) | 1536 | while (got < length) |
| 1534 | { | 1537 | { |
| 1535 | i = next_interval (i); | 1538 | i = next_interval (i); |
| 1536 | t->right = make_interval (); | 1539 | t = split_interval_right (t, got + 1); |
| 1537 | t->right->parent = t; | ||
| 1538 | t->right->position = t->position + got - 1; | ||
| 1539 | |||
| 1540 | t = t->right; | ||
| 1541 | t->total_length = length - got; | ||
| 1542 | copy_properties (i, t); | 1540 | copy_properties (i, t); |
| 1543 | got += LENGTH (i); | 1541 | got += LENGTH (i); |
| 1544 | } | 1542 | } |
| @@ -1549,21 +1547,6 @@ copy_intervals (tree, start, length) | |||
| 1549 | return balance_intervals (new); | 1547 | return balance_intervals (new); |
| 1550 | } | 1548 | } |
| 1551 | 1549 | ||
| 1552 | /* Give buffer SINK the properties of buffer SOURCE from POSITION | ||
| 1553 | to END. The properties are attached to SINK starting at position AT. | ||
| 1554 | |||
| 1555 | No range checking is done. */ | ||
| 1556 | |||
| 1557 | void | ||
| 1558 | insert_interval_copy (source, position, end, sink, at) | ||
| 1559 | struct buffer *source, *sink; | ||
| 1560 | register int position, end, at; | ||
| 1561 | { | ||
| 1562 | INTERVAL interval_copy = copy_intervals (source->intervals, | ||
| 1563 | position, end - position); | ||
| 1564 | graft_intervals_into_buffer (interval_copy, at, sink); | ||
| 1565 | } | ||
| 1566 | |||
| 1567 | /* Give STRING the properties of BUFFER from POSITION to LENGTH. */ | 1550 | /* Give STRING the properties of BUFFER from POSITION to LENGTH. */ |
| 1568 | 1551 | ||
| 1569 | void | 1552 | void |
| @@ -1579,37 +1562,3 @@ copy_intervals_to_string (string, buffer, position, length) | |||
| 1579 | interval_copy->parent = (INTERVAL) string; | 1562 | interval_copy->parent = (INTERVAL) string; |
| 1580 | XSTRING (string)->intervals = interval_copy; | 1563 | XSTRING (string)->intervals = interval_copy; |
| 1581 | } | 1564 | } |
| 1582 | |||
| 1583 | INTERVAL | ||
| 1584 | make_string_interval (string, start, length) | ||
| 1585 | struct Lisp_String *string; | ||
| 1586 | int start, length; | ||
| 1587 | { | ||
| 1588 | if (start < 1 || start > string->size) | ||
| 1589 | error ("Interval index out of range"); | ||
| 1590 | if (length < 1 || length > string->size - start + 1) | ||
| 1591 | error ("Interval won't fit"); | ||
| 1592 | |||
| 1593 | if (length == 0) | ||
| 1594 | return NULL_INTERVAL; | ||
| 1595 | |||
| 1596 | return make_new_interval (string->intervals, start, length); | ||
| 1597 | } | ||
| 1598 | |||
| 1599 | /* Create an interval of length LENGTH in buffer BUF at position START. */ | ||
| 1600 | |||
| 1601 | INTERVAL | ||
| 1602 | make_buffer_interval (buf, start, length) | ||
| 1603 | struct buffer *buf; | ||
| 1604 | int start, length; | ||
| 1605 | { | ||
| 1606 | if (start < BUF_BEG (buf) || start > BUF_Z (buf)) | ||
| 1607 | error ("Interval index out of range"); | ||
| 1608 | if (length < 1 || length > BUF_Z (buf) - start) | ||
| 1609 | error ("Interval won't fit"); | ||
| 1610 | |||
| 1611 | if (length == 0) | ||
| 1612 | return NULL_INTERVAL; | ||
| 1613 | |||
| 1614 | return make_new_interval (buf->intervals, start, length); | ||
| 1615 | } | ||
diff --git a/src/intervals.h b/src/intervals.h index 48d3daeaad1..29fca360c98 100644 --- a/src/intervals.h +++ b/src/intervals.h | |||
| @@ -167,15 +167,11 @@ extern INTERVAL find_interval (), next_interval (), previous_interval (); | |||
| 167 | extern INTERVAL merge_interval_left (), merge_interval_right (); | 167 | extern INTERVAL merge_interval_left (), merge_interval_right (); |
| 168 | extern void delete_interval (); | 168 | extern void delete_interval (); |
| 169 | extern INLINE void offset_intervals (); | 169 | extern INLINE void offset_intervals (); |
| 170 | extern void map_intervals (); | ||
| 171 | extern void graft_intervals_into_buffer (); | 170 | extern void graft_intervals_into_buffer (); |
| 172 | extern void set_point (); | 171 | extern void set_point (); |
| 173 | extern void verify_interval_modification (); | 172 | extern void verify_interval_modification (); |
| 174 | extern INTERVAL balance_intervals (); | 173 | extern INTERVAL balance_intervals (); |
| 175 | extern void insert_interval_copy(); | ||
| 176 | extern void copy_intervals_to_string (); | 174 | extern void copy_intervals_to_string (); |
| 177 | extern INTERVAL make_string_interval (); | ||
| 178 | extern INTERVAL make_buffer_interval (); | ||
| 179 | 175 | ||
| 180 | /* Declared in textprop.c */ | 176 | /* Declared in textprop.c */ |
| 181 | 177 | ||
| @@ -190,8 +186,6 @@ extern Lisp_Object Qmodification; | |||
| 190 | extern Lisp_Object Qforeground, Qbackground, Qfont, Qunderline, Qstipple; | 186 | extern Lisp_Object Qforeground, Qbackground, Qfont, Qunderline, Qstipple; |
| 191 | extern Lisp_Object Qinvisible, Qread_only; | 187 | extern Lisp_Object Qinvisible, Qread_only; |
| 192 | 188 | ||
| 193 | extern void run_hooks (); | ||
| 194 | |||
| 195 | extern Lisp_Object Ftext_properties_at (); | 189 | extern Lisp_Object Ftext_properties_at (); |
| 196 | extern Lisp_Object Fnext_property_change (), Fprevious_property_change (); | 190 | extern Lisp_Object Fnext_property_change (), Fprevious_property_change (); |
| 197 | extern Lisp_Object Fadd_text_properties (), Fset_text_properties (); | 191 | extern Lisp_Object Fadd_text_properties (), Fset_text_properties (); |
diff --git a/src/textprop.c b/src/textprop.c index e7387bd1262..350ceec9b1c 100644 --- a/src/textprop.c +++ b/src/textprop.c | |||
| @@ -27,6 +27,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |||
| 27 | zero-length intervals if they are implemented. This could be done | 27 | zero-length intervals if they are implemented. This could be done |
| 28 | inside next_interval and previous_interval. | 28 | inside next_interval and previous_interval. |
| 29 | 29 | ||
| 30 | set_properties needs to deal with the interval property cache. | ||
| 31 | |||
| 30 | It is assumed that for any interval plist, a property appears | 32 | It is assumed that for any interval plist, a property appears |
| 31 | only once on the list. Although some code i.e., remove_properties (), | 33 | only once on the list. Although some code i.e., remove_properties (), |
| 32 | handles the more general case, the uniqueness of properties is | 34 | handles the more general case, the uniqueness of properties is |
| @@ -324,7 +326,6 @@ erase_properties (i) | |||
| 324 | return 1; | 326 | return 1; |
| 325 | } | 327 | } |
| 326 | 328 | ||
| 327 | |||
| 328 | DEFUN ("text-properties-at", Ftext_properties_at, | 329 | DEFUN ("text-properties-at", Ftext_properties_at, |
| 329 | Stext_properties_at, 1, 2, 0, | 330 | Stext_properties_at, 1, 2, 0, |
| 330 | "Return the list of properties held by the character at POSITION\n\ | 331 | "Return the list of properties held by the character at POSITION\n\ |
| @@ -370,9 +371,34 @@ Returns nil if unsuccessful.") | |||
| 370 | return next->position; | 371 | return next->position; |
| 371 | } | 372 | } |
| 372 | 373 | ||
| 374 | DEFUN ("next-single-property-change", Fnext_single_property_change, | ||
| 375 | Snext_single_property_change, 3, 3, 0, | ||
| 376 | "Return the position after POSITION in OBJECT which has a different\n\ | ||
| 377 | value for PROPERTY than the text at POSITION. OBJECT may be a string or\n\ | ||
| 378 | buffer. Returns nil if unsuccessful.") | ||
| 379 | (pos, object, prop) | ||
| 380 | { | ||
| 381 | register INTERVAL i, next; | ||
| 382 | register Lisp_Object here_val; | ||
| 383 | |||
| 384 | i = validate_interval_range (object, &pos, &pos, soft); | ||
| 385 | if (NULL_INTERVAL_P (i)) | ||
| 386 | return Qnil; | ||
| 387 | |||
| 388 | here_val = Fget (prop, i->plist); | ||
| 389 | next = next_interval (i); | ||
| 390 | while (! NULL_INTERVAL_P (next) && EQ (here_val, Fget (prop, next->plist))) | ||
| 391 | next = next_interval (next); | ||
| 392 | |||
| 393 | if (NULL_INTERVAL_P (next)) | ||
| 394 | return Qnil; | ||
| 395 | |||
| 396 | return next->position; | ||
| 397 | } | ||
| 398 | |||
| 373 | DEFUN ("previous-property-change", Fprevious_property_change, | 399 | DEFUN ("previous-property-change", Fprevious_property_change, |
| 374 | Sprevious_property_change, 2, 2, 0, | 400 | Sprevious_property_change, 2, 2, 0, |
| 375 | "Return the position before POSITION in OBJECT which has properties\n\ | 401 | "Return the position preceding POSITION in OBJECT which has properties\n\ |
| 376 | different from those at POSITION. OBJECT may be a string or buffer.\n\ | 402 | different from those at POSITION. OBJECT may be a string or buffer.\n\ |
| 377 | Returns nil if unsuccessful.") | 403 | Returns nil if unsuccessful.") |
| 378 | (pos, object) | 404 | (pos, object) |
| @@ -393,6 +419,31 @@ Returns nil if unsuccessful.") | |||
| 393 | return previous->position + LENGTH (previous) - 1; | 419 | return previous->position + LENGTH (previous) - 1; |
| 394 | } | 420 | } |
| 395 | 421 | ||
| 422 | DEFUN ("previous-single-property-change", Fprevious_single_property_change, | ||
| 423 | Sprevious_single_property_change, 3, 3, 0, | ||
| 424 | "Return the position preceding POSITION in OBJECT which has a\n\ | ||
| 425 | different value for PROPERTY than the text at POSITION. OBJECT may be | ||
| 426 | a string or buffer. Returns nil if unsuccessful.") | ||
| 427 | (pos, object, prop) | ||
| 428 | { | ||
| 429 | register INTERVAL i, previous; | ||
| 430 | register Lisp_Object here_val; | ||
| 431 | |||
| 432 | i = validate_interval_range (object, &pos, &pos, soft); | ||
| 433 | if (NULL_INTERVAL_P (i)) | ||
| 434 | return Qnil; | ||
| 435 | |||
| 436 | here_val = Fget (prop, i->plist); | ||
| 437 | previous = previous_interval (i); | ||
| 438 | while (! NULL_INTERVAL_P (previous) | ||
| 439 | && EQ (here_val, Fget (prop, previous->plist))) | ||
| 440 | previous = previous_interval (previous); | ||
| 441 | if (NULL_INTERVAL_P (previous)) | ||
| 442 | return Qnil; | ||
| 443 | |||
| 444 | return previous->position + LENGTH (previous) - 1; | ||
| 445 | } | ||
| 446 | |||
| 396 | DEFUN ("add-text-properties", Fadd_text_properties, | 447 | DEFUN ("add-text-properties", Fadd_text_properties, |
| 397 | Sadd_text_properties, 4, 4, 0, | 448 | Sadd_text_properties, 4, 4, 0, |
| 398 | "Add the PROPERTIES (a property list) to the text of OBJECT\n\ | 449 | "Add the PROPERTIES (a property list) to the text of OBJECT\n\ |
| @@ -487,6 +538,7 @@ Otherwise return nil.") | |||
| 487 | Lisp_Object object, start, end, properties; | 538 | Lisp_Object object, start, end, properties; |
| 488 | { | 539 | { |
| 489 | register INTERVAL i, unchanged; | 540 | register INTERVAL i, unchanged; |
| 541 | register INTERVAL prev_changed = NULL_INTERVAL; | ||
| 490 | register int s, len; | 542 | register int s, len; |
| 491 | 543 | ||
| 492 | properties = validate_plist (properties); | 544 | properties = validate_plist (properties); |
| @@ -504,15 +556,18 @@ Otherwise return nil.") | |||
| 504 | { | 556 | { |
| 505 | unchanged = i; | 557 | unchanged = i; |
| 506 | i = split_interval_right (unchanged, s - unchanged->position + 1); | 558 | i = split_interval_right (unchanged, s - unchanged->position + 1); |
| 507 | copy_properties (unchanged, i); | 559 | set_properties (properties, i); |
| 508 | if (LENGTH (i) > len) | 560 | if (LENGTH (i) > len) |
| 509 | { | 561 | { |
| 510 | i = split_interval_left (i, len); | 562 | i = split_interval_right (i, len); |
| 511 | set_properties (properties, i); | 563 | copy_properties (unchanged, i); |
| 512 | return Qt; | 564 | return Qt; |
| 513 | } | 565 | } |
| 514 | 566 | ||
| 515 | set_properties (properties, i); | 567 | if (LENGTH (i) == len) |
| 568 | return Qt; | ||
| 569 | |||
| 570 | prev_changed = i; | ||
| 516 | len -= LENGTH (i); | 571 | len -= LENGTH (i); |
| 517 | i = next_interval (i); | 572 | i = next_interval (i); |
| 518 | } | 573 | } |
| @@ -523,17 +578,30 @@ Otherwise return nil.") | |||
| 523 | { | 578 | { |
| 524 | if (LENGTH (i) == len) | 579 | if (LENGTH (i) == len) |
| 525 | { | 580 | { |
| 526 | set_properties (properties, i); | 581 | if (NULL_INTERVAL_P (prev_changed)) |
| 582 | set_properties (properties, i); | ||
| 583 | else | ||
| 584 | merge_interval_left (i); | ||
| 527 | return Qt; | 585 | return Qt; |
| 528 | } | 586 | } |
| 529 | 587 | ||
| 530 | i = split_interval_left (i, len + 1); | 588 | i = split_interval_left (i, len + 1); |
| 531 | set_properties (properties, i); | 589 | if (NULL_INTERVAL_P (prev_changed)) |
| 590 | set_properties (properties, i); | ||
| 591 | else | ||
| 592 | merge_interval_left (i); | ||
| 532 | return Qt; | 593 | return Qt; |
| 533 | } | 594 | } |
| 534 | 595 | ||
| 535 | len -= LENGTH (i); | 596 | len -= LENGTH (i); |
| 536 | set_properties (properties, i); | 597 | if (NULL_INTERVAL_P (prev_changed)) |
| 598 | { | ||
| 599 | set_properties (properties, i); | ||
| 600 | prev_changed = i; | ||
| 601 | } | ||
| 602 | else | ||
| 603 | prev_changed = i = merge_interval_left (i); | ||
| 604 | |||
| 537 | i = next_interval (i); | 605 | i = next_interval (i); |
| 538 | } | 606 | } |
| 539 | 607 | ||
| @@ -557,6 +625,7 @@ was made, nil otherwise.") | |||
| 557 | 625 | ||
| 558 | s = XINT (start); | 626 | s = XINT (start); |
| 559 | len = XINT (end) - s; | 627 | len = XINT (end) - s; |
| 628 | |||
| 560 | if (i->position != s) | 629 | if (i->position != s) |
| 561 | { | 630 | { |
| 562 | /* No properties on this first interval -- return if | 631 | /* No properties on this first interval -- return if |
| @@ -719,7 +788,9 @@ percentage by which the left interval tree should not differ from the right."); | |||
| 719 | 788 | ||
| 720 | defsubr (&Stext_properties_at); | 789 | defsubr (&Stext_properties_at); |
| 721 | defsubr (&Snext_property_change); | 790 | defsubr (&Snext_property_change); |
| 791 | defsubr (&Snext_single_property_change); | ||
| 722 | defsubr (&Sprevious_property_change); | 792 | defsubr (&Sprevious_property_change); |
| 793 | defsubr (&Sprevious_single_property_change); | ||
| 723 | defsubr (&Sadd_text_properties); | 794 | defsubr (&Sadd_text_properties); |
| 724 | defsubr (&Sset_text_properties); | 795 | defsubr (&Sset_text_properties); |
| 725 | defsubr (&Sremove_text_properties); | 796 | defsubr (&Sremove_text_properties); |