| 
					
				 | 
			
			
				@@ -0,0 +1,262 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+;;; org-persist.el --- Persist data across Emacs sessions         -*- lexical-binding: t; -*- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+;; Copyright (C) 2021-2021 Free Software Foundation, Inc. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+;; Author: Ihor Radchenko <yantar92 at gmail dot com> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+;; Keywords: cache, storage 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+;; This file is part of GNU Emacs. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+;; GNU Emacs is free software: you can redistribute it and/or modify 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+;; it under the terms of the GNU General Public License as published by 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+;; the Free Software Foundation, either version 3 of the License, or 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+;; (at your option) any later version. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+;; GNU Emacs is distributed in the hope that it will be useful, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+;; but WITHOUT ANY WARRANTY; without even the implied warranty of 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+;; GNU General Public License for more details. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+;; You should have received a copy of the GNU General Public License 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+;;; Commentary: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+;; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+;; This file implements persistant data storage across Emacs sessions. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+;; Both global and buffer-local data can be stored. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+;;; Code: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(require 'org-compat) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(require 'org-id) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(declare-function org-back-to-heading "org" (&optional invisible-ok)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(declare-function org-next-visible-heading "org" (arg)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(declare-function org-at-heading-p "org" (&optional invisible-not-ok)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(defvar org-persist-path (org-file-name-concat user-emacs-directory "org-persist/") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  "Directory where the data is stored.") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(defvar org-persist-index-file "index" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  "File name used to store the data index.") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(defvar org-persist-before-write-hook nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  "Abnormal hook ran before saving data for a single variable in a buffer. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+The hook must accept the same arguments as `org-persist-write'. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+The hooks will be evaluated until a hook returns non-nil. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+If any of the hooks return non-nil, do not save the data.") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(defvar org-persist-before-read-hook nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  "Abnormal hook ran before reading data for a single variable in a buffer. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+The hook must accept the same arguments as `org-persist-read'. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+The hooks will be evaluated until a hook returns non-nil. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+If any of the hooks return non-nil, do not read the data.") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(defvar org-persist-after-read-hook nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  "Abnormal hook ran after reading data for a single variable in a buffer. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+The hook must accept the same arguments as `org-persist-read'.") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(defvar org-persist--index nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  "Global index. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+The index is a list of plists.  Each plist contains information about 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+a data variable.  Each plist contains the following properties: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  - `:variable'    list of variables to be stored in single file 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  - `:persist-file': data file name 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  - `:path':       buffer file path, if any 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  - `:inode':      buffer file inode, if any 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  - `:hash':       buffer hash, if any") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(defun org-persist--get-index (var &optional buffer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  "Return plist used to store VAR in BUFFER. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+When BUFFER is nil, return plist for global VAR." 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (let* ((buffer-file (when buffer (buffer-file-name (or (buffer-base-buffer buffer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                         buffer)))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         (inode (when buffer-file (file-attribute-inode-number (file-attributes buffer-file))))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    (let ((result (seq-find (lambda (plist) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                              (and (or (memq var (plist-get plist :variable)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                       (eq var (plist-get plist :variable))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                   (or (equal inode (plist-get plist :inode)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                       (equal buffer-file (plist-get plist :path))))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            org-persist--index))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      (when result 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (unless (equal buffer-file (plist-get result :path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          (setf result (plist-put result :path buffer-file)))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      (unless result 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (push (list :variable (if (listp var) var (list var)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :persist-file (replace-regexp-in-string "^.." "\\&/" (org-id-uuid)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :path buffer-file 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :inode inode 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :hash (when buffer (secure-hash 'md5 buffer))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              org-persist--index) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (setf result (car org-persist--index))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      result))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(defun org-persist--read-index () 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  "Read `org-persist--index'" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (unless org-persist--index 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    (when (file-exists-p (org-file-name-concat org-persist-path org-persist-index-file)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      (with-temp-buffer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (insert-file-contents (org-file-name-concat org-persist-path org-persist-index-file)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (setq org-persist--index (read (current-buffer))))))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(cl-defun org-persist-register (var &optional buffer &key inherit) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  "Register VAR in BUFFER to be persistent. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+Optional key INHERIT make VAR dependent on another variable.  Such 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+dependency means that data shared between variables will be preserved 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(see elisp#Circular Objects)." 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (unless org-persist--index (org-persist--read-index)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (when inherit 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    (let ((inherited-index (org-persist--get-index inherit buffer))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      (unless (memq var (plist-get inherited-index :variable)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (push var (plist-get inherited-index :variable))))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (org-persist--get-index var buffer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (when buffer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    (add-hook 'kill-buffer-hook #'org-persist-write-all-buffer 1000 'local))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(defun org-persist-unregister (var &optional buffer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  "Unregister VAR in BUFFER to be persistent. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+When BUFFER is `all', unregister VAR in all buffers." 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (unless org-persist--index (org-persist--read-index)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (setq org-persist--index 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (seq-remove 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         (lambda (plist) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+           (when (and (memq var (plist-get plist :variable)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      (or (eq buffer 'all) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          (eq (buffer-file-name 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                               (or (buffer-base-buffer buffer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                   buffer)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                              (plist-get plist :path)))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             (if (length> (plist-get plist :variable) 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                 (progn 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   (setq plist 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                         (plist-put plist :variable 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                    (delq var (plist-get plist :variable)))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   ;; Do not remove the index though. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   nil) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               (let ((persist-file (org-file-name-concat org-persist-path (plist-get plist :persist-file)))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                 (delete-file persist-file) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                 (when (directory-empty-p (file-name-directory persist-file)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   (delete-directory (file-name-directory persist-file)))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               'delete-from-index))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         org-persist--index)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (org-persist-gc)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(defun org-persist-write (var &optional buffer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  "Save buffer-local data in BUFFER for VAR." 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (unless (and buffer (not (get-buffer buffer))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    (unless (listp var) (setq var (list var))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    (with-current-buffer (or buffer (current-buffer)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      (let ((index (org-persist--get-index var buffer))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (setf index (plist-put index :hash (when buffer (secure-hash 'md5 buffer)))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (let ((print-circle t) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              print-level 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              print-length 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              print-quoted 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              (print-escape-control-characters t) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              (print-escape-nonascii t) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              (print-continuous-numbering t) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              print-number-table) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          (unless (seq-find (lambda (v) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                              (run-hook-with-args-until-success 'org-persist-before-write-hook v buffer)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            (plist-get index :variable)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            (unless (file-exists-p org-persist-path) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              (make-directory org-persist-path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            (with-temp-file (org-file-name-concat org-persist-path org-persist-index-file) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              (prin1 org-persist--index (current-buffer))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            (let ((file (org-file-name-concat org-persist-path (plist-get index :persist-file))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  (data (mapcar (lambda (s) (cons s (symbol-value s))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                (plist-get index :variable)))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              (unless (file-exists-p (file-name-directory file)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                (make-directory (file-name-directory file) t)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              (with-temp-file file 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                (prin1 data (current-buffer)))))))))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(defun org-persist-write-all (&optional buffer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  "Save all the persistent data." 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (dolist (index org-persist--index) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    (when (or (not (plist-get index :path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              (and (get-file-buffer (plist-get index :path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   (or (not buffer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                       (equal (buffer-file-name (or (buffer-base-buffer buffer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                    buffer)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                              (plist-get index :path))))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      (org-persist-write (plist-get index :variable) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              (when (plist-get index :path) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                (get-file-buffer (plist-get index :path))))))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(defun org-persist-write-all-buffer () 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  "Call `org-persist-write-all' in current buffer." 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (org-persist-write-all (current-buffer))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(defun org-persist-read (var &optional buffer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  "Restore VAR data in BUFFER." 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (let* ((index (org-persist--get-index var buffer)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         (persist-file (org-file-name-concat org-persist-path (plist-get index :persist-file))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         (data nil)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    (when (and (file-exists-p persist-file) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               (or (not buffer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   (equal (secure-hash 'md5 buffer) (plist-get index :hash)))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      (unless (seq-find (lambda (v) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          (run-hook-with-args-until-success 'org-persist-before-read-hook v buffer)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        (plist-get index :variable)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (with-temp-buffer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          (let ((coding-system-for-read 'utf-8) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                (read-circle t)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            (insert-file-contents persist-file)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          ;; FIXME: Reading sometimes fails to read circular objects. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          ;; I suspect that it happens when we have object reference 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          ;; #N# read before object definition #N=.  If it is really 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          ;; #so, it should be Emacs bug - either in `read' or in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          ;; #`prin1'.  Meanwhile, just fail silently when `read' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          ;; #fails to parse the saved cache object. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          (condition-case err 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              (setq data (read (current-buffer))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            (error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             (warn "Emacs reader failed to read data for %S:%S. The error was: %S" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   (or buffer "global") var (error-message-string err)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             (setq data nil)))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (with-current-buffer (or buffer (current-buffer)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          (cl-loop for var1 in (plist-get index :variable) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   do 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   (when (alist-get var1 data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                     (setf (symbol-value var1) (alist-get var1 data))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   (run-hook-with-args 'org-persist-after-read-hook var1 buffer))))))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(defun org-persist-read-all (&optional buffer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  "Restore all the persistent data in BUFFER." 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (unless org-persist--index (org-persist--read-index)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (dolist (index org-persist--index) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    (when (equal (buffer-file-name (or (buffer-base-buffer buffer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                       buffer)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                 (plist-get index :path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      (org-persist-read (plist-get index :variable) buffer)))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(defun org-persist-read-all-buffer () 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  "Call `org-persist-read-all' in current buffer." 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (org-persist-read-all (current-buffer))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(defun org-persist-gc () 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  "Remove stored data for not existing files or unregistered variables." 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  (let (new-index) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    (dolist (index org-persist--index) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      (when-let ((file (plist-get index :path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                 (persist-file (org-file-name-concat 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                org-persist-path 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                (plist-get index :persist-file)))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (if (file-exists-p file) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            (push index new-index) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          (when (file-exists-p persist-file) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            (delete-file persist-file) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            (when (directory-empty-p (file-name-directory persist-file)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              (delete-directory (file-name-directory persist-file))))))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    (setq org-persist--index (nreverse new-index)))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(add-hook 'kill-emacs-hook #'org-persist-gc) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(add-hook 'kill-emacs-hook #'org-persist-write-all 1000) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(add-hook 'after-init-hook #'org-persist-read-all) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+(provide 'org-persist) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+;;; org-persist.el ends here 
			 |