all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: "Stuart D. Herring" <herring@lanl.gov>
Cc: emacs-devel@gnu.org, Mathias Dahl <mathias.dahl@gmail.com>
Subject: Re: Missing `with' macro?
Date: Thu, 27 Jul 2006 19:14:10 -0700 (PDT)	[thread overview]
Message-ID: <33776.128.165.123.18.1154052850.squirrel@webmail.lanl.gov> (raw)
In-Reply-To: <E1G554h-0002Ol-5n@fencepost.gnu.org>

[-- Attachment #1: Type: text/plain, Size: 896 bytes --]

> To develop a general macro for this would be useful.  It is not a
> trivial thing.  Please start working on it if you want.  The case of
> just examining a file without altering it, since that is more common,
> and easier.  I suspect that we may need two totally different macros
> for the read-only case and the case of altering the file.

I've implemented a first draft of this, complete with file-writing
capacity in the same macro: see the attached file and please comment.  (In
particular, is there a clean way to silence `save-buffer' or the
equivalent?)  I still don't quite have papers, but I am led to believe
that it will happen Real Soon Now; since this isn't going into this
release AFAIK, I hope that's not a problem.

Davis

-- 
This product is sold by volume, not by mass.  If it appears too dense or
too sparse, it is because mass-energy conversion has occurred during
shipping.

[-- Attachment #2: with-file.el --]
[-- Type: application/octet-stream, Size: 5120 bytes --]

(put 'hide-message 'lisp-indent-function 0)
(defmacro hide-message (&rest body)
	"Execute BODY, then restore the previous contents of the echo area.
Messages produced by BODY are not logged."
	(let ((pm-sym (make-symbol "prev-msg")))
		`(let ((,pm-sym (current-message)) message-log-max)
			 ,@body
			 (message ,pm-sym))))

(put 'with-file 'lisp-indent-function 4)
(defmacro with-file (file visit reuse write &rest body)
	"Execute the forms in BODY in a buffer with FILE's text loaded.
Point begins at the beginning of the buffer, which is not narrowed.
The value returned is the value of the last form in BODY.

VISIT t means actually visit the file, loading its appropriate major mode and
local variables and such.  VISIT nil means do none of these things; BODY will
be executed in a buffer with the contents of FILE but that is visiting no
file.  Any other value for VISIT works like nil except that the file is read
literally (see `insert-file-contents-literally').

REUSE non-nil means to use an existing buffer if it is visiting FILE.  (The
value of `find-file-existing-other-name' affects this determination.)  The
buffer will only be re-used if its literal status (see `find-file-literally')
matches the literal status requested by VISIT.  Note that reusing a buffer may
mean that the text on which BODY operates differs from the actual contents of
FILE.

WRITE non-nil means to modify the file; if the BODY finishes normally, then
the buffer is saved if the file was visited or written otherwise.  If WRITE is
neither t nor nil, saving messages are suppressed.  The buffer will be
read-only when BODY is executed iff WRITE is nil.

If a buffer is created in the execution of this macro, it is killed when it
finishes (even in the case of abnormal exit), regardless of any unsaved
changes made."
	(let ((file-sym (make-symbol "file"))
				(visit-sym (make-symbol "visit"))
				(raw-sym (make-symbol "raw"))
				(reuse-sym (make-symbol "reuse"))
				(write-sym (make-symbol "write"))
				(quiet-sym (make-symbol "quiet"))
        (extant-sym (make-symbol "extant"))
        (extant-file-sym (make-symbol "extant-file"))
        (buf-sym (make-symbol "buf"))
				(reused-sym (make-symbol "reused"))
				(bro-sym (make-symbol "buf-readonly")))
		`(let* ((,file-sym ,file)
						(,visit-sym ,visit)
						(,raw-sym (and ,visit-sym (not (eq ,visit-sym t))))
						(,reuse-sym ,reuse)
						(,write-sym ,write)
						(,quiet-sym (and ,write-sym (not (eq ,write-sym t))))
						(,extant-sym (if find-file-existing-other-name
														 (find-buffer-visiting ,file-sym)
													 (get-file-buffer ,file-sym)))
						(,extant-file-sym (and ,extant-sym (buffer-file-name ,extant-sym)))
						(,buf-sym
						 (or (and ,reuse-sym ,extant-sym
											(eq (not (with-current-buffer ,extant-sym
																 find-file-literally))
													(not ,raw-sym))
											,extant-sym)
								 (if (eq ,visit-sym t)
										 (progn
											 ;; We need to pretend that any other visiting buffer
											 ;; doesn't actually exist.
											 (if ,extant-sym
													 (with-current-buffer ,extant-sym
														 (setq buffer-file-name nil)))
											 (find-file-noselect ,file-sym t))
									 (with-current-buffer (generate-new-buffer "*with-file*")
										 (if (eq ,visit-sym nil)
												 (insert-file-contents ,file-sym)
											 (insert-file-contents-literally ,file-sym))
										 (current-buffer)))))
						(,reused-sym (eq ,buf-sym ,extant-sym))
						(,bro-sym (with-current-buffer ,buf-sym buffer-read-only)))
			 (with-current-buffer ,buf-sym
				 (unwind-protect
						 (save-excursion
							 (save-restriction
								 (widen)
								 (goto-char (point-min))
								 ;; We don't just let-bind buffer-read-only because that
								 ;; interacts poorly with switching buffers.
								 (setq buffer-read-only (not ,write-sym))
								 (prog1 (save-current-buffer ,@body)
									 (and (buffer-live-p ,buf-sym) ,write-sym
												(if (or ,reused-sym (eq ,visit-sym t))
														(if ,quiet-sym (hide-message (save-buffer))
															(save-buffer))
													(let ((coding-system-for-write
																 (if ,raw-sym 'no-conversion
																	 coding-system-for-write)))
														(widen)
														(write-region (point-min) (point-max) ,file-sym nil
																					(if ,quiet-sym 'lambda))))))))
					 (when (buffer-live-p ,buf-sym)
						 (setq buffer-read-only ,bro-sym)
						 (unless ,reused-sym
							 (set-buffer-modified-p nil)
							 (kill-buffer nil)))
					 (when (buffer-live-p ,extant-sym)
						 (with-current-buffer ,extant-sym
							 (setq buffer-file-name ,extant-file-sym))))))))

(defun with-file-test (file arg)
	"Test `with-file' by inserting at the beginning of FILE.
Use 'silent with prefix ARG.  Use 'raw with two C-u's."
	(interactive "f\nP")
	(with-file file (if (equal arg '(16)) 'raw t) nil (if arg 'silent t)
		(insert "foo\n")
		;; Print some multibyte stuff to demonstrate the action of literal mode.
		(message "%S" (and (re-search-forward "[^\0-\d]" nil t)
											 (match-string 0)))))

[-- Attachment #3: Type: text/plain, Size: 142 bytes --]

_______________________________________________
Emacs-devel mailing list
Emacs-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/emacs-devel

  parent reply	other threads:[~2006-07-28  2:14 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-07-24 10:17 Missing `with' macro? Mathias Dahl
2006-07-24 13:46 ` Stefan Monnier
2006-07-24 14:33   ` Mathias Dahl
2006-07-24 18:22 ` Richard Stallman
2006-07-24 20:55   ` Jorgen Schaefer
2006-07-25  3:09     ` Richard Stallman
2006-07-28  2:14   ` Stuart D. Herring [this message]
2006-07-28  2:23     ` Stuart D. Herring
2006-07-29 15:18     ` Richard Stallman
2006-08-01  1:06       ` Stuart D. Herring
2006-08-07  5:01         ` Richard Stallman
2006-08-07 21:38           ` Stuart D. Herring
2006-08-08 18:01             ` Richard Stallman
2006-08-08 18:32               ` Stuart D. Herring
2006-08-09  4:58                 ` Richard Stallman
2006-08-08 18:01             ` Richard Stallman
2006-08-16 19:59               ` Stuart D. Herring
2006-08-17 15:18                 ` Richard Stallman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=33776.128.165.123.18.1154052850.squirrel@webmail.lanl.gov \
    --to=herring@lanl.gov \
    --cc=emacs-devel@gnu.org \
    --cc=mathias.dahl@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.