|
|
1.1 ! root 1: ;; File input and output commands for Emacs ! 2: ;; Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc. ! 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: ;;; Turn off backup files on VMS since it has version numbers. ! 27: (defconst make-backup-files (not (eq system-type 'vax-vms)) ! 28: "*Create a backup of each file when it is saved for the first time. ! 29: This can be done by renaming the file or by copying. ! 30: ! 31: Renaming means that Emacs renames the existing file so that it is a ! 32: backup file, then writes the buffer into a new file. Any other names ! 33: that the old file had will now refer to the backup file. ! 34: The new file is owned by you and its group is defaulted. ! 35: ! 36: Copying means that Emacs copies the existing file into the backup file, ! 37: then writes the buffer on top of the existing file. Any other names ! 38: that the old file had will now refer to the new (edited) file. ! 39: The file's owner and group are unchanged. ! 40: ! 41: The choice of renaming or copying is controlled by the variables ! 42: backup-by-copying, backup-by-copying-when-linked and ! 43: backup-by-copying-when-mismatch.") ! 44: ! 45: (defconst backup-by-copying nil ! 46: "*Non-nil means always use copying to create backup files. ! 47: See documentation of variable make-backup-files.") ! 48: ! 49: (defconst backup-by-copying-when-linked nil ! 50: "*Non-nil means use copying to create backups for files with multiple names. ! 51: This causes the alternate names to refer to the latest version as edited. ! 52: This variable is relevant only if backup-by-copying is nil.") ! 53: ! 54: (defconst backup-by-copying-when-mismatch nil ! 55: "*Non-nil means create backups by copying if this preserves owner or group. ! 56: Renaming may still be used (subject to control of other variables) ! 57: when it would not result in changing the owner or group of the file; ! 58: that is, for files which are owned by you and whose group matches ! 59: the default for a new file created there by you. ! 60: This variable is relevant only if backup-by-copying is nil.") ! 61: ! 62: (defconst buffer-offer-save nil ! 63: "*Non-nil in a buffer means offer to save the buffer on exit ! 64: even if the buffer is not visiting a file. Automatically local in ! 65: all buffers.") ! 66: (make-variable-buffer-local 'buffer-offer-save) ! 67: ! 68: (defconst file-precious-flag nil ! 69: "*Non-nil means protect against I/O errors while saving files. ! 70: Some modes set this non-nil in particular buffers.") ! 71: ! 72: (defvar version-control nil ! 73: "*Control use of version numbers for backup files. ! 74: t means make numeric backup versions unconditionally. ! 75: nil means make them for files that have some already. ! 76: never means do not make them.") ! 77: ! 78: (defvar dired-kept-versions 2 ! 79: "*When cleaning directory, number of versions to keep.") ! 80: ! 81: (defvar trim-versions-without-asking nil ! 82: "*If true, deletes excess backup versions silently. ! 83: Otherwise asks confirmation.") ! 84: ! 85: (defvar kept-old-versions 2 ! 86: "*Number of oldest versions to keep when a new numbered backup is made.") ! 87: ! 88: (defvar kept-new-versions 2 ! 89: "*Number of newest versions to keep when a new numbered backup is made. ! 90: Includes the new backup. Must be > 0") ! 91: ! 92: (defconst require-final-newline nil ! 93: "*t says silently put a newline at the end whenever a file is saved. ! 94: Non-nil but not t says ask user whether to add a newline in each such case. ! 95: nil means don't add newlines.") ! 96: ! 97: (defconst auto-save-default t ! 98: "*t says by default do auto-saving of every file-visiting buffer.") ! 99: ! 100: (defconst auto-save-visited-file-name nil ! 101: "*t says auto-save a buffer in the file it is visiting, when practical. ! 102: Normally auto-save files are written under other names.") ! 103: ! 104: (defconst save-abbrevs nil ! 105: "*Non-nil means save word abbrevs too when files are saved. ! 106: Loading an abbrev file sets this to t.") ! 107: ! 108: (defconst find-file-run-dired t ! 109: "*Non-nil says run dired if find-file is given the name of a directory.") ! 110: ! 111: (defvar find-file-not-found-hooks nil ! 112: "List of functions to be called for find-file on nonexistent file. ! 113: These functions are called as soon as the error is detected. ! 114: buffer-file-name is already set up. ! 115: The functions are called in the order given, ! 116: until one of them returns non-nil.") ! 117: ! 118: (defvar find-file-hooks nil ! 119: "List of functions to be called after a buffer is loaded from a file. ! 120: The buffer's local variables (if any) will have been processed before the ! 121: functions are called.") ! 122: ! 123: (defvar write-file-hooks nil ! 124: "List of functions to be called before writing out a buffer to a file. ! 125: If one of them returns non-nil, the file is considered already written ! 126: and the rest are not called.") ! 127: ! 128: (defconst inhibit-local-variables nil ! 129: "*Non-nil means query before obeying a file's local-variables list. ! 130: This applies when the local-variables list is scanned automatically ! 131: after you find a file. If you explicitly request such a scan with ! 132: \\[normal-mode], there is no query, regardless of this variable.") ! 133: ! 134: ;; Avoid losing in versions where CLASH_DETECTION is disabled. ! 135: (or (fboundp 'lock-buffer) ! 136: (fset 'lock-buffer 'ignore)) ! 137: (or (fboundp 'unlock-buffer) ! 138: (fset 'unlock-buffer 'ignore)) ! 139: ! 140: (defun pwd () ! 141: "Show the current default directory." ! 142: (interactive nil) ! 143: (message "Directory %s" default-directory)) ! 144: ! 145: (defun cd (dir) ! 146: "Make DIR become the current buffer's default directory." ! 147: (interactive "DChange default directory: ") ! 148: (setq dir (expand-file-name dir)) ! 149: (if (not (eq system-type 'vax-vms)) ! 150: (setq dir (file-name-as-directory dir))) ! 151: (if (not (file-directory-p dir)) ! 152: (error "%s is not a directory" dir) ! 153: (setq default-directory dir)) ! 154: (pwd)) ! 155: ! 156: (defun load-file (file) ! 157: "Load the file FILE of Lisp code." ! 158: (interactive "fLoad file: ") ! 159: (load (expand-file-name file) nil nil t)) ! 160: ! 161: (defun load-library (library) ! 162: "Load the library named LIBRARY. ! 163: This is an interface to the function `load'." ! 164: (interactive "sLoad library: ") ! 165: (load library)) ! 166: ! 167: (defun switch-to-buffer-other-window (buffer) ! 168: "Select buffer BUFFER in another window." ! 169: (interactive "BSwitch to buffer in other window: ") ! 170: (let ((pop-up-windows t)) ! 171: (pop-to-buffer buffer t))) ! 172: ! 173: (defun find-file (filename) ! 174: "Edit file FILENAME. ! 175: Switch to a buffer visiting file FILENAME, ! 176: creating one if none already exists." ! 177: (interactive "FFind file: ") ! 178: (switch-to-buffer (find-file-noselect filename))) ! 179: ! 180: (defun find-file-other-window (filename) ! 181: "Edit file FILENAME, in another window. ! 182: May create a new window, or reuse an existing one; ! 183: see the function display-buffer." ! 184: (interactive "FFind file in other window: ") ! 185: (switch-to-buffer-other-window (find-file-noselect filename))) ! 186: ! 187: (defun find-file-read-only (filename) ! 188: "Edit file FILENAME but don't save without confirmation. ! 189: Like find-file but marks buffer as read-only." ! 190: (interactive "fFind file read-only: ") ! 191: (find-file filename) ! 192: (setq buffer-read-only t)) ! 193: ! 194: (defun find-alternate-file (filename) ! 195: "Find file FILENAME, select its buffer, kill previous buffer. ! 196: If the current buffer now contains an empty file that you just visited ! 197: \(presumably by mistake), use this command to visit the file you really want." ! 198: (interactive "FFind alternate file: ") ! 199: (and (buffer-modified-p) ! 200: (not buffer-read-only) ! 201: (not (yes-or-no-p (format "Buffer %s is modified; kill anyway? " ! 202: (buffer-name)))) ! 203: (error "Aborted")) ! 204: (let ((obuf (current-buffer)) ! 205: (ofile buffer-file-name) ! 206: (oname (buffer-name))) ! 207: (rename-buffer " **lose**") ! 208: (setq buffer-file-name nil) ! 209: (unwind-protect ! 210: (progn ! 211: (unlock-buffer) ! 212: (find-file filename)) ! 213: (cond ((eq obuf (current-buffer)) ! 214: (setq buffer-file-name ofile) ! 215: (lock-buffer) ! 216: (rename-buffer oname)))) ! 217: (kill-buffer obuf))) ! 218: ! 219: (defun create-file-buffer (filename) ! 220: "Create a suitably named buffer for visiting FILENAME, and return it. ! 221: FILENAME (sans directory) is used unchanged if that name is free; ! 222: otherwise a string <2> or <3> or ... is appended to get an unused name." ! 223: (let ((lastname (file-name-nondirectory filename))) ! 224: (if (string= lastname "") ! 225: (setq lastname filename)) ! 226: (generate-new-buffer lastname))) ! 227: ! 228: (defun find-file-noselect (filename &optional nowarn) ! 229: "Read file FILENAME into a buffer and return the buffer. ! 230: If a buffer exists visiting FILENAME, return that one, ! 231: but verify that the file has not changed since visited or saved. ! 232: The buffer is not selected, just returned to the caller." ! 233: (setq filename (expand-file-name filename)) ! 234: (if (file-directory-p filename) ! 235: (if find-file-run-dired ! 236: (dired-noselect filename) ! 237: (error "%s is a directory." filename)) ! 238: (let ((buf (get-file-buffer filename)) ! 239: error) ! 240: (if buf ! 241: (or nowarn ! 242: (verify-visited-file-modtime buf) ! 243: (cond ((not (file-exists-p filename)) ! 244: (error "File %s no longer exists!" filename)) ! 245: ((yes-or-no-p ! 246: (if (buffer-modified-p buf) ! 247: "File has changed since last visited or saved. Flush your changes? " ! 248: "File has changed since last visited or saved. Read from disk? ")) ! 249: (save-excursion ! 250: (set-buffer buf) ! 251: (revert-buffer t t))))) ! 252: (save-excursion ! 253: (setq buf (create-file-buffer filename)) ! 254: (set-buffer buf) ! 255: (erase-buffer) ! 256: (condition-case () ! 257: (insert-file-contents filename t) ! 258: (file-error ! 259: (setq error t) ! 260: ;; Run find-file-not-found-hooks until one returns non-nil. ! 261: (let ((hooks find-file-not-found-hooks)) ! 262: (while (and hooks ! 263: (not (funcall (car hooks)))) ! 264: (setq hooks (cdr hooks)))))) ! 265: (setq default-directory (file-name-directory filename)) ! 266: (after-find-file error (not nowarn)))) ! 267: buf))) ! 268: ! 269: (defun after-find-file (&optional error warn) ! 270: "Called after finding a file and by the default revert function. ! 271: Sets buffer mode, parses local variables. ! 272: Optional args ERROR and WARN: ERROR non-nil means there was an ! 273: error in reading the file. WARN non-nil means warn if there ! 274: exists an auto-save file more recent than the visited file. ! 275: Finishes by calling the functions in find-file-hooks." ! 276: (setq buffer-read-only (not (file-writable-p buffer-file-name))) ! 277: (if noninteractive ! 278: nil ! 279: (let* (not-serious ! 280: (msg ! 281: (cond ((not buffer-read-only) ! 282: (if (and warn ! 283: (file-newer-than-file-p (make-auto-save-file-name) ! 284: buffer-file-name)) ! 285: "Auto save file is newer; consider M-x recover-file" ! 286: (setq not-serious t) ! 287: (if error "(New file)" nil))) ! 288: ((not error) ! 289: (setq not-serious t) ! 290: "File is write protected") ! 291: ((file-attributes buffer-file-name) ! 292: "File exists, but is read-protected.") ! 293: ((file-attributes (directory-file-name default-directory)) ! 294: "File not found and directory write-protected") ! 295: (t ! 296: "File not found and directory doesn't exist")))) ! 297: (if msg ! 298: (progn ! 299: (message msg) ! 300: (or not-serious (sit-for 1 t))))) ! 301: (if auto-save-default ! 302: (auto-save-mode t))) ! 303: (normal-mode t) ! 304: (mapcar 'funcall find-file-hooks)) ! 305: ! 306: (defun normal-mode (&optional find-file) ! 307: "Choose the major mode for this buffer automatically. ! 308: Also sets up any specified local variables of the file. ! 309: Uses the visited file name, the -*- line, and the local variables spec. ! 310: ! 311: This function is called automatically from `find-file'. In that case, ! 312: if `inhibit-local-variables' is non-`nil' we require confirmation before ! 313: processing a local variables spec. If you run `normal-mode' explicitly, ! 314: confirmation is never required." ! 315: (interactive) ! 316: (or find-file (funcall (or default-major-mode 'fundamental-mode))) ! 317: (condition-case err ! 318: (set-auto-mode) ! 319: (error (message "File mode specification error: %s" ! 320: (prin1-to-string err)))) ! 321: (condition-case err ! 322: (hack-local-variables (not find-file)) ! 323: (error (message "File local-variables error: %s" ! 324: (prin1-to-string err))))) ! 325: ! 326: ;(defvar auto-mode-alist ...) now in loaddefs.el ! 327: (defun set-auto-mode () ! 328: "Select major mode appropriate for current buffer. ! 329: May base decision on visited file name (See variable auto-mode-list) ! 330: or on buffer contents (-*- line or local variables spec), but does not look ! 331: for the \"mode:\" local variable. For that, use hack-local-variables." ! 332: ;; Look for -*-MODENAME-*- or -*- ... mode: MODENAME; ... -*- ! 333: (let (beg end mode) ! 334: (save-excursion ! 335: (goto-char (point-min)) ! 336: (skip-chars-forward " \t\n") ! 337: (if (and (search-forward "-*-" (save-excursion (end-of-line) (point)) t) ! 338: (progn ! 339: (skip-chars-forward " \t") ! 340: (setq beg (point)) ! 341: (search-forward "-*-" (save-excursion (end-of-line) (point)) t)) ! 342: (progn ! 343: (forward-char -3) ! 344: (skip-chars-backward " \t") ! 345: (setq end (point)) ! 346: (goto-char beg) ! 347: (if (search-forward ":" end t) ! 348: (progn ! 349: (goto-char beg) ! 350: (if (let ((case-fold-search t)) ! 351: (search-forward "mode:" end t)) ! 352: (progn ! 353: (skip-chars-forward " \t") ! 354: (setq beg (point)) ! 355: (if (search-forward ";" end t) ! 356: (forward-char -1) ! 357: (goto-char end)) ! 358: (skip-chars-backward " \t") ! 359: (setq mode (buffer-substring beg (point)))))) ! 360: (setq mode (buffer-substring beg end))))) ! 361: (funcall (intern (concat (downcase mode) "-mode"))) ! 362: (let ((alist auto-mode-alist) ! 363: (name buffer-file-name)) ! 364: (let ((case-fold-search (eq system-type 'vax-vms))) ! 365: ;; Remove backup-suffixes from file name. ! 366: (setq name (file-name-sans-versions name)) ! 367: ;; Find first matching alist entry. ! 368: (while (and (not mode) alist) ! 369: (if (string-match (car (car alist)) name) ! 370: (setq mode (cdr (car alist)))) ! 371: (setq alist (cdr alist)))) ! 372: (if mode (funcall mode))))))) ! 373: ! 374: (defun hack-local-variables (&optional force) ! 375: "Parse, and bind or evaluate as appropriate, any local variables ! 376: for current buffer." ! 377: ;; Look for "Local variables:" line in last page. ! 378: (save-excursion ! 379: (goto-char (point-max)) ! 380: (search-backward "\n\^L" (max (- (point-max) 3000) (point-min)) 'move) ! 381: (if (let ((case-fold-search t)) ! 382: (and (search-forward "Local Variables:" nil t) ! 383: (or (not inhibit-local-variables) ! 384: force ! 385: (y-or-n-p (format"Set local variables as specified at end of %s? " ! 386: (file-name-nondirectory buffer-file-name)))))) ! 387: (let ((continue t) ! 388: prefix prefixlen suffix beg) ! 389: ;; The prefix is what comes before "local variables:" in its line. ! 390: ;; The suffix is what comes after "local variables:" in its line. ! 391: (skip-chars-forward " \t") ! 392: (or (eolp) ! 393: (setq suffix (buffer-substring (point) ! 394: (progn (end-of-line) (point))))) ! 395: (goto-char (match-beginning 0)) ! 396: (or (bolp) ! 397: (setq prefix ! 398: (buffer-substring (point) ! 399: (progn (beginning-of-line) (point))))) ! 400: (if prefix (setq prefixlen (length prefix) ! 401: prefix (regexp-quote prefix))) ! 402: (if suffix (setq suffix (regexp-quote suffix))) ! 403: (while continue ! 404: ;; Look at next local variable spec. ! 405: (if selective-display (re-search-forward "[\n\C-m]") ! 406: (forward-line 1)) ! 407: ;; Skip the prefix, if any. ! 408: (if prefix ! 409: (if (looking-at prefix) ! 410: (forward-char prefixlen) ! 411: (error "Local variables entry is missing the prefix"))) ! 412: ;; Find the variable name; strip whitespace. ! 413: (skip-chars-forward " \t") ! 414: (setq beg (point)) ! 415: (skip-chars-forward "^:\n") ! 416: (if (eolp) (error "Missing colon in local variables entry")) ! 417: (skip-chars-backward " \t") ! 418: (let* ((str (buffer-substring beg (point))) ! 419: (var (read str)) ! 420: val) ! 421: ;; Setting variable named "end" means end of list. ! 422: (if (string-equal (downcase str) "end") ! 423: (setq continue nil) ! 424: ;; Otherwise read the variable value. ! 425: (skip-chars-forward "^:") ! 426: (forward-char 1) ! 427: (setq val (read (current-buffer))) ! 428: (skip-chars-backward "\n") ! 429: (skip-chars-forward " \t") ! 430: (or (if suffix (looking-at suffix) (eolp)) ! 431: (error "Local variables entry is terminated incorrectly")) ! 432: ;; Set the variable. "Variables" mode and eval are funny. ! 433: (cond ((eq var 'mode) ! 434: (funcall (intern (concat (downcase (symbol-name val)) ! 435: "-mode")))) ! 436: ((eq var 'eval) ! 437: (if (string= (user-login-name) "root") ! 438: (message "Ignoring `eval:' in file's local variables") ! 439: (eval val))) ! 440: (t (make-local-variable var) ! 441: (set var val)))))))))) ! 442: ! 443: (defun set-visited-file-name (filename) ! 444: "Change name of file visited in current buffer to FILENAME. ! 445: The next time the buffer is saved it will go in the newly specified file. ! 446: nil or empty string as argument means make buffer not be visiting any file. ! 447: Remember to delete the initial contents of the minibuffer ! 448: if you wish to pass an empty string as the argument." ! 449: (interactive "FSet visited file name: ") ! 450: (if filename ! 451: (setq filename ! 452: (if (string-equal filename "") ! 453: nil ! 454: (expand-file-name filename)))) ! 455: (or (equal filename buffer-file-name) ! 456: (null filename) ! 457: (progn ! 458: (lock-buffer filename) ! 459: (unlock-buffer))) ! 460: (setq buffer-file-name filename) ! 461: (if filename ! 462: (let ((new-name (file-name-nondirectory buffer-file-name))) ! 463: (if (eq system-type 'vax-vms) ! 464: (setq new-name (downcase new-name))) ! 465: (setq default-directory (file-name-directory buffer-file-name)) ! 466: (or (get-buffer new-name) (rename-buffer new-name)))) ! 467: (setq buffer-backed-up nil) ! 468: (clear-visited-file-modtime) ! 469: (kill-local-variable 'write-file-hooks) ! 470: (kill-local-variable 'revert-buffer-function) ! 471: ;; Rename the auto-save file to go with the new visited name. ! 472: ;; If auto-save was not already on, turn it on if appropriate. ! 473: (if buffer-auto-save-file-name ! 474: (rename-auto-save-file) ! 475: (auto-save-mode (and buffer-file-name auto-save-default))) ! 476: (if buffer-file-name ! 477: (set-buffer-modified-p t))) ! 478: ! 479: (defun write-file (filename) ! 480: "Write current buffer into file FILENAME. ! 481: Makes buffer visit that file, and marks it not modified." ! 482: (interactive "FWrite file: ") ! 483: (or (null filename) (string-equal filename "") ! 484: (set-visited-file-name filename)) ! 485: (set-buffer-modified-p t) ! 486: (save-buffer)) ! 487: ! 488: (defun backup-buffer () ! 489: "Make a backup of the disk file visited by the current buffer, if appropriate. ! 490: This is normally done before saving the buffer the first time. ! 491: If the value is non-nil, it is the result of `file-modes' on the original file; ! 492: this means that the caller, after saving the buffer, should change the modes ! 493: of the new file to agree with the old modes." ! 494: (and make-backup-files ! 495: (not buffer-backed-up) ! 496: (file-exists-p buffer-file-name) ! 497: (memq (aref (elt (file-attributes buffer-file-name) 8) 0) ! 498: '(?- ?l)) ! 499: (or (< (length buffer-file-name) 5) ! 500: (not (string-equal "/tmp/" (substring buffer-file-name 0 5)))) ! 501: (condition-case () ! 502: (let* ((backup-info (find-backup-file-name buffer-file-name)) ! 503: (backupname (car backup-info)) ! 504: (targets (cdr backup-info)) ! 505: setmodes) ! 506: ; (if (file-directory-p buffer-file-name) ! 507: ; (error "Cannot save buffer in directory %s" buffer-file-name)) ! 508: (condition-case () ! 509: (if (or file-precious-flag ! 510: (file-symlink-p buffer-file-name) ! 511: backup-by-copying ! 512: (and backup-by-copying-when-linked ! 513: (> (file-nlinks buffer-file-name) 1)) ! 514: (and backup-by-copying-when-mismatch ! 515: (let ((attr (file-attributes buffer-file-name))) ! 516: (or (nth 9 attr) ! 517: (/= (nth 2 attr) (user-uid)))))) ! 518: (copy-file buffer-file-name backupname t t) ! 519: (condition-case () ! 520: (delete-file backupname) ! 521: (file-error nil)) ! 522: (rename-file buffer-file-name backupname t) ! 523: (setq setmodes (file-modes backupname))) ! 524: (file-error ! 525: ;; If trouble writing the backup, write it in ~. ! 526: (setq backupname (expand-file-name "~/%backup%~")) ! 527: (message "Cannot write backup file; backing up in ~/%%backup%%~") ! 528: (sleep-for 1) ! 529: (copy-file buffer-file-name backupname t t))) ! 530: (setq buffer-backed-up t) ! 531: (if (and targets ! 532: (or trim-versions-without-asking ! 533: (y-or-n-p (format "Delete excess backup versions of %s? " ! 534: buffer-file-name)))) ! 535: (while targets ! 536: (condition-case () ! 537: (delete-file (car targets)) ! 538: (file-error nil)) ! 539: (setq targets (cdr targets)))) ! 540: setmodes) ! 541: (file-error nil)))) ! 542: ! 543: (defun file-name-sans-versions (name) ! 544: "Return FILENAME sans backup versions or strings. ! 545: This is a separate procedure so your site-init or startup file can ! 546: redefine it." ! 547: (substring name 0 ! 548: (if (eq system-type 'vax-vms) ! 549: (or (string-match ";[0-9]+\\'" name) ! 550: (string-match ".[0-9]+\\'" name) ! 551: (length name)) ! 552: (or (string-match "\\.~[0-9]+~\\'" name) ! 553: (string-match "~\\'" name) ! 554: (length name))))) ! 555: ! 556: (defun make-backup-file-name (file) ! 557: "Create the non-numeric backup file name for FILE. ! 558: This is a separate function so you can redefine it for customization." ! 559: (concat file "~")) ! 560: ! 561: (defun backup-file-name-p (file) ! 562: "Return non-nil if FILE is a backup file name (numeric or not). ! 563: This is a separate function so you can redefine it for customization. ! 564: You may need to redefine file-name-sans-versions as well." ! 565: (string-match "~$" file)) ! 566: ! 567: ;; I believe there is no need to alter this behavior for VMS; ! 568: ;; since backup files are not made on VMS, it should not get called. ! 569: (defun find-backup-file-name (fn) ! 570: "Find a file name for a backup file, and suggestions for deletions. ! 571: Value is a list whose car is the name for the backup file ! 572: and whose cdr is a list of old versions to consider deleting now." ! 573: (if (eq version-control 'never) ! 574: (list (make-backup-file-name fn)) ! 575: (let* ((base-versions (concat (file-name-nondirectory fn) ".~")) ! 576: (bv-length (length base-versions)) ! 577: (possibilities (file-name-all-completions ! 578: base-versions ! 579: (file-name-directory fn))) ! 580: (versions (sort (mapcar 'backup-extract-version possibilities) ! 581: '<)) ! 582: (high-water-mark (apply 'max (cons 0 versions))) ! 583: (deserve-versions-p ! 584: (or version-control ! 585: (> high-water-mark 0))) ! 586: (number-to-delete (- (length versions) ! 587: kept-old-versions kept-new-versions -1))) ! 588: (if (not deserve-versions-p) ! 589: (list (make-backup-file-name fn)) ! 590: (cons (concat fn ".~" (int-to-string (1+ high-water-mark)) "~") ! 591: (if (> number-to-delete 0) ! 592: (mapcar (function (lambda (n) ! 593: (concat fn ".~" (int-to-string n) "~"))) ! 594: (let ((v (nthcdr kept-old-versions versions))) ! 595: (rplacd (nthcdr (1- number-to-delete) v) ()) ! 596: v)))))))) ! 597: ! 598: (defun backup-extract-version (fn) ! 599: (if (and (string-match "[0-9]+~$" fn bv-length) ! 600: (= (match-beginning 0) bv-length)) ! 601: (string-to-int (substring fn bv-length -1)) ! 602: 0)) ! 603: ! 604: (defun file-nlinks (filename) ! 605: "Return number of names file FILENAME has." ! 606: (car (cdr (file-attributes filename)))) ! 607: ! 608: (defun save-buffer (&optional args) ! 609: "Save current buffer in visited file if modified. Versions described below. ! 610: ! 611: By default, makes the previous version into a backup file ! 612: if previously requested or if this is the first save. ! 613: With 1 or 3 \\[universal-argument]'s, marks this version ! 614: to become a backup when the next save is done. ! 615: With 2 or 3 \\[universal-argument]'s, ! 616: unconditionally makes the previous version into a backup file. ! 617: With argument of 0, never makes the previous version into a backup file. ! 618: ! 619: If a file's name is FOO, the names of its numbered backup versions are ! 620: FOO.~i~ for various integers i. A non-numbered backup file is called FOO~. ! 621: Numeric backups (rather than FOO~) will be made if value of ! 622: `version-control' is not the atom `never' and either there are already ! 623: numeric versions of the file being backed up, or `version-control' is ! 624: non-nil. ! 625: We don't want excessive versions piling up, so there are variables ! 626: `kept-old-versions', which tells Emacs how many oldest versions to keep, ! 627: and `kept-new-versions', which tells how many newest versions to keep. ! 628: Defaults are 2 old versions and 2 new. ! 629: `dired-kept-versions' controls dired's clean-directory (.) command. ! 630: If `trim-versions-without-asking' is nil, system will query user ! 631: before trimming versions. Otherwise it does it silently." ! 632: (interactive "p") ! 633: (let ((modp (buffer-modified-p)) ! 634: (large (> (buffer-size) 50000)) ! 635: (make-backup-files (and make-backup-files (not (eq args 0))))) ! 636: (and modp (memq args '(16 64)) (setq buffer-backed-up nil)) ! 637: (if (and modp large) (message "Saving file %s..." (buffer-file-name))) ! 638: (basic-save-buffer) ! 639: (and modp (memq args '(4 64)) (setq buffer-backed-up nil)))) ! 640: ! 641: (defun delete-auto-save-file-if-necessary () ! 642: "Delete the auto-save filename for the current buffer (if it has one) ! 643: if variable delete-auto-save-files is non-nil." ! 644: (and buffer-auto-save-file-name delete-auto-save-files ! 645: (progn ! 646: (condition-case () ! 647: (delete-file buffer-auto-save-file-name) ! 648: (file-error nil)) ! 649: (set-buffer-auto-saved)))) ! 650: ! 651: (defun basic-save-buffer () ! 652: "Save the current buffer in its visited file, if it has been modified." ! 653: (interactive) ! 654: (if (buffer-modified-p) ! 655: (let (setmodes tempsetmodes) ! 656: (or buffer-file-name ! 657: (progn ! 658: (setq buffer-file-name ! 659: (expand-file-name (read-file-name "File to save in: ") nil) ! 660: default-directory (file-name-directory buffer-file-name)) ! 661: (auto-save-mode auto-save-default))) ! 662: (if (not (file-writable-p buffer-file-name)) ! 663: (if (yes-or-no-p ! 664: (format "File %s is write-protected; try to save anyway? " ! 665: (file-name-nondirectory buffer-file-name))) ! 666: (setq tempsetmodes t) ! 667: (error ! 668: "Attempt to save to a file which you aren't allowed to write"))) ! 669: (or (verify-visited-file-modtime (current-buffer)) ! 670: (not (file-exists-p buffer-file-name)) ! 671: (yes-or-no-p ! 672: "Disk file has changed since visited or saved. Save anyway? ") ! 673: (error "Save not confirmed")) ! 674: (or buffer-backed-up ! 675: (setq setmodes (backup-buffer))) ! 676: (save-restriction ! 677: (widen) ! 678: (and (> (point-max) 1) ! 679: (/= (char-after (1- (point-max))) ?\n) ! 680: (or (eq require-final-newline t) ! 681: (and require-final-newline ! 682: (yes-or-no-p ! 683: (format "Buffer %s does not end in newline. Add one? " ! 684: (buffer-name))))) ! 685: (save-excursion ! 686: (goto-char (point-max)) ! 687: (insert ?\n))) ! 688: (let ((hooks write-file-hooks) ! 689: (done nil)) ! 690: (while (and hooks ! 691: (not (setq done (funcall (car hooks))))) ! 692: (setq hooks (cdr hooks))) ! 693: ;; If a hook returned t, file is already "written". ! 694: (cond ((not done) ! 695: (if file-precious-flag ! 696: ;; If file is precious, rename it away before ! 697: ;; overwriting it. ! 698: (let ((rename t) nodelete ! 699: (file (concat buffer-file-name "#"))) ! 700: (condition-case () ! 701: (progn (rename-file buffer-file-name file t) ! 702: (setq setmodes (file-modes file))) ! 703: (file-error (setq rename nil nodelete t))) ! 704: (unwind-protect ! 705: (progn (clear-visited-file-modtime) ! 706: (write-region (point-min) (point-max) ! 707: buffer-file-name nil t) ! 708: (setq rename nil)) ! 709: ;; If rename is still t, writing failed. ! 710: ;; So rename the old file back to original name, ! 711: (if rename ! 712: (progn ! 713: (rename-file file buffer-file-name t) ! 714: (clear-visited-file-modtime)) ! 715: ;; Otherwise we don't need the original file, ! 716: ;; so flush it. Unless we already lost it. ! 717: (or nodelete ! 718: (condition-case () ! 719: (delete-file file) ! 720: (error nil)))))) ! 721: ;; If file not writable, see if we can make it writable ! 722: ;; temporarily while we write it. ! 723: ;; But no need to do so if we have just backed it up ! 724: ;; (setmodes is set) because that says we're superseding. ! 725: (cond ((and tempsetmodes (not setmodes)) ! 726: ;; Change the mode back, after writing. ! 727: (setq setmodes (file-modes buffer-file-name)) ! 728: (set-file-modes buffer-file-name 511))) ! 729: (write-region (point-min) (point-max) ! 730: buffer-file-name nil t))))) ! 731: (if setmodes ! 732: (condition-case () ! 733: (set-file-modes buffer-file-name setmodes) ! 734: (error nil)))) ! 735: (delete-auto-save-file-if-necessary)) ! 736: (message "(No changes need to be saved)"))) ! 737: ! 738: (defun save-some-buffers (&optional arg exiting) ! 739: "Save some modified file-visiting buffers. Asks user about each one. ! 740: With argument, saves all with no questions." ! 741: (interactive "P") ! 742: (let (considered (list (buffer-list))) ! 743: (while list ! 744: (let ((buffer (car list))) ! 745: (and (buffer-modified-p buffer) ! 746: (save-excursion ! 747: (set-buffer buffer) ! 748: (and ! 749: (or buffer-file-name ! 750: (and exiting buffer-offer-save (> (buffer-size) 0))) ! 751: (setq considered t) ! 752: (or arg ! 753: (y-or-n-p (if buffer-file-name ! 754: (format "Save file %s? " ! 755: buffer-file-name) ! 756: (format "Save buffer %s? " (buffer-name))))) ! 757: (condition-case () ! 758: (save-buffer) ! 759: (error nil)))))) ! 760: (setq list (cdr list))) ! 761: (and save-abbrevs abbrevs-changed ! 762: (progn ! 763: (setq considered t) ! 764: (if (or arg ! 765: (y-or-n-p (format "Save abbrevs in %s? " abbrev-file-name))) ! 766: (write-abbrev-file nil)) ! 767: ;; Don't keep bothering user if he says no. ! 768: (setq abbrevs-changed nil))) ! 769: (if considered ! 770: (message "") ! 771: (message "(No files need saving)")))) ! 772: ! 773: (defun not-modified () ! 774: "Mark current buffer as unmodified, not needing to be saved." ! 775: (interactive) ! 776: (message "Modification-flag cleared") ! 777: (set-buffer-modified-p nil)) ! 778: ! 779: (defun toggle-read-only () ! 780: "Change whether this buffer is visiting its file read-only." ! 781: (interactive) ! 782: (setq buffer-read-only (not buffer-read-only)) ! 783: ;; Force mode-line redisplay ! 784: (set-buffer-modified-p (buffer-modified-p))) ! 785: ! 786: (defun insert-file (filename) ! 787: "Insert contents of file FILENAME into buffer after point. ! 788: Set mark after the inserted text." ! 789: (interactive "fInsert file: ") ! 790: (let ((tem (insert-file-contents filename))) ! 791: (push-mark (+ (point) (car (cdr tem)))))) ! 792: ! 793: (defun append-to-file (start end filename) ! 794: "Append the contents of the region to the end of file FILENAME. ! 795: When called from a function, expects three arguments, ! 796: START, END and FILENAME. START and END are buffer positions ! 797: saying what text to write." ! 798: (interactive "r\nFAppend to file: ") ! 799: (write-region start end filename t)) ! 800: ! 801: (defvar revert-buffer-function nil ! 802: "Function to use to revert this buffer, or nil to do the default.") ! 803: ! 804: (defun revert-buffer (&optional arg noconfirm) ! 805: "Replace the buffer text with the text of the visited file on disk. ! 806: This undoes all changes since the file was visited or saved. ! 807: If latest auto-save file is more recent than the visited file, ! 808: asks user whether to use that instead. ! 809: First argument (optional) non-nil means don't offer to use auto-save file. ! 810: This is the prefix arg when called interactively. ! 811: ! 812: Second argument (optional) non-nil means don't ask for confirmation at all. ! 813: ! 814: If revert-buffer-function's value is non-nil, it is called to do the work." ! 815: (interactive "P") ! 816: (if revert-buffer-function ! 817: (funcall revert-buffer-function arg noconfirm) ! 818: (let* ((opoint (point)) ! 819: (auto-save-p (and (null arg) (recent-auto-save-p) ! 820: buffer-auto-save-file-name ! 821: (file-readable-p buffer-auto-save-file-name) ! 822: (y-or-n-p ! 823: "Buffer has been auto-saved recently. Revert from auto-save file? "))) ! 824: (file-name (if auto-save-p ! 825: buffer-auto-save-file-name ! 826: buffer-file-name))) ! 827: (cond ((null file-name) ! 828: (error "Buffer does not seem to be associated with any file")) ! 829: ((not (file-exists-p file-name)) ! 830: (error "File %s no longer exists!" file-name)) ! 831: ((or noconfirm ! 832: (yes-or-no-p (format "Revert buffer from file %s? " ! 833: file-name))) ! 834: (let ((buffer-read-only nil)) ! 835: ;; Bind buffer-file-name to nil ! 836: ;; so that we don't try to lock the file. ! 837: (let ((buffer-file-name nil)) ! 838: (or auto-save-p ! 839: (unlock-buffer)) ! 840: (erase-buffer)) ! 841: (insert-file-contents file-name (not auto-save-p))) ! 842: (goto-char (min opoint (point-max))) ! 843: (after-find-file nil) ! 844: t))))) ! 845: ! 846: (defun recover-file (file) ! 847: "Visit file FILE, but get contents from its last auto-save file." ! 848: (interactive "FRecover file: ") ! 849: (setq file (expand-file-name file)) ! 850: (if (auto-save-file-name-p file) (error "%s is an auto-save file" file)) ! 851: (let ((file-name (let ((buffer-file-name file)) ! 852: (make-auto-save-file-name)))) ! 853: (cond ((not (file-newer-than-file-p file-name file)) ! 854: (error "Auto-save file %s not current" file-name)) ! 855: ((save-window-excursion ! 856: (if (not (eq system-type 'vax-vms)) ! 857: (with-output-to-temp-buffer "*Directory*" ! 858: (buffer-flush-undo standard-output) ! 859: (call-process "ls" nil standard-output nil ! 860: "-l" file file-name))) ! 861: (yes-or-no-p (format "Recover auto save file %s? " file-name))) ! 862: (switch-to-buffer (find-file-noselect file t)) ! 863: (let ((buffer-read-only nil)) ! 864: (erase-buffer) ! 865: (insert-file-contents file-name nil)) ! 866: (after-find-file nil)) ! 867: (t (error "Recover-file cancelled.")))) ! 868: (setq buffer-auto-save-file-name nil) ! 869: (message "Auto-save off in this buffer till you do M-x auto-save-mode.")) ! 870: ! 871: (defun kill-some-buffers () ! 872: "For each buffer, ask whether to kill it." ! 873: (interactive) ! 874: (let ((list (buffer-list))) ! 875: (while list ! 876: (let* ((buffer (car list)) ! 877: (name (buffer-name buffer))) ! 878: (and (not (string-equal name "")) ! 879: (/= (aref name 0) ? ) ! 880: (yes-or-no-p ! 881: (format "Buffer %s %s. Kill? " ! 882: name ! 883: (if (buffer-modified-p buffer) ! 884: "HAS BEEN EDITED" "is unmodified"))) ! 885: (kill-buffer buffer))) ! 886: (setq list (cdr list))))) ! 887: ! 888: (defun auto-save-mode (arg) ! 889: "Toggle auto-saving of contents of current buffer. ! 890: With arg, turn auto-saving on if arg is positive, else off." ! 891: (interactive "P") ! 892: (setq buffer-auto-save-file-name ! 893: (and (if (null arg) ! 894: (not buffer-auto-save-file-name) ! 895: (or (eq arg t) (listp arg) (and (integerp arg) (> arg 0)))) ! 896: (if (and buffer-file-name auto-save-visited-file-name ! 897: (not buffer-read-only)) ! 898: buffer-file-name ! 899: (make-auto-save-file-name)))) ! 900: (if (interactive-p) ! 901: (message "Auto-save %s (in this buffer)" ! 902: (if buffer-auto-save-file-name "on" "off"))) ! 903: buffer-auto-save-file-name) ! 904: ! 905: (defun rename-auto-save-file () ! 906: "Adjust current buffer's auto save file name for current conditions. ! 907: Also rename any existing auto save file." ! 908: (let ((osave buffer-auto-save-file-name)) ! 909: (setq buffer-auto-save-file-name ! 910: (make-auto-save-file-name)) ! 911: (if (and osave buffer-auto-save-file-name ! 912: (not (string= buffer-auto-save-file-name buffer-file-name)) ! 913: (not (string= buffer-auto-save-file-name osave)) ! 914: (file-exists-p osave)) ! 915: (rename-file osave buffer-auto-save-file-name t)))) ! 916: ! 917: (defun make-auto-save-file-name () ! 918: "Return file name to use for auto-saves of current buffer. ! 919: Does not consider auto-save-visited-file-name; that is checked ! 920: before calling this function. ! 921: You can redefine this for customization. ! 922: See also auto-save-file-name-p." ! 923: (if buffer-file-name ! 924: (concat (file-name-directory buffer-file-name) ! 925: "#" ! 926: (file-name-nondirectory buffer-file-name) ! 927: "#") ! 928: (expand-file-name (concat "#%" (buffer-name) "#")))) ! 929: ! 930: (defun auto-save-file-name-p (filename) ! 931: "Return non-nil if FILENAME can be yielded by make-auto-save-file-name. ! 932: FILENAME should lack slashes. ! 933: You can redefine this for customization." ! 934: (string-match "^#.*#$" filename)) ! 935: ! 936: (defconst list-directory-brief-switches "-CF" ! 937: "*Switches for list-directory to pass to `ls' for brief listing,") ! 938: (defconst list-directory-verbose-switches "-l" ! 939: "*Switches for list-directory to pass to `ls' for verbose listing,") ! 940: ! 941: (defun list-directory (dirname &optional verbose) ! 942: "Display a list of files in or matching DIRNAME, a la `ls'. ! 943: DIRNAME is globbed by the shell if necessary. ! 944: Prefix arg (second arg if noninteractive) means supply -l switch to `ls'. ! 945: Actions controlled by variables list-directory-brief-switches ! 946: and list-directory-verbose-switches." ! 947: (interactive (let ((pfx current-prefix-arg)) ! 948: (list (read-file-name (if pfx "List directory (verbose): " ! 949: "List directory (brief): ") ! 950: nil default-directory nil) ! 951: pfx))) ! 952: (let ((switches (if verbose list-directory-verbose-switches ! 953: list-directory-brief-switches)) ! 954: full-dir-p) ! 955: (or dirname (setq dirname default-directory)) ! 956: (if (file-directory-p dirname) ! 957: (progn ! 958: (setq full-dir-p t) ! 959: (or (string-match "/$" dirname) ! 960: (setq dirname (concat dirname "/"))))) ! 961: (setq dirname (expand-file-name dirname)) ! 962: (with-output-to-temp-buffer "*Directory*" ! 963: (buffer-flush-undo standard-output) ! 964: (princ "Directory ") ! 965: (princ dirname) ! 966: (terpri) ! 967: (if full-dir-p ! 968: (call-process "ls" nil standard-output nil ! 969: switches dirname) ! 970: (let ((default-directory (file-name-directory dirname))) ! 971: (call-process shell-file-name nil standard-output nil ! 972: "-c" (concat "exec ls " ! 973: switches " " ! 974: (file-name-nondirectory dirname)))))))) ! 975: ! 976: (defun save-buffers-kill-emacs (&optional arg) ! 977: "Offer to save each buffer, then kill this Emacs fork. ! 978: With prefix arg, silently save all file-visiting buffers, then kill." ! 979: (interactive "P") ! 980: (save-some-buffers arg t) ! 981: (kill-emacs)) ! 982: ! 983: (define-key ctl-x-map "\C-f" 'find-file) ! 984: (define-key ctl-x-map "\C-q" 'toggle-read-only) ! 985: (define-key ctl-x-map "\C-r" 'find-file-read-only) ! 986: (define-key ctl-x-map "\C-v" 'find-alternate-file) ! 987: (define-key ctl-x-map "\C-s" 'save-buffer) ! 988: (define-key ctl-x-map "s" 'save-some-buffers) ! 989: (define-key ctl-x-map "\C-w" 'write-file) ! 990: (define-key ctl-x-map "i" 'insert-file) ! 991: (define-key esc-map "~" 'not-modified) ! 992: (define-key ctl-x-map "\C-d" 'list-directory) ! 993: (define-key ctl-x-map "\C-c" 'save-buffers-kill-emacs) ! 994: ! 995: (defvar ctl-x-4-map (make-keymap) ! 996: "Keymap for subcommands of C-x 4") ! 997: (fset 'ctl-x-4-prefix ctl-x-4-map) ! 998: (define-key ctl-x-map "4" 'ctl-x-4-prefix) ! 999: (define-key ctl-x-4-map "f" 'find-file-other-window) ! 1000: (define-key ctl-x-4-map "\C-f" 'find-file-other-window) ! 1001: (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.