1 ;;; desktop.el --- save partial status of Emacs when killed
3 ;; Copyright (C) 1993, 1994, 1995, 1997, 2000, 2001
4 ;; Free Software Foundation, Inc.
6 ;; Author: Morten Welinder <terra@diku.dk>
7 ;; Maintainter: Lars Hansen <larsh@math.ku.dk>
8 ;; Keywords: convenience
9 ;; Favourite-brand-of-beer: None, I hate beer.
11 ;; This file is part of GNU Emacs.
13 ;; GNU Emacs is free software; you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation; either version 2, or (at your option)
18 ;; GNU Emacs is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs; see the file COPYING. If not, write to the
25 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 ;; Boston, MA 02111-1307, USA.
30 ;; Save the Desktop, i.e.,
31 ;; - some global variables
32 ;; - the list of buffers with associated files. For each buffer also
34 ;; - the default directory
36 ;; - the mark & mark-active
38 ;; - some local variables
40 ;; To use this, first put these two lines in the bottom of your .emacs
41 ;; file (the later the better):
43 ;; (desktop-load-default)
46 ;; Between these two lines you may wish to add something that updates the
47 ;; variables `desktop-globals-to-save' and/or `desktop-locals-to-save'. If
48 ;; for instance you want to save the local variable `foobar' for every buffer
49 ;; in which it is local, you could add the line
51 ;; (setq desktop-locals-to-save (cons 'foobar desktop-locals-to-save))
53 ;; To avoid saving excessive amounts of data you may also wish to add
54 ;; something like the following
56 ;; (add-hook 'kill-emacs-hook
58 ;; (desktop-truncate search-ring 3)
59 ;; (desktop-truncate regexp-search-ring 3)))
61 ;; which will make sure that no more than three search items are saved. You
62 ;; must place this line *after* the `(desktop-load-default)' line. See also
63 ;; the variable `desktop-save-hook'.
65 ;; Start Emacs in the root directory of your "project". The desktop saver
66 ;; is inactive by default. You activate it by M-x desktop-save RET. When
67 ;; you exit the next time the above data will be saved. This ensures that
68 ;; all the files you were editing will be reloaded the next time you start
69 ;; Emacs from the same directory and that points will be set where you
70 ;; left them. If you save a desktop file in your home directory it will
71 ;; act as a default desktop when you start Emacs from a directory that
72 ;; doesn't have its own. I never do this, but you may want to.
74 ;; Some words on minor modes: Most minor modes are controlled by
75 ;; buffer-local variables, which have a standard save / restore
76 ;; mechanism. To handle all minor modes, we take the following
77 ;; approach: (1) check whether the variable name from
78 ;; `minor-mode-alist' is also a function; and (2) use translation
79 ;; table `desktop-minor-mode-table' in the case where the two names
82 ;; By the way: don't use desktop.el to customize Emacs -- the file .emacs
83 ;; in your home directory is used for that. Saving global default values
84 ;; for buffers is an example of misuse.
86 ;; PLEASE NOTE: The kill ring can be saved as specified by the variable
87 ;; `desktop-globals-to-save' (by default it isn't). This may result in saving
88 ;; things you did not mean to keep. Use M-x desktop-clear RET.
90 ;; Thanks to hetrick@phys.uva.nl (Jim Hetrick) for useful ideas.
91 ;; avk@rtsg.mot.com (Andrew V. Klein) for a dired tip.
92 ;; chris@tecc.co.uk (Chris Boucher) for a mark tip.
93 ;; f89-kam@nada.kth.se (Klas Mellbourn) for a mh-e tip.
94 ;; kifer@sbkifer.cs.sunysb.edu (M. Kifer) for a bug hunt.
95 ;; treese@lcs.mit.edu (Win Treese) for ange-ftp tips.
96 ;; pot@cnuce.cnr.it (Francesco Potorti`) for misc. tips.
97 ;; ---------------------------------------------------------------------------
100 ;; Save window configuration.
101 ;; Recognize more minor modes.
106 ;; Make the compilation more silent
108 ;; We use functions from these modules
109 ;; We can't (require 'mh-e) since that wants to load something.
110 (mapcar 'require '(info dired reporter)))
112 (defvar desktop-file-version "206"
113 "Verion number of desktop file format.
114 Written into the desktop file and used at desktop read to provide
115 backward compatibility.")
117 ;; ----------------------------------------------------------------------------
118 ;; USER OPTIONS -- settings you might want to play with.
119 ;; ----------------------------------------------------------------------------
121 (defgroup desktop nil
122 "Save status of Emacs when you exit."
125 (defcustom desktop-enable nil
126 "*Non-nil enable Desktop to save the state of Emacs when you exit."
130 :initialize 'custom-initialize-default
133 (defcustom desktop-save 'ask-if-new
134 "*When the user changes desktop or quits emacs, should the desktop be saved?
135 \(in the current desktop directory)
138 ask-if-new -- ask if no desktop file exists, otherwise just save.
139 ask-if-exists -- ask if desktop file exists, otherwise don't save.
140 if-exists -- save if desktop file exists, otherwise don't save.
142 The desktop is never saved when `desktop-enable' is nil."
144 (const :tag "Always save" t)
145 (const :tag "Always ask" ask)
146 (const :tag "Ask if desktop file is new, else do save" ask-if-new)
147 (const :tag "Ask if desktop file exists, else don't save" ask-if-exists)
148 (const :tag "Save if desktop file exists, else don't" if-exists)
149 (const :tag "Never save" nil))
152 (defcustom desktop-base-file-name
153 (convert-standard-filename ".emacs.desktop")
154 "File for Emacs desktop, not including the directory name."
157 (defvaralias 'desktop-basefilename 'desktop-base-file-name)
159 (defcustom desktop-path '("." "~")
160 "List of directories to search for the desktop file.
161 The base name of the file is specified in `desktop-base-file-name'."
162 :type '(repeat directory)
165 (defcustom desktop-missing-file-warning nil
166 "*If non-nil then desktop warns when a file no longer exists.
167 Otherwise it simply ignores that file."
171 (defcustom desktop-no-desktop-file-hook nil
172 "Normal hook run after fail of `desktop-read' due to missing desktop file.
173 May e.g. be used to show a dired buffer."
177 (defcustom desktop-after-read-hook nil
178 "Normal hook run after a sucessful `desktop-read'.
179 May e.g. be used to show a buffer list."
183 (defcustom desktop-save-hook nil
184 "Hook run before desktop saves the state of Emacs.
185 This is useful for truncating history lists, for example."
189 (defcustom desktop-globals-to-save '(
190 desktop-missing-file-warning
196 "List of global variables to save when killing Emacs.
197 An element may be variable name (a symbol)
198 or a cons cell of the form (VAR . MAX-SIZE),
199 which means to truncate VAR's value to at most MAX-SIZE elements
200 \(if the value is a list) before saving the value.
201 Feature: Saving `kill-ring' implies saving `kill-ring-yank-pointer'."
202 :type '(repeat (restricted-sexp :match-alternatives (symbolp consp)))
205 (defcustom desktop-globals-to-clear '(
207 kill-ring-yank-pointer
209 search-ring-yank-pointer
211 regexp-search-ring-yank-pointer)
212 "List of global variables set to clear by `desktop-clear'.
213 An element may be variable name (a symbol) or a cons cell of the form
214 \(VAR . FORM). Symbols are set to nil and for cons cells VAR is set
215 to the value obtained by evaluateing FORM."
216 :type '(repeat (restricted-sexp :match-alternatives (symbolp consp)))
219 (defcustom desktop-clear-preserve-buffers-regexp
221 "Regexp identifying buffers that `desktop-clear' should not delete."
225 ;; Maintained for backward compatibility
226 (defcustom desktop-clear-preserve-buffers
227 '("*scratch*" "*Messages*")
228 "*List of buffer names that `desktop-clear' should not delete."
229 :type '(repeat string)
232 (defvar desktop-locals-to-save '(
233 desktop-locals-to-save ; Itself! Think it over.
239 change-log-default-name
241 "List of local variables to save for each buffer.
242 The variables are saved only when they really are local.")
243 (make-variable-buffer-local 'desktop-locals-to-save)
245 ;; We skip .log files because they are normally temporary.
246 ;; (ftp) files because they require passwords and whatnot.
247 ;; TAGS files to save time (tags-file-name is saved instead).
248 (defcustom desktop-buffers-not-to-save
249 "\\(^nn\\.a[0-9]+\\|\\.log\\|(ftp)\\|^tags\\|^TAGS\\)$"
250 "Regexp identifying buffers that are to be excluded from saving."
254 ;; Skip ange-ftp files
255 (defcustom desktop-files-not-to-save
257 "Regexp identifying files whose buffers are to be excluded from saving."
261 (defcustom desktop-buffer-modes-to-save
262 '(Info-mode rmail-mode)
263 "If a buffer is of one of these major modes, save the buffer name.
264 It is up to the functions in `desktop-buffer-handlers' to decide
265 whether the buffer should be recreated or not, and how."
266 :type '(repeat symbol)
269 (defcustom desktop-modes-not-to-save nil
270 "List of major modes whose buffers should not be saved."
271 :type '(repeat symbol)
274 (defcustom desktop-file-name-format 'absolute
275 "*Format in which desktop file names should be saved.
277 absolute -- Absolute file name.
278 tilde -- Relative to ~.
279 local -- Relative to directory of desktop file."
280 :type '(choice (const absolute) (const tilde) (const local))
283 (defcustom desktop-buffer-misc-functions
284 '(desktop-buffer-info-misc-data
285 desktop-buffer-dired-misc-data)
286 "*Functions used to determine auxiliary information for a buffer.
287 These functions are called in order, with no arguments. If a function
288 returns non-nil, its value is saved along with the desktop buffer for
289 which it was called; no further functions will be called.
291 File names should formatted using the call
292 \"(desktop-file-name FILE-NAME dirname)\".
294 Later, when desktop.el restores the buffers it has saved, each of the
295 `desktop-buffer-handlers' functions will have access to a buffer local
296 variable, named `desktop-buffer-misc', whose value is what the
297 \"misc\" function returned previously."
298 :type '(repeat function)
301 (defcustom desktop-buffer-handlers
302 '(desktop-buffer-dired
307 "*List of functions to call in order to create a buffer.
308 The functions are called without explicit parameters but can use the
312 desktop-buffer-file-name
314 desktop-buffer-major-mode
315 desktop-buffer-minor-modes
318 desktop-buffer-read-only
320 desktop-buffer-locals
322 If one function returns non-nil, no further functions are called.
323 If the function returns a buffer, then the saved mode settings
324 and variable values for that buffer are copied into it."
325 :type '(repeat function)
328 (put 'desktop-buffer-handlers 'risky-local-variable t)
330 (defcustom desktop-minor-mode-table
331 '((auto-fill-function auto-fill-mode)
333 "Table mapping minor mode variables to minor mode functions.
334 Each entry has the form (NAME RESTORE-FUNCTION).
335 NAME is the name of the buffer-local variable indicating that the minor
336 mode is active. RESTORE-FUNCTION is the function to activate the minor mode.
337 called. RESTORE-FUNCTION nil means don't try to restore the minor mode.
338 Only minor modes for which the name of the buffer-local variable
339 and the name of the minor mode function are different have to added to
344 ;; ----------------------------------------------------------------------------
345 (defvar desktop-dirname nil
346 "The directory in which the current desktop file resides.")
348 (defconst desktop-header
349 ";; --------------------------------------------------------------------------
350 ;; Desktop File for Emacs
351 ;; --------------------------------------------------------------------------
352 " "*Header to place in Desktop file.")
354 (defvar desktop-delay-hook nil
355 "Hooks run after all buffers are loaded; intended for internal use.")
357 ;; ----------------------------------------------------------------------------
358 (defun desktop-truncate (l n)
359 "Truncate LIST to at most N elements destructively."
360 (let ((here (nthcdr (1- n) l)))
364 ;; ----------------------------------------------------------------------------
365 (defun desktop-clear ()
367 This kills all buffers except for internal ones and those listed
368 in `desktop-clear-preserve-buffers'. Furthermore, it clears the
369 variables listed in `desktop-globals-to-clear'."
371 (dolist (var desktop-globals-to-clear)
373 (eval `(setq-default ,var nil))
374 (eval `(setq-default ,(car var) ,(cdr var)))))
375 (let ((buffers (buffer-list)))
377 (let ((bufname (buffer-name (car buffers))))
380 (string-match desktop-clear-preserve-buffers-regexp bufname)
381 (member bufname desktop-clear-preserve-buffers)
382 ;; Don't kill buffers made for internal purposes.
383 (and (not (equal bufname "")) (eq (aref bufname 0) ?\ ))
384 (kill-buffer (car buffers))))
385 (setq buffers (cdr buffers))))
386 (delete-other-windows))
388 ;; ----------------------------------------------------------------------------
389 (add-hook 'kill-emacs-hook 'desktop-kill)
391 (defun desktop-kill ()
392 "If `desktop-enable' is non-nil, do what `desktop-save' says to do.
393 If the desktop should be saved and `desktop-dirname'
394 is nil, ask the user where to save the desktop."
398 (let ((exists (file-exists-p (expand-file-name desktop-base-file-name desktop-dirname))))
401 (and exists (memq desktop-save '(ask-if-new if-exists)))
404 (memq desktop-save '(ask ask-if-new))
405 (and exists (eq desktop-save 'ask-if-exists)))
406 (y-or-n-p "Save desktop? ")))))
407 (unless desktop-dirname
408 (setq desktop-dirname
409 (file-name-as-directory
412 (lambda (dir) (interactive "DDirectory for desktop file: ") dir))))))
414 (desktop-save desktop-dirname)
416 (unless (yes-or-no-p "Error while saving the desktop. Ignore? ")
417 (signal (car err) (cdr err)))))))
419 ;; ----------------------------------------------------------------------------
420 (defun desktop-list* (&rest args)
421 (if (null (cdr args))
423 (setq args (nreverse args))
424 (let ((value (cons (nth 1 args) (car args))))
425 (setq args (cdr (cdr args)))
427 (setq value (cons (car args) value))
428 (setq args (cdr args)))
431 ;; ----------------------------------------------------------------------------
432 (defun desktop-internal-v2s (val)
433 "Convert VALUE to a pair (QUOTE . TXT); (eval (read TXT)) gives VALUE.
434 TXT is a string that when read and evaluated yields value.
435 QUOTE may be `may' (value may be quoted),
436 `must' (values must be quoted), or nil (value may not be quoted)."
438 ((or (numberp val) (null val) (eq t val))
439 (cons 'may (prin1-to-string val)))
441 (let ((copy (copy-sequence val)))
442 (set-text-properties 0 (length copy) nil copy)
443 ;; Get rid of text properties because we cannot read them
444 (cons 'may (prin1-to-string copy))))
446 (cons 'must (prin1-to-string val)))
451 (let ((res (desktop-internal-v2s el)))
457 (cons nil (concat "(vector "
458 (mapconcat (lambda (el)
459 (if (eq (car el) 'must)
460 (concat "'" (cdr el))
465 (cons 'may (concat "[" (mapconcat 'cdr pass1 " ") "]")))))
472 (let ((q.txt (desktop-internal-v2s (car p))))
473 (or anynil (setq anynil (null (car q.txt))))
474 (setq newlist (cons q.txt newlist)))
477 (let ((last (desktop-internal-v2s p))
479 (or anynil (setq anynil (null (car last))))
481 (setq newlist (cons '(must . ".") newlist)))
483 (setq newlist (cons last newlist))))
484 (setq newlist (nreverse newlist))
487 (concat (if use-list* "(desktop-list* " "(list ")
488 (mapconcat (lambda (el)
489 (if (eq (car el) 'must)
490 (concat "'" (cdr el))
496 (concat "(" (mapconcat 'cdr newlist " ") ")")))))
498 (cons nil (concat "(symbol-function '"
499 (substring (prin1-to-string val) 7 -1)
502 (let ((pos (prin1-to-string (marker-position val)))
503 (buf (prin1-to-string (buffer-name (marker-buffer val)))))
504 (cons nil (concat "(let ((mk (make-marker)))"
505 " (add-hook 'desktop-delay-hook"
506 " (list 'lambda '() (list 'set-marker mk "
507 pos " (get-buffer " buf ")))) mk)"))))
509 (cons 'may "\"Unprintable entity\""))))
511 ;; ----------------------------------------------------------------------------
512 (defun desktop-value-to-string (val)
513 "Convert VALUE to a string that when read evaluates to the same value.
514 Not all types of values are supported."
515 (let* ((print-escape-newlines t)
516 (float-output-format nil)
517 (quote.txt (desktop-internal-v2s val))
518 (quote (car quote.txt))
519 (txt (cdr quote.txt)))
524 ;; ----------------------------------------------------------------------------
525 (defun desktop-outvar (varspec)
526 "Output a setq statement for variable VAR to the desktop file.
527 The argument VARSPEC may be the variable name VAR (a symbol),
528 or a cons cell of the form (VAR . MAX-SIZE),
529 which means to truncate VAR's value to at most MAX-SIZE elements
530 \(if the value is a list) before saving the value."
533 (setq var (car varspec) size (cdr varspec))
537 (if (and (integerp size)
540 (desktop-truncate (eval var) size))
544 (desktop-value-to-string (symbol-value var))
547 ;; ----------------------------------------------------------------------------
548 (defun desktop-save-buffer-p (filename bufname mode &rest dummy)
549 "Return t if the desktop should record a particular buffer for next startup.
550 FILENAME is the visited file name, BUFNAME is the buffer name, and
551 MODE is the major mode."
552 (let ((case-fold-search nil))
553 (and (not (string-match desktop-buffers-not-to-save bufname))
554 (not (memq mode desktop-modes-not-to-save))
556 (not (string-match desktop-files-not-to-save filename)))
557 (and (eq mode 'dired-mode)
559 (set-buffer (get-buffer bufname))
560 (not (string-match desktop-files-not-to-save
561 default-directory))))
563 (memq mode desktop-buffer-modes-to-save))))))
565 ;; ----------------------------------------------------------------------------
566 (defun desktop-file-name (filename dirname)
567 "Convert FILENAME to format specified in `desktop-file-name-format'.
568 DIRNAME must be the directory in which the desktop file will be saved."
571 ((eq desktop-file-name-format 'tilde)
572 (let ((relative-name (file-relative-name (expand-file-name filename) "~")))
574 ((file-name-absolute-p relative-name) relative-name)
575 ((string= "./" relative-name) "~/")
576 ((string= "." relative-name) "~")
577 (t (concat "~/" relative-name)))))
578 ((eq desktop-file-name-format 'local) (file-relative-name filename dirname))
579 (t (expand-file-name filename))))
581 ;; ----------------------------------------------------------------------------
582 (defun desktop-save (dirname)
583 "Save the Desktop file. Parameter DIRNAME specifies where to save desktop."
584 (interactive "DDirectory to save desktop file in: ")
585 (run-hooks 'desktop-save-hook)
586 (setq dirname (file-name-as-directory (expand-file-name dirname)))
588 (let ((filename (expand-file-name desktop-base-file-name dirname))
595 (desktop-file-name (buffer-file-name) dirname)
607 (let ((special (assq mim desktop-minor-mode-table)))
608 (if special (cadr special) mim))
610 (mapcar #'car minor-mode-alist))
613 (list (mark t) mark-active)
615 (run-hook-with-args-until-success 'desktop-buffer-misc-functions)
616 (let ((locals desktop-locals-to-save)
617 (loclist (buffer-local-variables))
620 (let ((here (assq (car locals) loclist)))
622 (setq ll (cons here ll))
623 (when (member (car locals) loclist)
624 (setq ll (cons (car locals) ll)))))
625 (setq locals (cdr locals)))
628 (buf (get-buffer-create "*desktop*")))
633 ";; -*- coding: utf-8-emacs; -*-\n"
635 ";; Created " (current-time-string) "\n"
636 ";; Desktop file format version " desktop-file-version "\n"
637 ";; Emacs version " emacs-version "\n\n"
638 ";; Global section:\n")
639 (mapcar (function desktop-outvar) desktop-globals-to-save)
640 (if (memq 'kill-ring desktop-globals-to-save)
642 "(setq kill-ring-yank-pointer (nthcdr "
643 (int-to-string (- (length kill-ring) (length kill-ring-yank-pointer)))
646 (insert "\n;; Buffer section -- buffers listed in same order as in buffer list:\n")
650 (if (apply 'desktop-save-buffer-p l)
652 (insert "(desktop-create-buffer " desktop-file-version)
656 (insert "\n " (desktop-value-to-string e))))
660 (setq default-directory dirname)
661 (when (file-exists-p filename) (delete-file filename))
662 (let ((coding-system-for-write 'utf-8-emacs))
663 (write-region (point-min) (point-max) filename nil 'nomessage))))
664 (setq desktop-dirname dirname))
666 ;; ----------------------------------------------------------------------------
667 (defun desktop-remove ()
668 "Delete the Desktop file and inactivate the desktop system."
671 (let ((filename (expand-file-name desktop-base-file-name desktop-dirname)))
672 (setq desktop-dirname nil)
673 (if (file-exists-p filename)
674 (delete-file filename)))))
675 ;; ----------------------------------------------------------------------------
677 (defun desktop-read ()
678 "Read the Desktop file and the files it specifies.
679 This is a no-op when Emacs is running in batch mode.
680 Look for the desktop file according to the variables `desktop-base-file-name'
681 and `desktop-path'. If no desktop file is found, clear the desktop.
682 Returns t if it has read a desktop file, nil otherwise."
684 (unless noninteractive
685 (let ((dirs desktop-path))
690 (file-exists-p (expand-file-name desktop-base-file-name (car dirs)))))
691 (setq dirs (cdr dirs)))
692 (setq desktop-dirname (and dirs (file-name-as-directory (expand-file-name (car dirs)))))
694 (let ((desktop-first-buffer nil))
695 ;; Evaluate desktop buffer.
696 (load (expand-file-name desktop-base-file-name desktop-dirname) t t t)
697 ;; `desktop-create-buffer' puts buffers at end of the buffer list.
698 ;; We want buffers existing prior to evaluating the desktop (and not reused)
699 ;; to be placed at the end of the buffer list, so we move them here.
701 (nreverse (cdr (memq desktop-first-buffer (nreverse (buffer-list))))))
702 (switch-to-buffer (car (buffer-list)))
703 (run-hooks 'desktop-delay-hook)
704 (setq desktop-delay-hook nil)
705 (run-hooks 'desktop-after-read-hook)
706 (message "Desktop loaded.")
709 (run-hooks 'desktop-no-desktop-file-hook)
710 (message "No desktop file.")
713 ;; ----------------------------------------------------------------------------
715 (defun desktop-load-default ()
716 "Load the `default' start-up library manually.
717 Also inhibit further loading of it. Call this from your `.emacs' file
718 to provide correct modes for autoloaded files."
719 (if (not inhibit-default-init) ; safety check
722 (setq inhibit-default-init t))))
724 ;; ----------------------------------------------------------------------------
726 (defun desktop-change-dir (dir)
727 "Save and clear the desktop, then load the desktop from directory DIR.
728 However, if `desktop-enable' was nil at call, don't save the old desktop.
729 This function always sets `desktop-enable' to t."
730 (interactive "DNew directory: ")
731 (setq dir (file-name-as-directory (expand-file-name dir desktop-dirname)))
734 (setq desktop-enable t)
735 (let ((desktop-path (list dir))
736 (default-directory dir))
738 ;; Set `desktop-dirname' even in no desktop file was found
739 (setq desktop-dirname dir))
740 ;; ----------------------------------------------------------------------------
742 (defun desktop-save-in-load-dir ()
743 "Save desktop in directory from which it was loaded."
746 (desktop-save desktop-dirname)
747 (call-interactively 'desktop-save))
748 (message "Desktop saved in %s" desktop-dirname))
750 ;; ----------------------------------------------------------------------------
752 (defun desktop-revert ()
753 "Revert to the last loaded desktop."
755 (unless desktop-dirname (error "No desktop has been loaded"))
756 (setq desktop-enable nil)
757 (desktop-change-dir desktop-dirname))
759 ;; ----------------------------------------------------------------------------
760 ;; Note: the following functions use the dynamic variable binding in Lisp.
763 (eval-when-compile ; Just to silence the byte compiler
764 (defvar desktop-file-version)
765 (defvar desktop-buffer-file-name)
766 (defvar desktop-buffer-name)
767 (defvar desktop-buffer-major-mode)
768 (defvar desktop-buffer-minor-modes)
769 (defvar desktop-buffer-point)
770 (defvar desktop-buffer-mark)
771 (defvar desktop-buffer-read-only)
772 (defvar desktop-buffer-misc)
773 (defvar desktop-buffer-locals)
776 (defun desktop-buffer-info-misc-data ()
777 (if (eq major-mode 'Info-mode)
778 (list Info-current-file
781 ;; ----------------------------------------------------------------------------
782 (defun desktop-buffer-dired-misc-data ()
783 (when (eq major-mode 'dired-mode)
784 (eval-when-compile (defvar dirname))
786 ;; Value of `dired-directory'.
787 (if (consp dired-directory)
788 ;; Directory name followed by list of files.
789 (cons (desktop-file-name (car dired-directory) dirname) (cdr dired-directory))
790 ;; Directory name, optionally with with shell wildcard.
791 (desktop-file-name dired-directory dirname))
792 ;; Subdirectories in `dired-subdir-alist'.
796 (function (lambda (f) (desktop-file-name (car f) dirname)))
797 dired-subdir-alist))))))
799 ;; ----------------------------------------------------------------------------
800 (defun desktop-buffer-info () "Load an info file."
801 (if (eq 'Info-mode desktop-buffer-major-mode)
803 (let ((first (nth 0 desktop-buffer-misc))
804 (second (nth 1 desktop-buffer-misc)))
805 (when (and first second)
808 (Info-find-node first second))
809 (current-buffer))))))
811 ;; ----------------------------------------------------------------------------
812 (eval-when-compile (defvar rmail-buffer)) ; Just to silence the byte compiler.
813 (defun desktop-buffer-rmail () "Load an RMAIL file."
814 (if (eq 'rmail-mode desktop-buffer-major-mode)
815 (condition-case error
816 (progn (rmail-input desktop-buffer-file-name)
817 (if (eq major-mode 'rmail-mode)
821 (kill-buffer (current-buffer))
824 ;; ----------------------------------------------------------------------------
825 (defun desktop-buffer-mh () "Load a folder in the mh system."
826 (if (eq 'mh-folder-mode desktop-buffer-major-mode)
829 (mh-visit-folder desktop-buffer-name)
832 ;; ----------------------------------------------------------------------------
833 (defun desktop-buffer-dired () "Load a directory using dired."
834 (if (eq 'dired-mode desktop-buffer-major-mode)
835 ;; First element of `desktop-buffer-misc' is the value of `dired-directory'.
836 ;; This value is a directory name, optionally with with shell wildcard or
837 ;; a directory name followed by list of files.
838 (let* ((dired-directory (car desktop-buffer-misc))
839 (dir (if (consp dired-directory) (car dired-directory) dired-directory)))
840 (if (file-directory-p (file-name-directory dir))
842 (dired dired-directory)
843 (mapcar 'dired-maybe-insert-subdir (cdr desktop-buffer-misc))
845 (message "Directory %s no longer exists." dir)
849 ;; ----------------------------------------------------------------------------
850 (defun desktop-buffer-file ()
852 (if desktop-buffer-file-name
853 (if (or (file-exists-p desktop-buffer-file-name)
854 (and desktop-missing-file-warning
856 "File \"%s\" no longer exists. Re-create? "
857 desktop-buffer-file-name))))
858 (let ((buf (find-file-noselect desktop-buffer-file-name)))
860 (switch-to-buffer buf)
861 (error (pop-to-buffer buf)))
862 (and (not (eq major-mode desktop-buffer-major-mode))
863 (functionp desktop-buffer-major-mode)
864 (funcall desktop-buffer-major-mode))
868 ;; ----------------------------------------------------------------------------
869 ;; Create a buffer, load its file, set is mode, ...; called from Desktop file
872 (eval-when-compile ; Just to silence the byte compiler
873 (defvar desktop-first-buffer) ;; Dynamically bound in `desktop-read'
876 (defun desktop-create-buffer (
878 desktop-buffer-file-name
880 desktop-buffer-major-mode
881 desktop-buffer-minor-modes
884 desktop-buffer-read-only
887 desktop-buffer-locals)
888 ;; To make desktop files with relative file names possible, we cannot
889 ;; allow `default-directory' to change. Therefore we save current buffer.
892 (buffer-list (buffer-list))
893 (hlist desktop-buffer-handlers)
897 ;; Call desktop-buffer-handlers to create buffer.
898 (while (and (not result) hlist)
899 (setq handler (car hlist))
900 (setq result (funcall handler))
901 (setq hlist (cdr hlist)))
902 (unless (bufferp result) (setq result nil))
903 ;; Restore buffer list order with new buffer at end. Don't change
904 ;; the order for old desktop files (old desktop module behaviour).
905 (unless (< desktop-file-version 206)
906 (mapcar 'bury-buffer buffer-list)
907 (when result (bury-buffer result)))
909 (unless (or desktop-first-buffer (< desktop-file-version 206))
910 (setq desktop-first-buffer result))
912 (unless (equal (buffer-name) desktop-buffer-name)
913 (rename-buffer desktop-buffer-name))
916 ;; backwards compatible
917 (equal '(t) desktop-buffer-minor-modes)
919 (equal '(nil) desktop-buffer-minor-modes)
923 #'(lambda (minor-mode)
924 (when (functionp minor-mode) (funcall minor-mode 1)))
925 desktop-buffer-minor-modes)))
926 ;; Even though point and mark are non-nil when written by `desktop-save'
927 ;; they may be modified by handlers wanting to set point or mark themselves.
928 (when desktop-buffer-point (goto-char desktop-buffer-point))
929 (when desktop-buffer-mark
930 (if (consp desktop-buffer-mark)
932 (set-mark (car desktop-buffer-mark))
933 (setq mark-active (car (cdr desktop-buffer-mark))))
934 (set-mark desktop-buffer-mark)))
935 ;; Never override file system if the file really is read-only marked.
936 (if desktop-buffer-read-only (setq buffer-read-only desktop-buffer-read-only))
937 (while desktop-buffer-locals
938 (let ((this (car desktop-buffer-locals)))
940 ;; an entry of this form `(symbol . value)'
942 (make-local-variable (car this))
943 (set (car this) (cdr this)))
944 ;; an entry of the form `symbol'
945 (make-local-variable this)
947 (setq desktop-buffer-locals (cdr desktop-buffer-locals)))))))
949 ;; ----------------------------------------------------------------------------
950 ;; Backward compatibility -- update parameters to 205 standards.
951 (defun desktop-buffer (desktop-buffer-file-name desktop-buffer-name
952 desktop-buffer-major-mode
953 mim pt mk ro tl fc cfs cr desktop-buffer-misc)
954 (desktop-create-buffer 205 desktop-buffer-file-name desktop-buffer-name
955 desktop-buffer-major-mode (cdr mim) pt mk ro
957 (list (cons 'truncate-lines tl)
958 (cons 'fill-column fc)
959 (cons 'case-fold-search cfs)
960 (cons 'case-replace cr)
961 (cons 'overwrite-mode (car mim)))))
963 ;; ----------------------------------------------------------------------------
964 ;; When `desktop-enable' is non-nil and "--no-desktop" is not specified on the
965 ;; command line, we do the rest of what it takes to use desktop, but do it
966 ;; after finishing loading the init file.
967 ;; We cannot use `command-switch-alist' to process "--no-desktop" because these
968 ;; functions are processed after `after-init-hook'.
972 (let ((key "--no-desktop"))
973 (if (member key command-line-args)
974 (delete key command-line-args)
976 (desktop-load-default)
981 ;;; desktop.el ends here