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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/compat cae87e865b 3/3: Add buffer-hash and with-buffer-


From: ELPA Syncer
Subject: [elpa] externals/compat cae87e865b 3/3: Add buffer-hash and with-buffer-unmodified-if-unchanged
Date: Sun, 15 Jan 2023 15:57:26 -0500 (EST)

branch: externals/compat
commit cae87e865bf35ea166b7ed6df93d44bb5d6dc7ad
Author: Daniel Mendler <mail@daniel-mendler.de>
Commit: Daniel Mendler <mail@daniel-mendler.de>

    Add buffer-hash and with-buffer-unmodified-if-unchanged
---
 NEWS.org        |  2 ++
 compat-26.el    | 17 +++++++++++++++++
 compat-29.el    | 37 +++++++++++++++++++++++++++++++++++++
 compat-tests.el | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 compat.texi     | 32 ++++++++++++++++++++++++++++++++
 5 files changed, 135 insertions(+)

diff --git a/NEWS.org b/NEWS.org
index a7f5b0e648..dffc7d8cc6 100644
--- a/NEWS.org
+++ b/NEWS.org
@@ -2,12 +2,14 @@
 
 * Development
 
+- compat-26: Add ~buffer-hash~.
 - compat-27: Add ~fixnump~ and ~bignump~.
 - compat-27: Add ~with-minibuffer-selected-window~.
 - compat-27: Add generalized variables for ~decoded-time-*~.
 - compat-28: Add ~macroexp-warn-and-return~.
 - compat-28: Add ~subr-native-elisp-p~.
 - compat-28: Add ~bounds-of-thing-at-mouse~.
+- compat-29: Add ~with-buffer-unmodified-if-unchanged~.
 
 * Release of "Compat" Version 29.1.1.1
 
diff --git a/compat-26.el b/compat-26.el
index 398ce9aaa7..123ac4d5ef 100644
--- a/compat-26.el
+++ b/compat-26.el
@@ -27,6 +27,23 @@
 
 ;;;; Defined in fns.c
 
+(compat-defun buffer-hash (&optional buffer-or-name) ;; <OK>
+   "Return a hash of the contents of BUFFER-OR-NAME.
+This hash is performed on the raw internal format of the buffer,
+disregarding any coding systems.  If nil, use the current buffer.
+
+This function is useful for comparing two buffers running in the same
+Emacs, but is not guaranteed to return the same hash between different
+Emacs versions.  It should be somewhat more efficient on larger
+buffers than `secure-hash' is, and should not allocate more memory.
+
+It should not be used for anything security-related.  See
+`secure-hash' for these applications."
+   (with-current-buffer (or buffer-or-name (current-buffer))
+     (save-restriction
+       (widen)
+       (sha1 (current-buffer) (point-min) (point-max)))))
+
 (compat-defun assoc (key alist &optional testfn) ;; <OK>
   "Handle the optional TESTFN."
   :explicit t
diff --git a/compat-29.el b/compat-29.el
index fd3597c070..cd94215dd9 100644
--- a/compat-29.el
+++ b/compat-29.el
@@ -284,6 +284,43 @@ CONDITION."
 
 ;;;; Defined in subr-x.el
 
+(compat-defmacro with-buffer-unmodified-if-unchanged (&rest body) ;; <OK>
+  "Like `progn', but change buffer-modified status only if buffer text changes.
+If the buffer was unmodified before execution of BODY, and
+buffer text after execution of BODY is identical to what it was
+before, ensure that buffer is still marked unmodified afterwards.
+For example, the following won't change the buffer's modification
+status:
+
+  (with-buffer-unmodified-if-unchanged
+    (insert \"a\")
+    (delete-char -1))
+
+Note that only changes in the raw byte sequence of the buffer text,
+as stored in the internal representation, are monitored for the
+purpose of detecting the lack of changes in buffer text.  Any other
+changes that are normally perceived as \"buffer modifications\", such
+as changes in text properties, `buffer-file-coding-system', buffer
+multibyteness, etc. -- will not be noticed, and the buffer will still
+be marked unmodified, effectively ignoring those changes."
+  (declare (debug t) (indent 0))
+  (let ((hash (gensym))
+        (buffer (gensym)))
+    `(let ((,hash (and (not (buffer-modified-p))
+                       (buffer-hash)))
+           (,buffer (current-buffer)))
+       (prog1
+           (progn
+             ,@body)
+         ;; If we didn't change anything in the buffer (and the buffer
+         ;; was previously unmodified), then flip the modification status
+         ;; back to "unchanged".
+         (when (and ,hash (buffer-live-p ,buffer))
+           (with-current-buffer ,buffer
+             (when (and (buffer-modified-p)
+                        (equal ,hash (buffer-hash)))
+               (restore-buffer-modified-p nil))))))))
+
 (compat-defun add-display-text-property (start end prop value ;; <OK>
                                                &optional object)
   "Add display property PROP with VALUE to the text from START to END.
diff --git a/compat-tests.el b/compat-tests.el
index 88953dec75..1e977bbe35 100644
--- a/compat-tests.el
+++ b/compat-tests.el
@@ -733,6 +733,53 @@
 (ert-deftest garbage-collect-maybe ()
   (garbage-collect-maybe 10))
 
+(ert-deftest buffer-hahs ()
+  (should-equal (sha1 "foo") "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33")
+  (should-equal (with-temp-buffer
+                   (insert "foo")
+                   (buffer-hash))
+                 (sha1 "foo"))
+  ;; This tests whether the presence of a gap in the middle of the
+  ;; buffer is handled correctly.
+  (should-equal (with-temp-buffer
+                   (insert "foo")
+                   (goto-char 2)
+                   (insert " ")
+                   (backward-delete-char 1)
+                   (buffer-hash))
+                 (sha1 "foo")))
+
+(ert-deftest with-buffer-unmodified-if-unchanged ()
+  (with-temp-buffer
+    (with-buffer-unmodified-if-unchanged
+      (insert "t"))
+    (should (buffer-modified-p)))
+
+  (with-temp-buffer
+    (with-buffer-unmodified-if-unchanged
+      (insert "t")
+      (delete-char -1))
+    (should-not (buffer-modified-p)))
+
+  ;; Shouldn't error.
+  (should
+   (with-temp-buffer
+     (with-buffer-unmodified-if-unchanged
+       (insert "t")
+       (delete-char -1)
+       (kill-buffer))))
+
+  (with-temp-buffer
+    (let ((outer (current-buffer)))
+      (with-temp-buffer
+        (let ((inner (current-buffer)))
+          (with-buffer-unmodified-if-unchanged
+            (insert "t")
+            (delete-char -1)
+            (set-buffer outer))
+          (with-current-buffer inner
+            (should-not (buffer-modified-p))))))))
+
 (ert-deftest insert-into-buffer ()
   ;; Without optional compat--arguments
   (with-temp-buffer
diff --git a/compat.texi b/compat.texi
index 199afd2381..201385344a 100644
--- a/compat.texi
+++ b/compat.texi
@@ -505,6 +505,21 @@ generate a symbol with the same name.  The prefix defaults 
to
 See @code{gensym}.
 @end defvar
 
+@c copied from lispref/text.texi
+@defun buffer-hash &optional buffer-or-name
+Return a hash of @var{buffer-or-name}.  If @code{nil}, this defaults
+to the current buffer.  As opposed to @code{secure-hash}, this
+function computes the hash based on the internal representation of the
+buffer, disregarding any coding systems.  It's therefore only useful
+when comparing two buffers running in the same Emacs, and is not
+guaranteed to return the same hash between different Emacs versions.
+It should be somewhat more efficient on larger buffers than
+@code{secure-hash} is, and should not allocate more memory.
+@c Note that we do not document what hashing function we're using, or
+@c even whether it's a cryptographic hash, since that may change
+@c according to what we find useful.
+@end defun
+
 @c copied from lispref/files.texi
 @defun make-nearby-temp-file prefix &optional dir-flag suffix
 This function is similar to @code{make-temp-file}, but it creates a
@@ -2294,6 +2309,23 @@ you can say:
 @xref{Size of Displayed Text,,,elisp}.
 @end defun
 
+@c based on lisp/subr-x.el
+@defmac with-buffer-unmodified-if-unchanged &rest body@dots{}
+Evaluate @var{body} like @code{progn}, but change buffer-modified status
+only if buffer text changes.  If the buffer was unmodified before
+execution of BODY, and buffer text after execution of BODY is identical
+to what it was before, ensure that buffer is still marked unmodified
+afterwards.
+
+Note that only changes in the raw byte sequence of the buffer text, as
+stored in the internal representation, are monitored for the purpose of
+detecting the lack of changes in buffer text.  Any other changes that
+are normally perceived as "buffer modifications", such as changes in
+text properties, @code{buffer-file-coding-system}, buffer multibyteness,
+etc. -- will not be noticed, and the buffer will still be marked
+unmodified, effectively ignoring those changes.
+@end defmac
+
 @defun file-attribute-file-identifier
 Return the fields @code{(inodenum device)} as a list from attributes
 generated by @code{file-attributes}.



reply via email to

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