emacs-elpa-diffs
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]