X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/5a6c1d871eb47630435c4253286f550e9c91b0eb..1dc51c0019cd76097f7e885dedf538f0c3b4dcfb:/lisp/files.el diff --git a/lisp/files.el b/lisp/files.el index e96aace046..76167eb27c 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -444,13 +444,21 @@ use `before-save-hook'.") (defcustom enable-local-variables t "*Control use of local variables in files you visit. -The value can be t, nil or something else. +The value can be t, nil, :safe, or something else. A value of t means file local variables specifications are obeyed -if all the specified variables are safe. If any variables are -not safe, you will be queries before setting them. -A value of nil means file local variables are ignored. -Any other value means to always query. +if all the specified variable values are safe; if any values are +not safe, Emacs queries you, once, whether to set them all. +\(When you say yes to certain values, they are remembered as safe.) + +:safe means set the safe variables, and ignore the rest. +:all means set all variables, whether safe or not. + (Don't set it permanently to :all.) +nil means always ignore the file local variables. + +Any other value means always query you once whether to set them all. +\(When you say yes to certain values, they are remembered as safe, but +this has no effect when `enable-local-variables' is \"something else\".) This variable also controls use of major modes specified in a -*- line. @@ -458,7 +466,9 @@ a -*- line. The command \\[normal-mode], when used interactively, always obeys file local variable specifications and the -*- line, and ignores this variable." - :type '(choice (const :tag "Obey" t) + :type '(choice (const :tag "Query Unsafe" t) + (const :tag "Safe Only" :safe) + (const :tag "Do all" :all) (const :tag "Ignore" nil) (other :tag "Query" other)) :group 'find-file) @@ -698,7 +708,7 @@ This is an interface to the function `load'." (interactive (list (completing-read "Load library: " 'locate-file-completion - (cons load-path load-suffixes)))) + (cons load-path (get-load-suffixes))))) (load library)) (defun file-remote-p (file) @@ -989,6 +999,20 @@ documentation for additional customization information." (pop-to-buffer buffer t norecord) (raise-frame (window-frame (selected-window))))) +(defun display-buffer-other-frame (buffer) + "Switch to 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)) + (lower-frame (window-frame new-window)) + (make-frame-invisible (window-frame old-window)) + (make-frame-visible (window-frame old-window)))) + (defvar find-file-default nil "Used within `find-file-read-args'.") @@ -1764,8 +1788,7 @@ Uses the visited file name, the -*- line, and the local variables spec. This function is called automatically from `find-file'. In that case, we may set up the file-specified mode and local variables, -depending on the value of `enable-local-variables': if it is t, we do; -if it is nil, we don't; otherwise, we query. +depending on the value of `enable-local-variables'. In addition, if `local-enable-local-variables' is nil, we do not set local variables (though we do notice a mode specified with -*-.) @@ -1871,7 +1894,7 @@ in that case, this function acts as if `enable-local-variables' were t." ;; `auto-coding-alist' with `no-conversion' coding system. ("\\.\\(arc\\|zip\\|lzh\\|zoo\\|[jew]ar\\|xpi\\)\\'" . archive-mode) ("\\.\\(ARC\\|ZIP\\|LZH\\|ZOO\\|[JEW]AR\\|XPI\\)\\'" . archive-mode) - ("\\.sx[dmicw]\\'" . archive-mode) ; OpenOffice.org + ("\\.\\(sx[dmicw]\\|odt\\)\\'" . archive-mode) ; OpenOffice.org ;; Mailer puts message to be edited in ;; /tmp/Re.... or Message ("\\`/tmp/Re" . text-mode) @@ -1954,6 +1977,9 @@ REGEXP and search the list again for another match. If the file name matches `inhibit-first-line-modes-regexps', then `auto-mode-alist' is not processed. +The extensions whose FUNCTION is `archive-mode' should also +appear in `auto-coding-alist' with `no-conversion' coding system. + See also `interpreter-mode-alist', which detects executable script modes based on the interpreters they specify to run, and `magic-mode-alist', which determines modes based on file contents.") @@ -2218,6 +2244,138 @@ Otherwise, return nil; point may be changed." (setq end (point)) (goto-char beg) end)))) + +;;; Handling file local variables + +(defvar ignored-local-variables + '(ignored-local-variables safe-local-variable-values) + "Variables to be ignored in a file's local variable spec.") + +(defvar hack-local-variables-hook nil + "Normal hook run after processing a file's local variables specs. +Major modes can use this to examine user-specified local variables +in order to initialize other data structure based on them.") + +(defcustom safe-local-variable-values nil + "List variable-value pairs that are considered safe. +Each element is a cons cell (VAR . VAL), where VAR is a variable +symbol and VAL is a value that is considered safe." + :group 'find-file + :type 'alist) + +(defcustom safe-local-eval-forms nil + "*Expressions that are considered safe in an `eval:' local variable. +Add expressions to this list if you want Emacs to evaluate them, when +they appear in an `eval' local variable specification, without first +asking you for confirmation." + :group 'find-file + :version "22.1" + :type '(repeat sexp)) + +;; Risky local variables: +(mapc (lambda (var) (put var 'risky-local-variable t)) + '(after-load-alist + auto-mode-alist + buffer-auto-save-file-name + buffer-file-name + buffer-file-truename + buffer-undo-list + dabbrev-case-fold-search + dabbrev-case-replace + debugger + default-text-properties + display-time-string + enable-local-eval + enable-local-variables + eval + exec-directory + exec-path + file-name-handler-alist + font-lock-defaults + format-alist + frame-title-format + global-mode-string + header-line-format + icon-title-format + ignored-local-variables + imenu--index-alist + imenu-generic-expression + inhibit-quit + input-method-alist + load-path + max-lisp-eval-depth + max-specpdl-size + minor-mode-alist + minor-mode-map-alist + minor-mode-overriding-map-alist + mode-line-buffer-identification + mode-line-format + mode-line-modes + mode-line-modified + mode-line-mule-info + mode-line-position + mode-line-process + mode-name + outline-level + overriding-local-map + overriding-terminal-local-map + parse-time-rules + process-environment + rmail-output-file-alist + safe-local-variable-values + safe-local-eval-forms + save-some-buffers-action-alist + special-display-buffer-names + standard-input + standard-output + unread-command-events + vc-mode)) + +;; Safe local variables: +;; +;; For variables defined by major modes, the safety declarations can go into +;; the major mode's file, since that will be loaded before file variables are +;; processed. +;; +;; For variables defined by minor modes, put the safety declarations in the +;; file defining the minor mode after the defcustom/defvar using an autoload +;; cookie, e.g.: +;; +;; ;;;###autoload(put 'variable 'safe-local-variable 'stringp) +;; +;; Otherwise, when Emacs visits a file specifying that local variable, the +;; minor mode file may not be loaded yet. +;; +;; For variables defined in the C source code the declaration should go here: + +;; FIXME: Some variables should be moved according to the rules above. +(let ((string-or-null (lambda (a) (or (stringp a) (null a))))) + (eval + `(mapc (lambda (pair) + (put (car pair) 'safe-local-variable (cdr pair))) + '((byte-compile-dynamic . t) + (byte-compile-dynamic-docstrings . t) + (byte-compile-warnings . t) + (c-basic-offset . integerp) + (c-file-style . stringp) + (c-indent-level . integerp) + (comment-column . integerp) + (compile-command . string-or-null-p) + (find-file-visit-truename . t) + (fill-column . integerp) + (fill-prefix . string-or-null-p) + (indent-tabs-mode . t) + (kept-old-versions . integerp) + (kept-new-versions . integerp) + (left-margin . t) + (no-byte-compile . t) + (no-update-autoloads . t) + (outline-regexp . string-or-null-p) + (tab-width . integerp) ;; C source code + (truncate-lines . t) ;; C source code + (version-control . t))))) + +(put 'c-set-style 'safe-local-eval-function t) (defun hack-local-variables-confirm (vars unsafe-vars risky-vars) (if noninteractive @@ -2225,58 +2383,78 @@ Otherwise, return nil; point may be changed." (let ((name (if buffer-file-name (file-name-nondirectory buffer-file-name) (concat "buffer " (buffer-name)))) - char) + (offer-save (and (eq enable-local-variables t) unsafe-vars)) + prompt char) (save-window-excursion - (with-output-to-temp-buffer "*Local Variables*" + (let ((buf (get-buffer-create "*Local Variables*"))) + (pop-to-buffer buf) + (set (make-local-variable 'cursor-type) nil) + (erase-buffer) (if unsafe-vars - (progn (princ "The local variables list in ") - (princ name) - (princ "\ncontains values that may not be safe (*)") - (if risky-vars - (princ ", and variables that are risky (**).") - (princ "."))) + (insert "The local variables list in " name + "\ncontains values that may not be safe (*)" + (if risky-vars + ", and variables that are risky (**)." + ".")) (if risky-vars - (progn (princ "The local variables list in ") - (princ name) - (princ "\ncontains variables that are risky (**).")) - (princ "A local variables list is specified in ") - (princ name) - (princ "."))) - (princ "\n\nDo you want to apply it? You can type + (insert "The local variables list in " name + "\ncontains variables that are risky (**).") + (insert "A local variables list is specified in " name "."))) + (insert "\n\nDo you want to apply it? You can type y -- to apply the local variables list. -n -- to ignore the local variables list. -! -- to apply the local variables list, and mark these values (*) as - safe (in the future, they can be set automatically.)\n\n") +n -- to ignore the local variables list.") + (if offer-save + (insert " +! -- to apply the local variables list, and permanently mark these + values (*) as safe (in the future, they will be set automatically.)\n\n") + (insert "\n\n")) (dolist (elt vars) (cond ((member elt unsafe-vars) - (princ " * ")) + (insert " * ")) ((member elt risky-vars) - (princ " ** ")) + (insert " ** ")) (t - (princ " "))) - (princ (car elt)) - (princ " : ") - (princ (cdr elt)) - (princ "\n"))) - (message "Please type y, n, or !: ") - (let ((inhibit-quit t) - (cursor-in-echo-area t)) - (while (or (not (numberp (setq char (read-event)))) - (not (memq (downcase char) - '(?! ?y ?n ?\s ?\C-g)))) - (message "Please type y, n, or !: ")) - (if (= char ?\C-g) - (setq quit-flag nil))) - (setq char (downcase char)) - (when (and (= char ?!) unsafe-vars) - (dolist (elt unsafe-vars) - (push elt safe-local-variable-values)) - (customize-save-variable - 'safe-local-variable-values - safe-local-variable-values)) - (or (= char ?!) - (= char ?\s) - (= char ?y)))))) + (insert " "))) + (princ (car elt) buf) + (insert " : ") + (princ (cdr elt) buf) + (insert "\n")) + (setq prompt + (format "Please type %s%s: " + (if offer-save "y, n, or !" "y or n") + (if (< (line-number-at-pos) (window-body-height)) + "" + ", or C-v to scroll"))) + (goto-char (point-min)) + (let ((cursor-in-echo-area t) + (exit-chars + (if offer-save '(?! ?y ?n ?\s ?\C-g) '(?y ?n ?\s ?\C-g))) + done) + (while (not done) + (message prompt) + (setq char (read-event)) + (if (numberp char) + (if (eq char ?\C-v) + (condition-case nil + (scroll-up) + (error (goto-char (point-min)))) + (setq done (memq (downcase char) exit-chars)))))) + (setq char (downcase char)) + (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)))) + (kill-buffer buf) + (or (= char ?!) + (= char ?\s) + (= char ?y))))))) (defun hack-local-variables-prop-line (&optional mode-only) "Return local variables specified in the -*- line. @@ -2336,18 +2514,6 @@ and VAL is the specified value." mode-specified result)))) -(defvar hack-local-variables-hook nil - "Normal hook run after processing a file's local variables specs. -Major modes can use this to examine user-specified local variables -in order to initialize other data structure based on them.") - -(defcustom safe-local-variable-values nil - "List variable-value pairs that are considered safe. -Each element is a cons cell (VAR . VAL), where VAR is a variable -symbol and VAL is a value that is considered safe." - :group 'find-file - :type 'alist) - (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 @@ -2439,120 +2605,45 @@ is specified, returning t if it is specified." ;; variables (if MODE-ONLY is nil.) (if mode-only result - (setq result (nreverse result)) (dolist (ignored ignored-local-variables) (setq result (assq-delete-all ignored result))) (if (null enable-local-eval) (setq result (assq-delete-all 'eval result))) - ;; Find those variables that we may want to save to - ;; `safe-local-variable-values'. - (let (risky-vars unsafe-vars) - (dolist (elt result) - (let ((var (car elt)) - (val (cdr elt))) - (or (eq var 'mode) - (and (eq var 'eval) - (or (eq enable-local-eval t) - (hack-one-local-variable-eval-safep - (eval (quote val))))) - (safe-local-variable-p var val) - (and (risky-local-variable-p var val) - (push elt risky-vars)) - (push elt unsafe-vars)))) - (if (or (and (eq enable-local-variables t) - (null unsafe-vars) - (null risky-vars)) - (hack-local-variables-confirm - result unsafe-vars risky-vars)) - (dolist (elt result) - (hack-one-local-variable (car elt) (cdr elt))))) - (run-hooks 'hack-local-variables-hook))))) - -(defvar ignored-local-variables - '(ignored-local-variables safe-local-variable-values) - "Variables to be ignored in a file's local variable spec.") - -;; Get confirmation before setting these variables as locals in a file. -(put 'debugger 'risky-local-variable t) -(put 'enable-local-eval 'risky-local-variable t) -(put 'ignored-local-variables 'risky-local-variable t) -(put 'ignored-local-variables 'safe-local-variable-values t) -(put 'eval 'risky-local-variable t) -(put 'file-name-handler-alist 'risky-local-variable t) -(put 'inhibit-quit 'risky-local-variable t) -(put 'minor-mode-alist 'risky-local-variable t) -(put 'minor-mode-map-alist 'risky-local-variable t) -(put 'minor-mode-overriding-map-alist 'risky-local-variable t) -(put 'overriding-local-map 'risky-local-variable t) -(put 'overriding-terminal-local-map 'risky-local-variable t) -(put 'auto-mode-alist 'risky-local-variable t) -(put 'after-load-alist 'risky-local-variable t) -(put 'buffer-file-name 'risky-local-variable t) -(put 'buffer-undo-list 'risky-local-variable t) -(put 'buffer-auto-save-file-name 'risky-local-variable t) -(put 'buffer-file-truename 'risky-local-variable t) -(put 'default-text-properties 'risky-local-variable t) -(put 'exec-path 'risky-local-variable t) -(put 'load-path 'risky-local-variable t) -(put 'exec-directory 'risky-local-variable t) -(put 'process-environment 'risky-local-variable t) -(put 'dabbrev-case-fold-search 'risky-local-variable t) -(put 'dabbrev-case-replace 'risky-local-variable t) -;; Don't wait for outline.el to be loaded, for the sake of outline-minor-mode. -(put 'outline-level 'risky-local-variable t) -(put 'rmail-output-file-alist 'risky-local-variable t) -(put 'font-lock-defaults 'risky-local-variable t) -(put 'special-display-buffer-names 'risky-local-variable t) -(put 'frame-title-format 'risky-local-variable t) -(put 'global-mode-string 'risky-local-variable t) -(put 'header-line-format 'risky-local-variable t) -(put 'icon-title-format 'risky-local-variable t) -(put 'input-method-alist 'risky-local-variable t) -(put 'format-alist 'risky-local-variable t) -(put 'vc-mode 'risky-local-variable t) -(put 'imenu-generic-expression 'risky-local-variable t) -(put 'imenu--index-alist 'risky-local-variable t) -(put 'standard-input 'risky-local-variable t) -(put 'standard-output 'risky-local-variable t) -(put 'unread-command-events 'risky-local-variable t) -(put 'max-lisp-eval-depth 'risky-local-variable t) -(put 'max-specpdl-size 'risky-local-variable t) -(put 'mode-line-format 'risky-local-variable t) -(put 'mode-line-modified 'risky-local-variable t) -(put 'mode-line-mule-info 'risky-local-variable t) -(put 'mode-line-buffer-identification 'risky-local-variable t) -(put 'mode-line-modes 'risky-local-variable t) -(put 'mode-line-position 'risky-local-variable t) -(put 'mode-line-process 'risky-local-variable t) -(put 'mode-name 'risky-local-variable t) -(put 'display-time-string 'risky-local-variable t) -(put 'parse-time-rules 'risky-local-variable t) - -;; Commonly-encountered local variables that are safe: -(let ((string-or-null (lambda (a) (or (stringp a) (null a))))) - (eval - `(mapc (lambda (pair) - (put (car pair) 'safe-local-variable (cdr pair))) - '((byte-compile-dynamic . t) - (c-basic-offset . integerp) - (c-file-style . stringp) - (c-indent-level . integerp) - (comment-column . integerp) - (compile-command . ,string-or-null) - (fill-column . integerp) - (fill-prefix . ,string-or-null) - (indent-tabs-mode . t) - (kept-new-versions . integerp) - (no-byte-compile . t) - (no-update-autoloads . t) - (outline-regexp . ,string-or-null) - (page-delimiter . ,string-or-null) - (paragraph-start . ,string-or-null) - (paragraph-separate . ,string-or-null) - (sentence-end . ,string-or-null) - (sentence-end-double-space . t) - (tab-width . integerp) - (version-control . t))))) + (when result + (setq result (nreverse result)) + ;; Find those variables that we may want to save to + ;; `safe-local-variable-values'. + (let (risky-vars unsafe-vars) + (dolist (elt result) + (let ((var (car elt)) + (val (cdr elt))) + (or (eq var 'mode) + (and (eq var 'eval) + (or (eq enable-local-eval t) + (hack-one-local-variable-eval-safep + (eval (quote val))))) + (safe-local-variable-p var val) + (and (risky-local-variable-p var val) + (push elt risky-vars)) + (push elt unsafe-vars)))) + (if (eq enable-local-variables :safe) + ;; If caller wants only the safe variables, + ;; install only them. + (dolist (elt result) + (unless (or (memq (car elt) unsafe-vars) + (memq (car elt) risky-vars)) + (hack-one-local-variable (car elt) (cdr elt)))) + ;; Query, except in the case where all are known safe + ;; if the user wants no quuery in that case. + (if (or (and (eq enable-local-variables t) + (null unsafe-vars) + (null risky-vars)) + (eq enable-local-variables :all) + (hack-local-variables-confirm + result unsafe-vars risky-vars)) + (dolist (elt result) + (hack-one-local-variable (car elt) (cdr elt)))))) + (run-hooks 'hack-local-variables-hook)))))) (defun safe-local-variable-p (sym val) "Non-nil if SYM is safe as a file-local variable with value VAL. @@ -2561,15 +2652,11 @@ It is safe if any of these conditions are met: * There is a matching entry (SYM . VAL) in the `safe-local-variable-values' user option. - * The `safe-local-variable' property of SYM is t. - * The `safe-local-variable' property of SYM is a function that evaluates to a non-nil value with VAL as an argument." (or (member (cons sym val) safe-local-variable-values) (let ((safep (get sym 'safe-local-variable))) - (or (eq safep t) - (and (functionp safep) - (funcall safep val)))))) + (and (functionp safep) (funcall safep val))))) (defun risky-local-variable-p (sym &optional ignored) "Non-nil if SYM could be dangerous as a file-local variable. @@ -2591,17 +2678,6 @@ It is dangerous if either of these conditions are met: -[0-9]+$\\|font-lock-syntactic-keywords$\\|-frame-alist$\\|-mode-alist$\\|\ -map$\\|-map-alist$" (symbol-name sym)))) -(defcustom safe-local-eval-forms nil - "*Expressions that are considered \"safe\" in an `eval:' local variable. -Add expressions to this list if you want Emacs to evaluate them, when -they appear in an `eval' local variable specification, without first -asking you for confirmation." - :group 'find-file - :version "22.1" - :type '(repeat sexp)) - -(put 'c-set-style 'safe-local-eval-function t) - (defun hack-one-local-variable-quotep (exp) (and (consp exp) (eq (car exp) 'quote) (consp (cdr exp)))) @@ -2618,12 +2694,14 @@ asking you for confirmation." (and (eq (car exp) 'put) (hack-one-local-variable-quotep (nth 1 exp)) (hack-one-local-variable-quotep (nth 2 exp)) - (memq (nth 1 (nth 2 exp)) - '(lisp-indent-hook)) - ;; Only allow safe values of lisp-indent-hook; - ;; not functions. - (or (numberp (nth 3 exp)) - (equal (nth 3 exp) ''defun))) + (let ((prop (nth 1 (nth 2 exp))) (val (nth 3 exp))) + (cond ((eq prop 'lisp-indent-hook) + ;; Only allow safe values of lisp-indent-hook; + ;; not functions. + (or (numberp val) (equal val ''defun))) + ((eq prop 'edebug-form-spec) + ;; Only allow indirect form specs. + (edebug-basic-spec val))))) ;; Allow expressions that the user requested. (member exp safe-local-eval-forms) ;; Certain functions can be allowed with safe arguments @@ -3619,7 +3697,6 @@ This requires the external program `diff' to be in your `exec-path'." (?d diff-buffer-with-file "view changes in file")) "ACTION-ALIST argument used in call to `map-y-or-n-p'.") -(put 'save-some-buffers-action-alist 'risky-local-variable t) (defvar buffer-save-without-query nil "Non-nil means `save-some-buffers' should save this buffer without asking.") @@ -5096,6 +5173,7 @@ With prefix arg, silently save all file-visiting buffers, then kill." (define-key ctl-x-5-map "f" 'find-file-other-frame) (define-key ctl-x-5-map "\C-f" 'find-file-other-frame) (define-key ctl-x-5-map "r" 'find-file-read-only-other-frame) +(define-key ctl-x-5-map "\C-o" 'display-buffer-other-frame) ;; arch-tag: bc68d3ea-19ca-468b-aac6-3a4a7766101f ;;; files.el ends here