From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Eric Abrahamsen Newsgroups: gmane.emacs.bugs Subject: bug#28412: Acknowledgement (26.0.50; Let save-some-buffers accept write-contents-functions) Date: Sun, 10 Sep 2017 15:01:34 -0700 Message-ID: <87mv62jjr5.fsf@ericabrahamsen.net> References: <87bmmikyug.fsf@ericabrahamsen.net> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Trace: blaine.gmane.org 1505321605 4837 195.159.176.226 (13 Sep 2017 16:53:25 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Wed, 13 Sep 2017 16:53:25 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.0.50 (gnu/linux) To: 28412@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Mon Sep 11 00:03:27 2017 Return-path: Envelope-to: geb-bug-gnu-emacs@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 1drAJp-0001t8-Lg for geb-bug-gnu-emacs@m.gmane.org; Mon, 11 Sep 2017 00:03:10 +0200 Original-Received: from localhost ([::1]:54415 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1drAJw-0002uo-GE for geb-bug-gnu-emacs@m.gmane.org; Sun, 10 Sep 2017 18:03:16 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:34674) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1drAJo-0002t9-VW for bug-gnu-emacs@gnu.org; Sun, 10 Sep 2017 18:03:10 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1drAJj-0006SL-Vo for bug-gnu-emacs@gnu.org; Sun, 10 Sep 2017 18:03:08 -0400 Original-Received: from debbugs.gnu.org ([208.118.235.43]:51198) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1drAJj-0006SD-OV for bug-gnu-emacs@gnu.org; Sun, 10 Sep 2017 18:03:03 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1drAJh-0002n8-Ua for bug-gnu-emacs@gnu.org; Sun, 10 Sep 2017 18:03:03 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Eric Abrahamsen Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 10 Sep 2017 22:03:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 28412 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: Original-Received: via spool by 28412-submit@debbugs.gnu.org id=B28412.150508098110727 (code B ref 28412); Sun, 10 Sep 2017 22:03:01 +0000 Original-Received: (at 28412) by debbugs.gnu.org; 10 Sep 2017 22:03:01 +0000 Original-Received: from localhost ([127.0.0.1]:59879 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1drAJg-0002mt-Sa for submit@debbugs.gnu.org; Sun, 10 Sep 2017 18:03:01 -0400 Original-Received: from mail.ericabrahamsen.net ([50.56.99.223]:38304) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1drAJd-0002mi-D7 for 28412@debbugs.gnu.org; Sun, 10 Sep 2017 18:02:57 -0400 Original-Received: from localhost (71-35-182-76.tukw.qwest.net [71.35.182.76]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) (Authenticated sender: eric@ericabrahamsen.net) by mail.ericabrahamsen.net (Postfix) with ESMTPSA id 4F01BBFD10 for <28412@debbugs.gnu.org>; Sun, 10 Sep 2017 22:02:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mail.ericabrahamsen.net; s=mail; t=1505080976; bh=gkEuhLNY2epxaGR1yxCn3fVkI7idQ55+hLsev4ibl00=; h=From:To:Subject:In-Reply-To:References:Date:From; b=IItN6a8Mo764PZGdhFPzEsCSVrU85/vM3b6iuQwhNz3KpwAq/xwIsKnn0LFzc6gC3 7yx8C9Riqtw/hZGN1SsbnLfS3oISfFPs3gsmRlmzyl0LYFyG2FrNte2ezMIHX7The0 /rW9ap9zvAd4bDBxrrLSXKKFg9UU69rAIG1nq3mo= In-Reply-To: (GNU bug Tracking System's message of "Sun, 10 Sep 2017 21:52:02 +0000") X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 208.118.235.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.org gmane.emacs.bugs:136894 --=-=-= Content-Type: text/plain Damn, I think that was the wrong patch. Here's the latest one. --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0001-Allow-write-contents-functions-to-short-circuit-buff.patch >From 7b5f18648e3d4b2aa9a5af536a624d6518d8fdd7 Mon Sep 17 00:00:00 2001 From: Eric Abrahamsen Date: Thu, 25 May 2017 15:28:19 +0800 Subject: [PATCH] Allow write-contents-functions to short-circuit buffer saving * lisp/files.el (basic-save-buffer): If write-contents-functions is non-nil, give the functions in that hook a chance to save buffer contents before checking if buffer is visiting a file. (save-some-buffers): If write-contents-functions is non nil, consider the buffer eligible for a save prompt. * doc/lispref/files.texi (Saving Buffers): Mention new behavior, note that special-mode buffers can use this to "save" themselves. --- doc/lispref/files.texi | 18 +++++-- lisp/files.el | 136 +++++++++++++++++++++++++++---------------------- 2 files changed, 87 insertions(+), 67 deletions(-) diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index 2b692dbf68..a6ee0cc69c 100644 --- a/doc/lispref/files.texi +++ b/doc/lispref/files.texi @@ -457,15 +457,23 @@ Saving Buffers @defvar write-contents-functions This works just like @code{write-file-functions}, but it is intended for hooks that pertain to the buffer's contents, not to the particular -visited file or its location. Such hooks are usually set up by major -modes, as buffer-local bindings for this variable. This variable -automatically becomes buffer-local whenever it is set; switching to a -new major mode always resets this variable, but calling -@code{set-visited-file-name} does not. +visited file or its location, and can be used to create arbitrary save +processes for buffers that aren't visiting files at all. Such hooks +are usually set up by major modes, as buffer-local bindings for this +variable. This variable automatically becomes buffer-local whenever +it is set; switching to a new major mode always resets this variable, +but calling @code{set-visited-file-name} does not. If any of the functions in this hook returns non-@code{nil}, the file is considered already written and the rest are not called and neither are the functions in @code{write-file-functions}. + +When using this hook to save buffers that are not visiting files (for +instance, special-mode buffers), keep in mind that, if the function +fails to save correctly and returns a @code{nil} value, +@code{save-buffer} will go on to prompt the user for a file to save +the buffer in. If this is undesirable, consider having the function +fail by raising an error. @end defvar @defopt before-save-hook diff --git a/lisp/files.el b/lisp/files.el index 8ac1993754..1f88f86b76 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -514,10 +514,12 @@ 'write-contents-hooks 'write-contents-functions "22.1") (defvar write-contents-functions nil "List of functions to be called before writing out a buffer to a file. -Only used by `save-buffer'. -If one of them returns non-nil, the file is considered already written -and the rest are not called and neither are the functions in -`write-file-functions'. + +Only used by `save-buffer'. If one of them returns non-nil, the +file is considered already written and the rest are not called +and neither are the functions in `write-file-functions'. This +hook can thus be used to create save behavior for buffers that +are not visiting a file at all. This variable is meant to be used for hooks that pertain to the buffer's contents, not to the particular visited file; thus, @@ -4932,9 +4934,12 @@ save-buffer-coding-system (defun basic-save-buffer (&optional called-interactively) "Save the current buffer in its visited file, if it has been modified. -The hooks `write-contents-functions' and `write-file-functions' get a chance -to do the job of saving; if they do not, then the buffer is saved in -the visited file in the usual way. + +The hooks `write-contents-functions', `local-write-file-hooks' +and `write-file-functions' get a chance to do the job of saving; +if they do not, then the buffer is saved in the visited file in +the usual way. + Before and after saving the buffer, this function runs `before-save-hook' and `after-save-hook', respectively." (interactive '(called-interactively)) @@ -4943,29 +4948,14 @@ basic-save-buffer (if (buffer-base-buffer) (set-buffer (buffer-base-buffer))) (if (or (buffer-modified-p) - ;; handle the case when no modification has been made but - ;; the file disappeared since visited + ;; Handle the case when no modification has been made but + ;; the file disappeared since visited. (and buffer-file-name (not (file-exists-p buffer-file-name)))) (let ((recent-save (recent-auto-save-p)) setmodes) - ;; If buffer has no file name, ask user for one. - (or buffer-file-name - (let ((filename - (expand-file-name - (read-file-name "File to save in: " - nil (expand-file-name (buffer-name)))))) - (if (file-exists-p filename) - (if (file-directory-p filename) - ;; Signal an error if the user specified the name of an - ;; existing directory. - (error "%s is a directory" filename) - (unless (y-or-n-p (format-message - "File `%s' exists; overwrite? " - filename)) - (error "Canceled")))) - (set-visited-file-name filename))) - (or (verify-visited-file-modtime (current-buffer)) + (or (null buffer-file-name) + (verify-visited-file-modtime (current-buffer)) (not (file-exists-p buffer-file-name)) (yes-or-no-p (format @@ -4977,6 +4967,7 @@ basic-save-buffer (save-excursion (and (> (point-max) (point-min)) (not find-file-literally) + (null buffer-read-only) (/= (char-after (1- (point-max))) ?\n) (not (and (eq selective-display t) (= (char-after (1- (point-max))) ?\r))) @@ -4989,46 +4980,65 @@ basic-save-buffer (save-excursion (goto-char (point-max)) (insert ?\n)))) - ;; Support VC version backups. - (vc-before-save) ;; Don't let errors prevent saving the buffer. (with-demoted-errors (run-hooks 'before-save-hook)) - (or (run-hook-with-args-until-success 'write-contents-functions) - (run-hook-with-args-until-success 'local-write-file-hooks) - (run-hook-with-args-until-success 'write-file-functions) - ;; If a hook returned t, file is already "written". - ;; Otherwise, write it the usual way now. - (let ((dir (file-name-directory - (expand-file-name buffer-file-name)))) - (unless (file-exists-p dir) - (if (y-or-n-p - (format-message - "Directory `%s' does not exist; create? " dir)) - (make-directory dir t) - (error "Canceled"))) - (setq setmodes (basic-save-buffer-1)))) + ;; Give `write-contents-functions' a chance to + ;; short-circuit the whole process. + (unless (run-hook-with-args-until-success 'write-contents-functions) + ;; If buffer has no file name, ask user for one. + (or buffer-file-name + (let ((filename + (expand-file-name + (read-file-name "File to save in: " + nil (expand-file-name (buffer-name)))))) + (if (file-exists-p filename) + (if (file-directory-p filename) + ;; Signal an error if the user specified the name of an + ;; existing directory. + (error "%s is a directory" filename) + (unless (y-or-n-p (format-message + "File `%s' exists; overwrite? " + filename)) + (error "Canceled")))) + (set-visited-file-name filename))) + ;; Support VC version backups. + (vc-before-save) + (or (run-hook-with-args-until-success 'local-write-file-hooks) + (run-hook-with-args-until-success 'write-file-functions) + ;; If a hook returned t, file is already "written". + ;; Otherwise, write it the usual way now. + (let ((dir (file-name-directory + (expand-file-name buffer-file-name)))) + (unless (file-exists-p dir) + (if (y-or-n-p + (format-message + "Directory `%s' does not exist; create? " dir)) + (make-directory dir t) + (error "Canceled"))) + (setq setmodes (basic-save-buffer-1))))) ;; Now we have saved the current buffer. Let's make sure ;; that buffer-file-coding-system is fixed to what ;; actually used for saving by binding it locally. - (if save-buffer-coding-system - (setq save-buffer-coding-system last-coding-system-used) - (setq buffer-file-coding-system last-coding-system-used)) - (setq buffer-file-number - (nthcdr 10 (file-attributes buffer-file-name))) - (if setmodes - (condition-case () - (progn - (unless - (with-demoted-errors - (set-file-modes buffer-file-name (car setmodes))) - (set-file-extended-attributes buffer-file-name - (nth 1 setmodes)))) - (error nil)))) - ;; If the auto-save file was recent before this command, - ;; delete it now. - (delete-auto-save-file-if-necessary recent-save) - ;; Support VC `implicit' locking. - (vc-after-save) + (when buffer-file-name + (if save-buffer-coding-system + (setq save-buffer-coding-system last-coding-system-used) + (setq buffer-file-coding-system last-coding-system-used)) + (setq buffer-file-number + (nthcdr 10 (file-attributes buffer-file-name))) + (if setmodes + (condition-case () + (progn + (unless + (with-demoted-errors + (set-file-modes buffer-file-name (car setmodes))) + (set-file-extended-attributes buffer-file-name + (nth 1 setmodes)))) + (error nil))) + ;; Support VC `implicit' locking. + (vc-after-save)) + ;; If the auto-save file was recent before this command, + ;; delete it now. + (delete-auto-save-file-if-necessary recent-save)) (run-hooks 'after-save-hook)) (or noninteractive (not called-interactively) @@ -5255,7 +5265,9 @@ save-some-buffers (and pred (progn (set-buffer buffer) - (and buffer-offer-save (> (buffer-size) 0))))) + (and buffer-offer-save (> (buffer-size) 0)))) + (buffer-local-value + 'write-contents-functions buffer)) (or (not (functionp pred)) (with-current-buffer buffer (funcall pred))) (if arg -- 2.13.0 --=-=-=--