From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Stefan Monnier Newsgroups: gmane.emacs.devel Subject: Re: Don't complain about changed file when it hasn't changed Date: Mon, 29 Aug 2016 12:01:55 -0400 Message-ID: References: <83oa4bbq5b.fsf@gnu.org> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: blaine.gmane.org 1472486393 6936 195.159.176.226 (29 Aug 2016 15:59:53 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Mon, 29 Aug 2016 15:59:53 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/25.1.50 (gnu/linux) Cc: emacs-devel@gnu.org To: Eli Zaretskii Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Mon Aug 29 17:59:50 2016 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1beOyT-0001N5-1S for ged-emacs-devel@m.gmane.org; Mon, 29 Aug 2016 17:59:49 +0200 Original-Received: from localhost ([::1]:44358 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1beOyQ-0006PR-O3 for ged-emacs-devel@m.gmane.org; Mon, 29 Aug 2016 11:59:46 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:46868) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1beOxe-0006Lo-Vg for emacs-devel@gnu.org; Mon, 29 Aug 2016 11:59:00 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1beOxa-0008Re-QY for emacs-devel@gnu.org; Mon, 29 Aug 2016 11:58:57 -0400 Original-Received: from pruche.dit.umontreal.ca ([132.204.246.22]:38829) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1beOxa-0008RR-LE; Mon, 29 Aug 2016 11:58:54 -0400 Original-Received: from ceviche.home (lechon.iro.umontreal.ca [132.204.27.242]) by pruche.dit.umontreal.ca (8.14.7/8.14.1) with ESMTP id u7TFwp2e004365; Mon, 29 Aug 2016 11:58:52 -0400 Original-Received: by ceviche.home (Postfix, from userid 20848) id 45D6D66274; Mon, 29 Aug 2016 12:01:55 -0400 (EDT) In-Reply-To: <83oa4bbq5b.fsf@gnu.org> (Eli Zaretskii's message of "Mon, 29 Aug 2016 17:34:08 +0300") X-NAI-Spam-Flag: NO X-NAI-Spam-Threshold: 5 X-NAI-Spam-Score: 0 X-NAI-Spam-Rules: 1 Rules triggered RV5781=0 X-NAI-Spam-Version: 2.3.0.9418 : core <5781> : inlines <5148> : streams <1691987> : uri <2277390> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 132.204.246.22 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:206880 Archived-At: > Anyway, the proposed implementation misses a few subtleties, IMO: Revised patch, Stefan diff --git a/etc/NEWS b/etc/NEWS index 1290fa4..cdabeda 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -213,6 +213,10 @@ In modes where form feed was treated as a whitespace character, It now deletes whitespace after the last form feed thus behaving the same as in modes where the character is not whitespace. +** No more prompt about changed file when the file's content is unchanged. +Instead of only checking the modification time, Emacs now also checks +the file's actual content before prompting the user. + * Changes in Specialized Modes and Packages in Emacs 25.2 diff --git a/lisp/userlock.el b/lisp/userlock.el index a0c55fd..2295184 100644 --- a/lisp/userlock.el +++ b/lisp/userlock.el @@ -97,6 +97,28 @@ ask-user-about-lock-help (define-error 'file-supersession nil 'file-error) +(defun userlock--check-content-unchanged (fn) + (with-demoted-errors "Unchanged content check: %S" + (save-restriction + (widen) + (let ((buf (current-buffer)) + (cs buffer-file-coding-system) + (start (point-min)) + (end (point-max))) + ;; FIXME: To avoid a slow `insert-file-contents' on large or + ;; remote files, it'd be good to include file size in the + ;; "visited-modtime" check. + (when (with-temp-buffer + (let ((coding-system-for-read cs)) + (insert-file-contents fn)) + (when (= (buffer-size) (- end start)) ;Minor optimization. + (= 0 (let ((case-fold-search nil)) + (compare-buffer-substrings + buf start end + (current-buffer) (point-min) (point-max)))))) + (set-visited-file-modtime) + 'unchanged))))) + ;;;###autoload (defun ask-user-about-supersession-threat (fn) "Ask a user who is about to modify an obsolete buffer what to do. @@ -106,30 +128,30 @@ ask-user-about-supersession-threat You can rewrite this to use any criterion you like to choose which one to do. The buffer in question is current when this function is called." - (discard-input) - (save-window-excursion - (let ((prompt - (format "%s changed on disk; \ + (unless (userlock--check-content-unchanged fn) + (discard-input) + (save-window-excursion + (let ((prompt + (format "%s changed on disk; \ really edit the buffer? (y, n, r or C-h) " - (file-name-nondirectory fn))) - (choices '(?y ?n ?r ?? ?\C-h)) - answer) - (while (null answer) - (setq answer (read-char-choice prompt choices)) - (cond ((memq answer '(?? ?\C-h)) - (ask-user-about-supersession-help) - (setq answer nil)) - ((eq answer ?r) - ;; Ask for confirmation if buffer modified - (revert-buffer nil (not (buffer-modified-p))) - (signal 'file-supersession - (list "File reverted" fn))) - ((eq answer ?n) - (signal 'file-supersession - (list "File changed on disk" fn))))) - (message - "File on disk now will become a backup file if you save these changes.") - (setq buffer-backed-up nil)))) + (file-name-nondirectory fn)))) + (while + (let ((answer (read-char-choice prompt '(?y ?n ?r ?? ?\C-h)))) + (cond ((memq answer '(?? ?\C-h)) + (ask-user-about-supersession-help) + 'repeat) + ((eq answer ?r) + ;; Ask for confirmation if buffer modified + (revert-buffer nil (not (buffer-modified-p))) + (signal 'file-supersession + (list "File reverted" fn))) + ((eq answer ?n) + (signal 'file-supersession + (list "File changed on disk" fn))) + (t (null answer))))) + (message + "File on disk now will become a backup file if you save these changes.") + (setq buffer-backed-up nil))))) (defun ask-user-about-supersession-help () (with-output-to-temp-buffer "*Help*"