[comp.emacs] em-config.el - Save GNU Emacs buffer configurations between sessions.

weiner@novavax.UUCP (Bob Weiner) (09/26/89)

The wealth of generally useful GNU Emacs lisp code posted to this group
has dried up recently.  I thought I would start the flow again with this
posting.

This represents a prototype of a package that I never finished but that
became useful enough that I decided to post it.  The active code works
well, the unfinished parts are commented out and may be disregarded
unless you would like to extend the package.  Since it was a prototype,
the actual implementation has not been optimized at all.

Basically, it restores all buffers including major-modes, point
positions, and visible region bounds between sessions, giving you a
working context from day to day.  Note also the 'emc-start-file'
variable which may specify the first file that you always want to see in
an Emacs session (set it in your own init file).

Enjoy.

;;
;; FILE:         em-config.el
;; SUMMARY:      Save and restore Emacs configurations between sessions.
;; USAGE:        GNU Emacs Lisp Library
;;
;; AUTHOR:       Bob Weiner
;; ORG:          Motorola, Inc., Communications Sector, Applied Research
;; E-MAIL:       USENET:  weiner@novavax.UUCP
;;
;; ORIG-DATE:    22-Aug-89 at 16:07:48
;; LAST-MOD:     25-Sep-89 at 17:42:37 by Bob Weiner
;;
;; Copyright (C) 1989 Bob Weiner and Free Software Foundation, Inc.
;; Available for use and distribution under the same terms as GNU Emacs.
;;
;; This file is not part of GNU Emacs.
;;
;; DESCRIPTION:  
;;
;;   Currently saves only unmodified buffers visiting files.  Also
;;   saves only limited information about buffers.  It may not work
;;   properly with subsystem buffers that visit files.  It is best to
;;   kill these before saving a configuration.
;;
;;   The exceptions are that:
;;     An Info buffer is handled properly, so it need not be deleted.
;;     Any buffer in rmail-mode is not saved.  Thus, when 'rmail' is
;;     invoked it works properly.
;;
;;   To enable reading of Emacs state from last session at the start
;;   of a new session, put the following in your personal Emacs init file:
;;
;;          (load-library "em-config")
;;          (emc-restore)
;;
;;   Follow the above with this code to enable saving of Emacs state
;;   when quitting a session:
;;
;;         (defun save-buffers-kill-emacs (&optional arg)
;;            "Offer to save each buffer, save file configuration, then kill this Emacs fork.
;;         With prefix arg, silently save all file-visiting buffers, then kill."
;;           (interactive "P")
;;           (save-some-buffers arg t)
;;           (emc-save)
;;           (kill-emacs))
;;
;; DESCRIP-END.

(defconst emc-file "~/.em-config"
  "Default file into which to save Emacs session data.")

(defconst emc-start-file nil
  "Last file to read in each time the default Emacs configuration is loaded.
This makes it the first file seen by the user.")

(defun emc-save ()
  (interactive)
  (let ((standard-output (set-buffer (find-file-noselect emc-file))))
    (erase-buffer)
;;; (emc-save-session-data)
    (emc-save-buffer-data)
;;; (emc-save-window-data)
    (set-buffer standard-output)
    (save-buffer)
    ))

(defun emc-restore (&optional file)
  "Restore emacs configuration from optional FILE or 'emc-file'.
Adds buffers to current buffer list.  Returns t if the file is found,
otherwise nil."
  (interactive)
  (or file (setq file emc-file))
  (if (file-exists-p file)
      (let ((standard-input (set-buffer (find-file-noselect emc-file))))
	(goto-char (point-min))
;;;	(emc-restore-session-data)
	(emc-restore-buffer-data)
;;;     (emc-restore-window-data)
	(kill-buffer standard-input)
	(and emc-start-file (equal file emc-file)
	     (file-exists-p emc-start-file) (find-file emc-start-file))
	t)))

(defun buffer-major-mode= (buf mode)
  (eq (cdr (assq 'major-mode (buffer-local-variables buf))) mode))

(defun emc-save-buffer-data ()
  ;; Save only buffers visiting files; skip some in special modes.
  (let ((buf-list (mapcar '(lambda (buf)
			     (let ((bn (buffer-name buf)))
			       (if (and (not (buffer-major-mode= buf 'Info-mode))
					(or (null (buffer-file-name buf))
					    (string-match "^[ \*].*\*$" bn)
					    (buffer-major-mode= buf 'rmail-mode)
					    (equal bn (buffer-name
							standard-output))))
				   nil
				 bn)))
			  (reverse (buffer-list)))))
    (print buf-list)
    (mapcar '(lambda (buf)
	       (if (null buf)
		   nil
		 (set-buffer buf)
		 (if (eq major-mode 'Info-mode)
		     (progn (print major-mode)
			    (print Info-current-file)
			    (print Info-current-node)
			    (print (point)))
		   (print major-mode)
		   (print (buffer-name))
		   (print (buffer-file-name))
		   (print buffer-read-only)
		   (print (point))
		   (print (point-min))
		   (print (point-max)))
		 ))
	    buf-list)
    ))

(defun emc-restore-buffer-data ()
  (let ((buf-list (read))
	(buf-name) (file) (mode)
	(buf-read-only) (point)
	(point-min) (point-max)
	(mark-list))
    (mapcar '(lambda (buf)
	       (if (null buf)
		   nil
		 (setq mode (read))
		 (if (eq mode 'Info-mode)
		     (progn (info)
			    (Info-find-node (read) (read))
			    (goto-char (read)))
		   (setq buf-name (read)
			 file (read)
			 buf-read-only (read)
			 point (read)
			 point-min (read)
			 point-max (read))
		   (if (file-exists-p file)
		       (progn (find-file file)
			      (setq buffer-name buf-name
				    buffer-read-only buf-read-only)
			      (and mode (funcall mode))
			      (if (<= point (point-max))
				  (goto-char point))
			      (if (<= point-max (point-max))
				  (narrow-to-region point-min point-max)))))))
	    buf-list)
;;
;; Might want to do stuff and set buffer local variables from src/buffer.c.
;;
    ))


;;; Often won't work properly when used with an external window system.
;;; 
;;; (defun emc-save-session-data ()
;;;   (print (screen-height))
;;;   (print (screen-width))
;;;   )
;;; 
;;; (defun emc-restore-session-data ()
;;;   (set-screen-height (read))
;;;   (set-screen-width (read)))

;;; Not finished; emc-save-window-data does not seem to work properly.
;;;
;;; (defun emc-save-window-data ()
;;;   (let ((first-window (selected-window))
;;; 	(curr-window)
;;; 	(again t))
;;;     (set-buffer standard-output)
;;;     (goto-char (point-max))
;;;     (select-window first-window)
;;;     (while again
;;;       (let ((bn (buffer-name)))
;;; 	(if (or (string-match "^[ \*].*\*$" bn)
;;; 		(equal bn (buffer-name standard-output)))
;;; 	    nil
;;; 	  (print (buffer-file-name))
;;; 	  (print (buffer-name))
;;; 	  (print (window-edges))
;;; 	  (print (window-point))
;;; 	  (print (window-start))
;;; 	  (print (window-hscroll))))
;;;       (select-window (setq curr-window (next-window nil 1)))
;;;       (setq again (not (eq curr-window first-window))))))
;;; 
;;; (defun emc-restore-window-data (buf)
;;;   (let ((standard-input buf))
;;;     (find-file (read buf))
;;;     (setq buffer-name (read buf))
;;; ;;    (read <window-edges>)
;;;     (set-window-point (read buf))
;;;     (set-window-start (read buf))
;;;     (set-window-hscroll (read buf))))
;;; 

;; TO DO: save window configs ring



(provide 'em-config)
-- 
Bob Weiner, Motorola, Inc.,   USENET:  ...!gatech!uflorida!novavax!weiner
(407) 738-2087

bob@MorningStar.COM (Bob Sutterfield) (09/27/89)

In article <1502@novavax.UUCP> weiner@novavax.UUCP (Bob Weiner) writes:
   The wealth of generally useful GNU Emacs lisp code posted to this
   group has dried up recently.

That's probably because it's mostly moved over to gnu.emacs/info-gnu-emacs.

   I thought I would start the flow again with this posting.

Bravo!