commit add035f502c7d2ba40966f18c52f22e827047b23 (HEAD, refs/remotes/origin/master) Author: Michael Albinus Date: Tue Mar 29 09:26:05 2016 +0200 Fix typo in network-stream-tests.el * test/lisp/net/network-stream-tests.el (connect-to-tls-ipv6-nowait): Fix typo. diff --git a/test/lisp/net/network-stream-tests.el b/test/lisp/net/network-stream-tests.el index 91cc8b9..c9b7cc7 100644 --- a/test/lisp/net/network-stream-tests.el +++ b/test/lisp/net/network-stream-tests.el @@ -238,7 +238,7 @@ (skip-unless (executable-find "gnutls-serv")) (skip-unless (gnutls-available-p)) (skip-unless (not (eq system-type 'windows-nt))) - (skip-unless (featurep 'make-network-process '(family ipv6))) + (skip-unless (featurep 'make-network-process '(:family ipv6))) (let ((server (make-tls-server 44333)) (times 0) proc status) commit 2946344a231a915d5143017b70e91a9a7a9b11aa Author: Nicolas Petton Date: Tue Mar 29 09:19:32 2016 +0200 New function seq-sort-by in seq.el * lisp/emacs-lisp/seq.el (seq-sort-by): New function. * test/lisp/emacs-lisp/seq-tests.el: New test for seq-sort-by. * doc/lispref/sequences.texi: Add documentation for seq-sort-by. diff --git a/doc/lispref/sequences.texi b/doc/lispref/sequences.texi index f7d26e5..08e5e3a 100644 --- a/doc/lispref/sequences.texi +++ b/doc/lispref/sequences.texi @@ -763,6 +763,18 @@ according to @var{function}, a function of two arguments that returns non-@code{nil} if the first argument should sort before the second. @end defun +@defun seq-sort-by function predicate sequence + This function is similar to @code{seq-sort}, but the elements of +@var{sequence} are transformed by applying @var{function} on them +before being sorted. @var{function} is a function of one argument. + +@example +(seq-sort-by #'seq-length #'> ["a" "ab" "abc"]) +@result{} ["abc" "ab" "a"] +@end example +@end defun + + @defun seq-contains sequence elt &optional function This function returns the first element in @var{sequence} that is equal to @var{elt}. If the optional argument @var{function} is non-@code{nil}, diff --git a/lisp/emacs-lisp/seq.el b/lisp/emacs-lisp/seq.el index 8b7b594..89fad43 100644 --- a/lisp/emacs-lisp/seq.el +++ b/lisp/emacs-lisp/seq.el @@ -4,7 +4,7 @@ ;; Author: Nicolas Petton ;; Keywords: sequences -;; Version: 2.3 +;; Version: 2.14 ;; Package: seq ;; Maintainer: emacs-devel@gnu.org @@ -218,6 +218,16 @@ The result is a sequence of the same type as SEQUENCE." (cl-defmethod seq-sort (pred (list list)) (sort (seq-copy list) pred)) +(defun seq-sort-by (function pred sequence) + "Sort SEQUENCE using PRED as a comparison function. +Elements of SEQUENCE are transformed by FUNCTION before being +sorted. FUNCTION must be a function of one argument." + (seq-sort (lambda (a b) + (funcall pred + (funcall function a) + (funcall function b))) + sequence)) + (cl-defgeneric seq-reverse (sequence) "Return a sequence with elements of SEQUENCE in reverse order." (let ((result '())) diff --git a/test/lisp/emacs-lisp/seq-tests.el b/test/lisp/emacs-lisp/seq-tests.el index c9219b5..50543de 100644 --- a/test/lisp/emacs-lisp/seq-tests.el +++ b/test/lisp/emacs-lisp/seq-tests.el @@ -347,5 +347,10 @@ Evaluate BODY for each created sequence. (should (= (seq-position seq 'a #'eq) 0)) (should (null (seq-position seq (make-symbol "a") #'eq))))) +(ert-deftest test-seq-sort-by () + (let ((seq ["x" "xx" "xxx"])) + (should (equal (seq-sort-by #'seq-length #'> seq) + ["xxx" "xx" "x"])))) + (provide 'seq-tests) ;;; seq-tests.el ends here commit a30e7e12ed8465e2565dd318d921bc87f52ce18e Author: Lars Magne Ingebrigtsen Date: Mon Mar 28 19:11:22 2016 +0200 Mention the `M-q' changes diff --git a/etc/NEWS b/etc/NEWS index 0a36371..b358bfc 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -58,6 +58,10 @@ has been added. They are: 'file-attribute-type', compute a fash, non-consing hash of the contents of a buffer. --- +** `fill-paragraph' no longer marks the buffer as changed unless it +actually changed something. + +--- ** The locale language name 'ca' is now mapped to the language environment 'Catalan', which has been added. commit 742bf8243ca8155a1a139e90bcb654232513d8a9 Author: Lars Magne Ingebrigtsen Date: Mon Mar 28 19:08:33 2016 +0200 Have `M-q' not mark buffers are changed when they haven't * lisp/textmodes/fill.el (fill-paragraph): Use `buffer-hash' to avoid marking buffers as changed when they haven't. diff --git a/lisp/textmodes/fill.el b/lisp/textmodes/fill.el index 100e2a2..173d1c9 100644 --- a/lisp/textmodes/fill.el +++ b/lisp/textmodes/fill.el @@ -804,65 +804,75 @@ region, instead of just filling the current paragraph." (interactive (progn (barf-if-buffer-read-only) (list (if current-prefix-arg 'full) t))) - (or - ;; 1. Fill the region if it is active when called interactively. - (and region transient-mark-mode mark-active - (not (eq (region-beginning) (region-end))) - (or (fill-region (region-beginning) (region-end) justify) t)) - ;; 2. Try fill-paragraph-function. - (and (not (eq fill-paragraph-function t)) - (or fill-paragraph-function - (and (minibufferp (current-buffer)) - (= 1 (point-min)))) - (let ((function (or fill-paragraph-function - ;; In the minibuffer, don't count the width - ;; of the prompt. - 'fill-minibuffer-function)) - ;; If fill-paragraph-function is set, it probably takes care - ;; of comments and stuff. If not, it will have to set - ;; fill-paragraph-handle-comment back to t explicitly or - ;; return nil. - (fill-paragraph-handle-comment nil) - (fill-paragraph-function t)) - (funcall function justify))) - ;; 3. Try our syntax-aware filling code. - (and fill-paragraph-handle-comment - ;; Our code only handles \n-terminated comments right now. - comment-start (equal comment-end "") - (let ((fill-paragraph-handle-comment nil)) - (fill-comment-paragraph justify))) - ;; 4. If it all fails, default to the good ol' text paragraph filling. - (let ((before (point)) - (paragraph-start paragraph-start) - ;; Fill prefix used for filling the paragraph. - fill-pfx) - ;; Try to prevent code sections and comment sections from being - ;; filled together. - (when (and fill-paragraph-handle-comment comment-start-skip) - (setq paragraph-start - (concat paragraph-start "\\|[ \t]*\\(?:" - comment-start-skip "\\)"))) - (save-excursion - ;; To make sure the return value of forward-paragraph is meaningful, - ;; we have to start from the beginning of line, otherwise skipping - ;; past the last few chars of a paragraph-separator would count as - ;; a paragraph (and not skipping any chars at EOB would not count - ;; as a paragraph even if it is). - (move-to-left-margin) - (if (not (zerop (fill-forward-paragraph 1))) - ;; There's no paragraph at or after point: give up. - (setq fill-pfx "") - (let ((end (point)) - (beg (progn (fill-forward-paragraph -1) (point)))) - (goto-char before) - (setq fill-pfx - (if use-hard-newlines - ;; Can't use fill-region-as-paragraph, since this - ;; paragraph may still contain hard newlines. See - ;; fill-region. - (fill-region beg end justify) - (fill-region-as-paragraph beg end justify)))))) - fill-pfx))) + (let ((hash (and (not (buffer-modified-p)) + (buffer-hash)))) + (prog1 + (or + ;; 1. Fill the region if it is active when called interactively. + (and region transient-mark-mode mark-active + (not (eq (region-beginning) (region-end))) + (or (fill-region (region-beginning) (region-end) justify) t)) + ;; 2. Try fill-paragraph-function. + (and (not (eq fill-paragraph-function t)) + (or fill-paragraph-function + (and (minibufferp (current-buffer)) + (= 1 (point-min)))) + (let ((function (or fill-paragraph-function + ;; In the minibuffer, don't count + ;; the width of the prompt. + 'fill-minibuffer-function)) + ;; If fill-paragraph-function is set, it probably + ;; takes care of comments and stuff. If not, it + ;; will have to set fill-paragraph-handle-comment + ;; back to t explicitly or return nil. + (fill-paragraph-handle-comment nil) + (fill-paragraph-function t)) + (funcall function justify))) + ;; 3. Try our syntax-aware filling code. + (and fill-paragraph-handle-comment + ;; Our code only handles \n-terminated comments right now. + comment-start (equal comment-end "") + (let ((fill-paragraph-handle-comment nil)) + (fill-comment-paragraph justify))) + ;; 4. If it all fails, default to the good ol' text paragraph filling. + (let ((before (point)) + (paragraph-start paragraph-start) + ;; Fill prefix used for filling the paragraph. + fill-pfx) + ;; Try to prevent code sections and comment sections from being + ;; filled together. + (when (and fill-paragraph-handle-comment comment-start-skip) + (setq paragraph-start + (concat paragraph-start "\\|[ \t]*\\(?:" + comment-start-skip "\\)"))) + (save-excursion + ;; To make sure the return value of forward-paragraph is + ;; meaningful, we have to start from the beginning of + ;; line, otherwise skipping past the last few chars of a + ;; paragraph-separator would count as a paragraph (and + ;; not skipping any chars at EOB would not count as a + ;; paragraph even if it is). + (move-to-left-margin) + (if (not (zerop (fill-forward-paragraph 1))) + ;; There's no paragraph at or after point: give up. + (setq fill-pfx "") + (let ((end (point)) + (beg (progn (fill-forward-paragraph -1) (point)))) + (goto-char before) + (setq fill-pfx + (if use-hard-newlines + ;; Can't use fill-region-as-paragraph, since this + ;; paragraph may still contain hard newlines. See + ;; fill-region. + (fill-region beg end justify) + (fill-region-as-paragraph beg end justify)))))) + fill-pfx)) + ;; 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 + (equal hash (buffer-hash))) + (set-buffer-modified-p nil))))) (declare-function comment-search-forward "newcomment" (limit &optional noerror)) (declare-function comment-string-strip "newcomment" (str beforep afterp)) commit 15357f6d1f90b03719f650823ac6531a305a9818 Author: Lars Magne Ingebrigtsen Date: Mon Mar 28 19:07:39 2016 +0200 Add a new function `buffer-hash' * doc/lispref/text.texi (Checksum/Hash): Document `buffer-hash'. * src/fns.c (Fbuffer_hash): New function. (make_digest_string): Refactored out into its own function. (secure_hash): Use it. * test/src/fns-tests.el (fns-tests-hash-buffer): New tests. diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi index 4c3a1a0..5e47316 100644 --- a/doc/lispref/text.texi +++ b/doc/lispref/text.texi @@ -4468,6 +4468,20 @@ using the specified or chosen coding system. However, if coding instead. @end defun +@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 + @node Parsing HTML/XML @section Parsing HTML and XML @cindex parsing html diff --git a/etc/NEWS b/etc/NEWS index ce21532..0a36371 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -53,6 +53,10 @@ has been added. They are: 'file-attribute-type', 'file-attribute-modes', 'file-attribute-inode-number', and 'file-attribute-device-number' ++++ +** The new function `buffer-hash' has been added, and can be used to +compute a fash, non-consing hash of the contents of a buffer. + --- ** The locale language name 'ca' is now mapped to the language environment 'Catalan', which has been added. diff --git a/src/fns.c b/src/fns.c index 0e3fc27..9513387 100644 --- a/src/fns.c +++ b/src/fns.c @@ -4737,6 +4737,22 @@ returns nil, then (funcall TEST x1 x2) also returns nil. */) #include "sha256.h" #include "sha512.h" +Lisp_Object +make_digest_string (Lisp_Object digest, int digest_size) +{ + unsigned char *p = SDATA (digest); + int i; + + for (i = digest_size - 1; i >= 0; i--) + { + static char const hexdigit[16] = "0123456789abcdef"; + int p_i = p[i]; + p[2 * i] = hexdigit[p_i >> 4]; + p[2 * i + 1] = hexdigit[p_i & 0xf]; + } + return digest; +} + /* ALGORITHM is a symbol: md5, sha1, sha224 and so on. */ static Lisp_Object @@ -4936,17 +4952,7 @@ secure_hash (Lisp_Object algorithm, Lisp_Object object, Lisp_Object start, SSDATA (digest)); if (NILP (binary)) - { - unsigned char *p = SDATA (digest); - for (i = digest_size - 1; i >= 0; i--) - { - static char const hexdigit[16] = "0123456789abcdef"; - int p_i = p[i]; - p[2 * i] = hexdigit[p_i >> 4]; - p[2 * i + 1] = hexdigit[p_i & 0xf]; - } - return digest; - } + return make_digest_string (digest, digest_size); else return make_unibyte_string (SSDATA (digest), digest_size); } @@ -4997,6 +5003,45 @@ If BINARY is non-nil, returns a string in binary form. */) { return secure_hash (algorithm, object, start, end, Qnil, Qnil, binary); } + +DEFUN ("buffer-hash", Fbuffer_hash, Sbuffer_hash, 0, 1, 0, + doc: /* 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." */ ) + (Lisp_Object buffer_or_name) +{ + Lisp_Object buffer; + struct buffer *b; + struct sha1_ctx ctx; + Lisp_Object digest = make_uninit_string (SHA1_DIGEST_SIZE * 2); + + if (NILP (buffer_or_name)) + buffer = Fcurrent_buffer (); + else + buffer = Fget_buffer (buffer_or_name); + if (NILP (buffer)) + nsberror (buffer_or_name); + + b = XBUFFER (buffer); + sha1_init_ctx (&ctx); + + /* Process the first part of the buffer. */ + sha1_process_bytes (BUF_BEG_ADDR (b), + BUF_GPT_BYTE (b) - BUF_BEG_BYTE (b), + &ctx); + + /* If the gap is before the end of the buffer, process the last half + of the buffer. */ + if (BUF_GPT_BYTE (b) < BUF_Z_BYTE (b)) + sha1_process_bytes (BUF_GAP_END_ADDR (b), + BUF_Z_ADDR (b) - BUF_GAP_END_ADDR (b), + &ctx); + + sha1_finish_ctx (&ctx, SSDATA (digest)); + return make_digest_string (digest, SHA1_DIGEST_SIZE); +} + void syms_of_fns (void) @@ -5156,6 +5201,7 @@ this variable. */); defsubr (&Sbase64_decode_string); defsubr (&Smd5); defsubr (&Ssecure_hash); + defsubr (&Sbuffer_hash); defsubr (&Slocale_info); hashtest_eq.name = Qeq; diff --git a/test/src/fns-tests.el b/test/src/fns-tests.el index 688ff1f..8485896 100644 --- a/test/src/fns-tests.el +++ b/test/src/fns-tests.el @@ -219,3 +219,19 @@ (should (equal (func-arity (eval (lambda (x &optional y)) nil)) '(1 . 2))) (should (equal (func-arity (eval (lambda (x &optional y)) t)) '(1 . 2))) (should (equal (func-arity 'let) '(1 . unevalled)))) + +(ert-deftest fns-tests-hash-buffer () + (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"))))