# HG changeset patch # User Lars Hansen # Date 1064906542 0 # Node ID 7490e5357dba27d54fa8afa3f11c745c9c4e258c # Parent 0d905c2ca81428f02016c1d7c310ac5b80487723 A lot of comments updated. (desktop-save-mode): Minor mode introduced. (desktop-enable, desktop-clear-preserve-buffers): Variables made obsolete. (desktop-load-default): Function made obsolete. (desktop-locals-to-save): Variable made customizable. (desktop-read): Optional parameter `dirname' added. (desktop-change-dir, desktop-revert): Parameter `dirname' in `desktop-read' used. (desktop-save-in-load-dir): Renamed to `desktop-save-in-desktop-dir'. diff -r 0d905c2ca814 -r 7490e5357dba lisp/desktop.el --- a/lisp/desktop.el Mon Sep 29 22:56:46 2003 +0000 +++ b/lisp/desktop.el Tue Sep 30 07:22:22 2003 +0000 @@ -37,38 +37,19 @@ ;; - buffer-read-only ;; - some local variables -;; To use this, add these lines to the bottom of your .emacs file: -;; -;; (require 'desktop) -;; (setq desktop-enable t) +;; To use this, use customize to turn on desktop-save-mode or add the +;; following line somewhere in your .emacs file: ;; -;; Between the first 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 -;; -;; (add-to-list 'desktop-locals-to-save 'foobar) -;; -;; To avoid saving excessive amounts of data you may also wish to add -;; something like the following +;; (desktop-save-mode 1) ;; -;; (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'. +;; For further usage information, look at the section +;; "Saving Emacs Sessions" in the GNU Emacs Manual. -;; 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. +;; When the desktop module is loaded, the function `desktop-kill' is +;; added to the `kill-emacs-hook'. This function is responsible for +;; saving the desktop when Emacs is killed. Furthermore an anonymous +;; function is added to the `after-init-hook'. This function is +;; responsible for loading the desktop when Emacs is started. ;; Some words on minor modes: Most minor modes are controlled by ;; buffer-local variables, which have a standard save / restore @@ -121,24 +102,32 @@ "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") +;;;###autoload +(define-minor-mode desktop-save-mode + "Toggle desktop saving mode. +With numeric ARG, turn desktop saving on if ARG is positive, off +otherwise. See variable `desktop-save' for a description of when the +desktop is saved." + :global t + :group 'desktop) + +;; Maintained for backward compatibility +(defvaralias 'desktop-enable 'desktop-save-mode) +(make-obsolete-variable 'desktop-enable 'desktop-save-mode) (defcustom desktop-save 'ask-if-new - "*When the user changes desktop or quits emacs, should the desktop be saved? -\(in the current desktop directory) + "*Specifies whether the desktop should be saved when it is killed. +A desktop is killed when the user changes desktop or quits Emacs. +Possible values are: 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." +The desktop is never saved when `desktop-save-mode' is nil. +The variables `desktop-directory' and `desktop-base-file-name' +determine where the desktop is saved." :type '(choice (const :tag "Always save" t) (const :tag "Always ask" ask) @@ -150,7 +139,7 @@ (defcustom desktop-base-file-name (convert-standard-filename ".emacs.desktop") - "File for Emacs desktop, not including the directory name." + "Name of file for Emacs desktop, excluding the directory part." :type 'file :group 'desktop) (defvaralias 'desktop-basefilename 'desktop-base-file-name) @@ -162,13 +151,13 @@ :group 'desktop) (defcustom desktop-missing-file-warning nil - "*If non-nil then desktop warns when a file no longer exists. + "*If non-nil then `desktop-read' 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. + "Normal hook run when `desktop-read' can't find a desktop file. May e.g. be used to show a dired buffer." :type 'hook :group 'desktop) @@ -180,7 +169,7 @@ :group 'desktop) (defcustom desktop-save-hook nil - "Hook run before desktop saves the state of Emacs. + "Normal hook run before the desktop is saved in a desktop file. This is useful for truncating history lists, for example." :type 'hook :group 'desktop) @@ -192,11 +181,10 @@ 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. + "List of global variables saved by `desktop-save'. +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) @@ -208,7 +196,7 @@ search-ring-yank-pointer regexp-search-ring regexp-search-ring-yank-pointer) - "List of global variables set to clear by `desktop-clear'. + "List of global variables 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." @@ -216,19 +204,22 @@ :group 'desktop) (defcustom desktop-clear-preserve-buffers-regexp - "^\\*tramp/.+\\*$" + "^\\(\\*scratch\\*\\|\\*Messages\\*\\|\\*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." +(defcustom desktop-clear-preserve-buffers nil + "*List of buffer names that `desktop-clear' should not delete. +This variable is maintained for backward compatibility only. Use +`desktop-clear-preserve-buffers-regexp' instead." :type '(repeat string) :group 'desktop) +(make-obsolete-variable 'desktop-clear-preserve-buffers + 'desktop-clear-preserve-buffers-regexp) -(defvar desktop-locals-to-save '( +(defcustom desktop-locals-to-save '( desktop-locals-to-save ; Itself! Think it over. truncate-lines case-fold-search @@ -238,7 +229,9 @@ 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.") +The variables are saved only when they really are local." + :type '(repeat symbol) + :group 'desktop) (make-variable-buffer-local 'desktop-locals-to-save) ;; We skip .log files because they are normally temporary. @@ -250,7 +243,7 @@ :type 'regexp :group 'desktop) -;; Skip ange-ftp files +;; Skip tramp and ange-ftp files (defcustom desktop-files-not-to-save "^/[^/:]*:" "Regexp identifying files whose buffers are to be excluded from saving." @@ -259,7 +252,7 @@ (defcustom desktop-buffer-modes-to-save '(Info-mode rmail-mode) - "If a buffer is of one of these major modes, save the buffer name. + "If a buffer is of one of these major modes, save the buffer state. 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) @@ -283,17 +276,18 @@ '(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. +These functions are called by `desktop-save' in order, with no +arguments. If a function returns non-nil, its value is saved along +with the state of the buffer for which it was called; no further +functions will be called. -File names should formatted using the call +When file names are returned, they should be 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." +Later, when `desktop-read' restores buffers, each of the functions in +`desktop-buffer-handlers' will have access to a buffer local variable, +named `desktop-buffer-misc', whose value is what the function in +`desktop-buffer-misc-functions' returned." :type '(repeat function) :group 'desktop) @@ -303,7 +297,7 @@ desktop-buffer-mh desktop-buffer-info desktop-buffer-file) - "*List of functions to call in order to create a buffer. + "*Functions called by `desktop-read' in order to create a buffer. The functions are called without explicit parameters but can use the following variables: @@ -342,7 +336,7 @@ ;; ---------------------------------------------------------------------------- (defvar desktop-dirname nil - "The directory in which the current desktop file resides.") + "The directory in which the desktop file should be saved.") (defconst desktop-header ";; -------------------------------------------------------------------------- @@ -363,8 +357,9 @@ ;; ---------------------------------------------------------------------------- (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 +This kills all buffers except for internal ones and those matching +`desktop-clear-preserve-buffers-regexp' or listed in +`desktop-clear-preserve-buffers'. Furthermore, it clears the variables listed in `desktop-globals-to-clear'." (interactive) (dolist (var desktop-globals-to-clear) @@ -388,12 +383,12 @@ (add-hook 'kill-emacs-hook 'desktop-kill) (defun desktop-kill () - "If `desktop-enable' is non-nil, do what `desktop-save' says to do. + "If `desktop-save-mode' 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 + desktop-save-mode (let ((exists (file-exists-p (expand-file-name desktop-base-file-name desktop-dirname)))) (or (eq desktop-save t) @@ -579,7 +574,9 @@ ;; ---------------------------------------------------------------------------- (defun desktop-save (dirname) - "Save the Desktop file. Parameter DIRNAME specifies where to save desktop." + "Save the desktop in a desktop file. +Parameter DIRNAME specifies where to save the desktop file. +See also `desktop-base-file-name'." (interactive "DDirectory to save desktop file in: ") (run-hooks 'desktop-save-hook) (setq dirname (file-name-as-directory (expand-file-name dirname))) @@ -664,82 +661,98 @@ ;; ---------------------------------------------------------------------------- (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." + "Delete desktop file in `desktop-dirname'. +This function also sets `desktop-dirname' to nil." (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)))) + (when desktop-dirname + (let ((filename (expand-file-name desktop-base-file-name desktop-dirname))) + (setq desktop-dirname nil) + (when (file-exists-p filename) + (delete-file filename))))) ;; ---------------------------------------------------------------------------- ;;;###autoload +(defun desktop-read (&optional dirname) + "Read and process the desktop file in directory DIRNAME. +Look for a desktop file in DIRNAME, or if DIRNAME is omitted, look in +directories listed in `desktop-path'. If a desktop file is found, it +is processed and `desktop-after-read-hook' is run. If no desktop file +is found, clear the desktop and run `desktop-no-desktop-file-hook'. +This function is a no-op when Emacs is running in batch mode. +It returns t if a desktop file was loaded, nil otherwise." + (interactive) + (unless noninteractive + (setq desktop-dirname + (file-name-as-directory + (expand-file-name + (or + ;; If DIRNAME is specified, use it. + (and (< 0 (length dirname)) dirname) + ;; Otherwise search desktop file in desktop-path. + (let ((dirs desktop-path)) + (while + (and + dirs + (not + (file-exists-p (expand-file-name desktop-base-file-name (car dirs))))) + (setq dirs (cdr dirs))) + (and dirs (car dirs))) + ;; If not found and `desktop-path' is non-nil, use its first element. + (and desktop-path (car desktop-path)) + ;; Default: Home directory. + "~")))) + (if (file-exists-p (expand-file-name desktop-base-file-name desktop-dirname)) + ;; Desktop file found, process it. + (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) + ;; No desktop file found. + (desktop-clear) + (let ((default-directory desktop-dirname)) + (run-hooks 'desktop-no-desktop-file-hook)) + (message "No desktop file.") + nil))) + +;; ---------------------------------------------------------------------------- +;; Maintained for backward compatibility +;;;###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." +Also inhibit further loading of it." (if (not inhibit-default-init) ; safety check (progn (load "default" t t) (setq inhibit-default-init t)))) +(make-obsolete 'desktop-load-default 'desktop-save-mode) ;; ---------------------------------------------------------------------------- ;;;###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))) +(defun desktop-change-dir (dirname) + "Change to desktop saved in DIRNAME. +Kill the desktop as specified by variables `desktop-save-mode' and +`desktop-save', then clear the desktop and load the desktop file in +directory DIRNAME." + (interactive "DChange to directory: ") + (setq dirname (file-name-as-directory (expand-file-name dirname 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)) - ;; ---------------------------------------------------------------------------- + (desktop-read dirname)) + +;; ---------------------------------------------------------------------------- ;;;###autoload -(defun desktop-save-in-load-dir () - "Save desktop in directory from which it was loaded." +(defun desktop-save-in-desktop-dir () + "Save the desktop in directory `desktop-dirname'." (interactive) (if desktop-dirname (desktop-save desktop-dirname) @@ -751,9 +764,12 @@ (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)) + (unless desktop-dirname + (error "Unknown desktop directory")) + (unless (file-exists-p (expand-file-name desktop-base-file-name desktop-dirname)) + (error "No desktop file found")) + (desktop-clear) + (desktop-read desktop-dirname)) ;; ---------------------------------------------------------------------------- ;; Note: the following functions use the dynamic variable binding in Lisp. @@ -962,7 +978,7 @@ (cons 'overwrite-mode (car mim))))) ;; ---------------------------------------------------------------------------- -;; When `desktop-enable' is non-nil and "--no-desktop" is not specified on the +;; When `desktop-save-mode' 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 @@ -973,9 +989,7 @@ (let ((key "--no-desktop")) (if (member key command-line-args) (delete key command-line-args) - (when desktop-enable - (desktop-load-default) - (desktop-read)))))) + (when desktop-save-mode (desktop-read)))))) (provide 'desktop)