3404
|
1 ;;; desktop.el --- save partial status of Emacs when killed
|
|
2
|
|
3 ;; Copyright (C) 1993 Free Software Foundation, Inc.
|
|
4
|
|
5 ;; Author: Morten Welinder <terra@diku.dk>
|
|
6 ;; Version: 2.01
|
|
7
|
|
8 ;; This file is part of GNU Emacs.
|
|
9
|
|
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
|
|
11 ;; it under the terms of the GNU General Public License as published by
|
|
12 ;; the Free Software Foundation; either version 2, or (at your option)
|
|
13 ;; any later version.
|
|
14
|
|
15 ;; GNU Emacs is distributed in the hope that it will be useful,
|
|
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
18 ;; GNU General Public License for more details.
|
|
19
|
|
20 ;; You should have received a copy of the GNU General Public License
|
|
21 ;; along with GNU Emacs; see the file COPYING. If not, write to
|
|
22 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
23
|
|
24 ;;; Commentary:
|
|
25
|
|
26 ; Save the Desktop, i.e.,
|
|
27 ; - some global variables
|
|
28 ; - the list of buffers with associated files. For each buffer also
|
|
29 ; - the major mode
|
|
30 ; - the default directory
|
|
31 ; - the point
|
|
32 ; - the mark
|
|
33 ; - buffer-read-only
|
|
34 ; - truncate-lines
|
|
35 ; - case-fold-search
|
|
36 ; - case-replace
|
|
37 ; - fill-column
|
|
38
|
|
39 ; To use this, first put these three lines in the bottom of your .emacs
|
|
40 ; file (the later the better):
|
|
41 ;
|
|
42 ; (load "desktop")
|
|
43 ; (desktop-load-default)
|
|
44 ; (desktop-read)
|
|
45 ;
|
|
46
|
|
47 ; Start Emacs in the root directory of your "project". The desktop saver
|
|
48 ; is inactive by default. You activate it by M-X desktop-save RET. When
|
|
49 ; you exit the next time the above data will be saved. This ensures that
|
|
50 ; all the files you were editing will be reloaded the next time you start
|
|
51 ; Emacs from the same directory and that points will be set where you
|
|
52 ; left them.
|
|
53 ;
|
|
54 ; PLEASE NOTE: When the kill ring is saved as specified by the variable
|
|
55 ; `desktop-globals-to-save' (by default it isn't). This may result in saving
|
|
56 ; things you did not mean to keep. Use M-X desktop-clear RET.
|
|
57 ;
|
|
58 ; Thanks to hetrick@phys.uva.nl (Jim Hetrick) for useful ideas.
|
|
59 ; ---------------------------------------------------------------------------
|
|
60 ; HISTORY:
|
|
61 ;
|
|
62 ; Dec , 1992: Version 1.0 written; never released.
|
|
63 ; Jan , 1993: Minor modes now saved: auto-fill-mode, overwrite-mode.
|
|
64 ; Apr 26, 1993: Version 1.1 released.
|
|
65 ; Apr 29, 1993: Now supports RMAIL, Info, and dired modes.
|
|
66 ; Will now search home directory for desktop file.
|
|
67 ; desktop-save asks for directory to save in.
|
|
68 ; May 31, 1993: Version 1.3
|
|
69 ; Now works with Emacs 19.
|
|
70 ; Jun 1, 1993: Minor bug fix.
|
|
71 ;
|
|
72 ; TODO:
|
|
73 ;
|
|
74 ; Save window configuration.
|
|
75 ; Recognize more minor modes.
|
|
76 ; Save mark rings.
|
|
77 ; Start-up with buffer-menu???
|
|
78
|
|
79 ;;; Code:
|
|
80
|
|
81 ; USER OPTIONS -- settings you might want to play with.
|
|
82 ; -----------------------------------------------------------------------------
|
|
83 (defconst desktop-basefilename
|
|
84 (if (equal system-type 'ms-dos)
|
|
85 "emacs.dsk" ; Ms-Dos does not support multiple dots in file name
|
|
86 ".emacs.desktop")
|
|
87 "File for Emacs desktop. A directory name will be prepended to this name.")
|
|
88
|
|
89 (defvar desktop-missing-file-warning t
|
|
90 "*If non-nil then issue warning if a file no longer exists.
|
|
91 Otherwise simply ignore the file.")
|
|
92
|
|
93 (defvar desktop-globals-to-save
|
|
94 (list 'desktop-missing-file-warning
|
|
95 ; 'kill-ring ; Feature: Also saves kill-ring-yank-pointer
|
|
96 'desktop-globals-to-save) ; Itself!
|
|
97 "List of global variables to save when killing Emacs.")
|
|
98
|
|
99 (defvar desktop-buffers-not-to-save
|
|
100 "\\(\\.log\\|(ftp)\\)$"
|
|
101 "Regexp identifying buffers that are to be excluded from saving.")
|
|
102
|
|
103 (defvar desktop-buffer-handlers
|
|
104 '(desktop-buffer-dired
|
|
105 desktop-buffer-rmail
|
|
106 desktop-buffer-info
|
|
107 desktop-buffer-file)
|
|
108 "*List of functions to call in order to create a buffer.
|
|
109 The functions are called without parameters
|
|
110 but may access the the major mode as `mam',
|
|
111 the file name as `fn', the buffer name as `bn', the default directory as
|
|
112 `dd'. If some function returns non-nil no further functions are called.
|
|
113 If the function returns t then the buffer is considered created.")
|
|
114 ; ---------------------------------------------------------------------------
|
|
115 (defvar desktop-dirname nil
|
|
116 "The directory in which the current desktop file resides.")
|
|
117
|
|
118 (defconst desktop-header
|
|
119 "; ---------------------------------------------------------------------------
|
|
120 ; Desktop File for Emacs
|
|
121 ; ---------------------------------------------------------------------------
|
|
122 " "*Header to place in Desktop file.")
|
|
123 ; ---------------------------------------------------------------------------
|
|
124 (defconst postv18
|
|
125 (string-lessp "19" emacs-version)
|
|
126 "t is Emacs version 19 or later.")
|
|
127
|
|
128 (defun desktop-clear () "Empty the Desktop."
|
|
129 (interactive)
|
|
130 (setq kill-ring nil)
|
|
131 (setq kill-ring-yank-pointer nil)
|
|
132 (mapcar (function kill-buffer) (buffer-list)))
|
|
133 ; ---------------------------------------------------------------------------
|
|
134 (if (not (boundp 'desktop-kill))
|
|
135 (if postv18
|
|
136 (add-hook 'kill-emacs-hook 'desktop-kill)
|
|
137 (setq old-kill-emacs kill-emacs-hook)
|
|
138 (setq kill-emacs-hook
|
|
139 (function (lambda () (progn (desktop-kill)
|
|
140 (run-hooks old-kill-emacs)))))))
|
|
141 ; ---------------------------------------------------------------------------
|
|
142 (defun desktop-kill ()
|
|
143 (if desktop-dirname
|
|
144 (progn
|
|
145 (desktop-save desktop-dirname))))
|
|
146
|
|
147 ;(defun kill-emacs (&optional query)
|
|
148 ; "End this Emacs session.
|
|
149 ;Prefix ARG or optional first ARG non-nil means exit with no questions asked,
|
|
150 ;even if there are unsaved buffers. If Emacs is running non-interactively
|
|
151 ;and ARG is an integer, then Emacs exits with ARG as its exit code.
|
|
152 ;
|
|
153 ;If the variable `desktop-dirname' is non-nil,
|
|
154 ;the function desktop-save will be called first."
|
|
155 ; (interactive "P")
|
|
156 ; (if desktop-dirname (desktop-save desktop-dirname))
|
|
157 ; (original-kill-emacs query))
|
|
158 ; ---------------------------------------------------------------------------
|
|
159 (defun desktop-outvar (VAR)
|
|
160 "Output a setq statement for VAR to the desktop file."
|
|
161 (if (boundp VAR)
|
|
162 (progn
|
|
163 (insert "(setq ")
|
|
164 (prin1 VAR (current-buffer))
|
|
165 (insert " '")
|
|
166 (prin1 (symbol-value VAR) (current-buffer))
|
|
167 (insert ")\n"))))
|
|
168 ; ---------------------------------------------------------------------------
|
|
169 (defun desktop-save-buffer-p (filename bufname mode)
|
|
170 "Return t if should record a particular buffer for next startup.
|
|
171 FILENAME is the visited file name, BUFNAME is the buffer name, and
|
|
172 MODE is the major mode."
|
|
173
|
|
174 (or (and filename
|
|
175 (not (string-match desktop-buffers-not-to-save bufname)))
|
|
176 (and (null filename)
|
|
177 (memq mode '(Info-mode dired-mode rmail-mode)))))
|
|
178 ; ---------------------------------------------------------------------------
|
|
179 (defun desktop-save (dirname)
|
|
180 "Save the Desktop file. Parameter DIRNAME specifies where to save desktop."
|
|
181 (interactive "DDirectory to save desktop file in: ")
|
|
182 (save-excursion
|
|
183 (let ((filename (expand-file-name
|
|
184 (concat dirname desktop-basefilename)))
|
|
185 (info (nreverse
|
|
186 (mapcar
|
|
187 (function (lambda (b)
|
|
188 (set-buffer b)
|
|
189 (list
|
|
190 (buffer-file-name)
|
|
191 (buffer-name)
|
|
192 (list 'quote major-mode)
|
|
193 (list 'quote
|
|
194 (list overwrite-mode
|
|
195 (not (null
|
|
196 (if postv18
|
|
197 auto-fill-function
|
|
198 auto-fill-hook)))))
|
|
199 (point)
|
|
200 (if postv18
|
|
201 (mark t)
|
|
202 (mark))
|
|
203 buffer-read-only
|
|
204 truncate-lines
|
|
205 fill-column
|
|
206 case-fold-search
|
|
207 case-replace
|
|
208 (list
|
|
209 'quote
|
|
210 (cond ((equal major-mode 'Info-mode)
|
|
211 (list Info-current-file
|
|
212 Info-current-node))
|
|
213 ((equal major-mode 'dired-mode)
|
|
214 (list default-directory))
|
|
215 ))
|
|
216 )))
|
|
217 (buffer-list))))
|
|
218 (buf (get-buffer-create "*desktop*")))
|
|
219 (set-buffer buf)
|
|
220 (erase-buffer)
|
|
221
|
|
222 (insert desktop-header
|
|
223 "; Created " (current-time-string) "\n"
|
|
224 "; Emacs version " emacs-version "\n\n"
|
|
225 "; Global section:\n")
|
|
226 (mapcar (function desktop-outvar) desktop-globals-to-save)
|
|
227 (if (memq 'kill-ring desktop-globals-to-save)
|
|
228 (insert "(setq kill-ring-yank-pointer (nthcdr "
|
|
229 (int-to-string
|
|
230 (- (length kill-ring) (length kill-ring-yank-pointer)))
|
|
231 " kill-ring))\n"))
|
|
232
|
|
233 (insert "\n; Buffer section:\n")
|
|
234 (mapcar
|
|
235 (function (lambda (l)
|
|
236 (if (desktop-save-buffer-p
|
|
237 (car l)
|
|
238 (nth 1 l)
|
|
239 (nth 1 (nth 2 l)))
|
|
240 (progn
|
|
241 (insert "(desktop-buffer")
|
|
242 (mapcar
|
|
243 (function (lambda (e)
|
|
244 (insert "\n ")
|
|
245 (prin1 e (current-buffer))))
|
|
246 l)
|
|
247 (insert ")\n\n")))))
|
|
248 info)
|
|
249 (setq default-directory dirname)
|
|
250 (if (file-exists-p filename) (delete-file filename))
|
|
251 (write-region (point-min) (point-max) filename nil 'nomessage)))
|
|
252 (setq desktop-dirname dirname))
|
|
253 ; ---------------------------------------------------------------------------
|
|
254 (defun desktop-remove ()
|
|
255 "Delete the Desktop file and inactivate the desktop system."
|
|
256 (interactive)
|
|
257 (if desktop-dirname
|
|
258 (let ((filename (concat desktop-dirname desktop-basefilename)))
|
|
259 (if (file-exists-p filename) (delete-file filename))
|
|
260 (setq desktop-dirname nil))))
|
|
261 ; ---------------------------------------------------------------------------
|
|
262 (defun desktop-read ()
|
|
263 "Read the Desktop file and the files it specifies."
|
|
264 (interactive)
|
|
265 (let ((filename))
|
|
266 (if (file-exists-p (concat "./" desktop-basefilename))
|
|
267 (setq desktop-dirname (expand-file-name "./"))
|
|
268 (if (file-exists-p (concat "~/" desktop-basefilename))
|
|
269 (setq desktop-dirname (expand-file-name "~/"))
|
|
270 (setq desktop-dirname nil)))
|
|
271 (if desktop-dirname
|
|
272 (progn
|
|
273 (load (concat desktop-dirname desktop-basefilename) t t t)
|
|
274 (message "Desktop loaded."))
|
|
275 (desktop-clear))))
|
|
276 ; ---------------------------------------------------------------------------
|
|
277 (defun desktop-load-default ()
|
|
278 "Load the `default' start-up library manually.
|
|
279 Also inhibit further loading of it.
|
|
280 Call this from your `.emacs' file
|
|
281 provide correct modes for autoloaded files."
|
|
282 (if (not inhibit-default-init)
|
|
283 (progn
|
|
284 (load "default" t t)
|
|
285 (setq inhibit-default-init t))))
|
|
286 ; ---------------------------------------------------------------------------
|
|
287 (defun desktop-buffer-info () "Load an info file."
|
|
288 (if (equal 'Info-mode mam)
|
|
289 (progn
|
|
290 (require 'info)
|
|
291 (Info-find-node (nth 0 misc) (nth 1 misc))
|
|
292 t)))
|
|
293 ; ---------------------------------------------------------------------------
|
|
294 (defun desktop-buffer-rmail () "Load a RMAIL file."
|
|
295 (if (equal 'rmail-mode mam)
|
|
296 (progn (rmail-input fn) t)))
|
|
297 ; ---------------------------------------------------------------------------
|
|
298 (defun desktop-buffer-dired () "Load a directory using dired."
|
|
299 (if (equal 'dired-mode mam)
|
|
300 (progn (dired (nth 0 misc)) t)))
|
|
301 ; ---------------------------------------------------------------------------
|
|
302 (defun desktop-buffer-file () "Load a file."
|
|
303 (if fn
|
|
304 (if (or (file-exists-p fn)
|
|
305 (and desktop-missing-file-warning
|
|
306 (y-or-n-p (format
|
|
307 "File \"%s\" no longer exists. Re-create? "
|
|
308 fn))))
|
|
309 (progn (find-file fn) t)
|
|
310 'ignored)))
|
|
311 ; ---------------------------------------------------------------------------
|
|
312 ;;Create a buffer, load its file, set is mode, ...; called from Desktop file
|
|
313 ;; only.
|
|
314 (defun desktop-buffer (fn bn mam mim pt mk ro tl fc cfs cr misc)
|
|
315 (let ((hlist desktop-buffer-handlers)
|
|
316 (result)
|
|
317 (handler))
|
|
318 (while (and (not result) hlist)
|
|
319 (setq handler (car hlist))
|
|
320 (setq result (funcall handler))
|
|
321 (setq hlist (cdr hlist)))
|
|
322 (if (equal result t)
|
|
323 (progn
|
|
324 (if (not (equal (buffer-name) bn))
|
|
325 (rename-buffer bn))
|
|
326 (if (nth 0 mim)
|
|
327 (overwrite-mode 1)
|
|
328 (overwrite-mode 0))
|
|
329 (if (nth 1 mim)
|
|
330 (auto-fill-mode 1)
|
|
331 (overwrite-mode 0))
|
|
332 (goto-char pt)
|
|
333 (set-mark mk)
|
|
334 (setq buffer-read-only ro)
|
|
335 (setq truncate-lines tl)
|
|
336 (setq fill-column fc)
|
|
337 (setq case-fold-search cfs)
|
|
338 (setq case-replace cr)
|
|
339 ))))
|
|
340 ; ---------------------------------------------------------------------------
|
|
341
|
3405
|
342 (provide 'desktop)
|
3404
|
343
|
|
344 ;; desktop.el ends here.
|