home *** CD-ROM | disk | FTP | other *** search
- ;; capture.el -- functions to capture the state of an emacs session
- ;; This is file 1 of two files in the "regression" part of the "test" package.
- ;; See also achieve.el
- ;; Carl Lagoze, Franklin Davis
- ;; Copyright 1987 Wang Institute of Graduate Studies
- ;; $Header: tst-capture.el,v 1.21 87/07/29 17:24:58 davis Exp $
-
- (provide 'tst-capture)
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; some utilities
-
- (defmacro cadr (l)
- (list 'car (list 'cdr l)))
-
- (defun member (elt list)
- "Returns non-nil if ELT is an element of LIST. Comparison done with equal.
- The value is actually the tail of LIST whose car is ELT."
- (while (and list (not (equal elt (car list))))
- (setq list (cdr list)))
- list)
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; variables
-
- (defvar tst-vars-exclude-default (list "values" "obarray")
- "* Default list of global variable names to be excluded by
- tst-capture-state and tst-capture-state-to-file")
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; the interactive functions
-
- (defun tst-capture-state-to-file (file bufs-list vars-exclude)
- "Write the current state of the emacs session to FILE.
- BUFS-LIST is a list of buffer names to capture; if nil all buffers
- will be captured.
- VARS-EXCLUDE is a list of global variables to exclude. See
- tst-capture-state for documentation."
- (interactive "FFile name to write current state to:
- xList of buffers to capture (nil for all):
- xList global vars to exclude (all; none; nil for default excl. list): ")
- (let (state)
- (tst-capture-state 'state bufs-list vars-exclude)
- (tst-write-state-to-file state file)
- ) ;let
- ) ;defun tst-capture-state-to-file
-
- (defun tst-write-state-to-file (state file)
- "Write variable STATE containing captured emacs session state to FILE."
- (interactive "XState Name: \nFFile name to write state to: ")
- (let ()
- (message "Writing state to file...")
- (save-excursion
- (switch-to-buffer (make-temp-name "state"))
- (prin1 state (current-buffer))
- (write-file file)
- (kill-buffer (current-buffer))
- ) ; save-excursion
- ) ; let
- ) ; defun tst-write-state-to-file
-
-
- (defun tst-capture-state (statevar bufs-list vars-exclude)
- "Set variable STATE to the current state of the emacs session.
- BUFS-LIST is a list of buffer names to capture; if nil all buffers
- will be captured.
- VARS-EXCLUDE is a list of global variables to exclude;
- if value is nil, default list tst-vars-exclude-default will be used;
- if value is 'all' all global variables will be excluded (not captured);
- if value is 'none' no global variables will be excluded (everything captured).
- nil is returned in place of excluded variable if it exists.
-
- An exclude-list rather than an include-list is used because it's
- most important to exclude particularly nasty variables. Would be nice to
- extend this to have an include-list; perhaps also reg-exp for buffer names."
- (interactive "SState Variable:
- xList of buffers to capture (nil for all):
- xList global vars to exclude (all; none; nil for default excl. list): ")
- (let ()
- (makunbound statevar) ; don't want to capture old state var.
- (if (not (listp bufs-list))
- (error "Buffer-list must be a list of strings or nil")
- ) ; if
- (set statevar (list (tst-capture-globals-state vars-exclude)
- (tst-capture-processes-state)
- (tst-capture-buffers-state bufs-list)
- (tst-capture-windows-state)
- ))
- (message "Capturing state...done")
- ) ;let
- ) ;defun tst-capture-state
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; globals capture
-
- (defun tst-capture-globals-state (vars-exclude)
- "Capture global attributes of an Emacs session.
- VARS-EXCLUDE is a list of global variables to exclude;
- if value is nil, default list tst-vars-exclude-default will be used;
- if value is 'all' all global variables will be excluded (not captured);
- if value is 'none' no global variables will be excluded (everything captured)."
- (let ()
- (message "Capturing state of globals...")
- (cond ((null vars-exclude)
- (setq vars-exclude tst-vars-exclude-default))
- ((equal vars-exclude 'none) (setq vars-exclude nil))
- )
- (list 'session
- (list
- (if (equal vars-exclude 'all)
- nil
- ; else
- (tst-capture-global-syms-state vars-exclude))
- ;; (tst-capture-recursive-level-state)
- ) ; list
- ) ;list 'session
- ) ;let
- ) ;defun tst-capture-globals-state
-
- (defun tst-capture-global-syms-state (vars-exclude)
- "Return the names and values of all global variables except VARS-EXCLUDE
- as a single element a-list with the key 'global-vars. The second element
- of the alist is a list of two element lists. Each two element list
- consists of a global variable name and its value."
- (list 'global-bound-syms
- (delq nil ; remove "nil" from results
- (mapcar
- ; the lambda here allows
- ; mapcar to pass a second
- ; argument vars-exclude to
- ; function
- ; tst-get-bound-val-from-string
- ; while applying it to every
- ; element in list (all-completions...)
- '(lambda (sym-string)
- (tst-get-bound-val-from-string sym-string vars-exclude))
- (all-completions "" obarray 'boundp))
- ) ; delq
- ) ; list
- ) ; defun tst-capture-global-vars-state
-
- (defun tst-get-bound-val-from-string (sym-string vars-exclude)
- "Given a SYMBOL-NAME return a cons of the symbol and its value. The cons
- looks like (symbol . value). Note that storing new values in this cons does
- not change the symbol's value. Returns nil if SYMBOL-NAME in VARS-EXCLUDE."
- (cond ((not (stringp sym-string)) nil)
- ((member sym-string vars-exclude) nil) ; return nil for excluded vars
- (t (cons (car (read-from-string sym-string))
- (tst-convert-compound-symbols
- (eval (car (read-from-string sym-string))))))
- ) ; cond
- ) ;defun tst-get-bound-val-from-string
-
- (defun tst-convert-compound-symbols (sym)
- "Given a SYMBOL, convert all marker or process objects to descriptions
- of these objects. SYMBOL may be a list or atom or dotted pair."
- (cond ((null sym) sym)
- ((vectorp sym) sym)
- ((numberp sym) sym)
- ((and (listp sym)
- (atom (cdr sym))
- (cdr sym)) ; be sure it's not nil
- (cons ; sym is a dotted pair
- (tst-convert-compound-symbols (car sym))
- (tst-convert-compound-symbols (cdr sym))))
- ((and (listp sym) (atom (car (cdr sym)))) ; simple list
- (mapcar 'tst-convert-compound-symbols sym))
- ((atom sym)
- (cond ((markerp sym) (tst-convert-marker-symbol sym))
- ((processp sym) (tst-convert-process-symbol sym))
- ((windowp sym) (list 'window
- (tst-capture-window-state sym nil)))
- (t sym) ; not a complex object
- ) ; cond
- )
- (t sym)
- ) ; cond
- ) ; defun tst-convert-compound-symbols
-
-
- ;;; the following function is not used, but could be if someone wanted this
- (defun tst-capture-recursive-level-state ()
- "Capture the current recursive editing state (only the level)"
- (let ()
- (list 'recursive-level (recursion-depth))
- ) ;let
- ) ;tst-capture-recursive-level-state
-
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; processes
-
- (defun tst-capture-processes-state ()
- "Capture processes attributes of an EMACS session"
- (message "Capturing state of processes...")
- (list 'processes (tst-convert-compound-symbols (process-list)))
- ) ;defun tst-capture-processes-state
-
- (defun tst-convert-process-symbol (p)
- "Convert a process object into a list ('process <process-command>
- <process-exit-status> <process-filter> <process-name> <process-sentenel>
- <process-status>"
- (if (processp p)
- (list
- 'process
- (list 'buffer (if (process-buffer p) (buffer-name (process-buffer p))
- nil))
- (list 'process-mark (tst-convert-marker-symbol (process-mark p)))
- (list 'command (process-command p))
- (list 'exit-status (process-exit-status p))
- (list 'filter (process-filter p))
- (list 'name (process-name p))
- (list 'sentinel (process-sentinel p))
- (list 'status (process-status p))
- ) ; list
- ) ;if
- ) ;defun tst-convert-process-symbol
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; buffers
-
- (defun tst-capture-buffers-state (capture-bufs-list)
- "Return the states of all the active buffers in this session as a
- single element a-list with the key 'buffers. The second element of the
- alist is a list, each element of which is the state of an active buffer."
- ; Local Variables
- (let ((bufflist) (buff-state))
- (message "Capturing state of buffers...")
- (setq bufflist (buffer-list))
- (save-excursion
- (while bufflist
- (if (or (null capture-bufs-list) ; get all if no capture-bufs-list
- ; or get this buffer if in list
- (member (buffer-name (car bufflist)) capture-bufs-list))
- (progn
- (set-buffer (car bufflist))
- (setq buff-state
- (append buff-state
- (list (tst-capture-buffer-state))))
- ) ; progn
- ) ; if
- (setq bufflist (cdr bufflist))
- ) ; while
- ) ; save-excursion
- (cons 'buffers (list buff-state))
- ) ; let
- ) ; defun tst-capture-buffers-state
-
-
- (defun tst-capture-buffer-state ()
- "Return the state of the current buffer. The state is returned as an
- a-list"
- ; Local Variables
- (let ()
- (list
- (list 'buf-state-name (buffer-name))
- (list 'buf-state-file (buffer-file-name))
- (list 'buf-state-point (point))
- (list 'buf-state-mark (mark))
- (list 'buf-state-contents (buffer-string))
- (list 'buf-state-modified (buffer-modified-p))
- (list 'buf-state-local-map (current-local-map))
- (list 'buf-state-local-vars
- (mapcar 'tst-convert-compound-symbols (buffer-local-variables)))
- ) ; list
- ) ; let
- ) ; defun tst-capture-buffer-state
-
-
- (defun tst-convert-marker-symbol (marker-symbol)
- "Convert a marker object into a list (marker <point-value> <buffer>)"
- (if (markerp marker-symbol)
- (list
- 'marker
- (list 'position (marker-position marker-symbol))
- (if (null (marker-position marker-symbol)) nil ; no buf name if nil pos.
- (list 'buffer (buffer-name (marker-buffer marker-symbol))))
- ) ; list
- ) ; if
- ) ;defun tst-convert-marker-symbol
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; windows
-
- (defun tst-capture-windows-state ()
- "Return the state of emacs windows as a two element a-list. The first
- element is the key 'windows. The second element is a list
- representation of the binary tree abstraction of the window state. This
- tree is built by walking the windows (starting at the window positioned
- at 0,0) and doing a shift-reduce parse on the window-list. This parse
- has two productions:
- 0: reduce two windows to a combined window when their top/bottom
- edges are common.
- 1: reduce two windows to a combined window when their right/left
- edges are common.
- The parser has three states:
- 0: The start state. The stack is empty
- 1: 1 element on the stack
- 2: >1 element on the stack"
- (let ((stack) (state) (cur-window))
- (message "Capturing state of windows...")
- (save-window-excursion
- (setq cur-window (selected-window))
- (while (not (equal '(0 0) ;go to the upper left window
- (list (car (window-edges)) (cadr (window-edges)))))
- (select-window (next-window))
- ) ;while
- ;always shift first window
- (setq stack (tst-shift-window-stack stack cur-window))
- (setq state 1) ;state 1 when 1 element on stack
- ; At this point the base (0,0) window is on the stack and we are in
- ; state 1. Loop until we return to the condition where the state is
- ; 1 and the next window is the base window (reduced to the final state)
- (while (not (and (equal '(0 0)
- (list
- (car (window-edges (next-window)))
- (cadr (window-edges (next-window)))
- )
- )
- (= state 1)
- ))
- (if (= state 1) ;always shift
- (progn
- (select-window (next-window))
- (setq stack (tst-shift-window-stack stack cur-window))
- (setq state 2)
- ) ;progn
- (progn ;state 2
- (if (equal
- (tst-get-window-bottom-edge (cadr stack))
- (tst-get-window-top-edge (car stack)))
- (progn ;reduce by v rule
- (setq stack (tst-reduce-window-stack stack 'v))
- (if (= 1 (length stack))
- (progn
- (setq state 1)
- ) ;progn
- ) ;if
- ) ;progn
- (progn
- (if (equal
- (tst-get-window-right-edge (cadr stack))
- (tst-get-window-left-edge (car stack)))
- (progn
- (setq stack (tst-reduce-window-stack stack 'h))
- (if (= 1 (length stack))
- (progn
- (setq state 1)
- ) ;progn
- ) ;if
- )
- (progn
- (select-window (next-window))
- (setq stack (tst-shift-window-stack stack cur-window))
- ) ;progn
- ) ;if equal left and right edge
- ) ;progn-else of if top and bottom equal
- ) ;if equal top and bottom edge
- ) ;progn - state 2
- ) ;if equal state 1
- ) ;while not accept state
- ) ;save window excursion
- (list 'windows (car stack))
- ) ;let
- ) ;defun tst-capture-windows-state
-
- (defun tst-shift-window-stack (stack cur-window)
- "Perform a shift in the LR parse of the window configuration tree (i.e. put
- the state of the current window on top of the parse stack"
- (let ()
- (cons (tst-capture-window-state (selected-window) cur-window) stack)
- ) ;let
- ) ;shift-window-state
-
- (defun tst-reduce-window-stack (stack rule)
- "Perform a reduce in the LR parse of the window configuration tree. A reduce
- always pops two elements off the parse stack and pushes a new element that
- is a description of the 'combined' elements that were popped. The input
- argument rule is either 'v' if the two items at the top of the stack were
- split vertically, or 'h' if the two items at the top of the stack were
- split horizontally"
- (let ((wstatet) (wstatet-1) (combined) (edgest) (edgest-1))
- (setq wstatet (car stack))
- (setq wstatet-1 (cadr stack))
- (setq stack (cdr (cdr stack)))
- (setq combined (list
- (list 'children (list wstatet-1 wstatet))
- (list 'split rule)))
- (setq edgest (cadr (assoc 'window-edges wstatet)))
- (setq edgest-1 (cadr (assoc 'window-edges wstatet-1)))
- (setq combined (cons (list 'window-edges (list
- (car edgest-1)
- (cadr edgest-1)
- (cadr (cdr edgest))
- (cadr (cdr (cdr edgest)))
- )
- )
- combined))
-
- (setq stack (cons combined stack))
- ) ;let
- ) ;defun tst-reduce-window-stack
-
- (defun tst-get-window-top-edge (wstate)
- "Return the coordinates of the top edge of input window as a three element
- list consisting of (left-column row right-column)"
- (let ((edges))
- (setq edges (cadr (assoc 'window-edges wstate)))
- (list (car edges) (cadr edges) (cadr (cdr edges)))
- ) ;let
- ) ;defun tst-reg-get-top-edge
-
- (defun tst-get-window-bottom-edge (wstate)
- "Return the coordinates of the bottom edge of nput window as a three element
- list consisting of (left-column row right-column)"
- (let ((edges))
- (setq edges (cadr (assoc 'window-edges wstate)))
- (list (car edges) (cadr (cdr (cdr edges))) (cadr (cdr edges)))
- ) ;let
- ) ;defun tst-reg-get-top-edge
-
- (defun tst-get-window-left-edge (wstate)
- "Return the coordinates of the left edge of input window as a three element
- list consisting of (top-row column bottom-row)"
- (let ((edges))
- (setq edges (cadr (assoc 'window-edges wstate)))
- (list (cadr edges) (car edges) (cadr (cdr (cdr edges))))
- ) ;let
- ) ;defun tst-reg-get-left-edge
-
- (defun tst-get-window-right-edge (wstate)
- "Return the coordinates of the right edge of input window as a three element
- list consisting of (top-row column bottom-row)"
- (let ((edges))
- (setq edges (cadr (assoc 'window-edges wstate)))
- (list (cadr edges) (cadr (cdr edges)) (cadr (cdr (cdr edges))))
- ) ;let
- ) ;defun tst-reg-get-right-edge
-
- (defun tst-capture-window-state (window cur-window)
- "Return the state of the window as an a-list."
- (let ()
- (list
- (list 'window-edges (window-edges))
- (list 'window-buffer (buffer-name))
- (list 'window-start (window-start))
- (list 'window-point (window-point))
- (list 'current-window (equal window cur-window))
- )
- )
- )
-
-