home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume11
/
test.el
/
part02
/
tst-capture.el
< prev
next >
Wrap
Lisp/Scheme
|
1987-09-08
|
18KB
|
459 lines
;; 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))
)
)
)