Some checks are pending
CI / test (29.1) (push) Waiting to run
CI / test (30.2) (push) Waiting to run
CI / native-build (macos-latest) (push) Waiting to run
CI / native-build (ubuntu-latest) (push) Waiting to run
CI / native-build (windows-latest) (push) Waiting to run
CI / native-msrv (macos-latest) (push) Waiting to run
CI / native-msrv (ubuntu-latest) (push) Waiting to run
CI / native-msrv (windows-latest) (push) Waiting to run
429 lines
24 KiB
EmacsLisp
429 lines
24 KiB
EmacsLisp
;;; ebox-nested-scroll-tests.el --- Cached nested scroll publication -*- lexical-binding: t; -*-
|
|
|
|
;;; Commentary:
|
|
;; Fixed scroll allocations publish their retained windows locally while
|
|
;; preserving ancestor effects, native interaction and TP mount ownership.
|
|
|
|
;;; Code:
|
|
|
|
(require 'ert)
|
|
(require 'cl-lib)
|
|
(require 'ebox)
|
|
|
|
(defmacro ebox-nested-scroll-test--without-general-preparation (&rest body)
|
|
"Run cached publication BODY without document preparation or surface scans."
|
|
(declare (indent 0) (debug t))
|
|
`(let ((stages '(ebox-incremental-prepare-scoped-commit
|
|
ebox-incremental--prepare-declarative-runtime
|
|
ebox--runtime-index ebox-surface--surface-plan))
|
|
counters advices)
|
|
(unwind-protect
|
|
(progn
|
|
(dolist (stage stages)
|
|
(let* ((counter (cons stage 0))
|
|
(advice (lambda (&rest _) (cl-incf (cdr counter)))))
|
|
(push counter counters)
|
|
(push (cons stage advice) advices)
|
|
(advice-add stage :before advice)))
|
|
,@body)
|
|
(dolist (entry advices) (advice-remove (car entry) (cdr entry))))
|
|
(should (equal (nreverse counters)
|
|
(mapcar (lambda (stage) (cons stage 0)) stages)))))
|
|
|
|
(defmacro ebox-nested-scroll-test--with-buffer (&rest body)
|
|
"Run BODY with an isolated mounted surface and the Elisp renderer."
|
|
(declare (indent 0) (debug t))
|
|
`(cl-letf (((symbol-function 'ebox-native-reflow-layout-ready-p)
|
|
(lambda () nil)))
|
|
(let ((ebox-viewport-width 104) (ebox-viewport-height 30)
|
|
(ebox-runtime-idle-prewarm nil)
|
|
(ebox-runtime-idle-reflow-cache-prewarm nil))
|
|
(with-temp-buffer
|
|
(unwind-protect (progn ,@body)
|
|
(when (ebox-surface-buffer-mounted-p (current-buffer))
|
|
(ebox-unmount-buffer (current-buffer))))))))
|
|
|
|
(defun ebox-nested-scroll-test--input (&optional layout chrome peers)
|
|
"Build a scroll owner under LAYOUT with CHROME and PEERS other boxes."
|
|
(ebox-build
|
|
`(column :id "root" :width (px 104) :color "#204060"
|
|
(box :id "before" "before")
|
|
(,(or layout 'column)
|
|
,@(pcase layout
|
|
('row '(:width (px 104)))
|
|
('flex '(:width (px 104) :gap ((lh 0) (px 2))))
|
|
('grid '(:width (px 104) :grid-template-columns ((px 80) (px 20)))))
|
|
:background-color "#E0E8F0" :padding-left (px 2)
|
|
(box :id "scroll" :width (px 80) :height (lh 5) :overflow scroll
|
|
,@(when chrome '(:padding ((lh 1) (px 1)) :border-width (px 1)
|
|
:border-style solid :border-color "#456789"))
|
|
,@(cl-loop for number below 30
|
|
collect `(box :id ,(format "line-%d" number)
|
|
:help-echo ,(format "line %d" number)
|
|
:pointer hand
|
|
:hover-style (:background-color "#FFFFA0")
|
|
:keymap (keymap (13 . ignore))
|
|
,(format "line %02d" number))))
|
|
(box :id "sibling" :width (px 20) "sibling"))
|
|
,@(cl-loop for index below (or peers 0)
|
|
collect `(box :id ,(format "peer-%d" index) "peer"))
|
|
(box :id "after" "after"))))
|
|
|
|
(defun ebox-nested-scroll-test--region (id)
|
|
"Return ID's runtime region in the current mounted buffer."
|
|
(cdr (ebox-selector--region-target (ebox-region-resolve (current-buffer) id))))
|
|
|
|
(defun ebox-nested-scroll-test--mounts (&optional preserve-order-p)
|
|
"Return semantic IDs and their live mount ranges in the current buffer.
|
|
PRESERVE-ORDER-P retains attachment order for exact rollback checks."
|
|
(mapcar
|
|
(lambda (id)
|
|
(let* ((region (ebox-nested-scroll-test--region id))
|
|
(state (ebox--buffer-render-state (current-buffer)))
|
|
(object (gethash region (plist-get state :region-surface-object-table))))
|
|
(let ((ranges (mapcar (lambda (mount)
|
|
(cons (plist-get mount :start) (plist-get mount :end)))
|
|
(tp-object-mounts object))))
|
|
(cons id (if preserve-order-p ranges
|
|
(sort ranges
|
|
(lambda (left right)
|
|
(if (= (car left) (car right)) (< (cdr left) (cdr right))
|
|
(< (car left) (car right))))))))))
|
|
(append '("before" "scroll" "sibling" "after")
|
|
(cl-loop for index below 30 collect (format "line-%d" index)))))
|
|
|
|
(defun ebox-nested-scroll-test--parity ()
|
|
"Compare current paint, interactions and mounts with fresh committed input."
|
|
(let* ((state (ebox--buffer-render-state (current-buffer)))
|
|
(ebox-viewport-width (plist-get state :viewport-width))
|
|
(ebox-viewport-height (plist-get state :viewport-height))
|
|
(input (plist-get (ebox-surface-buffer-snapshot (current-buffer)) :input))
|
|
(actual (buffer-string))
|
|
(mounts (ebox-nested-scroll-test--mounts)))
|
|
(with-temp-buffer
|
|
(unwind-protect
|
|
(progn
|
|
(ebox-render-to-buffer (current-buffer) input)
|
|
(should (equal (substring-no-properties actual)
|
|
(buffer-substring-no-properties (point-min) (point-max))))
|
|
(dotimes (position (length actual))
|
|
(dolist (property '(face font-lock-face display help-echo mouse-face pointer keymap))
|
|
(should (equal (get-text-property position property actual)
|
|
(get-text-property (1+ position) property)))))
|
|
(should (equal mounts (ebox-nested-scroll-test--mounts))))
|
|
(when (ebox-surface-buffer-mounted-p (current-buffer))
|
|
(ebox-unmount-buffer (current-buffer)))))))
|
|
|
|
(ert-deftest ebox-nested-scroll-retained-fragments-own-newline-separators ()
|
|
"Retained paint ledgers cover separators with both neighboring owners."
|
|
(let* ((lines (list (propertize "before" 'ebox-content-owner 1)
|
|
(propertize "inside" 'ebox-content-owner 2)
|
|
(propertize "after" 'ebox-content-owner 3)))
|
|
(output (ebox-lines-join lines))
|
|
(retained (ebox-surface--scroll-fragment-data lines output))
|
|
(fresh (ebox-surface--rendered-fragments (copy-sequence output))))
|
|
(cl-labels ((roles-at (fragments position)
|
|
(plist-get
|
|
(cl-find-if (lambda (fragment)
|
|
(and (<= (plist-get fragment :start) position)
|
|
(< position (plist-get fragment :end))))
|
|
fragments)
|
|
:role-ids)))
|
|
(dotimes (position (length output))
|
|
(should (equal (roles-at retained position) (roles-at fresh position))))
|
|
(should (equal (roles-at retained 6) '((content-owner . 1) (content-owner . 2))))
|
|
(should (equal (roles-at retained 13) '((content-owner . 2) (content-owner . 3)))))
|
|
;; Leading/trailing unowned runs also depend on the adjacent line, so
|
|
;; these retain the complete scanner until that wider context is proved.
|
|
(dolist (boundary '(" unowned" "unowned "))
|
|
(let ((line (copy-sequence boundary)))
|
|
(put-text-property 1 (1- (length line)) 'ebox-content-owner 1 line)
|
|
(should-not (ebox-surface--scroll-line-fragment-template line))))))
|
|
|
|
(ert-deftest ebox-nested-scroll-cached-window-does-not-render-siblings ()
|
|
"One cached nested window avoids root renders and unrelated node work."
|
|
(ebox-nested-scroll-test--with-buffer
|
|
(ebox-render-to-buffer (current-buffer) (ebox-nested-scroll-test--input nil nil 200))
|
|
(let* ((region (ebox-nested-scroll-test--region "scroll"))
|
|
(owner (ebox--buffer-region-render-owner-node-id (current-buffer) region))
|
|
(child-region (ebox-nested-scroll-test--region "line-0"))
|
|
(child (ebox--buffer-region-render-owner-node (current-buffer) child-region))
|
|
(root-renders 0) (index-builds 0)
|
|
(render (symbol-function 'ebox-surface--render-candidate))
|
|
(layout (symbol-function 'ebox--render-layout))
|
|
(index (symbol-function 'ebox--runtime-index)))
|
|
(dolist (delta '(1 1 -1 -1))
|
|
(cl-letf (((symbol-function 'ebox-surface--render-candidate)
|
|
(lambda (&rest arguments)
|
|
(cl-incf root-renders) (apply render arguments)))
|
|
((symbol-function 'ebox--runtime-index)
|
|
(lambda (&rest arguments)
|
|
(cl-incf index-builds) (apply index arguments)))
|
|
((symbol-function 'ebox--render-layout)
|
|
(lambda (node)
|
|
(should (equal (plist-get node :node-id) owner))
|
|
(funcall layout node))))
|
|
(should (= (ebox--surface-scroll-region-by
|
|
(current-buffer) region delta nil) delta)))
|
|
(should (eq child (ebox--buffer-region-render-owner-node
|
|
(current-buffer) child-region)))
|
|
(ebox-nested-scroll-test--parity))
|
|
(should (= root-renders 0))
|
|
(should (= index-builds 0))
|
|
(ebox-nested-scroll-test--parity))))
|
|
|
|
(ert-deftest ebox-nested-scroll-preserves-allocated-layout-and-chrome ()
|
|
"Column, Row, Flex and Grid owners retain paint, slots and scroll identities."
|
|
(dolist (layout '(column row flex grid))
|
|
(dolist (chrome '(nil t))
|
|
(ert-info ((format "layout=%S chrome=%S" layout chrome))
|
|
(ebox-nested-scroll-test--with-buffer
|
|
(ebox-render-to-buffer (current-buffer)
|
|
(ebox-nested-scroll-test--input layout chrome))
|
|
(let* ((region (ebox-nested-scroll-test--region "scroll"))
|
|
(old-state (ebox--buffer-render-state (current-buffer)))
|
|
(old-box (gethash region (plist-get old-state :region-box-table)))
|
|
(old-scroll (gethash region (plist-get old-state :scroll-state-table))))
|
|
(cl-letf (((symbol-function 'ebox-surface--render-candidate)
|
|
(lambda (&rest _) (ert-fail "Nested allocation rendered root"))))
|
|
(should (= (ebox--surface-scroll-region-by
|
|
(current-buffer) region 1 nil) 1)))
|
|
(let* ((state (ebox--buffer-render-state (current-buffer)))
|
|
(box (gethash region (plist-get state :region-box-table)))
|
|
(scroll (gethash region (plist-get state :scroll-state-table))))
|
|
(should-not (eq old-box box))
|
|
(should (eq box (plist-get scroll :box)))
|
|
(should (= (or (ebox-get old-box :scroll-offset) 0) 0))
|
|
(should (= (plist-get old-scroll :scroll-offset) 0))
|
|
(should (= (ebox-get box :scroll-offset) 1))
|
|
(should (= (plist-get scroll :scroll-offset) 1)))
|
|
(ebox-nested-scroll-test--parity)))))))
|
|
|
|
(ert-deftest ebox-nested-scroll-independent-owners-retain-their-caches ()
|
|
"Side-by-side scrolls keep independent offsets across content and resize."
|
|
(ebox-nested-scroll-test--with-buffer
|
|
(ebox-render-to-buffer (current-buffer) (ebox-nested-scroll-test--input 'row))
|
|
(ebox-region-update "sibling" :height '(lh 5) :overflow 'scroll
|
|
:content "sibling 0\nsibling 1\nsibling 2\nsibling 3\nsibling 4\nsibling 5\nsibling 6\nsibling 7")
|
|
(let ((left (ebox-nested-scroll-test--region "scroll"))
|
|
(right (ebox-nested-scroll-test--region "sibling")))
|
|
(cl-letf (((symbol-function 'ebox-surface--render-candidate)
|
|
(lambda (&rest _) (ert-fail "Independent scroll rendered root"))))
|
|
(should (= (ebox--surface-scroll-region-by (current-buffer) right 2 nil) 2)))
|
|
(ebox-nested-scroll-test--parity)
|
|
(let* ((state (ebox--buffer-render-state (current-buffer)))
|
|
(scroll (gethash right (plist-get state :scroll-state-table)))
|
|
(lines (plist-get scroll :content-lines))
|
|
(revision (ebox-surface-buffer-revision (current-buffer)))
|
|
(objects (copy-hash-table (plist-get state :surface-node-object-table))))
|
|
(dolist (delta '(1 1 -1))
|
|
(ebox-nested-scroll-test--without-general-preparation
|
|
(cl-letf (((symbol-function 'ebox-surface--render-candidate)
|
|
(lambda (&rest _) (ert-fail "Independent scroll rendered root"))))
|
|
(should (= (ebox--surface-scroll-region-by
|
|
(current-buffer) left delta nil) delta))))
|
|
(cl-incf revision)
|
|
(should (= revision (ebox-surface-buffer-revision (current-buffer))))
|
|
(let ((next (gethash right (plist-get (ebox--buffer-render-state
|
|
(current-buffer)) :scroll-state-table))))
|
|
(should (= (plist-get next :scroll-offset) 2))
|
|
(should (eq (plist-get next :content-lines) lines)))
|
|
(ebox-nested-scroll-test--parity))
|
|
(maphash
|
|
(lambda (id object)
|
|
(should (eq object
|
|
(gethash id (plist-get (ebox--buffer-render-state (current-buffer))
|
|
:surface-node-object-table)))))
|
|
objects)
|
|
(let ((next (gethash right (plist-get (ebox--buffer-render-state
|
|
(current-buffer)) :scroll-state-table))))
|
|
(should (= (plist-get next :scroll-offset) 2))
|
|
(should (eq (plist-get next :content-lines) lines))))
|
|
(ebox-nested-scroll-test--parity)
|
|
(ebox-region-update "line-1" :content "UPDATED")
|
|
(should (string-match-p "UPDATED" (buffer-string)))
|
|
(should (= (plist-get (ebox--scroll-get-state right) :scroll-offset) 2))
|
|
(ebox-nested-scroll-test--parity)
|
|
(ebox-rerender-buffer-with-context (current-buffer) 120 35)
|
|
(should (= (plist-get (ebox--scroll-get-state left) :scroll-offset) 1))
|
|
(should (= (plist-get (ebox--scroll-get-state right) :scroll-offset) 2))
|
|
(ebox-nested-scroll-test--parity)
|
|
(ebox-nested-scroll-test--without-general-preparation
|
|
(should (= (ebox--surface-scroll-region-by (current-buffer) left -1 nil) -1)))
|
|
(ebox-nested-scroll-test--parity))))
|
|
|
|
(ert-deftest ebox-nested-scroll-rejection-restores-local-and-fallback-state ()
|
|
"TP rejection restores text, mounts and runtime on local and declined slots."
|
|
(dolist (fallback '(nil t))
|
|
(ebox-nested-scroll-test--with-buffer
|
|
(ebox-render-to-buffer (current-buffer) (ebox-nested-scroll-test--input))
|
|
;; Arbitrary inherited interactions deliberately require full projection.
|
|
(when fallback (ebox-region-update "root" :help-echo "enclosing action"))
|
|
(let* ((region (ebox-nested-scroll-test--region "scroll"))
|
|
(state (ebox--buffer-render-state (current-buffer)))
|
|
(scroll (gethash region (plist-get state :scroll-state-table)))
|
|
(box (plist-get scroll :box))
|
|
(before (buffer-string))
|
|
(mounts (ebox-nested-scroll-test--mounts t))
|
|
(revision (ebox-surface-buffer-revision (current-buffer)))
|
|
rejected-step
|
|
(root-renders 0)
|
|
(render (symbol-function 'ebox-surface--render-candidate)))
|
|
(cl-letf (((symbol-function 'ebox-surface--render-candidate)
|
|
(lambda (&rest arguments)
|
|
(cl-incf root-renders) (apply render arguments))))
|
|
(let ((tp--surface-publication-step-function
|
|
(lambda (step _surface)
|
|
(when (eq step 'client-state)
|
|
(setq rejected-step step)
|
|
(error "Reject nested scroll"))))
|
|
(attempt (lambda ()
|
|
(should-error (ebox--surface-scroll-region-by
|
|
(current-buffer) region 1 nil)))))
|
|
(if fallback (funcall attempt)
|
|
(ebox-nested-scroll-test--without-general-preparation
|
|
(funcall attempt)))))
|
|
(should (eq rejected-step 'client-state))
|
|
(should (eq state (ebox--buffer-render-state (current-buffer))))
|
|
(should (= revision (ebox-surface-buffer-revision (current-buffer))))
|
|
(should (equal-including-properties before (buffer-string)))
|
|
(should (equal mounts (ebox-nested-scroll-test--mounts t)))
|
|
(should (= (plist-get scroll :scroll-offset) 0))
|
|
(should (= (or (ebox-get box :scroll-offset) 0) 0))
|
|
(should (if fallback (> root-renders 0) (= root-renders 0)))
|
|
(if fallback
|
|
(should (= (ebox--surface-scroll-region-by (current-buffer) region 1 nil) 1))
|
|
(ebox-nested-scroll-test--without-general-preparation
|
|
(should (= (ebox--surface-scroll-region-by (current-buffer) region 1 nil) 1))))
|
|
(should (= (1+ revision) (ebox-surface-buffer-revision (current-buffer))))
|
|
(ebox-nested-scroll-test--parity)))))
|
|
|
|
(ert-deftest ebox-nested-scroll-updates-enclosing-cache-and-role-membership ()
|
|
"Inner motion repairs enclosing cache coordinates before outer scrolling."
|
|
(ebox-nested-scroll-test--with-buffer
|
|
(ebox-render-to-buffer (current-buffer) (ebox-nested-scroll-test--input nil nil 200))
|
|
(ebox-region-update "root" :height '(lh 15) :overflow 'scroll)
|
|
(let ((inner (ebox-nested-scroll-test--region "scroll"))
|
|
(outer (ebox-nested-scroll-test--region "root"))
|
|
(hidden (ebox-nested-scroll-test--region "line-0"))
|
|
(visible (ebox-nested-scroll-test--region "line-5")))
|
|
(ebox-nested-scroll-test--without-general-preparation
|
|
(cl-letf (((symbol-function 'ebox-surface--render-candidate)
|
|
(lambda (&rest _) (ert-fail "Inner scroll rendered enclosing root"))))
|
|
(should (= (ebox--surface-scroll-region-by (current-buffer) inner 1 nil) 1))))
|
|
(let* ((state (ebox--buffer-render-state (current-buffer)))
|
|
(scroll (gethash outer (plist-get state :scroll-state-table)))
|
|
(members (ebox--scroll-state-ensure-content-region-id-set scroll)))
|
|
(should (= (plist-get scroll :scroll-offset) 0))
|
|
(should (eq (plist-get scroll :box) (plist-get state :root-node)))
|
|
(should-not (gethash hidden members))
|
|
(should (gethash visible members))
|
|
(let ((bounds (plist-get scroll :region-line-bounds-index))
|
|
(fresh (ebox--scroll-build-region-line-bounds-index
|
|
(plist-get scroll :content-lines))))
|
|
(should (= (hash-table-count bounds) (hash-table-count fresh)))
|
|
(maphash (lambda (id range) (should (equal range (gethash id bounds)))) fresh)))
|
|
(ebox-nested-scroll-test--parity)
|
|
(ebox-region-update "line-5" :content "NEW VISIBLE")
|
|
(should (string-match-p "NEW VISIBLE" (buffer-string)))
|
|
(ebox-region-update "line-0" :content "NEW HIDDEN")
|
|
(should-not (string-match-p "NEW HIDDEN" (buffer-string)))
|
|
(ebox-nested-scroll-test--parity)
|
|
(should (= (ebox--surface-scroll-region-by (current-buffer) outer 2 nil) 2))
|
|
(ebox-nested-scroll-test--parity)
|
|
;; The inner allocation is partially clipped at this outer offset.
|
|
(should (= (ebox--surface-scroll-region-by (current-buffer) inner 1 nil) 1))
|
|
(ebox-nested-scroll-test--parity)
|
|
(should (= (ebox--surface-scroll-region-by (current-buffer) outer 10 nil) 10))
|
|
(let ((before (buffer-string)))
|
|
(cl-letf (((symbol-function 'ebox-surface--render-candidate)
|
|
(lambda (&rest _) (ert-fail "Hidden inner scroll rendered root"))))
|
|
(should (= (ebox--surface-scroll-region-by (current-buffer) inner 1 nil) 1)))
|
|
(should (equal (substring-no-properties before) (buffer-string)))
|
|
(dotimes (position (length before))
|
|
(dolist (property '(face font-lock-face display help-echo keymap mouse-face pointer))
|
|
(should (equal (get-text-property position property before)
|
|
(get-text-property (1+ position) property)))))
|
|
(ebox-nested-scroll-test--parity))
|
|
(should (= (ebox--surface-scroll-region-by (current-buffer) outer -12 nil) -12))
|
|
(ebox-nested-scroll-test--parity))))
|
|
|
|
(ert-deftest ebox-nested-scroll-enclosing-cache-rejection-is-atomic ()
|
|
"Rejected inner publication preserves both scroll caches and source boxes."
|
|
(ebox-nested-scroll-test--with-buffer
|
|
(ebox-render-to-buffer (current-buffer) (ebox-nested-scroll-test--input))
|
|
(ebox-region-update "root" :height '(lh 15) :overflow 'scroll)
|
|
(let* ((inner (ebox-nested-scroll-test--region "scroll"))
|
|
(outer (ebox-nested-scroll-test--region "root"))
|
|
(state (ebox--buffer-render-state (current-buffer)))
|
|
(table (plist-get state :scroll-state-table))
|
|
(before (buffer-string))
|
|
(mounts (ebox-nested-scroll-test--mounts t))
|
|
(revision (ebox-surface-buffer-revision (current-buffer)))
|
|
(outer-state (gethash outer table))
|
|
(outer-lines (plist-get outer-state :content-lines)))
|
|
(let ((tp--surface-publication-step-function
|
|
(lambda (step _surface)
|
|
(when (eq step 'client-state) (error "Reject enclosing cache")))))
|
|
(should-error (ebox--surface-scroll-region-by (current-buffer) inner 1 nil)))
|
|
(should (eq state (ebox--buffer-render-state (current-buffer))))
|
|
(should (eq outer-lines (plist-get (gethash outer table) :content-lines)))
|
|
(should (equal-including-properties before (buffer-string)))
|
|
(should (equal mounts (ebox-nested-scroll-test--mounts t)))
|
|
(should (= revision (ebox-surface-buffer-revision (current-buffer))))
|
|
(should (= (plist-get (gethash inner table) :scroll-offset) 0))
|
|
(should (= (ebox--surface-scroll-region-by (current-buffer) inner 1 nil) 1))
|
|
(ebox-nested-scroll-test--parity))))
|
|
|
|
(ert-deftest ebox-nested-scroll-enclosing-prefix-and-independent-owner-stay-current ()
|
|
"Ancestor prefix growth, materialization and resize retain inner state."
|
|
(ebox-nested-scroll-test--with-buffer
|
|
(ebox-render-to-buffer
|
|
(current-buffer)
|
|
(ebox-build
|
|
`(column :id "root" :width (px 104) :height (vh 50) :overflow scroll
|
|
(box :id "before" "before")
|
|
(column :id "scroll" :width (px 80) :height (vh 20) :overflow scroll
|
|
,@(cl-loop for n below 100 collect
|
|
`(box :id ,(format "line-%d" n) :help-echo ,(format "Action %d" n)
|
|
,(format "line %02d" n))))
|
|
(box :id "sibling" :width (px 20) :height (lh 6) :overflow scroll
|
|
"sibling 0\nsibling 1\nsibling 2\nsibling 3\nsibling 4\nsibling 5\nsibling 6\nsibling 7")
|
|
,@(cl-loop repeat 200 collect '(box "peer"))
|
|
(box :id "after" "after"))))
|
|
(let* ((inner (ebox-nested-scroll-test--region "scroll"))
|
|
(outer (ebox-nested-scroll-test--region "root"))
|
|
(other (ebox-nested-scroll-test--region "sibling"))
|
|
(old-outer (ebox--scroll-get-state outer))
|
|
(old-producer (plist-get old-outer :render-content-prefix))
|
|
(count (length (plist-get old-outer :content-lines))))
|
|
(should old-producer)
|
|
(cl-letf (((symbol-function 'ebox-surface--render-candidate)
|
|
(lambda (&rest _) (ert-fail "Cached inner motion rendered root"))))
|
|
(should (= (ebox--surface-scroll-region-by (current-buffer) inner 1 1) 1)))
|
|
(should-not (eq old-producer (plist-get (ebox--scroll-get-state outer) :render-content-prefix)))
|
|
(let ((lines (plist-get (ebox--scroll-get-state inner) :content-lines)))
|
|
(cl-letf (((symbol-function 'ebox-surface--render-candidate)
|
|
(lambda (&rest _) (ert-fail "Independent inner motion rendered root"))))
|
|
(should (= (ebox--surface-scroll-region-by (current-buffer) other 1 1) 1)))
|
|
(should (eq lines (plist-get (ebox--scroll-get-state inner) :content-lines))))
|
|
(ebox-nested-scroll-test--parity)
|
|
(dotimes (_ 40)
|
|
(should (= (ebox--surface-scroll-region-by (current-buffer) outer 1 1) 1)))
|
|
(should (> (length (plist-get (ebox--scroll-get-state outer) :content-lines)) count))
|
|
(should (= (ebox--surface-scroll-region-by (current-buffer) outer -40 1) -40))
|
|
(ebox-nested-scroll-test--parity)
|
|
(ebox--scroll-state-materialize-lines outer (ebox--scroll-get-state outer))
|
|
(should (= (ebox--surface-scroll-region-by (current-buffer) outer 1 1) 1))
|
|
(should (= (ebox--surface-scroll-region-by (current-buffer) outer -1 1) -1))
|
|
(ebox-nested-scroll-test--parity)
|
|
(ebox-rerender-buffer-with-context (current-buffer) 120 40)
|
|
(ebox-nested-scroll-test--parity)
|
|
(should (= (plist-get (ebox--scroll-get-state inner) :scroll-offset) 1))
|
|
(should (= (plist-get (ebox--scroll-get-state other) :scroll-offset) 1))
|
|
(should (= (ebox--surface-scroll-region-by (current-buffer) inner -1 1) -1))
|
|
(ebox-nested-scroll-test--parity))))
|
|
|
|
(provide 'ebox-nested-scroll-tests)
|
|
;;; ebox-nested-scroll-tests.el ends here
|