From e18022b7abd11e6474bf29d2875b2afdc32b0f02 Mon Sep 17 00:00:00 2001 From: Andreas Gerler Date: Sun, 22 Dec 2024 13:47:56 +0100 Subject: [PATCH] add persist Signed-off-by: Andreas Gerler --- elpa/persist-0.6.1.signed | 1 + elpa/persist-0.6.1/.elpaignore | 3 + elpa/persist-0.6.1/persist-autoloads.el | 28 +++ elpa/persist-0.6.1/persist-pkg.el | 2 + elpa/persist-0.6.1/persist.el | 249 +++++++++++++++++++++++ elpa/persist-0.6.1/persist.texi | 153 ++++++++++++++ elpa/persist-0.6.1/test/persist-tests.el | 146 +++++++++++++ 7 files changed, 582 insertions(+) create mode 100644 elpa/persist-0.6.1.signed create mode 100644 elpa/persist-0.6.1/.elpaignore create mode 100644 elpa/persist-0.6.1/persist-autoloads.el create mode 100644 elpa/persist-0.6.1/persist-pkg.el create mode 100644 elpa/persist-0.6.1/persist.el create mode 100644 elpa/persist-0.6.1/persist.texi create mode 100644 elpa/persist-0.6.1/test/persist-tests.el diff --git a/elpa/persist-0.6.1.signed b/elpa/persist-0.6.1.signed new file mode 100644 index 00000000..23cbb054 --- /dev/null +++ b/elpa/persist-0.6.1.signed @@ -0,0 +1 @@ +Good signature from 645357D2883A0966 GNU ELPA Signing Agent (2023) (trust undefined) created at 2024-06-15T23:10:02+0200 using EDDSA \ No newline at end of file diff --git a/elpa/persist-0.6.1/.elpaignore b/elpa/persist-0.6.1/.elpaignore new file mode 100644 index 00000000..dfdac464 --- /dev/null +++ b/elpa/persist-0.6.1/.elpaignore @@ -0,0 +1,3 @@ +Makefile +Cask +.gitignore \ No newline at end of file diff --git a/elpa/persist-0.6.1/persist-autoloads.el b/elpa/persist-0.6.1/persist-autoloads.el new file mode 100644 index 00000000..e6211720 --- /dev/null +++ b/elpa/persist-0.6.1/persist-autoloads.el @@ -0,0 +1,28 @@ +;;; persist-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*- +;; Generated by the `loaddefs-generate' function. + +;; This file is part of GNU Emacs. + +;;; Code: + +(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path))) + + + +;;; Generated autoloads from persist.el + +(register-definition-prefixes "persist" '("persist-")) + +;;; End of scraped data + +(provide 'persist-autoloads) + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; no-native-compile: t +;; coding: utf-8-emacs-unix +;; End: + +;;; persist-autoloads.el ends here diff --git a/elpa/persist-0.6.1/persist-pkg.el b/elpa/persist-0.6.1/persist-pkg.el new file mode 100644 index 00000000..8b6e40fd --- /dev/null +++ b/elpa/persist-0.6.1/persist-pkg.el @@ -0,0 +1,2 @@ +;; Generated package description from persist.el -*- no-byte-compile: t -*- +(define-package "persist" "0.6.1" "Persist Variables between Emacs Sessions" '((emacs "26.1")) :commit "5ea8f32ef50ce2b444d6918e17eedce9f74629af" :url "https://elpa.gnu.org/packages/persist.html" :authors '(("Phillip Lord" . "phillip.lord@russet.org.uk")) :maintainer '("Joseph Turner" . "persist-el@breatheoutbreathe.in")) diff --git a/elpa/persist-0.6.1/persist.el b/elpa/persist-0.6.1/persist.el new file mode 100644 index 00000000..49b3e9b5 --- /dev/null +++ b/elpa/persist-0.6.1/persist.el @@ -0,0 +1,249 @@ +;;; persist.el --- Persist Variables between Emacs Sessions -*- lexical-binding: t -*- + +;; Copyright (C) 2019, 2024 Free Software Foundation, Inc. + +;; Author: Phillip Lord +;; Maintainer: Joseph Turner +;; Package-Type: multi +;; Package-Requires: ((emacs "26.1")) +;; Version: 0.6.1 + +;; The contents of this file are subject to the GPL License, Version 3.0. + +;; This file is not part of Emacs + +;; This program 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. + +;; This program 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 this program. If not, see . + +;;; Commentary: + +;; This package provides variables which persist across sessions. + +;; The main entry point is `persist-defvar' which behaves like +;; `defvar' but which persists the variables between session. Variables +;; are automatically saved when Emacs exits. + +;; Other useful functions are `persist-save' which saves the variable +;; immediately, `persist-load' which loads the saved value, +;; `persist-reset' which resets to the default value. + +;; Values are stored in a directory in `user-emacs-directory', using +;; one file per value. This makes it easy to delete or remove unused +;; variables. + +;;; Code: + +(defvar persist--directory-location + (locate-user-emacs-file "persist") + "The location of persist directory.") + +(defvar persist--symbols nil + "List of symbols to persist.") + +(defvar persist-load-hook nil + "Special hook run on loading a variable. + +Hook functions are called with two values: the symbol and the +value it will be set to. If any function returns nil, the +variable is not set to the value.") + +(defun persist--file-location (symbol) + "Return the file name at which SYMBOL does or will persist." + (expand-file-name + (symbol-name symbol) + (or (get symbol 'persist-location) + persist--directory-location))) + +(defun persist--defvar-1 (symbol location) + "Set symbol up for persistence." + (when location + (persist-location symbol location)) + (persist-symbol symbol (symbol-value symbol)) + (persist-load symbol)) + +(defmacro persist-defvar (symbol initvalue docstring &optional location) + "Define SYMBOL as a persistent variable and return SYMBOL. + +This form is nearly equivalent to `defvar', except that the +variable persists between Emacs sessions. + +It does not support the optional parameters. Both INITVALUE and +DOCSTRING need to be given." + ;; We cannot distinguish between calls with initvalue of nil and a + ;; single parameter call. Unfortunately, these two calls have + ;; different semantics -- the single arity shuts up the byte + ;; compiler, but does not define the symbol. So, don't support a + ;; single arity persist-defvar. + + ;; Don't support 2-arity calls either because we are lazy and + ;; because if you want to persist it, you want to doc it. + (declare (debug (symbolp form stringp &optional form)) + (doc-string 3) + (indent defun)) + ;; Define inside progn so the byte compiler sees defvar + `(progn + (defvar ,symbol ,initvalue ,docstring) + ;; Access initvalue through its symbol because the defvar form + ;; has to stay at first level within a progn + (persist--defvar-1 ',symbol ,location) + ',symbol)) + +(defun persist-location (symbol directory) + "Set the directory for persisting the value of symbol. + +This does not force the loading of value from this directory, so +to persist a variable, you will normally need to call +`persist-load' to load a previously saved location." + (put symbol 'persist-location (expand-file-name directory))) + +(defun persist-symbol (symbol &optional initvalue) + "Make SYMBOL a persistent variable. + +If non-nil, INITVALUE is the value to which SYMBOL will be set if +`persist-reset' is called. Otherwise, the INITVALUE will be the +current `symbol-value' of SYMBOL. + +INITVALUE is set for the session and will itself not persist +across sessions. + +This does force the loading of value from this directory, so to +persist a variable, you will normally need to call `persist-load' +to load a previously saved location." + (let ((initvalue (or initvalue (symbol-value symbol)))) + (add-to-list 'persist--symbols symbol) + (put symbol 'persist t) + (put symbol 'persist-default (persist-copy initvalue)))) + +(defun persist--persistant-p (symbol) + "Return non-nil if SYMBOL is a persistent variable." + (get symbol 'persist)) + +(defun persist-save (symbol) + "Save SYMBOL now. + +Normally, it should not be necessary to call this explicitly, as +variables persist automatically when Emacs exits." + (unless (persist--persistant-p symbol) + (error (format + "Symbol %s is not persistent" symbol))) + (let ((symbol-file-loc (persist--file-location symbol))) + (if (persist-equal (symbol-value symbol) + (persist-default symbol)) + (when (file-exists-p symbol-file-loc) + (delete-file symbol-file-loc)) + (let ((dir-loc + (file-name-directory symbol-file-loc))) + (unless (file-exists-p dir-loc) + (mkdir dir-loc)) + (with-temp-buffer + (let (print-level + print-length + print-quoted + (print-escape-control-characters t) + (print-escape-nonascii t) + (print-circle t)) + (print (symbol-value symbol) (current-buffer))) + (write-region (point-min) (point-max) + symbol-file-loc + nil 'quiet)))))) + +(defun persist-default (symbol) + "Return the default value for SYMBOL." + (get symbol 'persist-default)) + +(defun persist-reset (symbol) + "Set the value of SYMBOL to a copy of the default." + (set symbol (persist-copy (persist-default symbol)))) + +(defun persist-load (symbol) + "Load the saved value of SYMBOL." + (when (file-exists-p (persist--file-location symbol)) + (with-temp-buffer + (insert-file-contents (persist--file-location symbol)) + (let ((val (read (current-buffer)))) + (when (run-hook-with-args-until-failure 'persist-load-hook + symbol val) + (set symbol val)))))) + +(defun persist-unpersist (symbol) + "Stop the value in SYMBOL from persisting. + +This does not remove any saved value of SYMBOL." + (put symbol 'persist nil) + (setq persist--symbols + (remove symbol persist--symbols))) + +(defun persist--save-all () + "Save all persistent symbols." + (mapc 'persist-save persist--symbols)) + +;; Save on kill-emacs-hook anyway +(add-hook 'kill-emacs-hook + 'persist--save-all) + +(defun persist-equal (a b) + "Return non-nil when the values of A and B are equal. +A and B are compared using `equal' unless they are both hash +tables. In that case, the following are compared: + +- hash table count +- hash table predicate +- values, using `persist-equal'" + (if (and (hash-table-p a) (hash-table-p b)) + (and (= (hash-table-count a) (hash-table-count b)) + (eq (hash-table-test a) (hash-table-test b)) + (catch 'done + (maphash + (lambda (key a-value) + (unless (persist-equal a-value (gethash key b (not a-value))) + (throw 'done nil))) + a) + t)) + (equal a b))) + +(defun persist-copy-tree (tree &optional vectors-and-records) + "Make a copy of TREE. +If TREE is a cons cell, this recursively copies both its car and its cdr. +Contrast to `copy-sequence', which copies only along the cdrs. +With the second argument VECTORS-AND-RECORDS non-nil, this +traverses and copies vectors and records as well as conses." + (declare (side-effect-free error-free)) + (if (consp tree) + (let (result) + (while (consp tree) + (let ((newcar (car tree))) + (if (or (consp (car tree)) + (and vectors-and-records + (or (vectorp (car tree)) (recordp (car tree))))) + (setq newcar (persist-copy-tree (car tree) vectors-and-records))) + (push newcar result)) + (setq tree (cdr tree))) + (nconc (nreverse result) + (if (and vectors-and-records (or (vectorp tree) (recordp tree))) + (persist-copy-tree tree vectors-and-records) + tree))) + (if (and vectors-and-records (or (vectorp tree) (recordp tree))) + (let ((i (length (setq tree (copy-sequence tree))))) + (while (>= (setq i (1- i)) 0) + (aset tree i (persist-copy-tree (aref tree i) vectors-and-records))) + tree) + tree))) + +(defun persist-copy (obj) + "Return copy of OBJ." + (if (hash-table-p obj) + (copy-hash-table obj) + (persist-copy-tree obj t))) + +(provide 'persist) +;;; persist.el ends here diff --git a/elpa/persist-0.6.1/persist.texi b/elpa/persist-0.6.1/persist.texi new file mode 100644 index 00000000..99f61a25 --- /dev/null +++ b/elpa/persist-0.6.1/persist.texi @@ -0,0 +1,153 @@ +\input texinfo +@setfilename persist.info +@settitle persist persistent variables + +@dircategory Emacs +@direntry +* Persist: (persist). Persistent variables for Emacs. +@end direntry + +@copying +Copyright @copyright{} 2019 Phillip Lord + +@quotation +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.2 or +any later version published by the Free Software Foundation; with no +Invariant Sections, with the Front-Cover, or Back-Cover Texts. A copy of +the license is included in the section entitled ``GNU Free Documentation +License'' in the Emacs manual. + +This document is part of a collection distributed under the GNU Free +Documentation License. If you want to distribute this document +separately from the collection, you can do so by adding a copy of the +license to the document, as described in section 6 of the license. + +All Emacs Lisp code contained in this document may be used, distributed, +and modified without restriction. +@end quotation +@end copying + +@titlepage +@title Persist -- Persistent Variables for Emacs +@author by Phillip Lord +@page +@insertcopying +@end titlepage + +@contents + +@node Top +@top Persist -- Persistent Variables for Emacs + +Persist is a library for making variables persistent; that it, their +state can be changed from the default and the new value will remain even +after Emacs has been closed and restarted. + +@menu +* Persist:: Simple Usage +* The details:: All functions for interacting with Persist +* Comparison:: How this relates to other, similar techniques +* Implementation:: How variables are saved +@end menu + +@node Persist +@section Persist + +This section describes simple usage of persist. + +@defmac persist-defvar (var initvalue docstring) body@dots{} +This macro is equivalent in form to @code{defvar}, except any changes to +the value of @code{var} will persist between sessions. This macro does +not support the lower arity versions of @code{defvar}. Both an +@code{initvalue} and @code{docstring} needs to be provided. +@end defmac + +@example +@group +(persist-defvar my-persistant-variable 10 + "A variable of no purpose. + +This variable is persistent between sessions") +@end group +@end example + + +@node The details +@section The details + + +@defmac persist-defvar (var initvalue docstring) body@dots{} +This macro is equivalent to @code{defvar} and can be used to make a +variable persistent. +@end defmac + +@defun persist-symbol (symbol &optional initvalue) +This function takes @code{symbol} for an existing, non-persistent variable +and makes it persistent. If @code{initvalue} is not given, then the +current value is used. For package developers, @code{persist-defvar} +would generally be preferred; this function might be useful for making +third-party variables persistent. +@end defun + +@example +@group +(defvar my-persistant-variable 10 + "A variable of no purpose") + +(persist-symbol 'my-persistant-variable 10) +@end group +@end example + +@defun persist-save (symbol) +This function saves @code{symbol} immediately rather than waiting till +the normal time +@end defun + +@defun persist-default (symbol) +Return the default value for @code{symbol}. The default value is +actually set for each session and does not persist from session to +session, although if the value is set by either @code{persist-defvar} or +@code{persist-symbol} saved it in a file, it will be set to the same +value across sessions. +@end defun + +@defun persist-reset (symbol) +Change the value of @code{symbol} to the last saved value if it exists. +@end defun + +@defun persist-location (symbol directory) +Values are usually persisted to a standard location; it is possible to +change this for individual symbol using this function. Be aware that +this does not call @code{persist-load}, so this will not restore a +previously saved value. +@end defun + +@node Comparison +@section Comparison + +There are several other packages which also persist aspects of Emacs +across sessions, however, these fulfil a different purpose. + +Custom persists values of variables across sessions. However, it does +this for user options, and is associated with a user interface for +editing the value. + +desktop.el is also user-centric and is aimed at persisting the session +in terms of buffers, modes and minor modes. It can be used to persist +individual variables, but this will also save the session which the user +may or may not want. + +savehist.el can save individual variables but, as with desktop.el, is a +a global setting and has other implications such as saving mini-buffer +history. + +@node Implementation +@section Implementation + +persist is implemented by saving values for each symbol into an +different. This makes it relatively easy to update or delete the stored +value for a variable by hand if necessary. It should scale to 10 or 100 +variables, but may get a bit slow after this. + +@bye diff --git a/elpa/persist-0.6.1/test/persist-tests.el b/elpa/persist-0.6.1/test/persist-tests.el new file mode 100644 index 00000000..d571325f --- /dev/null +++ b/elpa/persist-0.6.1/test/persist-tests.el @@ -0,0 +1,146 @@ +(require 'persist) +(require 'seq) + + +(defmacro with-local-temp-persist (&rest body) + (declare (debug body)) + `(unwind-protect + (let ((persist--directory-location "./persist/") + (persist--symbols nil)) + ,@body) + (delete-directory "./persist" t))) + +(ert-deftest test-persist-symbol () + (should + (let ((persist--symbols nil) + (sym (cl-gensym))) + (persist-symbol sym 10) + (seq-contains persist--symbols sym)))) + +(ert-deftest test-persist-save-only-persistant () + ;; do not save not persist variables + (should-error + (with-local-temp-persist + (persist-save (cl-gensym))) + :type 'error + :exclude-subtypes t)) + +(defmacro persist-test-persist-save (init default change printed-changed) + "Test persisting symbols. +- symbol is not persisted when value is set to INIT and default + value is set to DEFAULT. +- symbol is persisted when value is changed according to CHANGE. +- persisted file contents match PRINTED-CHANGED. +- symbol is not persisted after value is set back to DEFAULT." + `(with-local-temp-persist + (let ((sym (cl-gensym))) + (should-not (file-exists-p (persist--file-location sym))) + (set sym ,init) + (persist-symbol sym ,default) + (persist-save sym) + (should t) + (should-not (file-exists-p (persist--file-location sym))) + ,change + (persist-save sym) + (should (file-exists-p (persist--file-location sym))) + (should + (string-match-p + ,printed-changed + (with-temp-buffer + (insert-file-contents (persist--file-location sym)) + (buffer-string)))) + (set sym ,default) + (persist-save sym) + (should-not (file-exists-p (persist--file-location sym)))))) + +(ert-deftest test-persist-save-number () + "Test saving number." + (persist-test-persist-save 1 1 (set sym 2) "2")) + +(ert-deftest test-persist-save-string () + "Test saving string." + (persist-test-persist-save "foo" "foo" (set sym "bar") "bar")) + +(ert-deftest test-persist-save-hash () + "Test saving hash table." + (let* ((hash (make-hash-table)) + (default (copy-hash-table hash))) + (persist-test-persist-save hash default + (puthash 'foo "bar" (symbol-value sym)) + "#s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8125 data (foo \"bar\"))"))) + +(ert-deftest test-persist-save-record () + "Test saving record." + (let* ((rec (record 'foo 'a 'b)) + (default (copy-sequence rec))) + (persist-test-persist-save rec default + (setf (aref (symbol-value sym) 2) 'quux) + "#s(foo a quux)"))) + +(ert-deftest test-persist-load () + (with-local-temp-persist + (let ((sym (cl-gensym))) + (set sym 10) + ;; set this different to force save + (persist-symbol sym 1) + (persist-save sym) + (should (equal 10 (symbol-value sym))) + (set sym 30) + (should (equal 30 (symbol-value sym))) + (persist-load sym) + (should (equal 10 (symbol-value sym)))))) + +(ert-deftest test-persist-remove () + (with-local-temp-persist + (let ((sym (cl-gensym))) + (should-not (persist--persistant-p sym)) + (persist-symbol sym 10) + (should (persist--persistant-p sym)) + (persist-unpersist sym) + (should-not (persist--persistant-p sym))))) + +(ert-deftest test-persist-defvar () + (with-local-temp-persist + (defvar test-no-persist-variable 10 "docstring") + (persist-defvar test-persist-variable 20 "docstring") + (should-not (persist--persistant-p 'test-no-persist-variable)) + (should (persist--persistant-p 'test-persist-variable)) + (should (= 20 + (persist-default 'test-persist-variable))))) + +(ert-deftest test-persist-location () + (unwind-protect + (let ((sym (cl-gensym))) + (delete-directory "./persist-defined-location" t) + (set sym 10) + (persist-symbol sym 10) + (persist-location sym "./persist-defined-location") + (should + (equal (expand-file-name + (symbol-name sym) + "./persist-defined-location/") + (persist--file-location sym))) + (persist-save sym) + (should-not (file-exists-p (persist--file-location sym))) + (set sym 20) + (persist-save sym) + (should (file-exists-p (persist--file-location sym))) + (should + (string-match-p + "20" + (with-temp-buffer + (insert-file-contents (persist--file-location sym)) + (buffer-string)))) + (should-error + (persist-save 'fred))) + (delete-directory "./persist-defined-location" t))) + +(ert-deftest test-persist-reset () + "Symbol should be reset to a copy of the default." + (with-local-temp-persist + (persist-defvar persist--test-reset-variable (make-hash-table) "docstring") + (should-not (eq persist--test-reset-variable + (persist-default 'persist--test-reset-variable))) + (persist-reset 'persist--test-reset-variable) + (should-not (eq persist--test-reset-variable + (persist-default 'persist--test-reset-variable))))) -- 2.47.3