Function: ghostel--kitty-strip-orphan-top
ghostel--kitty-strip-orphan-top is a natively compiled function
defined in ghostel-kitty.el.
Signature
(ghostel--kitty-strip-orphan-top)
Documentation
Strip kitty image debris left at point-min by scrollback eviction.
Two distinct artifacts both surface here:
1. Collapsed overlays. delete-region clamps overlays inside the
deleted range to its start instead of deleting them, so an evicted
row's zero-width kitty overlays all snap onto the new point-min and
stack there (dozens for a tall image). Detected by counting
zero-width kitty overlays per start-position — more than one at the
same position is never legitimate (the placement loop emits at most
one overlay per row).
2. Orphan text-property slices. When eviction straddles an image, the
surviving rows keep their display slices into a now-incomplete
image. Detected by a slice y-offset > 0 at point-min (y=0 would
mean the row IS the image's top, so it's an intact image's first
row, not an orphan).
Source Code
;; Defined in /nix/store/1252krff0gb2kisjcpp45m50cpdskfrl-emacs-packages-deps/share/emacs/site-lisp/ghostel-kitty.el
(defun ghostel--kitty-strip-orphan-top ()
"Strip kitty image debris left at point-min by scrollback eviction.
Two distinct artifacts both surface here:
1. Collapsed overlays. `delete-region' clamps overlays inside the
deleted range to its start instead of deleting them, so an evicted
row's zero-width kitty overlays all snap onto the new point-min and
stack there (dozens for a tall image). Detected by counting
zero-width kitty overlays per start-position — more than one at the
same position is never legitimate (the placement loop emits at most
one overlay per row).
2. Orphan text-property slices. When eviction straddles an image, the
surviving rows keep their `display' slices into a now-incomplete
image. Detected by a slice y-offset > 0 at point-min (y=0 would
mean the row IS the image's top, so it's an intact image's first
row, not an orphan)."
(let ((inhibit-read-only t))
;; (1) Eviction-collapsed overlay stacks.
(let ((counts (make-hash-table)))
(dolist (ov (overlays-in (point-min) (point-max)))
(when (and (overlay-get ov 'ghostel-kitty)
(= (overlay-start ov) (overlay-end ov)))
(let ((pos (overlay-start ov)))
(puthash pos (1+ (gethash pos counts 0)) counts))))
(dolist (ov (overlays-in (point-min) (point-max)))
(when (and (overlay-get ov 'ghostel-kitty)
(= (overlay-start ov) (overlay-end ov))
(> (gethash (overlay-start ov) counts 0) 1))
(delete-overlay ov))))
;; (2) Orphan text-property slices at point-min.
(let ((slice-y (ghostel--kitty-slice-y-at (point-min))))
(when (and slice-y (> slice-y 0))
(let ((start (point-min))
(end (save-excursion
(goto-char (point-min))
(while (and (< (point) (point-max))
(or (get-text-property (point) 'ghostel-kitty)
(cl-some
(lambda (ov) (overlay-get ov 'ghostel-kitty))
(overlays-at (point)))))
(forward-line 1))
(point))))
(when (> end start)
(remove-text-properties
start end '(display nil line-height nil ghostel-kitty nil))
(dolist (ov (overlays-in start end))
(when (overlay-get ov 'ghostel-kitty)
(delete-overlay ov)))))))))