emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] Changes to emacs/lisp/desktop.el [emacs-unicode-2]


From: Kenichi Handa
Subject: [Emacs-diffs] Changes to emacs/lisp/desktop.el [emacs-unicode-2]
Date: Mon, 08 Sep 2003 08:53:53 -0400

Index: emacs/lisp/desktop.el
diff -c /dev/null emacs/lisp/desktop.el:1.60.2.1
*** /dev/null   Mon Sep  8 08:53:53 2003
--- emacs/lisp/desktop.el       Mon Sep  8 08:53:36 2003
***************
*** 0 ****
--- 1,981 ----
+ ;;; desktop.el --- save partial status of Emacs when killed
+ 
+ ;; Copyright (C) 1993, 1994, 1995, 1997, 2000, 2001
+ ;;   Free Software Foundation, Inc.
+ 
+ ;; Author: Morten Welinder <address@hidden>
+ ;; Maintainter: Lars Hansen <address@hidden>
+ ;; Keywords: convenience
+ ;; Favourite-brand-of-beer: None, I hate beer.
+ 
+ ;; This file is part of GNU Emacs.
+ 
+ ;; GNU Emacs 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.
+ 
+ ;; GNU Emacs 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, write to the
+ ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ ;; Boston, MA 02111-1307, USA.
+ 
+ ;;; Commentary:
+ 
+ ;; Save the Desktop, i.e.,
+ ;;    - some global variables
+ ;;    - the list of buffers with associated files.  For each buffer also
+ ;;            - the major mode
+ ;;            - the default directory
+ ;;            - the point
+ ;;            - the mark & mark-active
+ ;;            - buffer-read-only
+ ;;            - some local variables
+ 
+ ;; To use this, first put these two lines in the bottom of your .emacs
+ ;; file (the later the better):
+ ;;
+ ;;    (desktop-load-default)
+ ;;    (desktop-read)
+ ;;
+ ;; Between these two lines you may wish to add something that updates the
+ ;; variables `desktop-globals-to-save' and/or `desktop-locals-to-save'.  If
+ ;; for instance you want to save the local variable `foobar' for every buffer
+ ;; in which it is local, you could add the line
+ ;;
+ ;;    (setq desktop-locals-to-save (cons 'foobar desktop-locals-to-save))
+ ;;
+ ;; To avoid saving excessive amounts of data you may also wish to add
+ ;; something like the following
+ ;;
+ ;;    (add-hook 'kill-emacs-hook
+ ;;              '(lambda ()
+ ;;                 (desktop-truncate search-ring 3)
+ ;;                 (desktop-truncate regexp-search-ring 3)))
+ ;;
+ ;; which will make sure that no more than three search items are saved.  You
+ ;; must place this line *after* the `(desktop-load-default)' line.  See also
+ ;; the variable `desktop-save-hook'.
+ 
+ ;; Start Emacs in the root directory of your "project". The desktop saver
+ ;; is inactive by default.  You activate it by M-x desktop-save RET.  When
+ ;; you exit the next time the above data will be saved.  This ensures that
+ ;; all the files you were editing will be reloaded the next time you start
+ ;; Emacs from the same directory and that points will be set where you
+ ;; left them.  If you save a desktop file in your home directory it will
+ ;; act as a default desktop when you start Emacs from a directory that
+ ;; doesn't have its own.  I never do this, but you may want to.
+ 
+ ;; Some words on minor modes: Most minor modes are controlled by
+ ;; buffer-local variables, which have a standard save / restore
+ ;; mechanism.  To handle all minor modes, we take the following
+ ;; approach: (1) check whether the variable name from
+ ;; `minor-mode-alist' is also a function; and (2) use translation
+ ;; table `desktop-minor-mode-table' in the case where the two names
+ ;; are not the same.
+ 
+ ;; By the way: don't use desktop.el to customize Emacs -- the file .emacs
+ ;; in your home directory is used for that.  Saving global default values
+ ;; for buffers is an example of misuse.
+ 
+ ;; PLEASE NOTE: The kill ring can be saved as specified by the variable
+ ;; `desktop-globals-to-save' (by default it isn't).  This may result in saving
+ ;; things you did not mean to keep.  Use M-x desktop-clear RET.
+ 
+ ;; Thanks to  address@hidden (Jim Hetrick)      for useful ideas.
+ ;;            address@hidden (Andrew V. Klein)     for a dired tip.
+ ;;            address@hidden (Chris Boucher)       for a mark tip.
+ ;;            address@hidden (Klas Mellbourn)   for a mh-e tip.
+ ;;            address@hidden (M. Kifer) for a bug hunt.
+ ;;            address@hidden (Win Treese)        for ange-ftp tips.
+ ;;            address@hidden (Francesco Potorti`)  for misc. tips.
+ ;; ---------------------------------------------------------------------------
+ ;; TODO:
+ ;;
+ ;; Save window configuration.
+ ;; Recognize more minor modes.
+ ;; Save mark rings.
+ 
+ ;;; Code:
+ 
+ ;; Make the compilation more silent
+ (eval-when-compile
+   ;; We use functions from these modules
+   ;; We can't (require 'mh-e) since that wants to load something.
+   (mapcar 'require '(info dired reporter)))
+ 
+ (defvar desktop-file-version "206"
+   "Verion number of desktop file format.
+ Written into the desktop file and used at desktop read to provide
+ backward compatibility.")
+ 
+ ;; 
----------------------------------------------------------------------------
+ ;; USER OPTIONS -- settings you might want to play with.
+ ;; 
----------------------------------------------------------------------------
+ 
+ (defgroup desktop nil
+   "Save status of Emacs when you exit."
+   :group 'frames)
+ 
+ (defcustom desktop-enable nil
+   "*Non-nil enable Desktop to save the state of Emacs when you exit."
+   :group 'desktop
+   :type 'boolean
+   :require 'desktop
+   :initialize 'custom-initialize-default
+   :version "20.3")
+ 
+ (defcustom desktop-save 'ask-if-new
+   "*When the user changes desktop or quits emacs, should the desktop be saved?
+ \(in the current desktop directory)
+    t             -- always save.
+    ask           -- always ask.
+    ask-if-new    -- ask if no desktop file exists, otherwise just save.
+    ask-if-exists -- ask if desktop file exists, otherwise don't save.
+    if-exists     -- save if desktop file exists, otherwise don't save.
+    nil           -- never save.
+ The desktop is never saved when `desktop-enable' is nil."
+   :type '(choice
+     (const :tag "Always save" t)
+     (const :tag "Always ask" ask)
+     (const :tag "Ask if desktop file is new, else do save" ask-if-new)
+     (const :tag "Ask if desktop file exists, else don't save" ask-if-exists)
+     (const :tag "Save if desktop file exists, else don't" if-exists)
+     (const :tag "Never save" nil))
+   :group 'desktop)
+ 
+ (defcustom desktop-base-file-name
+   (convert-standard-filename ".emacs.desktop")
+   "File for Emacs desktop, not including the directory name."
+   :type 'file
+   :group 'desktop)
+ (defvaralias 'desktop-basefilename 'desktop-base-file-name)
+ 
+ (defcustom desktop-path '("." "~")
+   "List of directories to search for the desktop file.
+ The base name of the file is specified in `desktop-base-file-name'."
+   :type '(repeat directory)
+   :group 'desktop)
+ 
+ (defcustom desktop-missing-file-warning nil
+   "*If non-nil then desktop warns when a file no longer exists.
+ Otherwise it simply ignores that file."
+   :type 'boolean
+   :group 'desktop)
+ 
+ (defcustom desktop-no-desktop-file-hook nil
+   "Normal hook run after fail of `desktop-read' due to missing desktop file.
+ May e.g. be used to show a dired buffer."
+   :type 'hook
+   :group 'desktop)
+ 
+ (defcustom desktop-after-read-hook nil
+   "Normal hook run after a sucessful `desktop-read'.
+ May e.g. be used to show a buffer list."
+   :type 'hook
+   :group 'desktop)
+ 
+ (defcustom desktop-save-hook nil
+   "Hook run before desktop saves the state of Emacs.
+ This is useful for truncating history lists, for example."
+   :type 'hook
+   :group 'desktop)
+ 
+ (defcustom desktop-globals-to-save '(
+   desktop-missing-file-warning
+   tags-file-name
+   tags-table-list
+   search-ring
+   regexp-search-ring
+   register-alist)
+   "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.
+ Feature: Saving `kill-ring' implies saving `kill-ring-yank-pointer'."
+   :type '(repeat (restricted-sexp :match-alternatives (symbolp consp)))
+   :group 'desktop)
+ 
+ (defcustom desktop-globals-to-clear '(
+   kill-ring
+   kill-ring-yank-pointer
+   search-ring
+   search-ring-yank-pointer
+   regexp-search-ring
+   regexp-search-ring-yank-pointer)
+   "List of global variables set to clear by `desktop-clear'.
+ An element may be variable name (a symbol) or a cons cell of the form
+ \(VAR . FORM). Symbols are set to nil and for cons cells VAR is set
+ to the value obtained by evaluateing FORM."
+   :type '(repeat (restricted-sexp :match-alternatives (symbolp consp)))
+   :group 'desktop)
+ 
+ (defcustom desktop-clear-preserve-buffers-regexp
+   "^\\*tramp/.+\\*$"
+   "Regexp identifying buffers that `desktop-clear' should not delete."
+   :type 'regexp
+   :group 'desktop)
+ 
+ ;; Maintained for backward compatibility
+ (defcustom desktop-clear-preserve-buffers
+   '("*scratch*" "*Messages*")
+   "*List of buffer names that `desktop-clear' should not delete."
+   :type '(repeat string)
+   :group 'desktop)
+ 
+ (defvar desktop-locals-to-save '(
+   desktop-locals-to-save  ; Itself!  Think it over.
+   truncate-lines
+   case-fold-search
+   case-replace
+   fill-column
+   overwrite-mode
+   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.")
+ (make-variable-buffer-local 'desktop-locals-to-save)
+ 
+ ;; We skip .log files because they are normally temporary.
+ ;;         (ftp) files because they require passwords and whatnot.
+ ;;         TAGS files to save time (tags-file-name is saved instead).
+ (defcustom desktop-buffers-not-to-save
+   "\\(^nn\\.a[0-9]+\\|\\.log\\|(ftp)\\|^tags\\|^TAGS\\)$"
+   "Regexp identifying buffers that are to be excluded from saving."
+   :type 'regexp
+   :group 'desktop)
+ 
+ ;; Skip ange-ftp files
+ (defcustom desktop-files-not-to-save
+   "^/[^/:]*:"
+   "Regexp identifying files whose buffers are to be excluded from saving."
+   :type 'regexp
+   :group 'desktop)
+ 
+ (defcustom desktop-buffer-modes-to-save
+   '(Info-mode rmail-mode)
+   "If a buffer is of one of these major modes, save the buffer name.
+ It is up to the functions in `desktop-buffer-handlers' to decide
+ whether the buffer should be recreated or not, and how."
+   :type '(repeat symbol)
+   :group 'desktop)
+ 
+ (defcustom desktop-modes-not-to-save nil
+   "List of major modes whose buffers should not be saved."
+   :type '(repeat symbol)
+   :group 'desktop)
+ 
+ (defcustom desktop-file-name-format 'absolute
+   "*Format in which desktop file names should be saved.
+ Possible values are:
+    absolute -- Absolute file name.
+    tilde    -- Relative to ~.
+    local    -- Relative to directory of desktop file."
+   :type '(choice (const absolute) (const tilde) (const local))
+   :group 'desktop)
+ 
+ (defcustom desktop-buffer-misc-functions
+   '(desktop-buffer-info-misc-data
+     desktop-buffer-dired-misc-data)
+   "*Functions used to determine auxiliary information for a buffer.
+ These functions are called in order, with no arguments.  If a function
+ returns non-nil, its value is saved along with the desktop buffer for
+ which it was called; no further functions will be called.
+ 
+ File names should formatted using the call
+ \"(desktop-file-name FILE-NAME dirname)\".
+ 
+ Later, when desktop.el restores the buffers it has saved, each of the
+ `desktop-buffer-handlers' functions will have access to a buffer local
+ variable, named `desktop-buffer-misc', whose value is what the
+ \"misc\" function returned previously."
+   :type '(repeat function)
+   :group 'desktop)
+ 
+ (defcustom 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 can use the
+ following variables:
+ 
+    desktop-file-version
+    desktop-buffer-file-name
+    desktop-buffer-name
+    desktop-buffer-major-mode
+    desktop-buffer-minor-modes
+    desktop-buffer-point
+    desktop-buffer-mark
+    desktop-buffer-read-only
+    desktop-buffer-misc
+    desktop-buffer-locals
+ 
+ If one function returns non-nil, no further functions are called.
+ If the function returns a buffer, then the saved mode settings
+ and variable values for that buffer are copied into it."
+   :type '(repeat function)
+   :group 'desktop)
+ 
+ (put 'desktop-buffer-handlers 'risky-local-variable t)
+ 
+ (defcustom desktop-minor-mode-table
+   '((auto-fill-function auto-fill-mode)
+     (vc-mode nil))
+   "Table mapping minor mode variables to minor mode functions.
+ Each entry has the form (NAME RESTORE-FUNCTION).
+ NAME is the name of the buffer-local variable indicating that the minor
+ mode is active.  RESTORE-FUNCTION is the function to activate the minor mode.
+ called.  RESTORE-FUNCTION nil means don't try to restore the minor mode.
+ Only minor modes for which the name of the buffer-local variable
+ and the name of the minor mode function are different have to added to
+ this table."
+   :type 'sexp
+   :group 'desktop)
+ 
+ ;; 
----------------------------------------------------------------------------
+ (defvar desktop-dirname nil
+   "The directory in which the current desktop file resides.")
+ 
+ (defconst desktop-header
+ ";; --------------------------------------------------------------------------
+ ;; Desktop File for Emacs
+ ;; --------------------------------------------------------------------------
+ " "*Header to place in Desktop file.")
+ 
+ (defvar desktop-delay-hook nil
+   "Hooks run after all buffers are loaded; intended for internal use.")
+ 
+ ;; 
----------------------------------------------------------------------------
+ (defun desktop-truncate (l n)
+   "Truncate LIST to at most N elements destructively."
+   (let ((here (nthcdr (1- n) l)))
+     (if (consp here)
+       (setcdr here nil))))
+ 
+ ;; 
----------------------------------------------------------------------------
+ (defun desktop-clear ()
+   "Empty the Desktop.
+ This kills all buffers except for internal ones and those listed
+ in `desktop-clear-preserve-buffers'.  Furthermore, it clears the
+ variables listed in `desktop-globals-to-clear'."
+   (interactive)
+   (dolist (var desktop-globals-to-clear)
+     (if (symbolp var)
+       (eval `(setq-default ,var nil))
+       (eval `(setq-default ,(car var) ,(cdr var)))))
+   (let ((buffers (buffer-list)))
+     (while buffers
+       (let ((bufname (buffer-name (car buffers))))
+          (or
+            (null bufname)
+            (string-match desktop-clear-preserve-buffers-regexp bufname)
+            (member bufname desktop-clear-preserve-buffers)
+            ;; Don't kill buffers made for internal purposes.
+            (and (not (equal bufname "")) (eq (aref bufname 0) ?\ ))
+            (kill-buffer (car buffers))))
+       (setq buffers (cdr buffers))))
+   (delete-other-windows))
+ 
+ ;; 
----------------------------------------------------------------------------
+ (add-hook 'kill-emacs-hook 'desktop-kill)
+ 
+ (defun desktop-kill ()
+   "If `desktop-enable' is non-nil, do what `desktop-save' says to do.
+ If the desktop should be saved and `desktop-dirname'
+ is nil, ask the user where to save the desktop."
+   (when
+     (and
+       desktop-enable
+       (let ((exists (file-exists-p (expand-file-name desktop-base-file-name 
desktop-dirname))))
+         (or
+           (eq desktop-save 't)
+           (and exists (memq desktop-save '(ask-if-new if-exists)))
+           (and
+             (or
+               (memq desktop-save '(ask ask-if-new))
+               (and exists (eq desktop-save 'ask-if-exists)))
+             (y-or-n-p "Save desktop? ")))))
+     (unless desktop-dirname
+       (setq desktop-dirname
+         (file-name-as-directory
+           (expand-file-name
+             (call-interactively
+               (lambda (dir) (interactive "DDirectory for desktop file: ") 
dir))))))
+     (condition-case err
+       (desktop-save desktop-dirname)
+       (file-error
+         (unless (yes-or-no-p "Error while saving the desktop. Ignore? ")
+           (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); (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)
+     (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)
+     (let* ((special nil)
+          (pass1 (mapcar
+                  (lambda (el)
+                    (let ((res (desktop-internal-v2s el)))
+                      (if (null (car res))
+                          (setq special t))
+                      res))
+                  val)))
+       (if special
+         (cons nil (concat "(vector "
+                           (mapconcat (lambda (el)
+                                        (if (eq (car el) 'must)
+                                            (concat "'" (cdr el))
+                                          (cdr el)))
+                                      pass1
+                                      " ")
+                           ")"))
+       (cons 'may (concat "[" (mapconcat 'cdr pass1 " ") "]")))))
+    ((consp val)
+     (let ((p val)
+         newlist
+         use-list*
+         anynil)
+       (while (consp p)
+       (let ((q.txt (desktop-internal-v2s (car p))))
+         (or anynil (setq anynil (null (car q.txt))))
+         (setq newlist (cons q.txt newlist)))
+       (setq p (cdr p)))
+       (if p
+         (let ((last (desktop-internal-v2s p))
+               (el (car newlist)))
+           (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 (if use-list* "(desktop-list* "  "(list ")
+                       (mapconcat (lambda (el)
+                                    (if (eq (car el) 'must)
+                                        (concat "'" (cdr el))
+                                      (cdr el)))
+                                  newlist
+                                  " ")
+                       ")"))
+       (cons 'must
+             (concat "(" (mapconcat 'cdr newlist " ") ")")))))
+    ((subrp val)
+     (cons nil (concat "(symbol-function '"
+                     (substring (prin1-to-string val) 7 -1)
+                     ")")))
+    ((markerp val)
+     (let ((pos (prin1-to-string (marker-position val)))
+         (buf (prin1-to-string (buffer-name (marker-buffer val)))))
+       (cons nil (concat "(let ((mk (make-marker)))"
+                       " (add-hook 'desktop-delay-hook"
+                       " (list 'lambda '() (list 'set-marker mk "
+                       pos " (get-buffer " buf ")))) mk)"))))
+    (t                                 ; save as text
+     (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."
+   (let* ((print-escape-newlines t)
+        (float-output-format nil)
+        (quote.txt (desktop-internal-v2s val))
+        (quote (car quote.txt))
+        (txt (cdr quote.txt)))
+     (if (eq quote 'must)
+       (concat "'" txt)
+       txt)))
+ 
+ ;; 
----------------------------------------------------------------------------
+ (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.
+ FILENAME is the visited file name, BUFNAME is the buffer name, and
+ MODE is the major mode."
+   (let ((case-fold-search nil))
+     (and (not (string-match desktop-buffers-not-to-save bufname))
+        (not (memq mode desktop-modes-not-to-save))
+        (or (and filename
+                 (not (string-match desktop-files-not-to-save filename)))
+            (and (eq mode 'dired-mode)
+                 (save-excursion
+                   (set-buffer (get-buffer bufname))
+                   (not (string-match desktop-files-not-to-save
+                                      default-directory))))
+            (and (null filename)
+                 (memq mode desktop-buffer-modes-to-save))))))
+ 
+ ;; 
----------------------------------------------------------------------------
+ (defun desktop-file-name (filename dirname)
+   "Convert FILENAME to format specified in `desktop-file-name-format'.
+ DIRNAME must be the directory in which the desktop file will be saved."
+   (cond
+     ((not filename) nil)
+     ((eq desktop-file-name-format 'tilde)
+      (let ((relative-name (file-relative-name (expand-file-name filename) 
"~")))
+        (cond
+          ((file-name-absolute-p relative-name) relative-name)
+          ((string= "./" relative-name) "~/")
+          ((string= "." relative-name) "~")
+          (t (concat "~/" relative-name)))))
+     ((eq desktop-file-name-format 'local) (file-relative-name filename 
dirname))
+     (t (expand-file-name filename))))
+ 
+ ;; 
----------------------------------------------------------------------------
+ (defun desktop-save (dirname)
+   "Save the Desktop file. Parameter DIRNAME specifies where to save desktop."
+   (interactive "DDirectory to save desktop file in: ")
+   (run-hooks 'desktop-save-hook)
+   (setq dirname (file-name-as-directory (expand-file-name dirname)))
+   (save-excursion
+     (let ((filename (expand-file-name desktop-base-file-name dirname))
+           (info
+             (mapcar
+               (function
+                 (lambda (b)
+                   (set-buffer b)
+                   (list
+                     (desktop-file-name (buffer-file-name) dirname)
+                     (buffer-name)
+                     major-mode
+                     ;; minor modes
+                     (let (ret)
+                       (mapcar
+                         #'(lambda (mim)
+                           (and
+                             (boundp mim)
+                             (symbol-value mim)
+                             (setq ret
+                               (cons
+                                 (let ((special (assq mim 
desktop-minor-mode-table)))
+                                   (if special (cadr special) mim))
+                                 ret))))
+                         (mapcar #'car minor-mode-alist))
+                       ret)
+                     (point)
+                     (list (mark t) mark-active)
+                     buffer-read-only
+                     (run-hook-with-args-until-success 
'desktop-buffer-misc-functions)
+                     (let ((locals desktop-locals-to-save)
+                           (loclist (buffer-local-variables))
+                           (ll))
+                       (while locals
+                         (let ((here (assq (car locals) loclist)))
+                           (if here
+                             (setq ll (cons here ll))
+                             (when (member (car locals) loclist)
+                               (setq ll (cons (car locals) ll)))))
+                         (setq locals (cdr locals)))
+                       ll))))
+               (buffer-list)))
+           (buf (get-buffer-create "*desktop*")))
+       (set-buffer buf)
+       (erase-buffer)
+ 
+       (insert
+         ";; -*- coding: utf-8-emacs; -*-\n"
+         desktop-header
+         ";; Created " (current-time-string) "\n"
+         ";; Desktop file format version " desktop-file-version "\n"
+         ";; Emacs version " emacs-version "\n\n"
+         ";; Global section:\n")
+       (mapcar (function desktop-outvar) desktop-globals-to-save)
+       (if (memq 'kill-ring desktop-globals-to-save)
+         (insert
+           "(setq kill-ring-yank-pointer (nthcdr "
+           (int-to-string (- (length kill-ring) (length 
kill-ring-yank-pointer)))
+           " kill-ring))\n"))
+ 
+       (insert "\n;; Buffer section -- buffers listed in same order as in 
buffer list:\n")
+       (mapcar
+         (function
+           (lambda (l)
+             (if (apply 'desktop-save-buffer-p l)
+               (progn
+                 (insert "(desktop-create-buffer " desktop-file-version)
+                 (mapcar
+                   (function
+                     (lambda (e)
+                       (insert "\n  " (desktop-value-to-string e))))
+                   l)
+                 (insert ")\n\n")))))
+         info)
+       (setq default-directory dirname)
+       (when (file-exists-p filename) (delete-file filename))
+       (let ((coding-system-for-write 'utf-8-emacs))
+         (write-region (point-min) (point-max) filename nil 'nomessage))))
+   (setq desktop-dirname dirname))
+ 
+ ;; 
----------------------------------------------------------------------------
+ (defun desktop-remove ()
+   "Delete the Desktop file and inactivate the desktop system."
+   (interactive)
+   (if desktop-dirname
+       (let ((filename (expand-file-name desktop-base-file-name 
desktop-dirname)))
+     (setq desktop-dirname nil)
+     (if (file-exists-p filename)
+         (delete-file filename)))))
+ ;; 
----------------------------------------------------------------------------
+ ;;;###autoload
+ (defun desktop-read ()
+   "Read the Desktop file and the files it specifies.
+ This is a no-op when Emacs is running in batch mode.
+ Look for the desktop file according to the variables `desktop-base-file-name'
+ and `desktop-path'.  If no desktop file is found, clear the desktop.
+ Returns t if it has read a desktop file, nil otherwise."
+   (interactive)
+   (unless noninteractive
+     (let ((dirs desktop-path))
+       (while
+         (and
+           dirs
+           (not
+             (file-exists-p (expand-file-name desktop-base-file-name (car 
dirs)))))
+         (setq dirs (cdr dirs)))
+       (setq desktop-dirname (and dirs (file-name-as-directory 
(expand-file-name (car dirs)))))
+       (if desktop-dirname
+         (let ((desktop-first-buffer nil))
+           ;; Evaluate desktop buffer.
+           (load (expand-file-name desktop-base-file-name desktop-dirname) t t 
t)
+           ;; `desktop-create-buffer' puts buffers at end of the buffer list.
+           ;; We want buffers existing prior to evaluating the desktop (and 
not reused)
+           ;; to be placed at the end of the buffer list, so we move them here.
+           (mapcar 'bury-buffer
+                   (nreverse (cdr (memq desktop-first-buffer (nreverse 
(buffer-list))))))
+           (switch-to-buffer (car (buffer-list)))
+           (run-hooks 'desktop-delay-hook)
+           (setq desktop-delay-hook nil)
+           (run-hooks 'desktop-after-read-hook)
+           (message "Desktop loaded.")
+           t)
+         (desktop-clear)
+         (run-hooks 'desktop-no-desktop-file-hook)
+         (message "No desktop file.")
+         nil))))
+ 
+ ;; 
----------------------------------------------------------------------------
+ ;;;###autoload
+ (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."
+   (if (not inhibit-default-init)      ; safety check
+       (progn
+       (load "default" t t)
+       (setq inhibit-default-init t))))
+ 
+ ;; 
----------------------------------------------------------------------------
+ ;;;###autoload
+ (defun desktop-change-dir (dir)
+   "Save and clear the desktop, then load the desktop from directory DIR.
+ However, if `desktop-enable' was nil at call, don't save the old desktop.
+ This function always sets `desktop-enable' to t."
+   (interactive "DNew directory: ")
+   (setq dir (file-name-as-directory (expand-file-name dir desktop-dirname)))
+   (desktop-kill)
+   (desktop-clear)
+   (setq desktop-enable t)
+   (let ((desktop-path (list dir))
+         (default-directory dir))
+     (desktop-read))
+   ;; Set `desktop-dirname' even in no desktop file was found
+   (setq desktop-dirname dir))
+   ;; 
----------------------------------------------------------------------------
+ ;;;###autoload
+ (defun desktop-save-in-load-dir ()
+   "Save desktop in directory from which it was loaded."
+   (interactive)
+   (if desktop-dirname
+     (desktop-save desktop-dirname)
+     (call-interactively 'desktop-save))
+   (message "Desktop saved in %s" desktop-dirname))
+ 
+ ;; 
----------------------------------------------------------------------------
+ ;;;###autoload
+ (defun desktop-revert ()
+   "Revert to the last loaded desktop."
+   (interactive)
+   (unless desktop-dirname (error "No desktop has been loaded"))
+   (setq desktop-enable nil)
+   (desktop-change-dir desktop-dirname))
+ 
+ ;; 
----------------------------------------------------------------------------
+ ;; Note: the following functions use the dynamic variable binding in Lisp.
+ ;;
+ 
+ (eval-when-compile ; Just to silence the byte compiler
+   (defvar desktop-file-version)
+   (defvar desktop-buffer-file-name)
+   (defvar desktop-buffer-name)
+   (defvar desktop-buffer-major-mode)
+   (defvar desktop-buffer-minor-modes)
+   (defvar desktop-buffer-point)
+   (defvar desktop-buffer-mark)
+   (defvar desktop-buffer-read-only)
+   (defvar desktop-buffer-misc)
+   (defvar desktop-buffer-locals)
+ )
+ 
+ (defun desktop-buffer-info-misc-data ()
+   (if (eq major-mode 'Info-mode)
+       (list Info-current-file
+             Info-current-node)))
+ 
+ ;; 
----------------------------------------------------------------------------
+ (defun desktop-buffer-dired-misc-data ()
+   (when (eq major-mode 'dired-mode)
+     (eval-when-compile (defvar dirname))
+     (cons
+      ;; Value of `dired-directory'.
+      (if (consp dired-directory)
+        ;; Directory name followed by list of files.
+        (cons (desktop-file-name (car dired-directory) dirname) (cdr 
dired-directory))
+        ;; Directory name, optionally with with shell wildcard.
+        (desktop-file-name dired-directory dirname))
+      ;; Subdirectories in `dired-subdir-alist'.
+      (cdr
+       (nreverse
+        (mapcar
+       (function (lambda (f) (desktop-file-name (car f) dirname)))
+       dired-subdir-alist))))))
+ 
+ ;; 
----------------------------------------------------------------------------
+ (defun desktop-buffer-info () "Load an info file."
+   (if (eq 'Info-mode desktop-buffer-major-mode)
+       (progn
+       (let ((first (nth 0 desktop-buffer-misc))
+             (second (nth 1 desktop-buffer-misc)))
+       (when (and first second)
+         (require 'info)
+         (with-no-warnings
+          (Info-find-node first second))
+         (current-buffer))))))
+ 
+ ;; 
----------------------------------------------------------------------------
+ (eval-when-compile (defvar rmail-buffer)) ; Just to silence the byte compiler.
+ (defun desktop-buffer-rmail () "Load an RMAIL file."
+   (if (eq 'rmail-mode desktop-buffer-major-mode)
+       (condition-case error
+         (progn (rmail-input desktop-buffer-file-name)
+                          (if (eq major-mode 'rmail-mode)
+                              (current-buffer)
+                            rmail-buffer))
+       (file-locked
+        (kill-buffer (current-buffer))
+        'ignored))))
+ 
+ ;; 
----------------------------------------------------------------------------
+ (defun desktop-buffer-mh () "Load a folder in the mh system."
+   (if (eq 'mh-folder-mode desktop-buffer-major-mode)
+       (with-no-warnings
+       (mh-find-path)
+         (mh-visit-folder desktop-buffer-name)
+       (current-buffer))))
+ 
+ ;; 
----------------------------------------------------------------------------
+ (defun desktop-buffer-dired () "Load a directory using dired."
+   (if (eq 'dired-mode desktop-buffer-major-mode)
+       ;; First element of `desktop-buffer-misc' is the value of 
`dired-directory'.
+       ;; This value is a directory name, optionally with with shell wildcard 
or
+       ;; a directory name followed by list of files.
+       (let* ((dired-directory (car desktop-buffer-misc))
+            (dir (if (consp dired-directory) (car dired-directory) 
dired-directory)))
+       (if (file-directory-p (file-name-directory dir))
+           (progn
+             (dired dired-directory)
+             (mapcar 'dired-maybe-insert-subdir (cdr desktop-buffer-misc))
+             (current-buffer))
+         (message "Directory %s no longer exists." dir)
+         (sit-for 1)
+         'ignored))))
+ 
+ ;; 
----------------------------------------------------------------------------
+ (defun desktop-buffer-file ()
+   "Load a file."
+   (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? "
+                             desktop-buffer-file-name))))
+         (let ((buf (find-file-noselect desktop-buffer-file-name)))
+           (condition-case nil
+               (switch-to-buffer buf)
+             (error (pop-to-buffer buf)))
+           (and (not (eq major-mode desktop-buffer-major-mode))
+                (functionp desktop-buffer-major-mode)
+                (funcall desktop-buffer-major-mode))
+           buf)
+       'ignored)))
+ 
+ ;; 
----------------------------------------------------------------------------
+ ;; Create a buffer, load its file, set is mode, ...;  called from Desktop file
+ ;; only.
+ 
+ (eval-when-compile ; Just to silence the byte compiler
+    (defvar desktop-first-buffer) ;; Dynamically bound in `desktop-read'
+ )
+ 
+ (defun desktop-create-buffer (
+   desktop-file-version
+   desktop-buffer-file-name
+   desktop-buffer-name
+   desktop-buffer-major-mode
+   desktop-buffer-minor-modes
+   desktop-buffer-point
+   desktop-buffer-mark
+   desktop-buffer-read-only
+   desktop-buffer-misc
+   &optional
+   desktop-buffer-locals)
+   ;; To make desktop files with relative file names possible, we cannot
+   ;; allow `default-directory' to change. Therefore we save current buffer.
+   (save-current-buffer
+     (let (
+       (buffer-list (buffer-list))
+       (hlist desktop-buffer-handlers)
+       (result)
+       (handler)
+     )
+       ;; Call desktop-buffer-handlers to create buffer.
+       (while (and (not result) hlist)
+         (setq handler (car hlist))
+         (setq result (funcall handler))
+         (setq hlist (cdr hlist)))
+       (unless (bufferp result) (setq result nil))
+       ;; Restore buffer list order with new buffer at end. Don't change
+       ;; the order for old desktop files (old desktop module behaviour).
+       (unless (< desktop-file-version 206)
+         (mapcar 'bury-buffer buffer-list)
+         (when result (bury-buffer result)))
+       (when result
+         (unless (or desktop-first-buffer (< desktop-file-version 206))
+           (setq desktop-first-buffer result))
+         (set-buffer result)
+         (unless (equal (buffer-name) desktop-buffer-name)
+           (rename-buffer desktop-buffer-name))
+         ;; minor modes
+         (cond (
+           ;; backwards compatible
+           (equal '(t) desktop-buffer-minor-modes)
+           (auto-fill-mode 1))(
+           (equal '(nil) desktop-buffer-minor-modes)
+           (auto-fill-mode 0))(
+           t
+           (mapcar
+             #'(lambda (minor-mode)
+               (when (functionp minor-mode) (funcall minor-mode 1)))
+             desktop-buffer-minor-modes)))
+         ;; Even though point and mark are non-nil when written by 
`desktop-save'
+         ;; they may be modified by handlers wanting to set point or mark 
themselves.
+         (when desktop-buffer-point (goto-char desktop-buffer-point))
+         (when desktop-buffer-mark
+           (if (consp desktop-buffer-mark)
+             (progn
+               (set-mark (car desktop-buffer-mark))
+               (setq mark-active (car (cdr desktop-buffer-mark))))
+             (set-mark desktop-buffer-mark)))
+         ;; Never override file system if the file really is read-only marked.
+         (if desktop-buffer-read-only (setq buffer-read-only 
desktop-buffer-read-only))
+         (while desktop-buffer-locals
+           (let ((this (car desktop-buffer-locals)))
+             (if (consp this)
+               ;; an entry of this form `(symbol . value)'
+               (progn
+                 (make-local-variable (car this))
+                 (set (car this) (cdr this)))
+               ;; an entry of the form `symbol'
+               (make-local-variable this)
+               (makunbound this)))
+           (setq desktop-buffer-locals (cdr desktop-buffer-locals)))))))
+ 
+ ;; 
----------------------------------------------------------------------------
+ ;; Backward compatibility -- update parameters to 205 standards.
+ (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)
+                              (cons 'case-replace cr)
+                              (cons 'overwrite-mode (car mim)))))
+ 
+ ;; 
----------------------------------------------------------------------------
+ ;; When `desktop-enable' is non-nil and "--no-desktop" is not specified on the
+ ;; command line, we do the rest of what it takes to use desktop, but do it
+ ;; after finishing loading the init file.
+ ;; We cannot use `command-switch-alist' to process "--no-desktop" because 
these
+ ;; functions are processed after `after-init-hook'.
+ (add-hook
+   'after-init-hook
+   '(lambda ()
+     (let ((key "--no-desktop"))
+       (if (member key command-line-args)
+         (delete key command-line-args)
+         (when desktop-enable
+           (desktop-load-default)
+           (desktop-read))))))
+ 
+ (provide 'desktop)
+ 
+ ;;; desktop.el ends here




reply via email to

[Prev in Thread] Current Thread [Next in Thread]