[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/org d6117f895c 1/2: org-element-cache: Provide Elisp AP
|
From: |
ELPA Syncer |
|
Subject: |
[elpa] externals/org d6117f895c 1/2: org-element-cache: Provide Elisp API to store user data inside the cache |
|
Date: |
Thu, 4 Jan 2024 09:58:27 -0500 (EST) |
branch: externals/org
commit d6117f895c949577f29d523f0d415397f4697763
Author: Ihor Radchenko <yantar92@posteo.net>
Commit: Ihor Radchenko <yantar92@posteo.net>
org-element-cache: Provide Elisp API to store user data inside the cache
* lisp/org-element.el (org-element-cache-store-key):
(org-element-cache-get-key): New functions to store and retrieve data
associated with cached nodes. The data is stored inside
:fragile-cache and :robust-cache node properties.
(org-element--cache-shift-positions): Clear :fragile-cache when the
contents boundaries are changed. Optimize when OFFSET is 0.
* lisp/org-element.el (org-element--cache-process-request): Call
`org-element--cache-shift-positions' even for 0 offset to account for
:fragile-cache.
* etc/ORG-NEWS (New API functions to store data within
~org-element-cache~): Announce the new API.
* testing/lisp/test-org-element.el (test-org-element/cache-get-key):
New test.
---
etc/ORG-NEWS | 17 ++++++++
lisp/org-element.el | 94 +++++++++++++++++++++++++++++-----------
testing/lisp/test-org-element.el | 48 ++++++++++++++++++++
3 files changed, 133 insertions(+), 26 deletions(-)
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index a906d116f9..d49ec8b91f 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -778,6 +778,23 @@ Completion is enabled for links to man pages added using
~org-insert-link~:
library should be loaded first.
** New functions and changes in function arguments
+*** New API functions to store data within ~org-element-cache~
+
+Elisp programs can now store data inside Org element cache.
+
+The data will remain stored as long as the Org buffer text associated
+with the cached elements remains unchanged.
+
+Two options are available:
+ - Store the data until any text within element boundaries is changed
+ - Store the data, but ignore any changes inside element contents that
+ do not affect the high-level element structure. For example,
+ changes inside subheadings can be ignored for the data stored
+ inside parent heading element.
+
+The new functions are: ~org-element-cache-store-key~ and
+~org-element-cache-get-key~.
+
*** ~org-fold-hide-drawer-all~ is now interactive
~org-fold-hide-drawer-all~ is now a command, accepting two optional
diff --git a/lisp/org-element.el b/lisp/org-element.el
index e934c7844f..3758c26ef2 100644
--- a/lisp/org-element.el
+++ b/lisp/org-element.el
@@ -6304,7 +6304,8 @@ Properties are modified by side-effect."
;; Shift `:structure' property for the first plain list only: it
;; is the only one that really matters and it prevents from
;; shifting it more than once.
- (when (and (or (not props) (memq :structure props))
+ (when (and (not (zerop offset))
+ (or (not props) (memq :structure props))
(org-element-type-p element 'plain-list)
(not (org-element-type-p
;; Cached elements cannot have deferred `:parent'.
@@ -6314,25 +6315,28 @@ Properties are modified by side-effect."
(dolist (item structure)
(cl-incf (car item) offset)
(cl-incf (nth 6 item) offset))))
+ ;; Clear :fragile cache when contents is changed.
+ (when props (org-element-put-property element :fragile-cache nil))
;; Do not use loop for inline expansion to work during compile time.
- (when (or (not props) (memq :begin props))
- (cl-incf (org-element-begin element) offset))
- (when (or (not props) (memq :end props))
- (cl-incf (org-element-end element) offset))
- (when (or (not props) (memq :post-affiliated props))
- (cl-incf (org-element-post-affiliated element) offset))
- (when (and (or (not props) (memq :contents-begin props))
- (org-element-contents-begin element))
- (cl-incf (org-element-contents-begin element) offset))
- (when (and (or (not props) (memq :contents-end props))
- (org-element-contents-end element))
- (cl-incf (org-element-contents-end element) offset))
- (when (and (or (not props) (memq :robust-begin props))
- (org-element-property :robust-begin element))
- (cl-incf (org-element-property :robust-begin element) offset))
- (when (and (or (not props) (memq :robust-end props))
- (org-element-property :robust-end element))
- (cl-incf (org-element-property :robust-end element) offset)))
+ (unless (zerop offset)
+ (when (or (not props) (memq :begin props))
+ (cl-incf (org-element-begin element) offset))
+ (when (or (not props) (memq :end props))
+ (cl-incf (org-element-end element) offset))
+ (when (or (not props) (memq :post-affiliated props))
+ (cl-incf (org-element-post-affiliated element) offset))
+ (when (and (or (not props) (memq :contents-begin props))
+ (org-element-contents-begin element))
+ (cl-incf (org-element-contents-begin element) offset))
+ (when (and (or (not props) (memq :contents-end props))
+ (org-element-contents-end element))
+ (cl-incf (org-element-contents-end element) offset))
+ (when (and (or (not props) (memq :robust-begin props))
+ (org-element-property :robust-begin element))
+ (cl-incf (org-element-property :robust-begin element) offset))
+ (when (and (or (not props) (memq :robust-end props))
+ (org-element-property :robust-end element))
+ (cl-incf (org-element-property :robust-end element) offset))))
(defvar org-element--cache-interrupt-C-g t
"When non-nil, allow the user to abort `org-element--cache-sync'.
@@ -6714,13 +6718,12 @@ completing the request."
(setf (org-element--request-parent request) parent)
(throw 'org-element--cache-interrupt nil))
;; Shift element.
- (unless (zerop offset)
- (when (>= org-element--cache-diagnostics-level 3)
- (org-element--cache-log-message "Shifting positions (𝝙%S)
in %S::%S"
- offset
- (org-element-property
:org-element--cache-sync-key data)
-
(org-element--format-element data)))
- (org-element--cache-shift-positions data offset))
+ (when (>= org-element--cache-diagnostics-level 3)
+ (org-element--cache-log-message "Shifting positions (𝝙%S) in
%S::%S"
+ offset
+ (org-element-property
:org-element--cache-sync-key data)
+ (org-element--format-element
data)))
+ (org-element--cache-shift-positions data offset)
(let ((begin (org-element-begin data)))
;; Update PARENT and re-parent DATA, only when
;; necessary. Propagate new structures for lists.
@@ -7761,6 +7764,45 @@ the cache persistence in the buffer."
(add-hook 'clone-indirect-buffer-hook
#'org-element--cache-setup-change-functions)))))
+;;;###autoload
+(defun org-element-cache-store-key (epom key value &optional robust)
+ "Store KEY with VALUE associated with EPOM - point, marker, or element.
+The key can be retrieved as long as the element (provided or at point)
+contents is not modified.
+If optional argument ROBUST is non-nil, the key will be retained even
+when the contents (children) of current element are modified. Only
+non-robust element modifications (affecting the element properties
+other then begin/end boundaries) will invalidate the key then."
+ (let ((element (org-element-at-point epom))
+ (property (if robust :robust-cache :fragile-cache)))
+ (let ((key-store (org-element-property property element)))
+ (unless (hash-table-p key-store)
+ (setq key-store (make-hash-table :test #'equal))
+ (org-element-put-property element property key-store))
+ (puthash key value key-store))))
+
+;;;###autoload
+(defun org-element-cache-get-key (epom key &optional default)
+ "Get KEY associated with EPOM - point, marker, or element.
+Return DEFAULT when KEY is not associated with EPOM.
+The key can be retrieved as long as the element (provided or at point)
+contents is not modified."
+ (let ((element (org-element-at-point epom)))
+ (let ((key-store1 (org-element-property :fragile-cache element))
+ (key-store2 (org-element-property :robust-cache element)))
+ (let ((val1 (if (hash-table-p key-store1)
+ (gethash key key-store1 'not-found)
+ 'not-found))
+ (val2 (if (hash-table-p key-store2)
+ (gethash key key-store2 'not-found)
+ 'not-found)))
+ (cond
+ ((and (eq 'not-found val1)
+ (eq 'not-found val2))
+ default)
+ ((eq 'not-found val1) val2)
+ ((eq 'not-found val2) val1))))))
+
;;;###autoload
(defun org-element-cache-refresh (pos)
"Refresh cache at position POS."
diff --git a/testing/lisp/test-org-element.el b/testing/lisp/test-org-element.el
index a97d863c83..ca7d77e28b 100644
--- a/testing/lisp/test-org-element.el
+++ b/testing/lisp/test-org-element.el
@@ -5337,6 +5337,54 @@ modified by side effect, influencing the original
values."
org-element--cache-diagnostics-level))))
(should (memq var org-element-ignored-local-variables))))))
+(ert-deftest test-org-element/cache-get-key ()
+ "Test `org-element-cache-get-key' and `org-element-cache-store-key'."
+ (org-test-with-temp-text
+ "* Heading
+Paragraph
+with text <point>
+
+Another paragraph."
+ (org-element-cache-store-key
+ (org-element-lineage (org-element-at-point) '(headline))
+ :robust-key 'val-robust 'robust)
+ (org-element-cache-store-key
+ (org-element-lineage (org-element-at-point) '(headline))
+ :fragile-key 'val-fragile)
+ (insert "and more text.")
+ (should (eq 'val-robust
+ (org-element-cache-get-key
+ (org-element-lineage (org-element-at-point) '(headline))
+ :robust-key)))
+ (should (eq 'not-found
+ (org-element-cache-get-key
+ (org-element-lineage (org-element-at-point) '(headline))
+ :fragile-key 'not-found))))
+ ;; No length change in the altered.
+ (org-test-with-temp-text
+ "* Heading
+Paragraph
+<point>with text
+
+Another paragraph."
+ (org-element-cache-store-key
+ (org-element-lineage (org-element-at-point) '(headline))
+ :robust-key 'val-robust 'robust)
+ (org-element-cache-store-key
+ (org-element-lineage (org-element-at-point) '(headline))
+ :fragile-key 'val-fragile)
+ (search-forward "with")
+ (org-combine-change-calls (match-beginning 0) (match-end 0)
+ (replace-match "asdf"))
+ (should (eq 'val-robust
+ (org-element-cache-get-key
+ (org-element-lineage (org-element-at-point) '(headline))
+ :robust-key)))
+ (should (eq 'not-found
+ (org-element-cache-get-key
+ (org-element-lineage (org-element-at-point) '(headline))
+ :fragile-key 'not-found)))))
+
(provide 'test-org-element)
;;; test-org-element.el ends here