]> code.delx.au - gnu-emacs/blobdiff - lisp/desktop.el
(timezone-parse-date): Handle 1-digit year.
[gnu-emacs] / lisp / desktop.el
index a9fc0e226f14110b20a2d7c8622f9cb01e0e51e9..1eee466697abf074ea9b6f5ba5916c473530d77e 100644 (file)
@@ -1,9 +1,8 @@
 ;;; desktop.el --- save partial status of Emacs when killed
 
-;; Copyright (C) 1993, 1994 Free Software Foundation, Inc.
+;; Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
 
 ;; Author: Morten Welinder <terra@diku.dk>
-;; Version: 2.09
 ;; Keywords: customization
 ;; Favourite-brand-of-beer: None, I hate beer.
 
@@ -20,8 +19,9 @@
 ;; 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, write to
-;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
 
 ;;; Commentary:
 
@@ -50,7 +50,7 @@
 ;;
 ;;     (setq desktop-locals-to-save (cons 'foobar desktop-locals-to-save))
 ;;
-;; To avoid saving excessive amounts of data you may also with to add
+;; To avoid saving excessive amounts of data you may also wish to add
 ;; something like the following
 ;;
 ;;     (add-hook 'kill-emacs-hook
@@ -84,7 +84,8 @@
 ;;            chris@tecc.co.uk (Chris Boucher)       for a mark tip.
 ;;            f89-kam@nada.kth.se (Klas Mellbourn)   for a mh-e tip.
 ;;            kifer@sbkifer.cs.sunysb.edu (M. Kifer) for a bug hunt.
-;;            treese@lcs.mit.edu (Win Treese)        for ange-ftp ftps.
+;;            treese@lcs.mit.edu (Win Treese)        for ange-ftp tips.
+;;            pot@cnuce.cnr.it (Francesco Potorti`)  for misc. tips.
 ;; ---------------------------------------------------------------------------
 ;; TODO:
 ;;
 ;; USER OPTIONS -- settings you might want to play with.
 ;; ----------------------------------------------------------------------------
 (defconst desktop-basefilename
-  (if (eq system-type 'ms-dos)
-      "emacs.dsk" ; Ms-Dos does not support multiple dots in file name
-    ".emacs.desktop")
-  "File for Emacs desktop.  A directory name will be prepended to this name.")
+  (convert-standard-filename ".emacs.desktop")
+  "File for Emacs desktop, not including the directory name.")
 
 (defvar desktop-missing-file-warning t
-  "*If non-nil then issue warning if a file no longer exists.
-Otherwise simply ignore the file.")
+  "*If non-nil then desktop warns when a file no longer exists.
+Otherwise it simply ignores that file.")
 
 (defvar desktop-globals-to-save
   (list 'desktop-missing-file-warning
@@ -124,7 +123,11 @@ Otherwise simply ignore the file.")
        'register-alist
        ;; 'desktop-globals-to-save     ; Itself!
        )
-  "List of global variables to save when killing Emacs.")
+  "List of global variables to save when killing Emacs.
+An element may be variable name (a symbol)
+or a cons cell of the form  (VAR . MAX-SIZE),
+which means to truncate VAR's value to at most MAX-SIZE elements
+\(if the value is a list) before saving the value.")
 
 (defvar desktop-locals-to-save
   (list 'desktop-locals-to-save                ; Itself!  Think it over.
@@ -136,12 +139,12 @@ Otherwise simply ignore the file.")
        'change-log-default-name
        'line-number-mode
        )
-  "List of local variables to save for each buffer.  The variables are saved
-only when they really are local.")
+  "List of local variables to save for each buffer.
+The variables are saved only when they really are local.")
 (make-variable-buffer-local 'desktop-locals-to-save)
 
 ;; We skip .log files because they are normally temporary.
-;;         (ftp) files because they require passwords and whatsnot.
+;;         (ftp) files because they require passwords and whatnot.
 ;;         TAGS files to save time (tags-file-name is saved instead).
 (defvar desktop-buffers-not-to-save
  "\\(^nn\\.a[0-9]+\\|\\.log\\|(ftp)\\|^tags\\|^TAGS\\)$"
@@ -152,16 +155,30 @@ only when they really are local.")
   "^/[^/:]*:"
   "Regexp identifying files whose buffers are to be excluded from saving.")
 
+(defvar desktop-buffer-major-mode nil
+  "When desktop creates a buffer, this holds the desired Major mode.")
+
+(defvar desktop-buffer-file-name nil
+  "When desktop creates a buffer, this holds the file name to visit.")
+
+(defvar desktop-buffer-name nil
+  "When desktop creates a buffer, this holds the desired buffer name.")
+
+(defvar desktop-buffer-misc nil
+  "When desktop creates a buffer, this holds a list of misc info.
+It is used by the `desktop-buffer-handlers' functions.")
+
 (defvar desktop-buffer-handlers
   '(desktop-buffer-dired
     desktop-buffer-rmail
     desktop-buffer-mh
     desktop-buffer-info
     desktop-buffer-file)
-  "*List of functions to call in order to create a buffer.  The functions are
-called without explicit parameters but may access the the major mode as `mam',
-the file name as `fn', the buffer name as `bn', the default directory as
-`dd'.  If some function returns non-nil no further functions are called.
+  "*List of functions to call in order to create a buffer.
+The functions are called without explicit parameters but can use the
+variables `desktop-buffer-major-mode', `desktop-buffer-file-name',
+`desktop-buffer-name'.
+If one function returns non-nil, no further functions are called.
 If the function returns t then the buffer is considered created.")
 
 (defvar desktop-create-buffer-form "(desktop-create-buffer 205"
@@ -211,16 +228,30 @@ the like shorter.")
             nil
           (signal (car err) (cdr err)))))))
 ;; ----------------------------------------------------------------------------
+(defun desktop-list* (&rest args)
+  (if (null (cdr args))
+      (car args)
+    (setq args (nreverse args))
+    (let ((value (cons (nth 1 args) (car args))))
+      (setq args (cdr (cdr args)))
+      (while args
+       (setq value (cons (car args) value))
+       (setq args (cdr args)))
+      value)))
+
 (defun desktop-internal-v2s (val)
-  "Convert VALUE to a pair (quote . txt) where txt is a string that when read
-and evaluated yields value.  quote may be 'may (value may be quoted),
-'must (values must be quoted), or nil (value may not be quoted)."
+  "Convert VALUE to a pair (QUOTE . TXT); (eval (read TXT)) gives VALUE.
+TXT is a string that when read and evaluated yields value.
+QUOTE may be `may' (value may be quoted),
+`must' (values must be quoted), or nil (value may not be quoted)."
   (cond
    ((or (numberp val) (null val) (eq t val))
     (cons 'may (prin1-to-string val)))
    ((stringp val)
-    ;; Get rid of text properties because we cannot read them
-    (cons 'may (prin1-to-string (format "%s" val))))
+    (let ((copy (copy-sequence val)))
+      (set-text-properties 0 (length copy) nil copy)
+      ;; Get rid of text properties because we cannot read them
+      (cons 'may (prin1-to-string copy))))
    ((symbolp val)
     (cons 'must (prin1-to-string val)))
    ((vectorp val)
@@ -245,6 +276,7 @@ and evaluated yields value.  quote may be 'may (value may be quoted),
    ((consp val)
     (let ((p val)
          newlist
+         use-list*
          anynil)
       (while (consp p)
        (let ((q.txt (desktop-internal-v2s (car p))))
@@ -254,22 +286,15 @@ and evaluated yields value.  quote may be 'may (value may be quoted),
       (if p
          (let ((last (desktop-internal-v2s p))
                (el (car newlist)))
-           (setcar newlist
-                   (if (or anynil (setq anynil (null (car last))))
-                       (cons nil
-                             (concat "(cons "
-                                     (if (eq (car el) 'must) "'" "")
-                                     (cdr el)
-                                     " "
-                                     (if (eq (car last) 'must) "'" "")
-                                     (cdr last)
-                                     ")"))
-                     (cons 'must
-                           (concat (cdr el) " . " (cdr last)))))))
+           (or anynil (setq anynil (null (car last))))
+           (or anynil
+               (setq newlist (cons '(must . ".") newlist)))
+           (setq use-list* t)
+           (setq newlist (cons last newlist))))
       (setq newlist (nreverse newlist))
       (if anynil
          (cons nil
-               (concat "(list "
+               (concat (if use-list* "(desktop-list* "  "(list ")
                        (mapconcat (lambda (el)
                                     (if (eq (car el) 'must)
                                         (concat "'" (cdr el))
@@ -294,8 +319,8 @@ and evaluated yields value.  quote may be 'may (value may be quoted),
     (cons 'may "\"Unprintable entity\""))))
 
 (defun desktop-value-to-string (val)
-  "Convert VALUE to a string that when read evaluates to the same value.  Not
-all types of values are supported."
+  "Convert VALUE to a string that when read evaluates to the same value.
+Not all types of values are supported."
   (let* ((print-escape-newlines t)
         (float-output-format nil)
         (quote.txt (desktop-internal-v2s val))
@@ -305,14 +330,27 @@ all types of values are supported."
        (concat "'" txt)
       txt)))
 ;; ----------------------------------------------------------------------------
-(defun desktop-outvar (var)
-  "Output a setq statement for VAR to the desktop file."
-  (if (boundp var)
-      (insert "(setq "
-             (symbol-name var)
-             " "
-             (desktop-value-to-string (symbol-value var))
-             ")\n")))
+(defun desktop-outvar (varspec)
+  "Output a setq statement for variable VAR to the desktop file.
+The argument VARSPEC may be the variable name VAR (a symbol),
+or a cons cell of the form  (VAR . MAX-SIZE),
+which means to truncate VAR's value to at most MAX-SIZE elements
+\(if the value is a list) before saving the value."
+  (let (var size)
+    (if (consp varspec)
+       (setq var (car varspec) size (cdr varspec))
+      (setq var varspec))
+    (if (boundp var)
+       (progn
+         (if (and (integerp size)
+                  (> size 0)
+                  (listp (eval var)))
+             (desktop-truncate (eval var) size)) 
+         (insert "(setq "
+                 (symbol-name var)
+                 " "
+                 (desktop-value-to-string (symbol-value var))
+                 ")\n")))))
 ;; ----------------------------------------------------------------------------
 (defun desktop-save-buffer-p (filename bufname mode &rest dummy)
   "Return t if the desktop should record a particular buffer for next startup.
@@ -354,11 +392,13 @@ MODE is the major mode."
                                      (list Info-current-file
                                            Info-current-node))
                                     ((eq major-mode 'dired-mode)
-                                     (nreverse
-                                      (mapcar
-                                       (function car)
-                                       dired-subdir-alist)))
-                                    )
+                                     (cons
+                                      (expand-file-name dired-directory)
+                                      (cdr
+                                       (nreverse
+                                        (mapcar
+                                         (function car)
+                                         dired-subdir-alist))))))
                               (let ((locals desktop-locals-to-save)
                                     (loclist (buffer-local-variables))
                                     (ll))
@@ -415,25 +455,31 @@ MODE is the major mode."
            (delete-file filename)))))
 ;; ----------------------------------------------------------------------------
 (defun desktop-read ()
-  "Read the Desktop file and the files it specifies."
+  "Read the Desktop file and the files it specifies.
+This is a no-op when Emacs is running in batch mode."
   (interactive)
-  (let ((filename))
-    (if (file-exists-p (concat "./" desktop-basefilename))
-       (setq desktop-dirname (expand-file-name "./"))
-      (if (file-exists-p (concat "~/" desktop-basefilename))
-         (setq desktop-dirname (expand-file-name "~/"))
-       (setq desktop-dirname nil)))
-    (if desktop-dirname
-       (progn
-         (load (concat desktop-dirname desktop-basefilename) t t t)
-         (run-hooks 'desktop-delay-hook)
-         (message "Desktop loaded."))
-      (desktop-clear))))
+  (if noninteractive
+      nil
+    (let ((dirs '("./" "~/")))
+      (while (and dirs
+                 (not (file-exists-p (expand-file-name
+                                      desktop-basefilename
+                                      (car dirs)))))
+       (setq dirs (cdr dirs)))
+      (setq desktop-dirname (and dirs (expand-file-name (car dirs))))
+      (if desktop-dirname
+         (progn
+           (load (expand-file-name desktop-basefilename desktop-dirname)
+                 t t t)
+           (run-hooks 'desktop-delay-hook)
+           (setq desktop-delay-hook nil)
+           (message "Desktop loaded."))
+       (desktop-clear)))))
 ;; ----------------------------------------------------------------------------
 (defun desktop-load-default ()
-  "Load the `default' start-up library manually.  Also inhibit further loading
-of it.  Call this from your `.emacs' file to provide correct modes for
-autoloaded files."
+  "Load the `default' start-up library manually.
+Also inhibit further loading of it.  Call this from your `.emacs' file
+to provide correct modes for autoloaded files."
   (if (not inhibit-default-init)       ; safety check
       (progn
        (load "default" t t)
@@ -442,52 +488,54 @@ autoloaded files."
 ;; Note: the following functions use the dynamic variable binding in Lisp.
 ;;
 (defun desktop-buffer-info () "Load an info file."
-  (if (eq 'Info-mode mam)
+  (if (eq 'Info-mode desktop-buffer-major-mode)
       (progn
        (require 'info)
-       (Info-find-node (nth 0 misc) (nth 1 misc))
+       (Info-find-node (nth 0 desktop-buffer-misc) (nth 1 desktop-buffer-misc))
        t)))
 ;; ----------------------------------------------------------------------------
 (defun desktop-buffer-rmail () "Load an RMAIL file."
-  (if (eq 'rmail-mode mam)
+  (if (eq 'rmail-mode desktop-buffer-major-mode)
       (condition-case error
-         (progn (rmail-input fn) t)
+         (progn (rmail-input desktop-buffer-file-name) t)
        (file-locked
         (kill-buffer (current-buffer))
         'ignored))))
 ;; ----------------------------------------------------------------------------
 (defun desktop-buffer-mh () "Load a folder in the mh system."
-  (if (eq 'mh-folder-mode mam)
+  (if (eq 'mh-folder-mode desktop-buffer-major-mode)
       (progn
        (require 'mh-e)
        (mh-find-path)
-       (mh-visit-folder bn)
+       (mh-visit-folder desktop-buffer-name)
        t)))
 ;; ----------------------------------------------------------------------------
 (defun desktop-buffer-dired () "Load a directory using dired."
-  (if (eq 'dired-mode mam)
-      (if (file-directory-p (directory-file-name (car misc)))
+  (if (eq 'dired-mode desktop-buffer-major-mode)
+      (if (file-directory-p (file-name-directory (car desktop-buffer-misc)))
          (progn
-           (dired (car misc))
-           (mapcar (function dired-maybe-insert-subdir) (cdr misc))
+           (dired (car desktop-buffer-misc))
+           (mapcar 'dired-insert-subdir (cdr desktop-buffer-misc))
            t)
-       (message "Directory %s no longer exists." (car misc))
+       (message "Directory %s no longer exists." (car desktop-buffer-misc))
        (sit-for 1)
        'ignored)))
 ;; ----------------------------------------------------------------------------
 (defun desktop-buffer-file () "Load a file."
-  (if fn
-      (if (or (file-exists-p fn)
+  (if desktop-buffer-file-name
+      (if (or (file-exists-p desktop-buffer-file-name)
              (and desktop-missing-file-warning
                   (y-or-n-p (format
                              "File \"%s\" no longer exists. Re-create? "
-                             fn))))
-         (progn (find-file fn) t)
+                             desktop-buffer-file-name))))
+         (progn (find-file desktop-buffer-file-name) t)
        'ignored)))
 ;; ----------------------------------------------------------------------------
 ;; Create a buffer, load its file, set is mode, ...;  called from Desktop file
 ;; only.
-(defun desktop-create-buffer (ver fn bn mam mim pt mk ro misc &optional locals)
+(defun desktop-create-buffer (ver desktop-buffer-file-name desktop-buffer-name
+                                 desktop-buffer-major-mode
+                                 mim pt mk ro desktop-buffer-misc &optional locals)
   (let ((hlist desktop-buffer-handlers)
        (result)
        (handler))
@@ -497,8 +545,8 @@ autoloaded files."
       (setq hlist (cdr hlist)))
     (if (eq result t)
        (progn
-         (if (not (equal (buffer-name) bn))
-             (rename-buffer bn))
+         (if (not (equal (buffer-name) desktop-buffer-name))
+             (rename-buffer desktop-buffer-name))
          (auto-fill-mode (if (nth 0 mim) 1 0))
          (goto-char pt)
          (if (consp mk)
@@ -522,8 +570,12 @@ autoloaded files."
          ))))
 
 ;; Backward compatibility -- update parameters to 205 standards.
-(defun desktop-buffer (fn bn mam mim pt mk ro tl fc cfs cr misc)
-  (desktop-create-buffer 205 fn bn mam (cdr mim) pt mk ro misc
+(defun desktop-buffer (desktop-buffer-file-name desktop-buffer-name
+                      desktop-buffer-major-mode
+                      mim pt mk ro tl fc cfs cr desktop-buffer-misc)
+  (desktop-create-buffer 205 desktop-buffer-file-name desktop-buffer-name
+                        desktop-buffer-major-mode (cdr mim) pt mk ro
+                        desktop-buffer-misc
                         (list (cons 'truncate-lines tl)
                               (cons 'fill-column fc)
                               (cons 'case-fold-search cfs)