Skip to content

Commit c9e9bc7

Browse files
committed
fix(insert): inherit the full plist when extending a uniform interval
insert-and-inherit / insert-before-markers-and-inherit / insert-char with INHERIT compute the inherited properties via a between-intervals sticky merge that skips the front-sticky/rear-nonsticky meta keys and re-derives them, so inserting into the middle of one uniform interval dropped its `rear-nonsticky nil` (and any front-sticky/rear-nonsticky value). GNU's adjust_intervals_for_insertion (src/intervals.c) extends the interval and inherits its full plist verbatim in that case. Add a fast path at the top of inherited_text_properties_for_inserted_range_in_state: when the insert is strictly interior (both neighbors present) and the two neighbors carry the same property set -- our proxy for "one interval", since neomacs coalesces equal adjacent intervals -- and no real property is rear-nonsticky (by value or text-property-default-nonsticky), return the left neighbor's full plist. Otherwise fall through to the existing merge. Fixes insert_and_inherit_full_plist and insert_char_inherit_property_plist; the rear-nonsticky-blocks and sticky-merge-matrix cases still pass.
1 parent 2fbc7e7 commit c9e9bc7

1 file changed

Lines changed: 26 additions & 0 deletions

File tree

neovm-core/src/emacs_core/builtins/misc_eval.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -894,6 +894,32 @@ pub(crate) fn inherited_text_properties_for_inserted_range_in_state(
894894
let default_nonsticky =
895895
buffer_local_or_global_symbol_value(obarray, buf, "text-property-default-nonsticky");
896896

897+
// GNU `adjust_intervals_for_insertion` (src/intervals.c): inserting into the
898+
// MIDDLE of a single uniform interval extends that interval, so the inserted
899+
// text inherits its full plist verbatim -- including the front-sticky /
900+
// rear-nonsticky meta entries -- rather than the between-intervals sticky
901+
// merge below. This only applies strictly interior (both neighbors present,
902+
// never at point-min/point-max) and when the two neighbors carry the same
903+
// property set (our proxy for "one interval", since neomacs coalesces equal
904+
// adjacent intervals). A real property that is rear-nonsticky (by value or
905+
// by `text-property-default-nonsticky`) forces a split, so fall through to
906+
// the merge in that case.
907+
if !left_props.is_empty() && !right_props.is_empty() && left_map == right_map {
908+
let forces_split = left_props.iter().any(|(name, _)| {
909+
if *name == Value::symbol("front-sticky") || *name == Value::symbol("rear-nonsticky") {
910+
return false;
911+
}
912+
let default_rear_nonsticky = default_nonsticky
913+
.as_ref()
914+
.and_then(|value| assq_cdr(value, *name))
915+
.is_some_and(|v| v.is_truthy());
916+
matches_rear_nonsticky(left_rear, *name) || default_rear_nonsticky
917+
});
918+
if !forces_split {
919+
return left_props.clone();
920+
}
921+
}
922+
897923
let mut merged_props = Vec::new();
898924
let mut front_sticky = Vec::new();
899925
let mut rear_nonsticky = Vec::new();

0 commit comments

Comments
 (0)