X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/49f70d46ea38ceb7a501594db7f6ea35e19681aa..4a2f33d1a11e0608d521520afcb14ec13dd1a722:/lisp/files-x.el diff --git a/lisp/files-x.el b/lisp/files-x.el index afe7938055..f0102fd83a 100644 --- a/lisp/files-x.el +++ b/lisp/files-x.el @@ -1,10 +1,11 @@ ;;; files-x.el --- extended file handling commands -;; Copyright (C) 2009, 2010, 2011, 2012 Free Software Foundation, Inc. +;; Copyright (C) 2009-2016 Free Software Foundation, Inc. ;; Author: Juri Linkov -;; Maintainer: FSF +;; Maintainer: emacs-devel@gnu.org ;; Keywords: files +;; Package: emacs ;; This file is part of GNU Emacs. @@ -37,62 +38,60 @@ Intended to be used in the `interactive' spec of `add-file-local-variable', `delete-file-local-variable', `add-dir-local-variable', `delete-dir-local-variable'." - (let (default variable) - (setq default (variable-at-point)) - (setq default (and (symbolp default) (boundp default) + (let* ((default (variable-at-point)) + (default (and (symbolp default) (boundp default) (symbol-name default))) - (setq variable + (variable (completing-read (if default (format "%s (default %s): " prompt default) (format "%s: " prompt)) obarray (lambda (sym) - (or (user-variable-p sym) + (or (custom-variable-p sym) (get sym 'safe-local-variable) (memq sym '(mode eval coding unibyte)))) - nil nil nil default nil)) + nil nil nil default nil))) (and (stringp variable) (intern variable)))) (defun read-file-local-variable-value (variable) "Read value of file-local VARIABLE using completion. Intended to be used in the `interactive' spec of `add-file-local-variable' and `add-dir-local-variable'." - (let (default value) - (cond - ((eq variable 'mode) - (setq default (and (symbolp major-mode) (symbol-name major-mode))) - (setq value - (completing-read - (if default - (format "Add %s with value (default %s): " variable default) - (format "Add %s with value: " variable)) - obarray - (lambda (sym) - (string-match-p "-mode\\'" (symbol-name sym))) - nil nil nil default nil)) + (cond + ((eq variable 'mode) + (let* ((default (and (symbolp major-mode) (symbol-name major-mode))) + (value + (completing-read + (if default + (format "Add %s with value (default %s): " variable default) + (format "Add %s with value: " variable)) + obarray + (lambda (sym) + (string-match-p "-mode\\'" (symbol-name sym))) + nil nil nil default nil))) (and (stringp value) - (intern (replace-regexp-in-string "-mode\\'" "" value)))) - ((eq variable 'eval) - (let ((minibuffer-completing-symbol t)) - (read-from-minibuffer (format "Add %s with expression: " variable) - nil read-expression-map t - 'read-expression-history))) - ((eq variable 'coding) - (setq default (and (symbolp buffer-file-coding-system) - (symbol-name buffer-file-coding-system))) + (intern (replace-regexp-in-string "-mode\\'" "" value))))) + ((eq variable 'eval) + (read--expression (format "Add %s with expression: " variable))) + ((eq variable 'coding) + (let ((default (and (symbolp buffer-file-coding-system) + (symbol-name buffer-file-coding-system)))) (read-coding-system (if default - (format "Add %s with value (default %s): " variable default) - (format "Add %s with value: " variable)) - default)) - (t - (read (read-string (format "Add %s with value: " variable) - nil 'set-variable-value-history - (format "%S" - (cond ((eq variable 'unibyte) t) - ((boundp variable) - (symbol-value variable)))))))))) + (format "Add %s with value (default %s): " variable default) + (format "Add %s with value: " variable)) + default))) + (t + (let ((default (format "%S" + (cond ((eq variable 'unibyte) t) + ((boundp variable) + (symbol-value variable))))) + (minibuffer-completing-symbol t)) + (read-from-minibuffer (format "Add %s with value: " variable) + nil read-expression-map t + 'set-variable-value-history + default))))) (defun read-file-local-variable-mode () "Read per-directory file-local variable's mode using completion. @@ -107,14 +106,47 @@ Intended to be used in the `interactive' spec of obarray (lambda (sym) (and (string-match-p "-mode\\'" (symbol-name sym)) - (not (string-match-p "-minor-mode\\'" (symbol-name sym))))) + (not (or (memq sym minor-mode-list) + (string-match-p "-minor-mode\\'" + (symbol-name sym)))))) nil nil nil default nil))) (cond ((equal mode "nil") nil) ((and (stringp mode) (fboundp (intern mode))) (intern mode)) (t mode)))) -(defun modify-file-local-variable (variable value op) +(defun modify-file-local-variable-message (variable value op) + (let* ((not-value (make-symbol "")) + (old-value (cond ((eq variable 'mode) + major-mode) + ((eq variable 'coding) + buffer-file-coding-system) + (t (if (and (symbolp variable) + (boundp variable)) + (symbol-value variable) + not-value)))) + (new-value (if (eq op 'delete) + (cond ((eq variable 'mode) + (default-value 'major-mode)) + ((eq variable 'coding) + (default-value 'buffer-file-coding-system)) + (t (if (and (symbolp variable) + (default-boundp variable)) + (default-value variable) + not-value))) + (cond ((eq variable 'mode) + (let ((string (format "%S" value))) + (if (string-match-p "-mode\\'" string) + value + (intern (concat string "-mode"))))) + (t value))))) + (when (or (eq old-value not-value) + (eq new-value not-value) + (not (equal old-value new-value))) + (message "%s" (substitute-command-keys + "For this change to take effect revisit file using \\[revert-buffer]"))))) + +(defun modify-file-local-variable (variable value op &optional interactive) "Modify file-local VARIABLE in Local Variables depending on operation OP. If OP is `add-or-replace' then delete all existing settings of @@ -148,7 +180,7 @@ from the Local Variables list ignoring the input argument VALUE." (goto-char (point-max)) (let ((comment-style 'plain) - (comment-start (or comment-start ";;; "))) + (comment-start (or comment-start ";; "))) (comment-region (prog1 (setq beg (point)) (insert "\nLocal Variables:\nEnd:\n")) @@ -197,10 +229,13 @@ from the Local Variables list ignoring the input argument VALUE." ((eq variable 'mode) (goto-char beg)) ((null replaced-pos) (goto-char end)) (replaced-pos (goto-char replaced-pos))) - (insert (format "%s%S: %S%s\n" prefix variable value suffix))))))) + (insert (format "%s%S: %S%s\n" prefix variable value suffix)))) + + (when interactive + (modify-file-local-variable-message variable value op))))) ;;;###autoload -(defun add-file-local-variable (variable value) +(defun add-file-local-variable (variable value &optional interactive) "Add file-local VARIABLE with its VALUE to the Local Variables list. This command deletes all existing settings of VARIABLE (except `mode' @@ -212,17 +247,24 @@ then this function adds the first line containing the string `Local Variables:' and the last line containing the string `End:'." (interactive (let ((variable (read-file-local-variable "Add file-local variable"))) - (list variable (read-file-local-variable-value variable)))) - (modify-file-local-variable variable value 'add-or-replace)) + ;; Error before reading value. + (if (equal variable 'lexical-binding) + (user-error "The `%s' variable must be set at the start of the file" + variable)) + (list variable (read-file-local-variable-value variable) t))) + (if (equal variable 'lexical-binding) + (user-error "The `%s' variable must be set at the start of the file" + variable)) + (modify-file-local-variable variable value 'add-or-replace interactive)) ;;;###autoload -(defun delete-file-local-variable (variable) +(defun delete-file-local-variable (variable &optional interactive) "Delete all settings of file-local VARIABLE from the Local Variables list." (interactive - (list (read-file-local-variable "Delete file-local variable"))) - (modify-file-local-variable variable nil 'delete)) + (list (read-file-local-variable "Delete file-local variable") t)) + (modify-file-local-variable variable nil 'delete interactive)) -(defun modify-file-local-variable-prop-line (variable value op) +(defun modify-file-local-variable-prop-line (variable value op &optional interactive) "Modify file-local VARIABLE in the -*- line depending on operation OP. If OP is `add-or-replace' then delete all existing settings of @@ -255,19 +297,40 @@ from the -*- line ignoring the input argument VALUE." (goto-char (point-min)) - ;; Skip interpreter magic line "#!" - (when (looking-at "^\\(#!\\|'\\\\\"\\)") + ;; Skip interpreter magic line "#!" or XML declaration. + (when (or (looking-at file-auto-mode-skip) + (looking-at "<\\?xml[^>\n]*>$")) (forward-line 1)) (let ((comment-style 'plain) - (comment-start (or comment-start ";;; "))) - (comment-region - (prog1 (point) - (insert "-*-") - (setq beg (point-marker)) - (setq end (point-marker)) - (insert "-*-\n")) - (point)))) + (comment-start (or comment-start ";;; ")) + (line-beg (line-beginning-position)) + (ce nil)) + (comment-normalize-vars) + ;; If the first line contains a comment. + (if (save-excursion + (and (looking-at comment-start-skip) + (goto-char (match-end 0)) + (re-search-forward comment-end-skip) + (goto-char (match-beginning 0)) + ;; Still on the same line? + (equal line-beg (line-beginning-position)) + (setq ce (point)))) + ;; Add local variables to the end of the existing comment. + (progn + (goto-char ce) + (insert " -*-") + (setq beg (point-marker)) + (setq end (point-marker)) + (insert "-*-")) + ;; Otherwise, add a new comment before the first line. + (comment-region + (prog1 (point) + (insert "-*-") + (setq beg (point-marker)) + (setq end (point-marker)) + (insert "-*-\n")) + (point))))) (cond ((looking-at "[ \t]*\\([^ \t\n\r:;]+\\)\\([ \t]*-\\*-\\)") @@ -298,11 +361,11 @@ from the -*- line ignoring the input argument VALUE." (or (looking-at "[ \t]*\\([^ \t\n:]+\\)[ \t]*:[ \t]*") (throw 'exit (message "Malformed -*- line"))) (goto-char (match-end 0)) - (let ((key (intern (match-string 1))) - (val (save-restriction - (narrow-to-region (point) end) - (let ((read-circle nil)) - (read (current-buffer)))))) + (let ((key (intern (match-string 1)))) + (save-restriction + (narrow-to-region (point) end) + (let ((read-circle nil)) + (read (current-buffer)))) (skip-chars-forward " \t;") (when (eq key variable) (delete-region (match-beginning 0) (point)) @@ -315,14 +378,19 @@ from the -*- line ignoring the input argument VALUE." ((null replaced-pos) (goto-char end)) (replaced-pos (goto-char replaced-pos))) (if (and (not (eq (char-before) ?\;)) - (not (equal (point) (marker-position beg)))) + (not (equal (point) (marker-position beg))) + ;; When existing `-*- -*-' is empty, beg > end. + (not (> (marker-position beg) (marker-position end)))) (insert ";")) (unless (eq (char-before) ?\s) (insert " ")) (insert (format "%S: %S;" variable value)) - (unless (eq (char-after) ?\s) (insert " ")))))))) + (unless (eq (char-after) ?\s) (insert " "))))) + + (when interactive + (modify-file-local-variable-message variable value op))))) ;;;###autoload -(defun add-file-local-variable-prop-line (variable value) +(defun add-file-local-variable-prop-line (variable value &optional interactive) "Add file-local VARIABLE with its VALUE to the -*- line. This command deletes all existing settings of VARIABLE (except `mode' @@ -333,15 +401,17 @@ If there is no -*- line at the beginning of the current file buffer then this function adds it." (interactive (let ((variable (read-file-local-variable "Add -*- file-local variable"))) - (list variable (read-file-local-variable-value variable)))) - (modify-file-local-variable-prop-line variable value 'add-or-replace)) + (list variable (read-file-local-variable-value variable) t))) + (modify-file-local-variable-prop-line variable value 'add-or-replace interactive)) ;;;###autoload -(defun delete-file-local-variable-prop-line (variable) +(defun delete-file-local-variable-prop-line (variable &optional interactive) "Delete all settings of file-local VARIABLE from the -*- line." (interactive - (list (read-file-local-variable "Delete -*- file-local variable"))) - (modify-file-local-variable-prop-line variable nil 'delete)) + (list (read-file-local-variable "Delete -*- file-local variable") t)) + (modify-file-local-variable-prop-line variable nil 'delete interactive)) + +(defvar auto-insert) ; from autoinsert.el (defun modify-dir-local-variable (mode variable value op) "Modify directory-local VARIABLE in .dir-locals.el depending on operation OP. @@ -359,18 +429,28 @@ from the MODE alist ignoring the input argument VALUE." (catch 'exit (unless enable-local-variables (throw 'exit (message "Directory-local variables are disabled"))) - (let ((variables-file (or (and (buffer-file-name) (not (file-remote-p (buffer-file-name))) (dir-locals-find-file (buffer-file-name))) dir-locals-file)) variables) - + (if (consp variables-file) ; result from cache + ;; If cache element has an mtime, assume it came from a file. + ;; Otherwise, assume it was set directly. + (setq variables-file (if (nth 2 variables-file) + (expand-file-name dir-locals-file + (car variables-file)) + (cadr variables-file)))) + ;; I can't be bothered to handle this case right now. + ;; Dir locals were set directly from a class. You need to + ;; directly modify the class in dir-locals-class-alist. + (and variables-file (not (stringp variables-file)) + (throw 'exit (message "Directory locals were not set from a file"))) ;; Don't create ".dir-locals.el" for the deletion operation. - (when (and (eq op 'delete) - (not (file-exists-p variables-file))) - (throw 'exit (message "File .dir-locals.el not found"))) - + (and (eq op 'delete) + (or (not variables-file) + (not (file-exists-p variables-file))) + (throw 'exit (message "No .dir-locals.el file was found"))) (let ((auto-insert nil)) (find-file variables-file)) (widen) @@ -403,7 +483,7 @@ from the MODE alist ignoring the input argument VALUE." ;; Insert modified alist of directory-local variables. (insert ";;; Directory Local Variables\n") - (insert ";;; See Info node `(emacs) Directory Variables' for more information.\n\n") + (insert ";;; For more information see (info \"(emacs) Directory Variables\")\n\n") (pp (sort variables (lambda (a b) (cond @@ -460,5 +540,4 @@ from the MODE alist ignoring the input argument VALUE." (provide 'files-x) -;; arch-tag: 949d263c-30a8-4b49-af26-cda97c7c5477 ;;; files-x.el ends here