;;; winhist.el --- window configuration history ;; Copyright 1997 Bob Glickstein. ;; Author: Bob Glickstein ;; Maintainer: Bob Glickstein ;; Version: 3.0 ;; 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. ;;; 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-timer nil) (defvar winhist-delay .125 "*Seconds after Emacs becomes idle before recording window configuration.") (defvar winhist-frames nil "Alist of the form ((frame . (ring . index)) ...).") (defvar winhist-ring-size 100 "*How many window configurations to automatically remember.") (defvar winhist-mode nil) (defvar winhist-traversing nil) (defvar winhist-changed nil) ;; This function goes in window-configuration-change-hook. (defsubst winhist-notice-change () (setq winhist-changed (selected-frame))) ;; This function goes in post-command-hook. (defun winhist-maybe-record-configuration () (if (and winhist-changed winhist-mode (not winhist-traversing) (not (window-minibuffer-p (selected-window)))) (let ((entry (assq winhist-changed winhist-frames))) (unless entry (setq entry (cons winhist-changed (cons (make-ring winhist-ring-size) 0)) winhist-frames (cons entry winhist-frames))) (ring-insert (car (cdr entry)) (current-window-configuration)) (setcdr (cdr entry) 0))) (setq winhist-changed nil) (setq winhist-traversing nil)) (defun winhist-traverse (&optional n) "Move backward through the window configuration history by N entries." (interactive "p") (let ((entry (assq (selected-frame) winhist-frames)) ring index conf) (unless entry (error "No window history for this frame.")) (setq ring (car (cdr entry)) index (+ n (cdr (cdr entry))) conf (ring-ref ring index) winhist-traversing t) (setcdr (cdr entry) index) (when conf (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))) (when winhist-timer (cancel-timer winhist-timer) (setq winhist-timer nil)) (if winhist-mode (if (boundp 'window-configuration-change-hook) (progn (add-hook 'window-configuration-change-hook 'winhist-notice-change) (setq winhist-timer (run-with-idle-timer winhist-delay t 'winhist-maybe-record-configuration))) (progn (setq winhist-mode nil) (error "This version of Emacs does not have `window-configuration-change-hook'"))) (setq winhist-frames nil) (remove-hook 'window-configuration-change-hook 'winhist-notice-change))) (provide 'winhist) ;;; winhist.el ends here