Optimize reactive text property updates: only update relevant buffers
1. When using setq-local, only update the current buffer 2. When using setq, update all buffers that have the text property Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
This commit is contained in:
parent
a32abe5101
commit
08e7dfc728
64
tp-tests.el
64
tp-tests.el
@ -2680,5 +2680,69 @@ Returns list of (START END VALUE) intervals."
|
|||||||
(ignore-errors (makunbound 'tp-test-init-name))
|
(ignore-errors (makunbound 'tp-test-init-name))
|
||||||
(ignore-errors (makunbound 'tp-test-init-other)))))
|
(ignore-errors (makunbound 'tp-test-init-other)))))
|
||||||
|
|
||||||
|
(ert-deftest tp-test-setq-local-only-updates-current-buffer ()
|
||||||
|
"Test that setq-local only updates text properties in the current buffer."
|
||||||
|
(let ((buf1 nil)
|
||||||
|
(buf2 nil))
|
||||||
|
(unwind-protect
|
||||||
|
(progn
|
||||||
|
;; Define a reactive layer
|
||||||
|
(tp-define-layer test-multi-buf-layer
|
||||||
|
:props (face (:foreground $tp-test-multi-color)))
|
||||||
|
;; Create first buffer with layer applied
|
||||||
|
(setq buf1 (generate-new-buffer " *test-buf1*"))
|
||||||
|
(with-current-buffer buf1
|
||||||
|
(insert "Hello World")
|
||||||
|
(tp-set 1 6 'test-multi-buf-layer))
|
||||||
|
;; Create second buffer with layer applied
|
||||||
|
(setq buf2 (generate-new-buffer " *test-buf2*"))
|
||||||
|
(with-current-buffer buf2
|
||||||
|
(insert "Hello World")
|
||||||
|
(tp-set 1 6 'test-multi-buf-layer))
|
||||||
|
;; Use setq-local in buf1
|
||||||
|
(with-current-buffer buf1
|
||||||
|
(setq-local tp-test-multi-color "red"))
|
||||||
|
;; buf1 should be updated
|
||||||
|
(with-current-buffer buf1
|
||||||
|
(should (equal (plist-get (get-text-property 1 'face) :foreground) "red")))
|
||||||
|
;; buf2 should NOT be updated (still nil)
|
||||||
|
(with-current-buffer buf2
|
||||||
|
(should (equal (plist-get (get-text-property 1 'face) :foreground) nil))))
|
||||||
|
;; Cleanup
|
||||||
|
(when (buffer-live-p buf1) (kill-buffer buf1))
|
||||||
|
(when (buffer-live-p buf2) (kill-buffer buf2))
|
||||||
|
(ignore-errors (makunbound 'tp-test-multi-color)))))
|
||||||
|
|
||||||
|
(ert-deftest tp-test-setq-updates-all-buffers-with-property ()
|
||||||
|
"Test that setq updates text properties in all buffers that have the property."
|
||||||
|
(let ((buf1 nil)
|
||||||
|
(buf2 nil))
|
||||||
|
(unwind-protect
|
||||||
|
(progn
|
||||||
|
;; Define a reactive layer
|
||||||
|
(tp-define-layer test-global-layer
|
||||||
|
:props (face (:foreground $tp-test-global-color)))
|
||||||
|
;; Create first buffer with layer applied
|
||||||
|
(setq buf1 (generate-new-buffer " *test-buf1*"))
|
||||||
|
(with-current-buffer buf1
|
||||||
|
(insert "Hello World")
|
||||||
|
(tp-set 1 6 'test-global-layer))
|
||||||
|
;; Create second buffer with layer applied
|
||||||
|
(setq buf2 (generate-new-buffer " *test-buf2*"))
|
||||||
|
(with-current-buffer buf2
|
||||||
|
(insert "Hello World")
|
||||||
|
(tp-set 1 6 'test-global-layer))
|
||||||
|
;; Use global setq
|
||||||
|
(setq tp-test-global-color "blue")
|
||||||
|
;; Both buffers should be updated
|
||||||
|
(with-current-buffer buf1
|
||||||
|
(should (equal (plist-get (get-text-property 1 'face) :foreground) "blue")))
|
||||||
|
(with-current-buffer buf2
|
||||||
|
(should (equal (plist-get (get-text-property 1 'face) :foreground) "blue"))))
|
||||||
|
;; Cleanup
|
||||||
|
(when (buffer-live-p buf1) (kill-buffer buf1))
|
||||||
|
(when (buffer-live-p buf2) (kill-buffer buf2))
|
||||||
|
(ignore-errors (makunbound 'tp-test-global-color)))))
|
||||||
|
|
||||||
(provide 'tp-ert-tests)
|
(provide 'tp-ert-tests)
|
||||||
;;; tp-ert-tests.el ends here
|
;;; tp-ert-tests.el ends here
|
||||||
|
|||||||
34
tp.el
34
tp.el
@ -206,11 +206,14 @@ Only the reactive portions of the properties are stored for each variable."
|
|||||||
(tp--unregister-layer-computed layer-name)
|
(tp--unregister-layer-computed layer-name)
|
||||||
(tp--unregister-layer-data layer-name))
|
(tp--unregister-layer-data layer-name))
|
||||||
|
|
||||||
(defun tp--reactive-variable-watcher (symbol newval operation _where)
|
(defun tp--reactive-variable-watcher (symbol newval operation where)
|
||||||
"Watcher function called when a reactive variable changes.
|
"Watcher function called when a reactive variable changes.
|
||||||
SYMBOL is the variable that changed.
|
SYMBOL is the variable that changed.
|
||||||
NEWVAL is the new value being set.
|
NEWVAL is the new value being set.
|
||||||
OPERATION is the type of operation (set, let, unlet, makunbound, defvaralias).
|
OPERATION is the type of operation (set, let, unlet, makunbound, defvaralias).
|
||||||
|
WHERE indicates where the variable was set:
|
||||||
|
- nil for global `setq' or `set'
|
||||||
|
- a buffer for `setq-local'
|
||||||
Updates all layers that depend on this variable.
|
Updates all layers that depend on this variable.
|
||||||
|
|
||||||
Only 'set' operations trigger updates because:
|
Only 'set' operations trigger updates because:
|
||||||
@ -243,8 +246,10 @@ Only 'set' operations trigger updates because:
|
|||||||
(cl-loop for (key val) on resolved-props by #'cddr
|
(cl-loop for (key val) on resolved-props by #'cddr
|
||||||
do (setq current-props (plist-put current-props key val)))
|
do (setq current-props (plist-put current-props key val)))
|
||||||
(tp--set-layer-props layer-name current-props))))))
|
(tp--set-layer-props layer-name current-props))))))
|
||||||
;; Update all text regions with this layer
|
;; Update text regions with this layer
|
||||||
(tp--update-layer-regions layer-name))))))
|
;; If WHERE is a buffer (setq-local), only update that buffer
|
||||||
|
;; If WHERE is nil (setq), update all buffers that have the text property
|
||||||
|
(tp--update-layer-regions layer-name where))))))
|
||||||
|
|
||||||
(defun tp--invoke-layer-watchers (layer-name symbol newval oldval)
|
(defun tp--invoke-layer-watchers (layer-name symbol newval oldval)
|
||||||
"Invoke all registered watcher callbacks for LAYER-NAME watching SYMBOL.
|
"Invoke all registered watcher callbacks for LAYER-NAME watching SYMBOL.
|
||||||
@ -401,12 +406,25 @@ If a variable is not bound, define it with the initial value (nil if not specifi
|
|||||||
(unless (boundp var-sym)
|
(unless (boundp var-sym)
|
||||||
(set var-sym initial-val)))))
|
(set var-sym initial-val)))))
|
||||||
|
|
||||||
(defun tp--update-layer-regions (layer-name)
|
(defun tp--update-layer-regions (layer-name &optional where)
|
||||||
"Update all text regions that have LAYER-NAME applied.
|
"Update text regions that have LAYER-NAME applied.
|
||||||
Re-applies the layer properties using tp-search-map and tp-add."
|
Re-applies the layer properties using tp-search-map and tp-add.
|
||||||
|
|
||||||
|
WHERE specifies which buffers to update:
|
||||||
|
- If WHERE is a buffer, only update that buffer (setq-local case).
|
||||||
|
- If WHERE is nil, update all buffers that have the text property (setq case)."
|
||||||
(let ((props (tp-layer-props layer-name)))
|
(let ((props (tp-layer-props layer-name)))
|
||||||
(when props
|
(when props
|
||||||
;; Update in all buffers
|
(if (and where (bufferp where) (buffer-live-p where))
|
||||||
|
;; setq-local case: only update the specific buffer
|
||||||
|
(with-current-buffer where
|
||||||
|
(save-excursion
|
||||||
|
(tp-search-map
|
||||||
|
(lambda (_text start end)
|
||||||
|
(tp-add start end props)
|
||||||
|
nil)
|
||||||
|
'tp-name layer-name)))
|
||||||
|
;; setq case: update all buffers that have the text property
|
||||||
(dolist (buf (buffer-list))
|
(dolist (buf (buffer-list))
|
||||||
(when (buffer-live-p buf)
|
(when (buffer-live-p buf)
|
||||||
(with-current-buffer buf
|
(with-current-buffer buf
|
||||||
@ -419,7 +437,7 @@ Re-applies the layer properties using tp-search-map and tp-add."
|
|||||||
(tp-add start end props)
|
(tp-add start end props)
|
||||||
;; Return nil to skip text replacement
|
;; Return nil to skip text replacement
|
||||||
nil)
|
nil)
|
||||||
'tp-name layer-name))))))))
|
'tp-name layer-name)))))))))
|
||||||
|
|
||||||
(defun tp-reactive-reset ()
|
(defun tp-reactive-reset ()
|
||||||
"Reset all reactive text property watchers and dependencies."
|
"Reset all reactive text property watchers and dependencies."
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user