Path: news2.funet.fi!news.eunet.fi!EU.net!howland.erols.net!infeed2.internetmci.com!newsfeed.internetmci.com!news.wco.com!not-for-mail
From: Bob Glickstein <bobg@hiro.zanshin.com>
Newsgroups: gnu.emacs.sources
Subject: winhist-mode v2.1 (was Re: winhist-mode v1.0)
Date: 22 Jul 1997 15:53:48 -0700
Organization: Zanshin Inc., Marin County, CA
Lines: 131
Message-ID: <m1yb6yitqb.fsf@hiro.zanshin.com>
References: <m190z0wdn6.fsf@hiro.zanshin.com>
Reply-To: Bob Glickstein <bobg@zanshin.com>
NNTP-Posting-Host: gw.zanshin.com
X-Attribution: BG
X-Newsreader: Gnus v5.5/Emacs 20.0
Xref: news2.funet.fi gnu.emacs.sources:6240

RMS pointed out to me the existence of winner-mode, which is very much
like winhist-mode.  But I still like winhist-mode better.  I stole one
good idea from winner-mode, that of only recording the window
configuration once per command loop.  Here's the new version.


;;; winhist.el --- window configuration history

;; Copyright 1997 Bob Glickstein.      <http://www.zanshin.com/~bobg/>

;; Author: Bob Glickstein <bobg@zanshin.com>
;; Maintainer: Bob Glickstein <bobg@zanshin.com>
;; Version: 2.1

;; This file is not part of GNU Emacs.

;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published
;; by the Free Software Foundation; either version 2, or (at your
;; option) any later version.

;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, send e-mail to
;; this program's maintainer or write to the Free Software Foundation,
;; Inc., 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA.

;;; Plug:

;; Check out my book, "Writing GNU Emacs Extensions," from O'Reilly
;; and Associates.  <http://www.ora.com/catalog/gnuext/>

;;; Commentary:

;; `winhist-mode' is a global mode that records every change to the
;; window configuration in a "ring" (like the yank ring or the mark
;; ring).  It is then possible to step backward and forward through
;; the history of window configurations.  I find this to be valuable
;; for restoring mental context when working on a complex project.

;; This works imperfectly because of vagaries in the way buffers and
;; windows are connected and manipulated by various packages.  In
;; particular, sometimes several consecutive window configurations in
;; the history may seem to be identical.  But it's better than
;; nothing, and I also like it better than some packages that require
;; you to remember to save and possibly name a window configuration
;; before restoring it.

;; To use this package, add
;;  (require 'winhist)
;;  (winhist-mode 1)
;; to your .emacs.  You should then bind keysequences to the commands
;; `winhist-backward' and `winhist-forward'.  I prefer:
;;  (global-set-key "\M-B" 'winhist-backward)
;;  (global-set-key "\M-F" 'winhist-forward)

;;; Code:

(require 'ring)

(defvar winhist-ring-size 100
  "*How many window configurations to automatically remember.")
(defvar winhist-mode nil)
(defvar winhist-ring nil)
(defvar winhist-ring-index 0)
(defvar winhist-traversing nil)
(defvar winhist-changed nil)

;; This function goes in window-configuration-change-hook.
(defsubst winhist-notice-change ()
  (setq winhist-changed t))

;; This function goes in post-command-hook.
(defun winhist-maybe-record-configuration ()
  (if (and winhist-changed
	   winhist-ring
	   (not winhist-traversing)
	   (not (window-minibuffer-p (selected-window))))
      (progn
	(setq winhist-ring-index 0)
	(ring-insert winhist-ring (current-window-configuration))))
  (setq winhist-changed nil
	winhist-traversing nil))

(defun winhist-traverse (&optional n)
  "Move backward through the window configuration history by N entries."
  (interactive "p")
  (let* ((index (+ winhist-ring-index n))
	 (conf (ring-ref winhist-ring index)))
    (setq winhist-ring-index index
	  winhist-traversing t)
    (if conf
	(progn
	  (set-window-configuration conf)
	  (message "Window history: %d" index)))))

(defalias 'winhist-backward 'winhist-traverse)

(defsubst winhist-forward (&optional n)
  "Move forward through the window configuration history by N entries."
  (interactive "p")
  (winhist-traverse (- n)))

(defun winhist-mode (&optional arg)
  "Toggle recording of window configuration changes.
With optional ARG, turn winhist-mode on iff positive, off otherwise.
The number of window configurations that are memorized is controlled
by `winhist-ring-size'.
To traverse the window configuration history, use \\[winhist-backward]
and \\[winhist-forward]."
  (interactive "P")
  (setq winhist-mode
	(if (null arg)
	    (not winhist-mode)
	  (> (prefix-numeric-value arg) 0)))
  (if winhist-mode
      (progn
	(setq winhist-ring (make-ring winhist-ring-size))
	(add-hook 'window-configuration-change-hook 'winhist-notice-change)
	(add-hook 'post-command-hook 'winhist-maybe-record-configuration))
    (setq winhist-ring nil)
    (remove-hook 'window-configuration-change-hook 'winhist-notice-change)
    (remove-hook 'post-command-hook 'winhist-maybe-record-configuration)))

(provide 'winhist)

;;; winhist.el ends here
