|
|
1.1 root 1: ;; File input and output commands for Emacs
2: ;; Copyright (C) 1985 Richard M. Stallman.
3:
4: ;; This file is part of GNU Emacs.
5:
6: ;; GNU Emacs is distributed in the hope that it will be useful,
7: ;; but WITHOUT ANY WARRANTY. No author or distributor
8: ;; accepts responsibility to anyone for the consequences of using it
9: ;; or for whether it serves any particular purpose or works at all,
10: ;; unless he says so in writing. Refer to the GNU Emacs General Public
11: ;; License for full details.
12:
13: ;; Everyone is granted permission to copy, modify and redistribute
14: ;; GNU Emacs, but only under the conditions described in the
15: ;; GNU Emacs General Public License. A copy of this license is
16: ;; supposed to have been given to you along with GNU Emacs so you
17: ;; can know your rights and responsibilities. It should be in a
18: ;; file named COPYING. Among other things, the copyright notice
19: ;; and this notice must be preserved on all copies.
20:
21:
22: (defconst delete-auto-save-files t
23: "*Non-nil means delete a buffer's auto-save file
24: when the buffer is saved for real.")
25:
26: (defconst make-backup-files t
27: "*Create a backup of each file when it is saved for the first time.
28: This can be done by renaming the file or by copying, according to the
29: values of backup-by-copying and backup-by-copying-when-linked.")
30:
31: (defconst backup-by-copying nil
32: "*Non-nil means create backups of files by copying rather than by renaming.")
33:
34: (defconst backup-by-copying-when-linked nil
35: "*Non-nil means create backups of multi-named files by copying
36: rather than by renaming.
37: This causes the alternate names to refer to the latest version as edited.")
38:
39: (defvar version-control nil
40: "*Control use of version numbers for backup files.
41: t means make numeric backup versions unconditionally.
42: nil means make them for files that have some already.
43: never means do not make them.")
44:
45: (defvar dired-kept-versions 2
46: "*When cleaning directory, number of versions to keep.")
47:
48: (defvar trim-versions-without-asking nil
49: "*If true, deletes excess backup versions silently.
50: Otherwise asks confirmation.")
51:
52: (defvar kept-old-versions 2
53: "*Number of oldest versions to keep when a new numbered backup is made.")
54:
55: (defvar kept-new-versions 2
56: "*Number of newest versions to keep when a new numbered backup is made.
57: Includes the new backup. Must be > 0")
58:
59: (defconst require-final-newline nil
60: "*t says silently put a newline at the end whenever a file is saved.
61: Non-nil but not t says ask user whether to add a newline in each such case.
62: nil means don't add newlines.")
63:
64: (defconst auto-save-default t
65: "*t says by default do auto-saving of every file-visiting buffer.")
66:
67: (defconst auto-save-visited-file-name nil
68: "*t says auto-save a buffer in the file it is visiting, when practical.
69: Normally auto-save files are written under other names.")
70:
71: (defconst save-abbrevs t
72: "*Non-nil means save word abbrevs too when files are saved.")
73:
74: (defconst find-file-run-dired t
75: "*Non-nil says run dired if find-file is given the name of a directory.")
76:
77: (defvar find-file-not-found-hook nil
78: "*If non-nil specifies a function to be called for find-file on nonexistent file.
79: This function is called as soon as the error is detected.
80: buffer-file-name is already set up.")
81:
82: (defvar find-file-hook nil
83: "*If non-nil specifies a function to be called after a buffer
84: is found or reverted from a file.
85: The buffer's local variables (if any) will have been processed before the
86: function is called.")
87:
88: (defvar write-file-hook nil
89: "*If non-nil specifies a function to be called before writing out a buffer
90: to a file.")
91:
92: ;; Avoid losing in versions where CLASH_DETECTION is disabled.
93: (or (fboundp 'lock-buffer)
94: (fset 'lock-buffer 'ignore))
95: (or (fboundp 'unlock-buffer)
96: (fset 'unlock-buffer 'ignore))
97:
98: (defun pwd ()
99: "Show the current default directory."
100: (interactive nil)
101: (message "Directory %s" default-directory))
102:
103: (defun cd (dir)
104: "Make DIR become the current buffer's default directory."
105: (interactive "DChange default directory: ")
106: (setq dir (expand-file-name dir))
107: ;; (interactive "D") really doesn't do the right thing at all
108: (or (string-match "/$" dir)
109: (setq dir (concat dir "/")))
110: (if (not (file-directory-p dir))
111: (error "%s is not a directory" dir)
112: (setq default-directory dir))
113: (pwd))
114:
115: (defun switch-to-buffer-other-window (buffer)
116: "Select buffer BUFFER in another window."
117: (interactive "BSwitch to buffer in other window: ")
118: (let ((pop-up-windows t))
119: (pop-to-buffer buffer t)))
120:
121: (defun find-file (filename)
122: "Edit file FILENAME.
123: Switch to a buffer visiting file FILENAME,
124: creating one if none already exists."
125: (interactive "FFind file: ")
126: (switch-to-buffer (find-file-noselect filename)))
127:
128: (defun find-file-other-window (filename)
129: "Edit file FILENAME, in another window.
130: May create a new window, or reuse an existing one;
131: see the function display-buffer."
132: (interactive "FFind file in other window: ")
133: (switch-to-buffer-other-window (find-file-noselect filename)))
134:
135: (defun find-file-read-only (filename)
136: "Edit file FILENAME but don't save without confirmation.
137: Like find-file but marks buffer as read-only."
138: (interactive "fFind file read-only: ")
139: (find-file filename)
140: (setq buffer-read-only t))
141:
142: (defun find-alternate-file (filename)
143: "Find file FILENAME, select its buffer, kill previous buffer.
144: If the current buffer now contains an empty file that you just visited
145: \(presumably by mistake), use this command to visit the file you really want."
146: (interactive "FFind alternate file: ")
147: (if (null buffer-file-name)
148: (error "Non-file buffer"))
149: (and (buffer-modified-p)
150: (not (yes-or-no-p (format "Buffer %s is modified; kill anyway? "
151: (buffer-name))))
152: (error "Aborted"))
153: (let ((obuf (current-buffer))
154: (ofile buffer-file-name)
155: (oname (buffer-name)))
156: (rename-buffer " **lose**")
157: (setq buffer-file-name nil)
158: (unwind-protect
159: (progn
160: (unlock-buffer)
161: (find-file filename))
162: (cond ((eq obuf (current-buffer))
163: (setq buffer-file-name ofile)
164: (lock-buffer)
165: (rename-buffer oname))))
166: (kill-buffer obuf)))
167:
168: (defvar ask-about-buffer-names nil
169: "*Non-nil means ask user for buffer name when there is a conflict.
170: The default is to generate a unique name with no interaction.")
171:
172: (defun create-file-buffer (filename)
173: "Creates a suitably named buffer for visiting FILENAME, and returns it."
174: (let ((base (file-name-nondirectory filename)))
175: (if (and (get-buffer base)
176: ask-about-buffer-names)
177: (get-buffer-create
178: (let ((tem (read-string (format
179: "Buffer name \"%s\" is in use; type a new name, or Return to clobber: "
180: base))))
181: (if (equal tem "") base tem)))
182: (generate-new-buffer base))))
183:
184: (defun find-file-noselect (filename)
185: "Read file FILENAME into a buffer and return the buffer.
186: If a buffer exists visiting FILENAME, return that one,
187: but verify that the file has not changed since visited or saved.
188: The buffer is not selected, just returned to the caller."
189: (if (file-directory-p filename)
190: (if find-file-run-dired
191: (dired-noselect filename)
192: (error "%s is a directory." filename))
193: (let ((buf (get-file-buffer filename))
194: error)
195: (if buf
196: (or (verify-visited-file-modtime buf)
197: (if (not (file-exists-p filename))
198: (progn (message "Note: file %s no longer exists" filename)
199: t))
200: (not (yes-or-no-p
201: (if (buffer-modified-p buf)
202: "File has changed since last visited or saved. Flush your changes? "
203: "File has changed since last visited or saved. Read from disk? ")))
204: (save-excursion
205: (set-buffer buf)
206: (revert-buffer t)))
207: (save-excursion
208: (setq buf (create-file-buffer filename)
209: filename (expand-file-name filename))
210: (set-buffer buf)
211: (erase-buffer)
212: (condition-case ()
213: (insert-file-contents filename t)
214: (file-error
215: (setq error t
216: buffer-file-name filename)
217: (if find-file-not-found-hook
218: (funcall find-file-not-found-hook))))
219: (setq default-directory (file-name-directory filename))
220: (after-find-file error)))
221: buf)))
222:
223:
224: (defun after-find-file (error)
225: "Called after finding a file and by the default revert function.
226: Sets buffer mode, parses local variables, calls find-file-hook."
227: (setq buffer-read-only (not (file-writable-p buffer-file-name)))
228: (if noninteractive
229: nil
230: (message (cond ((not buffer-read-only)
231: (if error "(New file)" ""))
232: ((not error)
233: "File is write protected")
234: ((file-attributes buffer-file-name)
235: ;; file-exists-p is not the right thing above, as that
236: ;; returns t iff the file is READABLE by you
237: "File exists, but is read-protected.")
238: ((file-attributes default-directory)
239: "File not found and directory write-protected")
240: (t
241: "File not found and directory doesn't exist")))
242: (if auto-save-default
243: (auto-save-mode t)))
244: (normal-mode))
245:
246: (defun normal-mode ()
247: "Choose the major mode for this buffer automatically.
248: Also sets up any specified local variables of the file.
249: Uses the visited file name, the -*- line, and the local variables spec.
250: Finishes by calling value of find-file-hook if that's not nil."
251: (interactive)
252: (condition-case err
253: (set-auto-mode)
254: (error (message "Error processing file's mode specifications: %s"
255: (prin1-to-string err))))
256: (condition-case err
257: (hack-local-variables)
258: (error (message "Error processing file's local variables: %s"
259: (prin1-to-string err))))
260: (and find-file-hook
261: (funcall find-file-hook)))
262:
263: ;(defvar auto-mode-alist ...) now in loaddefs.el
264: (defun set-auto-mode ()
265: "Select major mode appropriate for current buffer.
266: May base decision on visited file name (See variable auto-mode-list)
267: or on buffer contents (-*- line or local variables spec), but does not look
268: for the \"mode:\" local variable. For that, use hack-local-variables."
269: ;; Look for -*-MODENAME-*- or -*- ... mode: MODENAME; ... -*-
270: (let (beg end mode)
271: (save-excursion
272: (goto-char (point-min))
273: (skip-chars-forward " \t\n")
274: (if (and (search-forward "-*-" (save-excursion (end-of-line) (point)) t)
275: (progn
276: (skip-chars-forward " \t")
277: (setq beg (point))
278: (search-forward "-*-" (save-excursion (end-of-line) (point)) t))
279: (progn
280: (forward-char -3)
281: (skip-chars-backward " \t")
282: (setq end (point))
283: (goto-char beg)
284: (if (search-forward ":" end t)
285: (progn
286: (goto-char beg)
287: (if (let ((case-fold-search t))
288: (search-forward "mode:" end t))
289: (progn
290: (skip-chars-forward " \t")
291: (setq beg (point))
292: (if (search-forward ";" end t)
293: (forward-char -1)
294: (goto-char end))
295: (skip-chars-backward " \t")
296: (setq mode (buffer-substring beg (point))))))
297: (setq mode (buffer-substring beg end)))))
298: (funcall (intern (concat (downcase mode) "-mode")))
299: (let ((alist auto-mode-alist)
300: (name buffer-file-name))
301: (let (case-fold-search)
302: ;; Remove backup-suffixes from file name.
303: (setq name (substring name 0
304: (or (string-match "\\.~[0-9]+~\\'" name)
305: (string-match "~\\'" name)
306: (length name))))
307: ;; Find first matching alist entry.
308: (while (and (not mode) alist)
309: (if (string-match (car (car alist)) name)
310: (setq mode (cdr (car alist))))
311: (setq alist (cdr alist))))
312: (if mode (funcall mode)))))))
313:
314: (defun hack-local-variables ()
315: "Parse, and bind or evaluate as appropriate, any local variables
316: for current buffer."
317: ;; Look for "Local variables:" line in last page.
318: (save-excursion
319: (goto-char (point-max))
320: (search-backward "\n\^L" (max (- (point-max) 3000) (point-min)) 'move)
321: (if (let ((case-fold-search t))
322: (search-forward "Local Variables:" nil t))
323: (let ((continue t)
324: prefix prefixlen suffix beg)
325: ;; The prefix is what comes before "local variables:" in its line.
326: ;; The suffix is what comes after "local variables:" in its line.
327: (or (eolp)
328: (setq suffix (buffer-substring (point)
329: (progn (end-of-line) (point)))))
330: (goto-char (match-beginning 0))
331: (or (bolp)
332: (setq prefix
333: (buffer-substring (point)
334: (progn (beginning-of-line) (point)))))
335: (if prefix (setq prefixlen (length prefix)
336: prefix (regexp-quote prefix)))
337: (if suffix (setq suffix (regexp-quote suffix)))
338: (while continue
339: ;; Look at next local variable spec.
340: (forward-line 1)
341: ;; Skip the prefix, if any.
342: (if prefix
343: (if (looking-at prefix)
344: (forward-char prefixlen)
345: (error "Local variables entry is missing the prefix")))
346: ;; Find the variable name; strip whitespace.
347: (skip-chars-forward " \t")
348: (setq beg (point))
349: (skip-chars-forward "^:\n")
350: (if (eolp) (error "Missing colon in local variables entry"))
351: (skip-chars-backward " \t")
352: (let* ((str (buffer-substring beg (point)))
353: (var (read str))
354: val)
355: ;; Setting variable named "end" means end of list.
356: (if (string-equal (downcase str) "end")
357: (setq continue nil)
358: ;; Otherwise read the variable value.
359: (skip-chars-forward "^:")
360: (forward-char 1)
361: (setq val (read (current-buffer)))
362: (skip-chars-backward "\n")
363: (skip-chars-forward " \t")
364: (or (if suffix (looking-at suffix) (eolp))
365: (error "Local variables entry is terminated incorrectly"))
366: ;; Set the variable. "Variables" mode and eval are funny.
367: (cond ((eq var 'mode)
368: (funcall (intern (concat (downcase (symbol-name val))
369: "-mode"))))
370: ((eq var 'eval)
371: (eval val))
372: (t (make-local-variable var)
373: (set var val))))))))))
374:
375: (defun set-visited-file-name (filename)
376: "Change name of file visited in current buffer to FILENAME.
377: The next time the buffer is saved it will go in the newly specified file.
378: nil or empty string as argument means make buffer not be visiting any file."
379: (interactive "FSet visited file name: ")
380: (if filename
381: (setq filename
382: (if (string-equal filename "")
383: nil
384: (expand-file-name filename))))
385: (or (equal filename buffer-file-name)
386: (null filename)
387: (progn
388: (lock-buffer filename)
389: (unlock-buffer)))
390: (setq buffer-file-name filename)
391: (if filename
392: (progn
393: (setq default-directory (file-name-directory buffer-file-name))
394: (or (get-buffer (file-name-nondirectory buffer-file-name))
395: (rename-buffer (file-name-nondirectory buffer-file-name)))))
396: (setq buffer-backed-up nil)
397: (clear-visited-file-modtime)
398: (auto-save-mode (and buffer-file-name auto-save-default))
399: (if buffer-file-name
400: (set-buffer-modified-p t)))
401:
402: (defun write-file (filename)
403: "Write current buffer into file FILENAME.
404: Makes buffer visit that file, and marks it not modified."
405: (interactive "FWrite file: ")
406: (or (null filename) (string-equal filename "")
407: (set-visited-file-name filename))
408: (set-buffer-modified-p t)
409: (save-buffer))
410:
411: (defun backup-buffer ()
412: "Make a backup of the disk file visited by the current buffer.
413: This is done before saving the buffer the first time."
414: (and make-backup-files
415: (not buffer-backed-up)
416: (file-exists-p buffer-file-name)
417: (memq (aref (elt (file-attributes buffer-file-name) 8) 0)
418: '(?- ?l))
419: (or (< (length buffer-file-name) 5)
420: (not (string-equal "/tmp/" (substring buffer-file-name 0 5))))
421: (condition-case ()
422: (let* ((backup-info (find-backup-file-name buffer-file-name))
423: (backupname (car backup-info))
424: (targets (cdr backup-info))
425: setmodes)
426: ; (if (file-directory-p buffer-file-name)
427: ; (error "Cannot save buffer in directory %s" buffer-file-name))
428: (if (or (file-symlink-p buffer-file-name)
429: backup-by-copying
430: (and backup-by-copying-when-linked
431: (> (file-nlinks buffer-file-name) 1)))
432: (copy-file buffer-file-name backupname t)
433: (condition-case ()
434: (delete-file backupname)
435: (file-error nil))
436: (rename-file buffer-file-name backupname t)
437: (setq setmodes (file-modes backupname)))
438: (setq buffer-backed-up t)
439: (if (and targets
440: (or trim-versions-without-asking
441: (y-or-n-p (format "Delete excess backup versions of %s? "
442: buffer-file-name))))
443: (while targets
444: (condition-case ()
445: (delete-file (car targets))
446: (file-error nil))
447: (setq targets (cdr targets))))
448: setmodes)
449: (file-error nil))))
450:
451: (defun find-backup-file-name (fn)
452: "Find a file name for a backup file, and suggestions for deletions.
453: Value is a list whose car is the name for the backup file
454: and whose cdr is a list of old versions to consider deleting now."
455: (if (eq version-control 'never)
456: (list (concat fn "~"))
457: (let* ((base-versions (concat (file-name-nondirectory fn) ".~"))
458: (bv-length (length base-versions))
459: (possibilities (file-name-all-completions
460: base-versions
461: (file-name-directory fn)))
462: (versions (sort (mapcar 'backup-extract-version possibilities)
463: '<))
464: (high-water-mark (apply 'max (cons 0 versions)))
465: (deserve-versions-p
466: (or version-control
467: (> high-water-mark 0)))
468: (number-to-delete (- (length versions)
469: kept-old-versions kept-new-versions -1)))
470: (if (not deserve-versions-p)
471: (list (concat fn "~"))
472: (cons (concat fn ".~" (int-to-string (1+ high-water-mark)) "~")
473: (if (> number-to-delete 0)
474: (mapcar (function (lambda (n)
475: (concat fn ".~" (int-to-string n) "~")))
476: (let ((v (nthcdr kept-old-versions versions)))
477: (rplacd (nthcdr (1- number-to-delete) v) ())
478: v))))))))
479:
480: (defun backup-extract-version (fn)
481: (string-to-int (substring fn bv-length -1)))
482:
483: (defun file-nlinks (filename)
484: "Return number of names file FILENAME has."
485: (car (cdr (file-attributes filename))))
486:
487: (defun save-buffer (&optional args)
488: "Save current buffer in visited file if modified. Versions described below.
489:
490: With no arg, only backs up if first save or previously motivated.
491: With 1 or 3 \\[universal-argument]'s, marks this version to be backed up.
492: With 2 or 3 \\[universal-argument]'s, unconditionally backs up previous \
493: version.
494:
495: If a file's name is FOO, the names of numbered versions are
496: FOO.~i~ for various integers i.
497: Numeric backups (rather than FOO~) will be made if value of
498: version-control is not the atom never and either there are already
499: numeric versions of the file being backed up, or version-control is
500: non-nil.
501: dired-kept-versions controls dired's clean-directory (.) command.
502: We don't want excessive versions piling up, so variables
503: kept-old-versions , which tells system how many oldest versions to
504: keep, and kept-new-versions , which tells how many new versions to
505: keep, are provided. Defaults are 2 old versions and 2 new.
506: If trim-versions-without-asking is nil, system will query user
507: before trimming versions. Otherwise it does it silently."
508: (interactive "p")
509: (let ((modp (buffer-modified-p)))
510: (and modp (memq args '(4 64)) (setq buffer-backed-up nil))
511: (basic-save-buffer)
512: (and modp (memq args '(16 64)) (setq buffer-backed-up nil))))
513:
514: (defun delete-auto-save-file-if-necessary ()
515: "Delete the auto-save filename for the current buffer (if it has one)
516: if variable delete-auto-save-files is non-nil."
517: (and buffer-auto-save-file-name delete-auto-save-files
518: (progn
519: (condition-case ()
520: (delete-file buffer-auto-save-file-name)
521: (file-error nil))
522: (set-buffer-auto-saved))))
523:
524: (defun basic-save-buffer ()
525: "Save the current buffer in its visited file, if it has been modified."
526: (interactive)
527: (if (buffer-modified-p)
528: (let (setmodes tempsetmodes)
529: (or buffer-file-name
530: (setq buffer-file-name
531: (expand-file-name (read-file-name "File to save in: ") nil)
532: default-directory (file-name-directory buffer-file-name)))
533: (if (not (file-writable-p buffer-file-name))
534: (if (yes-or-no-p
535: (format "File %s is write-protected; try to save anyway? "
536: (file-name-nondirectory buffer-file-name)))
537: (setq tempsetmodes t)
538: (error
539: "Attempt to save to a file which you aren't allowed to write")))
540: (or (verify-visited-file-modtime (current-buffer))
541: (not (file-exists-p buffer-file-name))
542: (yes-or-no-p
543: "File has changed on disk since last visited or saved. Save anyway? ")
544: (error "Save not confirmed"))
545: (or buffer-backed-up
546: (setq setmodes (backup-buffer)))
547: (save-restriction
548: (widen)
549: (and (> (point-max) 1)
550: (/= (char-after (1- (point-max))) ?\n)
551: (or (eq require-final-newline t)
552: (and require-final-newline
553: (yes-or-no-p
554: (format "Buffer %s does not end in newline. Add one? "
555: (buffer-name)))))
556: (save-excursion
557: (goto-char (point-max))
558: (insert ?\n)))
559: (and write-file-hook
560: (funcall write-file-hook))
561: ;; If file not writable, see if we can make it writable
562: ;; temporarily while we write it.
563: ;; But no need to do so if we have just backed up the file
564: ;; (if setmodes is set) because in that case we are superseding.
565: (cond ((and tempsetmodes (not setmodes))
566: ;; Change the mode back, after writing.
567: (setq setmodes (file-modes buffer-file-name))
568: (set-file-modes buffer-file-name 511)))
569: (write-region (point-min) (point-max) buffer-file-name nil t)
570: (if setmodes
571: (condition-case ()
572: (set-file-modes buffer-file-name setmodes)
573: (error nil))))
574: (delete-auto-save-file-if-necessary))
575: (message "(No changes need to be saved)")))
576:
577: (defun save-some-buffers (&optional arg)
578: "Save some modified file-visiting buffers. Asks user about each one.
579: With argument, saves all with no questions."
580: (interactive "P")
581: (let (considered (list (buffer-list)))
582: (while list
583: (let ((buffer (car list)))
584: (condition-case ()
585: (and (buffer-modified-p buffer)
586: (buffer-file-name buffer)
587: (setq considered t)
588: (or arg
589: (y-or-n-p (format "Save file %s? " (buffer-file-name buffer))))
590: (save-excursion
591: (set-buffer buffer)
592: (save-buffer)))
593: (error nil)))
594: (setq list (cdr list)))
595: (and save-abbrevs abbrevs-changed
596: (setq considered t)
597: (or arg
598: (y-or-n-p (format "Save abbrevs in %s? " abbrev-file-name)))
599: (progn
600: (write-abbrev-file nil)
601: (setq abbrevs-changed nil)))
602: (if considered
603: (message "")
604: (message "(No files need saving)"))))
605:
606: (defun not-modified ()
607: "Mark current buffer as unmodified, not needing to be saved."
608: (interactive)
609: (message "Modification-flag cleared")
610: (set-buffer-modified-p nil))
611:
612: (defun toggle-read-only ()
613: "Change whether this buffer is visiting its file read-only."
614: (interactive)
615: (setq buffer-read-only (not buffer-read-only))
616: ;; Force mode-line redisplay
617: (set-buffer-modified-p (buffer-modified-p)))
618:
619: (defun insert-file (filename)
620: "Insert contents of file FILENAME into buffer after point.
621: Set mark after the inserted text."
622: (interactive "fInsert file: ")
623: (let ((tem (insert-file-contents filename)))
624: (push-mark (+ (point) (car (cdr tem))))))
625:
626: (defun append-to-file (start end filename)
627: "Append the contents of the region to the end of file FILENAME.
628: When called from a function, expects three arguments,
629: START, END and FILENAME. START and END are buffer positions
630: saying what text to write."
631: (interactive "r\nFAppend to file: ")
632: (write-region start end filename t))
633:
634: (defvar revert-buffer-function nil
635: "Function to use to revert this buffer, or nil to do the default.")
636:
637: (defun revert-buffer (&optional arg)
638: "Replace the buffer text with the text of the visited file on disk.
639: This undoes all changes since the file was visited or saved.
640: If latest auto-save file is more recent than the visited file,
641: asks user whether to use that instead, unless a non-nil argument is given.
642:
643: If revert-buffer-function's value is non-nil, it is called to do the work."
644: (interactive "P")
645: (if revert-buffer-function
646: (funcall revert-buffer-function arg)
647: (let* ((opoint (point))
648: (auto-save-p (and (null arg) (recent-auto-save-p)
649: (y-or-n-p
650: "Buffer has been auto-saved recently. Revert from auto-save file? ")))
651: (file-name (if auto-save-p
652: buffer-auto-save-file-name
653: buffer-file-name)))
654: (cond ((null file-name)
655: (error "Buffer does not seem to be associated with any file"))
656: ((not (file-exists-p file-name))
657: (error "File %s no longer exists!" file-name))
658: ((yes-or-no-p (format "Revert buffer from file %s? " file-name))
659: (let ((buffer-read-only nil))
660: ;; Bind buffer-file-name to nil
661: ;; so that we don't try to lock the file.
662: (let ((buffer-file-name nil))
663: (or auto-save-p
664: (unlock-buffer))
665: (erase-buffer))
666: (insert-file-contents file-name (not auto-save-p)))
667: (after-find-file nil)
668: (or find-file-hook ; the hook may have set point itself
669: (goto-char (min opoint (point-max)))))))))
670:
671: (defun recover-file (file)
672: "Visit file FILE, then get contents from its last auto-save file."
673: (interactive "FRecover file: ")
674: (find-file file)
675: (let ((file-name (make-auto-save-file-name)))
676: (cond ((not (file-exists-p file-name))
677: (error "Auto-save file %s does not exist" file-name))
678: ((yes-or-no-p (format "Recover buffer from file %s? " file-name))
679: (let ((buffer-read-only nil))
680: (erase-buffer)
681: (insert-file-contents file-name nil))
682: (after-find-file nil))))
683: (setq buffer-auto-save-file-name nil)
684: (message "Auto-save turned off, for now, in this buffer"))
685:
686: (defun kill-some-buffers ()
687: "For each buffer, ask whether to kill it."
688: (interactive)
689: (let ((list (buffer-list)))
690: (while list
691: (let* ((buffer (car list))
692: (name (buffer-name buffer)))
693: (and (not (string-equal name ""))
694: (/= (aref name 0) ? )
695: (yes-or-no-p
696: (format "Buffer %s %s. Kill? "
697: name
698: (if (buffer-modified-p buffer)
699: "HAS BEEN EDITED" "is unmodified")))
700: (kill-buffer buffer)))
701: (setq list (cdr list)))))
702:
703: (defun auto-save-mode (arg)
704: "Toggle auto-saving of contents of current buffer.
705: With arg, turn auto-saving on if arg is positive, else off."
706: (interactive "P")
707: (setq buffer-auto-save-file-name
708: (and (if (null arg)
709: (not buffer-auto-save-file-name)
710: (or (eq arg t) (listp arg) (and (integerp arg) (> arg 0))))
711: (if (and buffer-file-name auto-save-visited-file-name
712: (not buffer-read-only))
713: buffer-file-name
714: (make-auto-save-file-name)))))
715:
716: (defun make-auto-save-file-name ()
717: "Return file name to use for auto-saves of current buffer.
718: Does not consider auto-save-visited-file-name; that is checked
719: before calling this function.
720: This is a separate function so your .emacs file or site-init.el can redefine it.
721: See also auto-save-file-name-p."
722: (if buffer-file-name
723: (concat (file-name-directory buffer-file-name)
724: "#"
725: (file-name-nondirectory buffer-file-name))
726: (expand-file-name (concat "#%" (buffer-name)))))
727:
728: (defun auto-save-file-name-p (filename)
729: "Return t if FILENAME can be yielded by make-auto-save-file-name.
730: FILENAME should lack slashes.
731: This is a separate function so your .emacs file or site-init.el can redefine it."
732: (string-match "^#" filename))
733:
734: (defconst list-directory-brief-switches "-CF"
735: "*Switches for list-directory to pass to `ls' for brief listing,")
736: (defconst list-directory-verbose-switches "-l"
737: "*Switches for list-directory to pass to `ls' for verbose listing,")
738:
739: (defun list-directory (dirname &optional verbose)
740: "Display a list of files in or matching DIRNAME, a la `ls'.
741: DIRNAME is globbed by the shell if necessary.
742: Prefix arg (second arg if noninteractive) means supply -l switch to `ls'.
743: Actions controlled by variables list-directory-brief-switches
744: and list-directory-verbose-switches."
745: (interactive (let ((pfx current-prefix-arg))
746: (list (read-file-name (if pfx "List directory (verbose): "
747: "List directory (brief): ")
748: nil default-directory nil)
749: pfx)))
750: (let ((switches (if verbose list-directory-verbose-switches
751: list-directory-brief-switches))
752: full-dir-p)
753: (or dirname (setq dirname default-directory))
754: (if (file-directory-p dirname)
755: (progn
756: (setq full-dir-p t)
757: (or (string-match "/$" dirname)
758: (setq dirname (concat dirname "/")))))
759: (setq dirname (expand-file-name dirname))
760: (with-output-to-temp-buffer "*Directory*"
761: (buffer-flush-undo standard-output)
762: (princ "Directory ")
763: (princ dirname)
764: (terpri)
765: (if full-dir-p
766: (call-process "/bin/ls" nil standard-output nil
767: switches dirname)
768: (let ((default-directory (file-name-directory dirname)))
769: (call-process shell-file-name nil standard-output nil
770: "-c" (concat "exec /bin/ls "
771: switches " "
772: (file-name-nondirectory dirname))))))))
773:
774: (defun save-buffers-kill-emacs ()
775: "Offer to save each buffer, then kill this Emacs fork."
776: (interactive)
777: (save-some-buffers)
778: (kill-emacs))
779:
780: (define-key ctl-x-map "\C-f" 'find-file)
781: (define-key ctl-x-map "\C-q" 'toggle-read-only)
782: (define-key ctl-x-map "\C-r" 'find-file-read-only)
783: (define-key ctl-x-map "\C-v" 'find-alternate-file)
784: (define-key ctl-x-map "\C-s" 'save-buffer)
785: (define-key ctl-x-map "s" 'save-some-buffers)
786: (define-key ctl-x-map "\C-w" 'write-file)
787: (define-key ctl-x-map "i" 'insert-file)
788: (define-key esc-map "~" 'not-modified)
789: (define-key ctl-x-map "\C-d" 'list-directory)
790: (define-key ctl-x-map "\C-c" 'save-buffers-kill-emacs)
791:
792: (defvar ctl-x-4-map (make-keymap)
793: "Keymap for subcommands of C-x 4")
794: (fset 'ctl-x-4-prefix ctl-x-4-map)
795: (define-key ctl-x-map "4" 'ctl-x-4-prefix)
796: (define-key ctl-x-4-map "f" 'find-file-other-window)
797: (define-key ctl-x-4-map "\C-f" 'find-file-other-window)
798: (define-key ctl-x-4-map "b" 'switch-to-buffer-other-window)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.