Summary #
When a delete overlaps multiple replacement-text spans, buffer:delete_char only removes the first discovered span (by reverse iteration) and returns early, leaving other overlapping spans in place.
The Problem #
In src/cursed/buffer.lua, delete_char iterates self._properties in reverse order and upon finding a span whose attrs.text is set and that overlaps the deletion range, it removes that span and returns immediately. If multiple replacement-text spans overlap the same deletion range (e.g., two adjacent virtual text spans), only the last one in iteration order is removed; the others remain, possibly causing stale virtual text.
Impact #
- correctness: Buffer::delete_char only removes the last overlapping replacement-text span; other overlapping spans remain, leading to stale virtual text overlays.
Recommended Fix #
Change the loop to remove ALL overlapping replacement-text spans (i.e., continue iterating after table.remove), then return after processing all matches. Alternatively, collect indices first and remove in descending order.
Commit range: 757d8a9f..757d8a9f
Code Review: CR-2026-07-25-3