[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}.