ebox/ebox-render-context.el

158 lines
7.0 KiB
EmacsLisp

;;; ebox-render-context.el --- Shared render context binding -*- lexical-binding: t; -*-
;;; Commentary:
;; Owns the compile-safe render-context binding shared by the incremental
;; planner and the buffer backend. Keeping this macro below both modules avoids
;; their runtime dependency cycle becoming an invalid byte-compiled function.
;;; Code:
(defvar ebox-viewport-width nil)
(defvar ebox-viewport-height nil)
(defvar ebox--render-runtime-revision nil)
(defvar ebox--surface-materialization-active nil)
(defvar ebox--render-cache-table nil)
(defvar ebox--render-cache-signature-cache nil)
(defvar ebox--viewport-dependent-node-ids-cache nil)
(defvar ebox--viewport-dependent-subtree-cache nil)
(defvar ebox--viewport-height-dependent-subtree-cache nil)
(defvar ebox--flex-content-min-width-table nil
"Render-owned box measurements reusable by native scene compilation.")
(defvar ebox--render-owned-text-values nil
"Candidate-local text-property values explicitly created by Ebox.")
(defvar ebox--render-output-provenance-table
(make-hash-table :test #'eq :weakness 'key)
"Weak map from rendered strings to Ebox-owned property values.")
(defun ebox--render-owned-text-values-for (property &optional create)
"Return the active candidate registry for PROPERTY when CREATE is non-nil."
(when (hash-table-p ebox--render-owned-text-values)
(or (gethash property ebox--render-owned-text-values)
(when create
(let ((values (make-hash-table :test #'eq :weakness 'key)))
(puthash property values ebox--render-owned-text-values)
values)))))
(defun ebox--register-render-owned-text-value (property value)
"Register Ebox-created VALUE for PROPERTY in the active render candidate."
(when value
(when-let ((values (ebox--render-owned-text-values-for property t)))
(puthash value t values)))
value)
(defun ebox--render-owned-text-value-p (property value &optional registry)
"Return non-nil when VALUE is Ebox-owned for PROPERTY.
REGISTRY defaults to the active render candidate."
(let ((ebox--render-owned-text-values
(or registry ebox--render-owned-text-values)))
(when-let ((values (ebox--render-owned-text-values-for property)))
(gethash value values))))
(defun ebox--register-render-owned-face-values (source rendered)
"Register Ebox-generated face identities added to RENDERED from SOURCE."
(when (and (stringp source)
(stringp rendered)
(= (length source) (length rendered))
(hash-table-p ebox--render-owned-text-values))
(let ((position 0)
(length (length rendered)))
(while (< position length)
(let ((next
(min (or (next-property-change position source) length)
(or (next-property-change position rendered) length)))
(source-face (get-text-property position 'face source))
(rendered-face (get-text-property position 'face rendered)))
(when (and rendered-face (null source-face))
(ebox--register-render-owned-text-value 'face rendered-face))
(setq position next)))))
rendered)
(defun ebox--record-render-output-provenance (rendered)
"Record owned property identities actually present in RENDERED."
(when (and (stringp rendered)
(hash-table-p ebox--render-owned-text-values))
(let ((provenance (make-hash-table :test #'eq))
(position 0)
(length (length rendered)))
(remhash rendered ebox--render-output-provenance-table)
(while (< position length)
(let ((next (or (next-property-change position rendered) length))
(properties (text-properties-at position rendered)))
(while properties
(let* ((property (pop properties))
(value (pop properties))
(owned (ebox--render-owned-text-value-p property value)))
(when owned
(let ((values (or (gethash property provenance)
(let ((new (make-hash-table
:test #'eq :weakness 'key)))
(puthash property new provenance)
new))))
(puthash value t values)))))
(setq position next)))
(when (> (hash-table-count provenance) 0)
(puthash rendered provenance ebox--render-output-provenance-table))))
rendered)
(defun ebox--replay-render-output-provenance (rendered)
"Replay owned property identities recorded for RENDERED into this candidate."
(when (and (stringp rendered)
(hash-table-p ebox--render-owned-text-values))
(when-let ((provenance
(gethash rendered ebox--render-output-provenance-table)))
(maphash
(lambda (property values)
(let ((owned (ebox--render-owned-text-values-for property t)))
(maphash (lambda (value _marker)
(puthash value t owned))
values)))
provenance)))
rendered)
(declare-function ebox--buffer-render-state
"ebox-incremental" (buffer))
(defmacro ebox--with-buffer-render-context (buffer &rest body)
"Evaluate BODY using BUFFER's stored render context."
(declare (indent 1) (debug t))
(let ((target-buffer (make-symbol "target-buffer"))
(render-state (make-symbol "render-state")))
`(let* ((,target-buffer ,buffer)
(,render-state
(ebox--buffer-render-state ,target-buffer)))
(with-current-buffer ,target-buffer
(let* ((ebox-viewport-width
(plist-get ,render-state :viewport-width))
(ebox-viewport-height
(plist-get ,render-state :viewport-height))
(ebox--render-runtime-revision
(plist-get ,render-state :runtime-revision))
(ebox--surface-materialization-active t)
(ebox--render-cache-table
(plist-get ,render-state :render-cache))
(ebox--render-cache-signature-cache
(or ebox--render-cache-signature-cache
(plist-get ,render-state :render-signature-cache)
(make-hash-table :test 'eq)))
(ebox--viewport-dependent-node-ids-cache
(or ebox--viewport-dependent-node-ids-cache
(make-hash-table :test 'eq)))
(ebox--viewport-dependent-subtree-cache
(or ebox--viewport-dependent-subtree-cache
(make-hash-table :test 'eq)))
(ebox--viewport-height-dependent-subtree-cache
(or ebox--viewport-height-dependent-subtree-cache
(plist-get
,render-state
:viewport-height-dependent-subtree-cache)
(make-hash-table :test 'eq)))
(ebox--flex-content-min-width-table
(or ebox--flex-content-min-width-table
(plist-get ,render-state :flex-content-min-widths))))
,@body)))))
(provide 'ebox-render-context)
;;; ebox-render-context.el ends here