diff options
Diffstat (limited to 'lisp/emacs-lisp/checkdoc.el')
-rw-r--r-- | lisp/emacs-lisp/checkdoc.el | 194 |
1 files changed, 113 insertions, 81 deletions
diff --git a/lisp/emacs-lisp/checkdoc.el b/lisp/emacs-lisp/checkdoc.el index e6c2b8306be..a45c7dd04cc 100644 --- a/lisp/emacs-lisp/checkdoc.el +++ b/lisp/emacs-lisp/checkdoc.el @@ -3,7 +3,7 @@ ;; Copyright (C) 1997-2025 Free Software Foundation, Inc. ;; Author: Eric M. Ludlam <zappo@gnu.org> -;; Old-Version: 0.6.2 +;; Maintainer: emacs-devel@gnu.org ;; Keywords: docs, maint, lisp ;; This file is part of GNU Emacs. @@ -290,6 +290,7 @@ made in the style guide relating to order." Currently, all recognized keywords must be on `finder-known-keywords'." :version "25.1" :type 'boolean) +;;;###autoload(put 'checkdoc-package-keywords-flag 'safe-local-variable #'booleanp) (defvar checkdoc-style-functions nil "Hook run after the standard style check is completed. @@ -308,11 +309,12 @@ problem discovered. This is useful for adding additional checks.") (defvar checkdoc-diagnostic-buffer "*Style Warnings*" "Name of warning message buffer.") -(defcustom checkdoc-verb-check-experimental-flag t +(defcustom checkdoc-verb-check-experimental-flag nil "Non-nil means to attempt to check the voice of the doc string. This check keys off some words which are commonly misused. See the variable `checkdoc-common-verbs-wrong-voice' if you wish to add your own." - :type 'boolean) + :type 'boolean + :version "31.1") ;;;###autoload(put 'checkdoc-verb-check-experimental-flag 'safe-local-variable #'booleanp) (defvar checkdoc-generate-compile-warnings-flag nil @@ -320,6 +322,14 @@ variable `checkdoc-common-verbs-wrong-voice' if you wish to add your own." Do not set this by hand, use a function like `checkdoc-current-buffer' with a universal argument.") +(defcustom checkdoc-allow-quoting-nil-and-t nil + "If non-nil, don't warn when the symbols nil and t are quoted. + +In other words, it allows writing them like this: \\=`nil\\=', \\=`t\\='." + :type 'boolean + :version "31.1") +;;;###autoload(put 'checkdoc-allow-quoting-nil-and-t 'safe-local-variable #'booleanp) + (defcustom checkdoc-symbol-words '("beginning-of-buffer" "beginning-of-line" "byte-code" "byte-compile" "command-line" "end-of-buffer" "end-of-line" @@ -343,18 +353,19 @@ See Info node `(elisp) Documentation Tips' for background." ;; This is how you can use checkdoc to make mass fixes on the Emacs ;; source tree: ;; -;; (setq checkdoc--argument-missing-flag nil) ; optional +;; (setq checkdoc-arguments-missing-flag nil) ; optional ;; (setq checkdoc--disambiguate-symbol-flag nil) ; optional ;; (setq checkdoc--interactive-docstring-flag nil) ; optional -;; (setq checkdoc-verb-check-experimental-flag nil) +;; (setq checkdoc-permit-comma-termination-flag t) ; optional ;; Then use `M-x find-dired' ("-name '*.el'") and `M-x checkdoc-dired' -(defvar checkdoc--argument-missing-flag t - "Non-nil means warn if arguments are missing from docstring. -This variable is intended for use on Emacs itself, where the -large number of libraries means it is impractical to fix all -of these warnings en masse. In almost any other case, setting -this to anything but t is likely to be counter-productive.") +(define-obsolete-variable-alias 'checkdoc--argument-missing-flag + 'checkdoc-arguments-missing-flag "31.1") +(defcustom checkdoc-arguments-missing-flag t + "Non-nil means warn if function arguments are missing from docstring." + :type 'boolean + :version "31.1") +;;;###autoload(put 'checkdoc-arguments-missing-flag 'safe-local-variable 'booleanp) (defvar checkdoc--disambiguate-symbol-flag t "Non-nil means ask to disambiguate Lisp symbol. @@ -1085,7 +1096,7 @@ Optional argument TAKE-NOTES causes all errors to be logged." Evaluation is done first so the form will be read before the documentation is checked. If there is a documentation error, then the display of what was evaluated will be overwritten by the diagnostic message." - (interactive) + (interactive nil emacs-lisp-mode) (call-interactively #'eval-defun) (checkdoc-defun)) @@ -1096,7 +1107,7 @@ Call `error' if the doc string has problems. If NO-ERROR is non-nil, then do not call error, but call `message' instead. If the doc string passes the test, then check the function for rogue white space at the end of each line." - (interactive) + (interactive nil emacs-lisp-mode) (save-excursion (beginning-of-defun) (when (checkdoc--next-docstring) @@ -1841,7 +1852,7 @@ function,command,variable,option or symbol." ms1)))))) (looking-at "[.?!]"))) (insert ".")) nil) - (when checkdoc--argument-missing-flag + (when checkdoc-arguments-missing-flag (checkdoc-create-error (format-message "Argument `%s' should appear (as %s) in the doc string" @@ -1953,17 +1964,18 @@ Replace with \"%s\"?" original replace) (length ms))) nil))) ;; t and nil case - (save-excursion - (if (re-search-forward "\\([`‘]\\(t\\|nil\\)['’]\\)" e t) - (if (checkdoc-autofix-ask-replace - (match-beginning 1) (match-end 1) - (format "%s should not appear in quotes. Remove?" - (match-string 2)) - (match-string 2) t) - nil - (checkdoc-create-error - "Symbols t and nil should not appear in single quotes" - (match-beginning 1) (match-end 1))))) + (unless checkdoc-allow-quoting-nil-and-t + (save-excursion + (if (re-search-forward "\\([`‘]\\(t\\|nil\\)['’]\\)" e t) + (if (checkdoc-autofix-ask-replace + (match-beginning 1) (match-end 1) + (format "%s should not appear in quotes. Remove?" + (match-string 2)) + (match-string 2) t) + nil + (checkdoc-create-error + "Symbols t and nil should not appear in single quotes" + (match-beginning 1) (match-end 1)))))) ;; Here is some basic sentence formatting (checkdoc-sentencespace-region-engine (point) e) ;; Here are common proper nouns that should always appear capitalized. @@ -2106,7 +2118,7 @@ The text checked is between START and LIMIT." (goto-char start) (while (and (< (point) p) (re-search-forward "\\\\\"" limit t)) (setq c (1+ c))) - (and (< 0 c) (= (% c 2) 0)))))) + (and (< 0 c) (evenp c)))))) (defun checkdoc-in-abbreviation-p (begin) "Return non-nil if point is at an abbreviation. @@ -2134,7 +2146,7 @@ Examples of recognized abbreviations: \"e.g.\", \"i.e.\", \"cf.\"." (seq (any "cC") "f") ; cf. (seq (any "eE") ".g") ; e.g. (seq (any "iI") "." (any "eE")) ; i.e. - "a.k.a" "etc" "vs" "N.B" + "a.k.a" "etc" "vs" "N.B" "U.S" ;; Some non-standard or less common ones that we ;; might as well accept. "Inc" "Univ" "misc" "resp") @@ -2473,25 +2485,33 @@ Code:, and others referenced in the style guide." (setq err (or - ;; * A footer. Not compartmentalized from lm-verify: too bad. - ;; The following is partially clipped from lm-verify + ;; * Library footer (save-excursion (goto-char (point-max)) - (if (not (re-search-backward - ;; This should match the requirement in - ;; `package-buffer-info'. - (concat "^;;; " (regexp-quote (concat fn fe)) " ends here") - nil t)) - (if (checkdoc-y-or-n-p "No identifiable footer! Add one?") - (progn - (goto-char (point-max)) - (insert "\n(provide '" fn ")\n\n;;; " fn fe " ends here\n")) - (checkdoc-create-error - (format "The footer should be: (provide '%s)\\n;;; %s%s ends here" - fn fn fe) - ;; The buffer may be empty. - (max (point-min) (1- (point-max))) - (point-max))))) + (let* ((footer-line (lm-package-needs-footer-line))) + (if (not (re-search-backward + ;; This should match the requirement in + ;; `package-buffer-info'. + (if footer-line + (concat "^;;; " (regexp-quote (concat fn fe)) " ends here") + (concat "\n(provide '" fn ")\n")) + nil t)) + (if (checkdoc-y-or-n-p (if footer-line + "No identifiable footer! Add one?" + "No `provide' statement! Add one?")) + (progn + (goto-char (point-max)) + (insert (if footer-line + (concat "\n(provide '" fn ")\n\n;;; " fn fe " ends here\n") + (concat "\n(provide '" fn ")\n")))) + (checkdoc-create-error + (if footer-line + (format "The footer should be: (provide '%s)\\n;;; %s%s ends here" + fn fn fe) + (format "The footer should be: (provide '%s)\\n" fn)) + ;; The buffer may be empty. + (max (point-min) (1- (point-max))) + (point-max)))))) err)) ;; The below checks will not return errors if the user says NO @@ -2532,14 +2552,18 @@ Code:, and others referenced in the style guide." "Search between BEG and END for a style error with message text. Optional arguments BEG and END represent the boundary of the check. The default boundary is the entire buffer." - (let ((e nil) - (type nil)) + (let ((e nil)) (if (not (or beg end)) (setq beg (point-min) end (point-max))) (goto-char beg) - (while (setq type (checkdoc-message-text-next-string end)) + (while-let ((type (checkdoc-message-text-next-string end))) (setq e (checkdoc-message-text-engine type))) e)) +(defvar checkdoc--warning-function-re + (rx (or "display-warning" "org-display-warning" + "warn" "lwarn" + "message-box"))) + (defun checkdoc-message-text-next-string (end) "Move cursor to the next checkable message string after point. Return the message classification. @@ -2552,6 +2576,7 @@ Argument END is the maximum bounds to search in." (group (or (seq (* (or wordchar (syntax symbol))) "error") + (regexp checkdoc--warning-function-re) (seq (* (or wordchar (syntax symbol))) (or "y-or-n-p" "yes-or-no-p") (? "-with-timeout")) @@ -2559,8 +2584,13 @@ Argument END is the maximum bounds to search in." (+ (any "\n\t "))) end t)) (let* ((fn (match-string 1)) - (type (cond ((string-match "error" fn) - 'error) + (type (cond ((string-match "error" fn) + 'error) + ((string-match (rx bos + (regexp checkdoc--warning-function-re) + eos) + fn) + 'warning) (t 'y-or-n-p)))) (if (string-match "checkdoc-autofix-ask-replace" fn) (progn (forward-sexp 2) @@ -2630,30 +2660,33 @@ should not end with a period, and should start with a capital letter. The function `y-or-n-p' has similar constraints. Argument TYPE specifies the type of question, such as `error' or `y-or-n-p'." ;; If type is nil, then attempt to derive it. - (if (not type) - (save-excursion - (up-list -1) - (if (looking-at "(format") - (up-list -1)) - (setq type - (cond ((looking-at "(error") - 'error) - (t 'y-or-n-p))))) + (unless type + (save-excursion + (up-list -1) + (when (looking-at "(format") + (up-list -1)) + (setq type + (cond ((looking-at "(error") + 'error) + ((looking-at + (rx "(" (regexp checkdoc--warning-function-re) + (syntax whitespace))) + 'warning) + (t 'y-or-n-p))))) (let ((case-fold-search nil)) (or ;; From the documentation of the symbol `error': ;; In Emacs, the convention is that error messages start with a capital ;; letter but *do not* end with a period. Please follow this convention ;; for the sake of consistency. - (if (and (checkdoc--error-bad-format-p) - (not (checkdoc-autofix-ask-replace - (match-beginning 1) (match-end 1) - "Capitalize your message text?" - (capitalize (match-string 1)) - t))) - (checkdoc-create-error "Messages should start with a capital letter" - (match-beginning 1) (match-end 1)) - nil) + (when (and (checkdoc--error-bad-format-p) + (not (checkdoc-autofix-ask-replace + (match-beginning 1) (match-end 1) + "Capitalize your message text?" + (capitalize (match-string 1)) + t))) + (checkdoc-create-error "Messages should start with a capital letter" + (match-beginning 1) (match-end 1))) ;; In general, sentences should have two spaces after the period. (checkdoc-sentencespace-region-engine (point) (save-excursion (forward-sexp 1) @@ -2663,19 +2696,18 @@ Argument TYPE specifies the type of question, such as `error' or `y-or-n-p'." (save-excursion (forward-sexp 1) (point))) ;; Here are message type specific questions. - (if (and (eq type 'error) - (save-excursion (forward-sexp 1) - (forward-char -2) - (looking-at "\\.")) - (not (checkdoc-autofix-ask-replace (match-beginning 0) - (match-end 0) - "Remove period from error?" - "" - t))) - (checkdoc-create-error - "Error messages should *not* end with a period" - (match-beginning 0) (match-end 0)) - nil) + (when (and (eq type 'error) + (save-excursion (forward-sexp 1) + (forward-char -2) + (looking-at "\\.")) + (not (checkdoc-autofix-ask-replace (match-beginning 0) + (match-end 0) + "Remove period from error?" + "" + t))) + (checkdoc-create-error + "Error messages should *not* end with a period" + (match-beginning 0) (match-end 0))) ;; From `(elisp) Programming Tips': "A question asked in the ;; minibuffer with `yes-or-no-p' or `y-or-n-p' should start with ;; a capital letter and end with '?'." @@ -2828,7 +2860,7 @@ function called to create the messages." ;;;###autoload (defun checkdoc-package-keywords () "Find package keywords that aren't in `finder-known-keywords'." - (interactive) + (interactive nil emacs-lisp-mode) (require 'finder) (let ((unrecognized-keys (cl-remove-if |