summaryrefslogtreecommitdiff
path: root/desktop-conf.el
blob: 6fa2ab001650c73e8f50349e45de70c84588ab54 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
;;; desktop-conf.el --- Configure desktop mode       -*- lexical-binding: t; -*-

;; Copyright (C) 2022  Jean Sévère Durand

;; Author: Jean Sévère Durand <durand@jsdurand.xyz>
;; Keywords: data, files, internal, maint

;; This program 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 3 of the License, or
;; (at your option) any later version.

;; This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.

;;; Commentary:

;; Configure the desktop-mode, which saves caches of Emacs states.

;;; Code:

;;; Basic settings

(setq desktop-auto-save-timeout 600)
(setq desktop-dirname "/Users/durand/.emacs.d/")
(setq desktop-path '("/Users/durand/.emacs.d/"))
(setq desktop-base-file-name "desktop")
(setq desktop-files-not-to-save nil)
(setq desktop-globals-to-clear nil)
(setq desktop-load-locked-desktop t)
(setq desktop-missing-file-warning nil)
(setq desktop-restore-eager t)
(setq desktop-restore-frames nil)
(setq desktop-save 'ask-if-new)

;;; Also save bookmarks before

(defun durand-bookmark-save ()
  "Silently save bookmarks."
  (let ((inhibit-message t))
    (cond ((featurep 'bookmark) (bookmark-save nil nil nil)))))

(add-hook 'desktop-save-hook #'durand-bookmark-save)

;;; Overwrite the saving function

;; Modify to hard-code the directory to save the desktop file.
(defun durand-desktop-save-a
    (dirname &optional release only-if-changed version)
  "Save the state of Emacs in a desktop file in directory DIRNAME.
Optional argument RELEASE non-nil says we're done with this
desktop, in which case this function releases the lock of the
desktop file in DIRNAME.
If ONLY-IF-CHANGED is non-nil, compare the current desktop
information to that in the desktop file, and if the desktop
information has not changed since it was last saved, then do
not rewrite the file.

To restore the desktop, use `desktop-read'.

This function can save the desktop in either format version
208 (which only Emacs 25.1 and later can read) or version
206 (which is readable by any Emacs from version 22.1 onwards).
By default, it will use the same format the desktop file had when
it was last saved, or version 208 when writing a fresh desktop
file.

To upgrade a version 206 file to version 208, call this command
explicitly with a prefix argument: \\[universal-argument] \\[desktop-save].
If you are upgrading from Emacs 24 or older, we recommend to do
this once you decide you no longer need compatibility with versions
of Emacs before 25.1.

To downgrade a version 208 file to version 206, use a double prefix
argument: \\[universal-argument] \\[universal-argument] \\[desktop-save].

Emacs will ask for confirmation when you upgrade or downgrade your
desktop file.

In a non-interactive call, VERSION can be given as an integer, either
206 or 208, to specify the format version in which to save the file,
no questions asked."
  (interactive (list
                ;; Or should we just use (car desktop-path)?
                (let ((default (car desktop-path)))
                  (read-directory-name "Directory to save desktop file in: "
                                       default default t))
                nil
                nil
                current-prefix-arg))
  (setq desktop-dirname (file-name-as-directory (expand-file-name dirname)))
  (save-excursion
    (let ((eager desktop-restore-eager)
	  (new-modtime (file-attribute-modification-time
			(file-attributes (desktop-full-file-name)))))
      (when
	  (or (not new-modtime)		; nothing to overwrite
	      (equal desktop-file-modtime new-modtime)
	      (yes-or-no-p (if desktop-file-modtime
			       (if (time-less-p desktop-file-modtime
						new-modtime)
				   "Desktop file is more recent than the one loaded.  Save anyway? "
				 "Desktop file isn't the one loaded.  Overwrite it? ")
			     "Current desktop was not loaded from a file.  Overwrite this desktop file? "))
	      (unless release (error "Desktop file conflict")))

	;; If we're done with it, release the lock.
	;; Otherwise, claim it if it's unclaimed or if we created it.
	(if release
	    (desktop-release-lock)
	  (unless (and new-modtime (desktop-owner)) (desktop-claim-lock)))

        ;; What format are we going to write the file in?
        (setq desktop-io-file-version
              (cond
               ((equal version '(4))
                (if (or (eq desktop-io-file-version 208)
                        (yes-or-no-p "Save desktop file in format 208 \
\(Readable by Emacs 25.1 and later only)? "))
                    208
                  (or desktop-io-file-version desktop-native-file-version)))
               ((equal version '(16))
                (if (or (eq desktop-io-file-version 206)
                        (yes-or-no-p "Save desktop file in format 206 \
\(Readable by all Emacs versions since 22.1)? "))
                    206
                  (or desktop-io-file-version desktop-native-file-version)))
               ((memq version '(206 208))
                version)
               ((null desktop-io-file-version) ; As yet, no desktop file exists.
                desktop-native-file-version)
               (t
                desktop-io-file-version)))

	(with-temp-buffer
	  (insert
	   ";; -*- mode: emacs-lisp; lexical-binding:t; coding: utf-8-emacs; -*-\n"
	   desktop-header
	   ";; Created " (current-time-string) "\n"
	   ";; Desktop file format version " (format "%d" desktop-io-file-version) "\n"
	   ";; Emacs version " emacs-version "\n")
	  (save-excursion (run-hooks 'desktop-save-hook))
	  (goto-char (point-max))
	  (insert "\n;; Global section:\n")
	  ;; Called here because we save the window/frame state as a global
	  ;; variable for compatibility with previous Emacsen.
	  (desktop-save-frameset)
	  (unless (memq 'desktop-saved-frameset desktop-globals-to-save)
	    (desktop-outvar 'desktop-saved-frameset))
	  (mapc #'desktop-outvar desktop-globals-to-save)
	  (setq desktop-saved-frameset nil) ; after saving desktop-globals-to-save
	  (when (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")
	  (dolist (l (mapcar #'desktop-buffer-info (buffer-list)))
	    (let ((base (pop l)))
	      (when (apply #'desktop-save-buffer-p l)
		(insert "("
			(if (or (not (integerp eager))
				(if (zerop eager)
				    nil
				  (setq eager (1- eager))))
			    "desktop-create-buffer"
			  "desktop-append-buffer-args")
			" "
			(format "%d" desktop-io-file-version))
		;; If there's a non-empty base name, we save it instead of the buffer name
		(when (and base (not (string= base "")))
		  (setcar (nthcdr 1 l) base))
		(dolist (e l)
		  (insert "\n  " (desktop-value-to-string e)))
		(insert ")\n\n"))))

	  (setq default-directory desktop-dirname)
	  ;; When auto-saving, avoid writing if nothing has changed since the last write.
	  (let* ((beg (and only-if-changed
			   (save-excursion
			     (goto-char (point-min))
			     ;; Don't check the header with changing timestamp
			     (and (search-forward "Global section" nil t)
				  ;; Also skip the timestamp in desktop-saved-frameset
				  ;; if it's saved in the first non-header line
				  (search-forward "desktop-saved-frameset"
						  (line-beginning-position 3) t)
				  ;; This is saved after the timestamp
				  (search-forward (format "%S" desktop--app-id) nil t))
			     (point))))
		 (checksum (and beg (md5 (current-buffer) beg (point-max) 'utf-8-emacs))))
	    (unless (and checksum (equal checksum desktop-file-checksum))
	      (let ((coding-system-for-write 'utf-8-emacs))
		(write-region (point-min) (point-max) (desktop-full-file-name) nil 'nomessage))
	      (setq desktop-file-checksum checksum)
	      ;; We remember when it was modified (which is presumably just now).
	      (setq desktop-file-modtime (file-attribute-modification-time
					  (file-attributes
					   (desktop-full-file-name)))))))))))

(advice-add 'desktop-save :override 'durand-desktop-save-a)

;;; Enable the mode

(desktop-save-mode 1)


(provide 'desktop-conf)
;;; desktop-conf.el ends here