X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/7e27ce9cdb691909a33667d5e2b186d23bb7c9c4..c33134511b466d746312becbc0e4ef59bb9258ac:/lisp/files.el diff --git a/lisp/files.el b/lisp/files.el index ffc0b33119..5bdb26f4e9 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -151,6 +151,7 @@ Automatically local in all buffers." :type 'boolean :group 'backup) (make-variable-buffer-local 'buffer-offer-save) +(put 'buffer-offer-save 'permanent-local t) (defcustom find-file-existing-other-name t "Non-nil means find a file under alternative names, in existing buffers. @@ -278,7 +279,7 @@ The value `never' means do not make them." :group 'backup :group 'vc) (put 'version-control 'safe-local-variable - '(lambda (x) (or (booleanp x) (equal x 'never)))) + (lambda (x) (or (booleanp x) (equal x 'never)))) (defcustom dired-kept-versions 2 "When cleaning directory, number of versions to keep." @@ -635,22 +636,22 @@ the value of `default-directory'." "Value of the CDPATH environment variable, as a list. Not actually set up until the first time you use it.") -(defun parse-colon-path (cd-path) +(defun parse-colon-path (search-path) "Explode a search path into a list of directory names. Directories are separated by occurrences of `path-separator' \(which is colon in GNU and GNU-like systems)." ;; We could use split-string here. - (and cd-path + (and search-path (let (cd-list (cd-start 0) cd-colon) - (setq cd-path (concat cd-path path-separator)) - (while (setq cd-colon (string-match path-separator cd-path cd-start)) + (setq search-path (concat search-path path-separator)) + (while (setq cd-colon (string-match path-separator search-path cd-start)) (setq cd-list (nconc cd-list (list (if (= cd-start cd-colon) nil (substitute-in-file-name (file-name-as-directory - (substring cd-path cd-start cd-colon))))))) + (substring search-path cd-start cd-colon))))))) (setq cd-start (+ cd-colon 1))) cd-list))) @@ -866,11 +867,10 @@ and return the directory. Return nil if not found." ;; `name' in /home or in /. (setq file (abbreviate-file-name file)) (let ((root nil) - (prev-file file) ;; `user' is not initialized outside the loop because ;; `file' may not exist, so we may have to walk up part of the - ;; hierarchy before we find the "initial UID". - (user nil) + ;; hierarchy before we find the "initial UID". Note: currently unused + ;; (user nil) try) (while (not (or root (null file) @@ -887,8 +887,7 @@ and return the directory. Return nil if not found." (string-match locate-dominating-stop-dir-regexp file))) (setq try (file-exists-p (expand-file-name name file))) (cond (try (setq root file)) - ((equal file (setq prev-file file - file (file-name-directory + ((equal file (setq file (file-name-directory (directory-file-name file)))) (setq file nil)))) root)) @@ -958,10 +957,10 @@ reasonable to let-bind this variable to a value less then the time period between two checks. Example: - \(defun display-time-file-nonempty-p \(file) - \(let \(\(remote-file-name-inhibit-cache \(- display-time-interval 5))) - \(and \(file-exists-p file) - \(< 0 \(nth 7 \(file-attributes \(file-chase-links file)))))))" + (defun display-time-file-nonempty-p (file) + (let ((remote-file-name-inhibit-cache (- display-time-interval 5))) + (and (file-exists-p file) + (< 0 (nth 7 (file-attributes (file-chase-links file)))))))" :group 'files :version "24.1" :type `(choice @@ -1140,6 +1139,37 @@ it means chase no more than that many links and then stop." (setq count (1+ count)))) newname)) +;; A handy function to display file sizes in human-readable form. +;; See http://en.wikipedia.org/wiki/Kibibyte for the reference. +(defun file-size-human-readable (file-size &optional flavor) + "Produce a string showing FILE-SIZE in human-readable form. + +Optional second argument FLAVOR controls the units and the display format: + + If FLAVOR is nil or omitted, each kilobyte is 1024 bytes and the produced + suffixes are \"k\", \"M\", \"G\", \"T\", etc. + If FLAVOR is `si', each kilobyte is 1000 bytes and the produced suffixes + are \"k\", \"M\", \"G\", \"T\", etc. + If FLAVOR is `iec', each kilobyte is 1024 bytes and the produced suffixes + are \"KiB\", \"MiB\", \"GiB\", \"TiB\", etc." + (let ((power (if (or (null flavor) (eq flavor 'iec)) + 1024.0 + 1000.0)) + (post-fixes + ;; none, kilo, mega, giga, tera, peta, exa, zetta, yotta + (list "" "k" "M" "G" "T" "P" "E" "Z" "Y"))) + (while (and (>= file-size power) (cdr post-fixes)) + (setq file-size (/ file-size power) + post-fixes (cdr post-fixes))) + (format (if (> (mod file-size 1.0) 0.05) + "%.1f%s%s" + "%.0f%s%s") + file-size + (if (and (eq flavor 'iec) (string= (car post-fixes) "k")) + "K" + (car post-fixes)) + (if (eq flavor 'iec) "iB" "")))) + (defun make-temp-file (prefix &optional dir-flag suffix) "Create a temporary file. The returned file name (created by appending some random characters at the end @@ -1259,100 +1289,6 @@ return value, which may be passed as the REQUIRE-MATCH arg to 'confirm) (t nil))) -(defun read-buffer-to-switch (prompt) - "Read the name of a buffer to switch to and return as a string. -It is intended for `switch-to-buffer' family of commands since they -need to omit the name of current buffer from the list of completions -and default values." - (let ((rbts-completion-table (internal-complete-buffer-except))) - (minibuffer-with-setup-hook - (lambda () - (setq minibuffer-completion-table rbts-completion-table) - ;; Since rbts-completion-table is built dynamically, we - ;; can't just add it to the default value of - ;; icomplete-with-completion-tables, so we add it - ;; here manually. - (if (and (boundp 'icomplete-with-completion-tables) - (listp icomplete-with-completion-tables)) - (set (make-local-variable 'icomplete-with-completion-tables) - (cons rbts-completion-table - icomplete-with-completion-tables)))) - (read-buffer prompt (other-buffer (current-buffer)) - (confirm-nonexistent-file-or-buffer))))) - -(defun switch-to-buffer-other-window (buffer-or-name &optional norecord) - "Select the buffer specified by BUFFER-OR-NAME in another window. -BUFFER-OR-NAME may be a buffer, a string \(a buffer name), or -nil. Return the buffer switched to. - -If called interactively, prompt for the buffer name using the -minibuffer. The variable `confirm-nonexistent-file-or-buffer' -determines whether to request confirmation before creating a new -buffer. - -If BUFFER-OR-NAME is a string and does not identify an existing -buffer, create a new buffer with that name. If BUFFER-OR-NAME is -nil, switch to the buffer returned by `other-buffer'. - -Optional second argument NORECORD non-nil means do not put this -buffer at the front of the list of recently selected ones. - -This uses the function `display-buffer' as a subroutine; see its -documentation for additional customization information." - (interactive - (list (read-buffer-to-switch "Switch to buffer in other window: "))) - (let ((pop-up-windows t) - same-window-buffer-names same-window-regexps) - (pop-to-buffer buffer-or-name t norecord))) - -(defun switch-to-buffer-other-frame (buffer-or-name &optional norecord) - "Switch to buffer BUFFER-OR-NAME in another frame. -BUFFER-OR-NAME may be a buffer, a string \(a buffer name), or -nil. Return the buffer switched to. - -If called interactively, prompt for the buffer name using the -minibuffer. The variable `confirm-nonexistent-file-or-buffer' -determines whether to request confirmation before creating a new -buffer. - -If BUFFER-OR-NAME is a string and does not identify an existing -buffer, create a new buffer with that name. If BUFFER-OR-NAME is -nil, switch to the buffer returned by `other-buffer'. - -Optional second arg NORECORD non-nil means do not put this -buffer at the front of the list of recently selected ones. - -This uses the function `display-buffer' as a subroutine; see its -documentation for additional customization information." - (interactive - (list (read-buffer-to-switch "Switch to buffer in other frame: "))) - (let ((pop-up-frames t) - same-window-buffer-names same-window-regexps) - (pop-to-buffer buffer-or-name t norecord))) - -(defun display-buffer-other-frame (buffer) - "Display buffer BUFFER in another frame. -This uses the function `display-buffer' as a subroutine; see -its documentation for additional customization information." - (interactive "BDisplay buffer in other frame: ") - (let ((pop-up-frames t) - same-window-buffer-names same-window-regexps - (old-window (selected-window)) - new-window) - (setq new-window (display-buffer buffer t)) - ;; This may have been here in order to prevent the new frame from hiding - ;; the old frame. But it does more harm than good. - ;; Maybe we should call `raise-window' on the old-frame instead? --Stef - ;;(lower-frame (window-frame new-window)) - - ;; This may have been here in order to make sure the old-frame gets the - ;; focus. But not only can it cause an annoying flicker, with some - ;; window-managers it just makes the window invisible, with no easy - ;; way to recover it. --Stef - ;;(make-frame-invisible (window-frame old-window)) - ;;(make-frame-visible (window-frame old-window)) - )) - (defmacro minibuffer-with-setup-hook (fun &rest body) "Temporarily add FUN to `minibuffer-setup-hook' while executing BODY. BODY should use the minibuffer at most once. @@ -1544,6 +1480,8 @@ expand wildcards (if any) and replace the file with multiple files." (other-window 1) (find-alternate-file filename wildcards)))) +(defvar kill-buffer-hook) ; from buffer.c + (defun find-alternate-file (filename &optional wildcards) "Find file FILENAME, select its buffer, kill previous buffer. If the current buffer now contains an empty file that you just visited @@ -2042,7 +1980,7 @@ This function ensures that none of these modifications will take place." (inhibit-file-name-operation 'insert-file-contents)) (unwind-protect (progn - (fset 'find-buffer-file-type (lambda (filename) t)) + (fset 'find-buffer-file-type (lambda (_filename) t)) (insert-file-contents filename visit beg end replace)) (if find-buffer-file-type-function (fset 'find-buffer-file-type find-buffer-file-type-function) @@ -2100,10 +2038,8 @@ the file contents into it using `insert-file-contents-literally'." (confirm-nonexistent-file-or-buffer)))) (switch-to-buffer (find-file-noselect filename nil t))) -(defvar after-find-file-from-revert-buffer nil) - (defun after-find-file (&optional error warn noauto - after-find-file-from-revert-buffer + _after-find-file-from-revert-buffer nomodes) "Called after finding a file and by the default revert function. Sets buffer mode, parses local variables. @@ -2111,8 +2047,8 @@ Optional args ERROR, WARN, and NOAUTO: ERROR non-nil means there was an error in reading the file. WARN non-nil means warn if there exists an auto-save file more recent than the visited file. NOAUTO means don't mess with auto-save mode. -Fourth arg AFTER-FIND-FILE-FROM-REVERT-BUFFER non-nil - means this call was from `revert-buffer'. +Fourth arg AFTER-FIND-FILE-FROM-REVERT-BUFFER is ignored +\(see `revert-buffer-in-progress-p' for similar functionality). Fifth arg NOMODES non-nil means don't alter the file's modes. Finishes by calling the functions in `find-file-hook' unless NOMODES is non-nil." @@ -2125,7 +2061,11 @@ unless NOMODES is non-nil." ((not warn) nil) ((and error (file-attributes buffer-file-name)) (setq buffer-read-only t) - "File exists, but cannot be read") + (if (and (file-symlink-p buffer-file-name) + (not (file-exists-p + (file-chase-links buffer-file-name)))) + "Symbolic link that points to nonexistent file" + "File exists, but cannot be read")) ((not buffer-read-only) (if (and warn ;; No need to warn if buffer is auto-saved @@ -2153,7 +2093,7 @@ unless NOMODES is non-nil." (message "%s" msg) (or not-serious (sit-for 1 t)))) (when (and auto-save-default (not noauto)) - (auto-save-mode t))) + (auto-save-mode 1))) ;; Make people do a little extra work (C-x C-q) ;; before altering a backup file. (when (backup-file-name-p buffer-file-name) @@ -2212,6 +2152,8 @@ in that case, this function acts as if `enable-local-variables' were t." (interactive) (funcall (or (default-value 'major-mode) 'fundamental-mode)) (let ((enable-local-variables (or (not find-file) enable-local-variables))) + ;; FIXME this is less efficient than it could be, since both + ;; s-a-m and h-l-v may parse the same regions, looking for "mode:". (report-errors "File mode specification error: %s" (set-auto-mode)) (report-errors "File local-variables error: %s" @@ -2331,7 +2273,12 @@ since only a single case-insensitive search through the alist is made." ("\\.icn\\'" . icon-mode) ("\\.sim\\'" . simula-mode) ("\\.mss\\'" . scribe-mode) + ;; The Fortran standard does not say anything about file extensions. + ;; .f90 was widely used for F90, now we seem to be trapped into + ;; using a different extension for each language revision. + ;; Anyway, the following extensions are supported by gfortran. ("\\.f9[05]\\'" . f90-mode) + ("\\.f0[38]\\'" . f90-mode) ("\\.indent\\.pro\\'" . fundamental-mode) ; to avoid idlwave-mode ("\\.\\(pro\\|PRO\\)\\'" . idlwave-mode) ("\\.srt\\'" . srecode-template-mode) @@ -2357,6 +2304,7 @@ ARC\\|ZIP\\|LZH\\|LHA\\|ZOO\\|[JEW]AR\\|XPI\\|RAR\\|7Z\\)\\'" . archive-mode) ("\\.dtd\\'" . sgml-mode) ("\\.ds\\(ss\\)?l\\'" . dsssl-mode) ("\\.js\\'" . js-mode) ; javascript-mode would be better + ("\\.json\\'" . js-mode) ("\\.[ds]?vh?\\'" . verilog-mode) ;; .emacs or .gnus or .viper following a directory delimiter in ;; Unix, MSDOG or VMS syntax. @@ -2395,6 +2343,7 @@ ARC\\|ZIP\\|LZH\\|LHA\\|ZOO\\|[JEW]AR\\|XPI\\|RAR\\|7Z\\)\\'" . archive-mode) ("\\.ebrowse\\'" . ebrowse-tree-mode) ("#\\*mail\\*" . mail-mode) ("\\.g\\'" . antlr-mode) + ("\\.mod\\'" . m2-mode) ("\\.ses\\'" . ses-mode) ("\\.docbook\\'" . sgml-mode) ("\\.com\\'" . dcl-mode) @@ -2405,8 +2354,6 @@ ARC\\|ZIP\\|LZH\\|LHA\\|ZOO\\|[JEW]AR\\|XPI\\|RAR\\|7Z\\)\\'" . archive-mode) ("\\.ppd\\'" . conf-ppd-mode) ("java.+\\.conf\\'" . conf-javaprop-mode) ("\\.properties\\(?:\\.[a-zA-Z0-9._-]+\\)?\\'" . conf-javaprop-mode) - ;; *.cf, *.cfg, *.conf, *.config[.local|.de_DE.UTF8|...], */config - ("[/.]c\\(?:on\\)?f\\(?:i?g\\)?\\(?:\\.[a-zA-Z0-9._-]+\\)?\\'" . conf-mode-maybe) ("\\`/etc/\\(?:DIR_COLORS\\|ethers\\|.?fstab\\|.*hosts\\|lesskey\\|login\\.?de\\(?:fs\\|vperm\\)\\|magic\\|mtab\\|pam\\.d/.*\\|permissions\\(?:\\.d/.+\\)?\\|protocols\\|rpc\\|services\\)\\'" . conf-space-mode) ("\\`/etc/\\(?:acpid?/.+\\|aliases\\(?:\\.d/.+\\)?\\|default/.+\\|group-?\\|hosts\\..+\\|inittab\\|ksysguarddrc\\|opera6rc\\|passwd-?\\|shadow-?\\|sysconfig/.+\\)\\'" . conf-mode) ;; ChangeLog.old etc. Other change-log-mode entries are above; @@ -2428,11 +2375,14 @@ ARC\\|ZIP\\|LZH\\|LHA\\|ZOO\\|[JEW]AR\\|XPI\\|RAR\\|7Z\\)\\'" . archive-mode) ;; Using mode nil rather than `ignore' would let the search continue ;; through this list (with the shortened name) rather than start over. ("\\.~?[0-9]+\\.[0-9][-.0-9]*~?\\'" nil t) + ("\\.\\(?:orig\\|in\\|[bB][aA][kK]\\)\\'" nil t) + ;; This should come after "in" stripping (e.g. config.h.in). + ;; *.cf, *.cfg, *.conf, *.config[.local|.de_DE.UTF8|...], */config + ("[/.]c\\(?:on\\)?f\\(?:i?g\\)?\\(?:\\.[a-zA-Z0-9._-]+\\)?\\'" . conf-mode-maybe) ;; The following should come after the ChangeLog pattern ;; for the sake of ChangeLog.1, etc. ;; and after the .scm.[0-9] and CVS' . patterns too. - ("\\.[1-9]\\'" . nroff-mode) - ("\\.\\(?:orig\\|in\\|[bB][aA][kK]\\)\\'" nil t))) + ("\\.[1-9]\\'" . nroff-mode))) "Alist of filename patterns vs corresponding major mode functions. Each element looks like (REGEXP . FUNCTION) or (REGEXP FUNCTION NON-NIL). \(NON-NIL stands for anything that is not nil; the value does not matter.) @@ -2491,6 +2441,7 @@ and `magic-mode-alist', which determines modes based on file contents.") ("ksh" . sh-mode) ("oash" . sh-mode) ("pdksh" . sh-mode) + ("rbash" . sh-mode) ("rc" . sh-mode) ("rpm" . sh-mode) ("sh" . sh-mode) @@ -2586,23 +2537,24 @@ Also applies to `magic-fallback-mode-alist'.") "Select major mode appropriate for current buffer. To find the right major mode, this function checks for a -*- mode tag, +checks for a `mode:' entry in the Local Variables section of the file, checks if it uses an interpreter listed in `interpreter-mode-alist', matches the buffer beginning against `magic-mode-alist', compares the filename against the entries in `auto-mode-alist', then matches the buffer beginning against `magic-fallback-mode-alist'. -It does not check for the `mode:' local variable in the -Local Variables section of the file; for that, use `hack-local-variables'. - -If `enable-local-variables' is nil, this function does not check for a --*- mode tag. +If `enable-local-variables' is nil, this function does not check for +any mode: tag anywhere in the file. If the optional argument KEEP-MODE-IF-SAME is non-nil, then we set the major mode only if that would change it. In other words we don't actually set it to the same mode the buffer already has." ;; Look for -*-MODENAME-*- or -*- ... mode: MODENAME; ... -*- (let (end done mode modes) - ;; Find a -*- mode tag + ;; Once we drop the deprecated feature where mode: is also allowed to + ;; specify minor-modes (ie, there can be more than one "mode:"), we can + ;; remove this section and just let (hack-local-variables t) handle it. + ;; Find a -*- mode tag. (save-excursion (goto-char (point-min)) (skip-chars-forward " \t\n") @@ -2637,6 +2589,14 @@ we don't actually set it to the same mode the buffer already has." (or (set-auto-mode-0 mode keep-mode-if-same) ;; continuing would call minor modes again, toggling them off (throw 'nop nil)))))) + (and (not done) + enable-local-variables + (setq mode (hack-local-variables t)) + (not (memq mode modes)) ; already tried and failed + (if (not (functionp mode)) + (message "Ignoring unknown mode `%s'" mode) + (setq done t) + (set-auto-mode-0 mode keep-mode-if-same))) ;; If we didn't, look for an interpreter specified in the first line. ;; As a special case, allow for things like "#!/bin/env perl", which ;; finds the interpreter anywhere in $PATH. @@ -2662,7 +2622,7 @@ we don't actually set it to the same mode the buffer already has." (min (point-max) (+ (point-min) magic-mode-regexp-match-limit))) (assoc-default nil magic-mode-alist - (lambda (re dummy) + (lambda (re _dummy) (if (functionp re) (funcall re) (looking-at re))))))) @@ -2715,7 +2675,7 @@ we don't actually set it to the same mode the buffer already has." (min (point-max) (+ (point-min) magic-mode-regexp-match-limit))) (assoc-default nil magic-fallback-mode-alist - (lambda (re dummy) + (lambda (re _dummy) (if (functionp re) (funcall re) (looking-at re))))))) @@ -2869,18 +2829,19 @@ asking you for confirmation." ;; ;; For variables defined in the C source code the declaration should go here: -(mapc (lambda (pair) - (put (car pair) 'safe-local-variable (cdr pair))) - '((buffer-read-only . booleanp) ;; C source code - (default-directory . stringp) ;; C source code - (fill-column . integerp) ;; C source code - (indent-tabs-mode . booleanp) ;; C source code - (left-margin . integerp) ;; C source code - (no-update-autoloads . booleanp) - (tab-width . integerp) ;; C source code - (truncate-lines . booleanp) ;; C source code - (word-wrap . booleanp) ;; C source code - (bidi-display-reordering . booleanp))) ;; C source code +(dolist (pair + '((buffer-read-only . booleanp) ;; C source code + (default-directory . stringp) ;; C source code + (fill-column . integerp) ;; C source code + (indent-tabs-mode . booleanp) ;; C source code + (left-margin . integerp) ;; C source code + (no-update-autoloads . booleanp) + (lexical-binding . booleanp) ;; C source code + (tab-width . integerp) ;; C source code + (truncate-lines . booleanp) ;; C source code + (word-wrap . booleanp) ;; C source code + (bidi-display-reordering . booleanp))) ;; C source code + (put (car pair) 'safe-local-variable (cdr pair))) (put 'bidi-paragraph-direction 'safe-local-variable (lambda (v) (memq v '(nil right-to-left left-to-right)))) @@ -2987,74 +2948,69 @@ n -- to ignore the local variables list.") (setq char nil))) (kill-buffer buf) (when (and offer-save (= char ?!) unsafe-vars) - (dolist (elt unsafe-vars) - (add-to-list 'safe-local-variable-values elt)) - ;; When this is called from desktop-restore-file-buffer, - ;; coding-system-for-read may be non-nil. Reset it before - ;; writing to .emacs. - (if (or custom-file user-init-file) - (let ((coding-system-for-read nil)) - (customize-save-variable - 'safe-local-variable-values - safe-local-variable-values)))) + (customize-push-and-save 'safe-local-variable-values unsafe-vars)) (memq char '(?! ?\s ?y)))))) (defun hack-local-variables-prop-line (&optional mode-only) "Return local variables specified in the -*- line. -Ignore any specification for `mode:' and `coding:'; -`set-auto-mode' should already have handled `mode:', -`set-auto-coding' should already have handled `coding:'. - -If MODE-ONLY is non-nil, all we do is check whether the major -mode is specified, returning t if it is specified. Otherwise, -return an alist of elements (VAR . VAL), where VAR is a variable -and VAL is the specified value." +Returns an alist of elements (VAR . VAL), where VAR is a variable +and VAL is the specified value. Ignores any specification for +`mode:' and `coding:' (which should have already been handled +by `set-auto-mode' and `set-auto-coding', respectively). +Throws an error if the -*- line is malformed. + +If MODE-ONLY is non-nil, just returns the symbol specifying the +mode, if there is one, otherwise nil." (save-excursion (goto-char (point-min)) (let ((end (set-auto-mode-1)) - result mode-specified) - ;; Parse the -*- line into the RESULT alist. - ;; Also set MODE-SPECIFIED if we see a spec or `mode'. + result) (cond ((not end) nil) ((looking-at "[ \t]*\\([^ \t\n\r:;]+\\)\\([ \t]*-\\*-\\)") - ;; Simple form: "-*- MODENAME -*-". Already handled. - (setq mode-specified t) - nil) + ;; Simple form: "-*- MODENAME -*-". + (if mode-only + (intern (concat (match-string 1) "-mode")))) (t ;; Hairy form: '-*-' [ ':' ';' ]* '-*-' ;; (last ";" is optional). - (while (< (point) end) + ;; If MODE-ONLY, just check for `mode'. + ;; Otherwise, parse the -*- line into the RESULT alist. + (while (and (or (not mode-only) + (not result)) + (< (point) end)) (or (looking-at "[ \t]*\\([^ \t\n:]+\\)[ \t]*:[ \t]*") (error "Malformed -*- line")) (goto-char (match-end 0)) ;; There used to be a downcase here, ;; but the manual didn't say so, ;; and people want to set var names that aren't all lc. - (let ((key (intern (match-string 1))) - (val (save-restriction - (narrow-to-region (point) end) - (let ((read-circle nil)) - (read (current-buffer)))))) - ;; It is traditional to ignore - ;; case when checking for `mode' in set-auto-mode, - ;; so we must do that here as well. - ;; That is inconsistent, but we're stuck with it. - ;; The same can be said for `coding' in set-auto-coding. - (or (and (equal (downcase (symbol-name key)) "mode") - (setq mode-specified t)) - (equal (downcase (symbol-name key)) "coding") - (condition-case nil - (push (cons (if (eq key 'eval) - 'eval - (indirect-variable key)) - val) result) - (error nil))) - (skip-chars-forward " \t;"))))) - - (if mode-only - mode-specified - result)))) + (let* ((key (intern (match-string 1))) + (val (save-restriction + (narrow-to-region (point) end) + (let ((read-circle nil)) + (read (current-buffer))))) + ;; It is traditional to ignore + ;; case when checking for `mode' in set-auto-mode, + ;; so we must do that here as well. + ;; That is inconsistent, but we're stuck with it. + ;; The same can be said for `coding' in set-auto-coding. + (keyname (downcase (symbol-name key)))) + (if mode-only + (and (equal keyname "mode") + (setq result + (intern (concat (downcase (symbol-name val)) + "-mode")))) + (or (equal keyname "coding") + (condition-case nil + (push (cons (cond ((eq key 'eval) 'eval) + ;; Downcase "Mode:". + ((equal keyname "mode") 'mode) + (t (indirect-variable key))) + val) result) + (error nil)))) + (skip-chars-forward " \t;"))) + result))))) (defun hack-local-variables-filter (variables dir-name) "Filter local variable settings, querying the user if necessary. @@ -3113,8 +3069,12 @@ DIR-NAME is the name of the associated directory. Otherwise it is nil." (defun hack-local-variables (&optional mode-only) "Parse and put into effect this buffer's local variables spec. -If MODE-ONLY is non-nil, all we do is check whether the major mode -is specified, returning t if it is specified." +Uses `hack-local-variables-apply' to apply the variables. + +If MODE-ONLY is non-nil, all we do is check whether a \"mode:\" +is specified, and return the corresponding mode symbol, or nil. +In this case, we try to ignore minor-modes, and only return a +major-mode." (let ((enable-local-variables (and local-enable-local-variables enable-local-variables)) result) @@ -3123,88 +3083,100 @@ is specified, returning t if it is specified." (report-errors "Directory-local variables error: %s" (hack-dir-local-variables))) (when (or mode-only enable-local-variables) - (setq result (hack-local-variables-prop-line mode-only)) - ;; Look for "Local variables:" line in last page. - (save-excursion - (goto-char (point-max)) - (search-backward "\n\^L" (max (- (point-max) 3000) (point-min)) - 'move) - (when (let ((case-fold-search t)) - (search-forward "Local Variables:" nil t)) - (skip-chars-forward " \t") - ;; suffix is what comes after "local variables:" in its line. - ;; prefix is what comes before "local variables:" in its line. - (let ((suffix - (concat - (regexp-quote (buffer-substring (point) - (line-end-position))) - "$")) - (prefix - (concat "^" (regexp-quote - (buffer-substring (line-beginning-position) - (match-beginning 0))))) - beg) - - (forward-line 1) - (let ((startpos (point)) - endpos - (thisbuf (current-buffer))) - (save-excursion - (unless (let ((case-fold-search t)) - (re-search-forward - (concat prefix "[ \t]*End:[ \t]*" suffix) - nil t)) - ;; This used to be an error, but really all it means is - ;; that this may simply not be a local-variables section, - ;; so just ignore it. - (message "Local variables list is not properly terminated")) - (beginning-of-line) - (setq endpos (point))) - - (with-temp-buffer - (insert-buffer-substring thisbuf startpos endpos) - (goto-char (point-min)) - (subst-char-in-region (point) (point-max) ?\^m ?\n) - (while (not (eobp)) - ;; Discard the prefix. - (if (looking-at prefix) - (delete-region (point) (match-end 0)) - (error "Local variables entry is missing the prefix")) - (end-of-line) - ;; Discard the suffix. - (if (looking-back suffix) - (delete-region (match-beginning 0) (point)) - (error "Local variables entry is missing the suffix")) - (forward-line 1)) - (goto-char (point-min)) - - (while (not (eobp)) - ;; Find the variable name; strip whitespace. - (skip-chars-forward " \t") - (setq beg (point)) - (skip-chars-forward "^:\n") - (if (eolp) (error "Missing colon in local variables entry")) - (skip-chars-backward " \t") - (let* ((str (buffer-substring beg (point))) - (var (let ((read-circle nil)) - (read str))) - val) - ;; Read the variable value. - (skip-chars-forward "^:") - (forward-char 1) - (let ((read-circle nil)) - (setq val (read (current-buffer)))) - (if mode-only - (if (eq var 'mode) - (setq result t)) - (unless (eq var 'coding) - (condition-case nil - (push (cons (if (eq var 'eval) - 'eval - (indirect-variable var)) - val) result) - (error nil))))) - (forward-line 1)))))))) + ;; If MODE-ONLY is non-nil, and the prop line specifies a mode, + ;; then we're done, and have no need to scan further. + (unless (and (setq result (hack-local-variables-prop-line mode-only)) + mode-only) + ;; Look for "Local variables:" line in last page. + (save-excursion + (goto-char (point-max)) + (search-backward "\n\^L" (max (- (point-max) 3000) (point-min)) + 'move) + (when (let ((case-fold-search t)) + (search-forward "Local Variables:" nil t)) + (skip-chars-forward " \t") + ;; suffix is what comes after "local variables:" in its line. + ;; prefix is what comes before "local variables:" in its line. + (let ((suffix + (concat + (regexp-quote (buffer-substring (point) + (line-end-position))) + "$")) + (prefix + (concat "^" (regexp-quote + (buffer-substring (line-beginning-position) + (match-beginning 0))))) + beg) + + (forward-line 1) + (let ((startpos (point)) + endpos + (thisbuf (current-buffer))) + (save-excursion + (unless (let ((case-fold-search t)) + (re-search-forward + (concat prefix "[ \t]*End:[ \t]*" suffix) + nil t)) + ;; This used to be an error, but really all it means is + ;; that this may simply not be a local-variables section, + ;; so just ignore it. + (message "Local variables list is not properly terminated")) + (beginning-of-line) + (setq endpos (point))) + + (with-temp-buffer + (insert-buffer-substring thisbuf startpos endpos) + (goto-char (point-min)) + (subst-char-in-region (point) (point-max) ?\^m ?\n) + (while (not (eobp)) + ;; Discard the prefix. + (if (looking-at prefix) + (delete-region (point) (match-end 0)) + (error "Local variables entry is missing the prefix")) + (end-of-line) + ;; Discard the suffix. + (if (looking-back suffix) + (delete-region (match-beginning 0) (point)) + (error "Local variables entry is missing the suffix")) + (forward-line 1)) + (goto-char (point-min)) + + (while (and (not (eobp)) + (or (not mode-only) + (not result))) + ;; Find the variable name; strip whitespace. + (skip-chars-forward " \t") + (setq beg (point)) + (skip-chars-forward "^:\n") + (if (eolp) (error "Missing colon in local variables entry")) + (skip-chars-backward " \t") + (let* ((str (buffer-substring beg (point))) + (var (let ((read-circle nil)) + (read str))) + val val2) + (and (equal (downcase (symbol-name var)) "mode") + (setq var 'mode)) + ;; Read the variable value. + (skip-chars-forward "^:") + (forward-char 1) + (let ((read-circle nil)) + (setq val (read (current-buffer)))) + (if mode-only + (and (eq var 'mode) + ;; Specifying minor-modes via mode: is + ;; deprecated, but try to reject them anyway. + (not (string-match + "-minor\\'" + (setq val2 (downcase (symbol-name val))))) + (setq result (intern (concat val2 "-mode")))) + (unless (eq var 'coding) + (condition-case nil + (push (cons (if (eq var 'eval) + 'eval + (indirect-variable var)) + val) result) + (error nil))))) + (forward-line 1))))))))) ;; Now we've read all the local variables. ;; If MODE-ONLY is non-nil, return whether the mode was specified. (cond (mode-only result) @@ -3214,6 +3186,14 @@ is specified, returning t if it is specified." (hack-local-variables-apply))))) (defun hack-local-variables-apply () + "Apply the elements of `file-local-variables-alist'. +If there are any elements, runs `before-hack-local-variables-hook', +then calls `hack-one-local-variable' to apply the alist elements one by one. +Finishes by running `hack-local-variables-hook', regardless of whether +the alist is empty or not. + +Note that this function ignores a `mode' entry if it specifies the same +major mode as the buffer already has." (when file-local-variables-alist ;; Any 'evals must run in the Right sequence. (setq file-local-variables-alist @@ -3239,7 +3219,7 @@ It is safe if any of these conditions are met: ;; can't assure us that the value is safe. (with-demoted-errors (funcall safep val)))))) -(defun risky-local-variable-p (sym &optional ignored) +(defun risky-local-variable-p (sym &optional _ignored) "Non-nil if SYM could be dangerous as a file-local variable. It is dangerous if either of these conditions are met: @@ -3296,21 +3276,25 @@ It is dangerous if either of these conditions are met: ;; Certain functions can be allowed with safe arguments ;; or can specify verification functions to try. (and (symbolp (car exp)) - (let ((prop (get (car exp) 'safe-local-eval-function))) - (cond ((eq prop t) - (let ((ok t)) - (dolist (arg (cdr exp)) - (unless (hack-one-local-variable-constantp arg) - (setq ok nil))) - ok)) - ((functionp prop) - (funcall prop exp)) - ((listp prop) - (let ((ok nil)) - (dolist (function prop) - (if (funcall function exp) - (setq ok t))) - ok))))))) + ;; Allow (minor)-modes calls with no arguments. + ;; This obsoletes the use of "mode:" for such things. (Bug#8613) + (or (and (member (cdr exp) '(nil (1) (-1))) + (string-match "-mode\\'" (symbol-name (car exp)))) + (let ((prop (get (car exp) 'safe-local-eval-function))) + (cond ((eq prop t) + (let ((ok t)) + (dolist (arg (cdr exp)) + (unless (hack-one-local-variable-constantp arg) + (setq ok nil))) + ok)) + ((functionp prop) + (funcall prop exp)) + ((listp prop) + (let ((ok nil)) + (dolist (function prop) + (if (funcall function exp) + (setq ok t))) + ok)))))))) (defun hack-one-local-variable (var val) "Set local variable VAR with value VAL. @@ -3895,11 +3879,17 @@ See also `file-name-version-regexp'." (let ((handler (find-file-name-handler file 'file-ownership-preserved-p))) (if handler (funcall handler 'file-ownership-preserved-p file) - (let ((attributes (file-attributes file))) + (let ((attributes (file-attributes file 'integer))) ;; Return t if the file doesn't exist, since it's true that no ;; information would be lost by an (attempted) delete and create. (or (null attributes) - (= (nth 2 attributes) (user-uid))))))) + (= (nth 2 attributes) (user-uid)) + ;; Files created on Windows by Administrator (RID=500) + ;; have the Administrators group (RID=544) recorded as + ;; their owner. Rewriting them will still preserve the + ;; owner. + (and (eq system-type 'windows-nt) + (= (user-uid) 500) (= (nth 2 attributes) 544))))))) (defun file-name-sans-extension (filename) "Return FILENAME sans final \"extension\". @@ -4476,6 +4466,7 @@ Before and after saving the buffer, this function runs (dir-writable (file-writable-p dir))) (if (or (and file-precious-flag dir-writable) (and break-hardlink-on-save + (file-exists-p buffer-file-name) (> (file-nlinks buffer-file-name) 1) (or dir-writable (error (concat (format @@ -4600,6 +4591,9 @@ You can answer `y' to save, `n' not to save, `C-r' to look at the buffer in question with `view-buffer' before deciding or `d' to view the differences using `diff-buffer-with-file'. +This command first saves any buffers where `buffer-save-without-query' is +non-nil, without asking. + Optional argument (the prefix) non-nil means save all with no questions. Optional second argument PRED determines which buffers are considered: If PRED is nil, all the file-visiting buffers are considered. @@ -4708,7 +4702,7 @@ and `view-read-only' is non-nil, enter view mode." (view-mode-enter)) (t (setq buffer-read-only (not buffer-read-only)) (force-mode-line-update))) - (if (vc-backend buffer-file-name) + (if (memq (vc-backend buffer-file-name) '(RCS SCCS)) (message "%s" (substitute-command-keys (concat "File is under version-control; " "use \\[vc-next-action] to check in/out")))))) @@ -4788,7 +4782,10 @@ visited a file in a nonexistent directory. Noninteractively, the second (optional) argument PARENTS, if non-nil, says whether to create parent directories that don't -exist. Interactively, this happens by default." +exist. Interactively, this happens by default. + +If creating the directory or directories fail, an error will be +raised." (interactive (list (read-file-name "Make directory: " default-directory default-directory nil nil) @@ -4994,6 +4991,10 @@ hook functions. If `revert-buffer-function' is used to override the normal revert mechanism, this hook is not used.") +(defvar revert-buffer-in-progress-p nil + "Non-nil if a `revert-buffer' operation is in progress, nil otherwise. +This is true even if a `revert-buffer-function' is being used.") + (defvar revert-buffer-internal-hook) (defun revert-buffer (&optional ignore-auto noconfirm preserve-modes) @@ -5016,7 +5017,7 @@ sake of backward compatibility. IGNORE-AUTO is optional, defaulting to nil. Optional second argument NOCONFIRM means don't ask for confirmation -at all. \(The variable `revert-without-query' offers another way to +at all. (The variable `revert-without-query' offers another way to revert buffers without querying for confirmation.) Optional third argument PRESERVE-MODES non-nil means don't alter @@ -5036,10 +5037,12 @@ non-nil, it is called instead of rereading visited file contents." ;; interface, but leaving the programmatic interface the same. (interactive (list (not current-prefix-arg))) (if revert-buffer-function - (funcall revert-buffer-function ignore-auto noconfirm) + (let ((revert-buffer-in-progress-p t)) + (funcall revert-buffer-function ignore-auto noconfirm)) (with-current-buffer (or (buffer-base-buffer (current-buffer)) (current-buffer)) - (let* ((auto-save-p (and (not ignore-auto) + (let* ((revert-buffer-in-progress-p t) + (auto-save-p (and (not ignore-auto) (recent-auto-save-p) buffer-auto-save-file-name (file-readable-p buffer-auto-save-file-name) @@ -5130,7 +5133,7 @@ non-nil, it is called instead of rereading visited file contents." ;; have changed the truename. (setq buffer-file-truename (abbreviate-file-name (file-truename buffer-file-name))) - (after-find-file nil nil t t preserve-modes) + (after-find-file nil nil t nil preserve-modes) ;; Run after-revert-hook as it was before we reverted. (setq-default revert-buffer-internal-hook global-hook) (if local-hook @@ -5167,7 +5170,7 @@ non-nil, it is called instead of rereading visited file contents." (save-excursion (let ((switches dired-listing-switches)) (if (file-symlink-p file) - (setq switches (concat switches "L"))) + (setq switches (concat switches " -L"))) (set-buffer standard-output) ;; Use insert-directory-safely, not insert-directory, ;; because these files might not exist. In particular, @@ -5210,7 +5213,7 @@ Then you'll be asked about a number of files to recover." (error "No previous sessions to recover"))) (let ((ls-lisp-support-shell-wildcards t)) (dired (concat auto-save-list-file-prefix "*") - (concat dired-listing-switches "t"))) + (concat dired-listing-switches " -t"))) (save-excursion (goto-char (point-min)) (or (looking-at " Move to the session you want to recover,") @@ -5568,7 +5571,8 @@ default directory. However, if FULL is non-nil, they are absolute." contents) (while dirs (when (or (null (car dirs)) ; Possible if DIRPART is not wild. - (file-directory-p (directory-file-name (car dirs)))) + (and (file-directory-p (directory-file-name (car dirs))) + (file-readable-p (car dirs)))) (let ((this-dir-contents ;; Filter out "." and ".." (delq nil @@ -6132,8 +6136,8 @@ With prefix ARG, silently save all file-visiting buffers, then kill." (setq active t)) (setq processes (cdr processes))) (or (not active) - (list-processes t) - (yes-or-no-p "Active processes exist; kill them and exit anyway? ")))) + (progn (list-processes t) + (yes-or-no-p "Active processes exist; kill them and exit anyway? "))))) ;; Query the user for other things, perhaps. (run-hook-with-args-until-failure 'kill-emacs-query-functions) (or (null confirm-kill-emacs)