]> code.delx.au - gnu-emacs/blobdiff - lisp/emacs-lisp/checkdoc.el
* emacs-lisp/checkdoc.el (checkdoc-proper-noun-region-engine): Use
[gnu-emacs] / lisp / emacs-lisp / checkdoc.el
index 862a7efe04629d7755c576c3700ecd84e63f9fab..6b226be0b28ca01d4a787200431462c29e34acd7 100644 (file)
@@ -1,7 +1,7 @@
 ;;; checkdoc.el --- check documentation strings for style requirements
 
 ;; Copyright (C) 1997, 1998, 2001, 2002, 2003, 2004,
-;;   2005, 2006, 2007 Free Software Foundation, Inc.
+;;   2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
 ;; Author: Eric M. Ludlam <zappo@gnu.org>
 ;; Version: 0.6.2
@@ -9,10 +9,10 @@
 
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,9 +20,7 @@
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 ;;
 (defvar checkdoc-version "0.6.1"
   "Release version of checkdoc you are currently running.")
 
-;; From custom web page for compatibility between versions of custom:
-(eval-and-compile
- (condition-case ()
-     (require 'custom)
-   (error nil))
- (if (and (featurep 'custom) (fboundp 'custom-declare-variable))
-     nil ;; We've got what we needed
-     ;; We have the old custom-library, hack around it!
-     (defmacro defgroup (&rest args)
-       nil)
-     (defmacro custom-add-option (&rest args)
-       nil)
-     (defmacro defcustom (var value doc &rest args)
-       `(defvar ,var ,value ,doc))))
+(require 'help-mode) ;; for help-xref-info-regexp
+(require 'thingatpt) ;; for handy thing-at-point-looking-at
 
 (defvar compilation-error-regexp-alist)
 (defvar compilation-mode-font-lock-keywords)
   :group 'lisp
   :version "20.3")
 
+(defcustom checkdoc-minor-mode-string " CDoc"
+  "String to display in mode line when Checkdoc mode is enabled; nil for none."
+  :type '(choice string (const :tag "None" nil))
+  :group 'checkdoc
+  :version "23.1")
+
 (defcustom checkdoc-autofix-flag 'semiautomatic
   "Non-nil means attempt auto-fixing of doc strings.
 If this value is the symbol `query', then the user is queried before
@@ -227,13 +219,14 @@ and that it's good but not required practice to make non user visible items
 have doc strings."
   :group 'checkdoc
   :type 'boolean)
-(put 'checkdoc-force-docstrings-flag 'safe-local-variable 'booleanp)
+;;;###autoload(put 'checkdoc-force-docstrings-flag 'safe-local-variable 'booleanp)
 
-(defcustom checkdoc-force-history-flag t
+(defcustom checkdoc-force-history-flag nil
   "Non-nil means that files should have a History section or ChangeLog file.
 This helps document the evolution of, and recent changes to, the package."
   :group 'checkdoc
   :type 'boolean)
+;;;###autoload(put 'checkdoc-force-history-flag 'safe-local-variable 'booleanp)
 
 (defcustom checkdoc-permit-comma-termination-flag nil
   "Non-nil means the first line of a docstring may end with a comma.
@@ -243,7 +236,7 @@ should be used when the first part could stand alone as a sentence, but
 it indicates that a modifying clause follows."
   :group 'checkdoc
   :type 'boolean)
-(put 'checkdoc-permit-comma-termination-flag 'safe-local-variable 'booleanp)
+;;;###autoload(put 'checkdoc-permit-comma-termination-flag 'safe-local-variable 'booleanp)
 
 (defcustom checkdoc-spellcheck-documentation-flag nil
   "Non-nil means run Ispell on text based on value.
@@ -281,6 +274,7 @@ the same order as they appear in the argument list.  No mention is
 made in the style guide relating to order."
   :group 'checkdoc
   :type 'boolean)
+;;;###autoload(put 'checkdoc-arguments-in-order-flag 'safe-local-variable 'booleanp)
 
 (defvar checkdoc-style-hooks nil
   "Hooks called after the standard style check is completed.
@@ -318,11 +312,19 @@ Do not set this by hand, use a function like `checkdoc-current-buffer'
 with a universal argument.")
 
 (defcustom checkdoc-symbol-words nil
-  "A list of symbols which also happen to make good words.
-These symbol-words are ignored when unquoted symbols are searched for.
+  "A list of symbol names (strings) which also happen to make good words.
+These words are ignored when unquoted symbols are searched for.
 This should be set in an Emacs Lisp file's local variables."
   :group 'checkdoc
   :type '(repeat (symbol :tag "Word")))
+;;;###autoload(put 'checkdoc-symbol-words 'safe-local-variable 'checkdoc-list-of-strings-p)
+
+;;;###autoload
+(defun checkdoc-list-of-strings-p (obj)
+  ;; this is a function so it might be shared by checkdoc-proper-noun-list
+  ;; and/or checkdoc-ispell-lisp-words in the future
+  (and (listp obj)
+       (not (memq nil (mapcar 'stringp obj)))))
 
 (defvar checkdoc-proper-noun-list
   '("ispell" "xemacs" "emacs" "lisp")
@@ -512,7 +514,7 @@ the users will view as each check is completed."
 CHECK is a list of four strings stating the current status of each
 test; the nth string describes the status of the nth test."
   (let (temp-buffer-setup-hook)
-    (with-output-to-temp-buffer " *Checkdoc Status*"
+    (with-output-to-temp-buffer "*Checkdoc Status*"
       (princ-list
        "Buffer comments and tags:  " (nth 0 check) "\n"
        "Documentation style:       " (nth 1 check) "\n"
@@ -520,7 +522,7 @@ test; the nth string describes the status of the nth test."
        "Unwanted Spaces:           " (nth 3 check)
        )))
   (shrink-window-if-larger-than-buffer
-   (get-buffer-window " *Checkdoc Status*"))
+   (get-buffer-window "*Checkdoc Status*"))
   (message nil)
   (sit-for 0))
 
@@ -854,7 +856,8 @@ With a prefix argument (in Lisp, the argument TAKE-NOTES),
 store all errors found in a warnings buffer,
 otherwise stop after the first error."
   (interactive "P")
-  (if (interactive-p) (message "Checking buffer for style..."))
+  (if (called-interactively-p 'interactive)
+      (message "Checking buffer for style..."))
   ;; Assign a flag to spellcheck flag
   (let ((checkdoc-spellcheck-documentation-flag
         (car (memq checkdoc-spellcheck-documentation-flag
@@ -871,7 +874,7 @@ otherwise stop after the first error."
        (checkdoc-start)
        (checkdoc-message-text)
        (checkdoc-rogue-spaces)
-       (not (interactive-p))
+       (not (called-interactively-p 'interactive))
        (if take-notes (checkdoc-show-diagnostics))
        (message "Checking buffer for style...Done."))))
 
@@ -885,7 +888,7 @@ a separate buffer."
   (interactive "P")
   (let ((p (point)))
     (goto-char (point-min))
-    (if (and take-notes (interactive-p))
+    (if (and take-notes (called-interactively-p 'interactive))
        (checkdoc-start-section "checkdoc-start"))
     (checkdoc-continue take-notes)
     ;; Go back since we can't be here without success above.
@@ -921,7 +924,7 @@ is the starting location.  If this is nil, `point-min' is used instead."
          (if (not take-notes)
              (error "%s" (checkdoc-error-text msg)))))
     (checkdoc-show-diagnostics)
-    (if (interactive-p)
+    (if (called-interactively-p 'interactive)
        (message "No style warnings."))))
 
 (defun checkdoc-next-docstring ()
@@ -969,10 +972,10 @@ Optional argument INTERACT permits more interactive fixing."
         (e (checkdoc-rogue-space-check-engine nil nil interact))
        (checkdoc-generate-compile-warnings-flag
         (or take-notes checkdoc-generate-compile-warnings-flag)))
-    (if (not (interactive-p))
+    (if (not (called-interactively-p 'interactive))
        e
       (if e
-         (message (checkdoc-error-text e))
+         (message "%s" (checkdoc-error-text e))
        (checkdoc-show-diagnostics)
        (message "Space Check: done.")))))
 
@@ -987,13 +990,14 @@ Optional argument TAKE-NOTES causes all errors to be logged."
         (checkdoc-generate-compile-warnings-flag
          (or take-notes checkdoc-generate-compile-warnings-flag)))
     (setq e (checkdoc-message-text-search))
-    (if (not (interactive-p))
+    (if (not (called-interactively-p 'interactive))
        e
       (if e
          (error "%s" (checkdoc-error-text e))
        (checkdoc-show-diagnostics)))
     (goto-char p))
-  (if (interactive-p) (message "Checking interactive message text...done.")))
+  (if (called-interactively-p 'interactive)
+      (message "Checking interactive message text...done.")))
 
 ;;;###autoload
 (defun checkdoc-eval-defun ()
@@ -1032,17 +1036,18 @@ space at the end of each line."
             (end (save-excursion (end-of-defun) (point)))
             (msg (checkdoc-this-string-valid)))
        (if msg (if no-error
-                   (message (checkdoc-error-text msg))
+                   (message "%s" (checkdoc-error-text msg))
                  (error "%s" (checkdoc-error-text msg)))
          (setq msg (checkdoc-message-text-search beg end))
          (if msg (if no-error
-                     (message (checkdoc-error-text msg))
+                     (message "%s" (checkdoc-error-text msg))
                    (error "%s" (checkdoc-error-text msg)))
            (setq msg (checkdoc-rogue-space-check-engine beg end))
            (if msg (if no-error
-                       (message (checkdoc-error-text msg))
+                       (message "%s" (checkdoc-error-text msg))
                      (error "%s" (checkdoc-error-text msg))))))
-       (if (interactive-p) (message "Checkdoc: done."))))))
+       (if (called-interactively-p 'interactive)
+           (message "Checkdoc: done."))))))
 
 ;;; Ispell interface for forcing a spell check
 ;;
@@ -1176,7 +1181,7 @@ generating a buffered list of errors."
     ;; Override some bindings
     (define-key map "\C-\M-x" 'checkdoc-eval-defun)
     (define-key map "\C-x`" 'checkdoc-continue)
-    (if (not (string-match "XEmacs" emacs-version))
+    (if (not (featurep 'xemacs))
        (define-key map [menu-bar emacs-lisp eval-buffer]
          'checkdoc-eval-current-buffer))
     ;; Add some new bindings under C-c ?
@@ -1202,9 +1207,8 @@ generating a buffered list of errors."
     map)
   "Keymap used to override evaluation key-bindings for documentation checking.")
 
-(defvaralias 'checkdoc-minor-keymap 'checkdoc-minor-mode-map)
-(make-obsolete-variable 'checkdoc-minor-keymap
-                        'checkdoc-minor-mode-map)
+(define-obsolete-variable-alias 'checkdoc-minor-keymap
+    'checkdoc-minor-mode-map "21.1")
 
 ;; Add in a menubar with easy-menu
 
@@ -1243,14 +1247,15 @@ generating a buffered list of errors."
 ;;;###autoload
 (define-minor-mode checkdoc-minor-mode
   "Toggle Checkdoc minor mode, a mode for checking Lisp doc strings.
-With prefix ARG, turn Checkdoc minor mode on iff ARG is positive.
+With prefix ARG, turn Checkdoc minor mode on if ARG is positive, otherwise
+turn it off.
 
 In Checkdoc minor mode, the usual bindings for `eval-defun' which is
 bound to \\<checkdoc-minor-mode-map>\\[checkdoc-eval-defun] and `checkdoc-eval-current-buffer' are overridden to include
 checking of documentation strings.
 
 \\{checkdoc-minor-mode-map}"
-  nil " CDoc" nil
+  nil checkdoc-minor-mode-string nil
   :group 'checkdoc)
 
 ;;; Subst utils
@@ -1647,25 +1652,28 @@ function,command,variable,option or symbol." ms1))))))
                 (checkdoc-create-error
                  "Flag variable doc strings should usually start: Non-nil means"
                  s (marker-position e) t))
+             ;; Don't rename variable to "foo-flag".  This is unnecessary
+             ;; and such names often end up inconvenient when the variable
+             ;; is later expanded to non-boolean values. --Stef
             ;; If the doc string starts with "Non-nil means"
-            (if (and (looking-at "\"\\*?Non-nil\\s-+means\\s-+")
-                     (not (string-match "-flag$" (car fp))))
-                (let ((newname
-                       (if (string-match "-p$" (car fp))
-                           (concat (substring (car fp) 0 -2) "-flag")
-                         (concat (car fp) "-flag"))))
-                  (if (checkdoc-y-or-n-p
-                       (format
-                        "Rename to %s and Query-Replace all occurrences? "
-                        newname))
-                      (progn
-                        (beginning-of-defun)
-                        (query-replace-regexp
-                         (concat "\\<" (regexp-quote (car fp)) "\\>")
-                         newname))
-                    (checkdoc-create-error
-                     "Flag variable names should normally end in `-flag'" s
-                     (marker-position e)))))
+            ;; (if (and (looking-at "\"\\*?Non-nil\\s-+means\\s-+")
+            ;;          (not (string-match "-flag$" (car fp))))
+            ;;     (let ((newname
+            ;;         (if (string-match "-p$" (car fp))
+            ;;             (concat (substring (car fp) 0 -2) "-flag")
+            ;;           (concat (car fp) "-flag"))))
+            ;;       (if (checkdoc-y-or-n-p
+            ;;         (format
+            ;;          "Rename to %s and Query-Replace all occurrences? "
+            ;;          newname))
+            ;;           (progn
+            ;;          (beginning-of-defun)
+            ;;          (query-replace-regexp
+            ;;           (concat "\\<" (regexp-quote (car fp)) "\\>")
+            ;;           newname))
+            ;;         (checkdoc-create-error
+            ;;          "Flag variable names should normally end in `-flag'" s
+            ;;          (marker-position e)))))
             ;; Done with variables
             ))
           (t
@@ -1782,10 +1790,9 @@ function,command,variable,option or symbol." ms1))))))
                                        checkdoc-common-verbs-wrong-voice))
                        (if (not rs) (error "Verb voice alist corrupted"))
                        (setq replace (let ((case-fold-search nil))
-                                       (save-match-data
-                                         (if (string-match "^[A-Z]" original)
-                                             (capitalize (cdr rs))
-                                           (cdr rs)))))
+                                       (if (string-match-p "^[A-Z]" original)
+                                           (capitalize (cdr rs))
+                                         (cdr rs))))
                        (if (checkdoc-autofix-ask-replace
                             (match-beginning 1) (match-end 1)
                             (format "Use the imperative for \"%s\".  \
@@ -1813,11 +1820,10 @@ Replace with \"%s\"? " original replace)
                      "[^-([`':a-zA-Z]\\(\\w+[:-]\\(\\w\\|\\s_\\)+\\)[^]']"
                      e t))
           (setq ms (match-string 1))
-          (save-match-data
-            ;; A . is a \s_ char, so we must remove periods from
-            ;; sentences more carefully.
-            (if (string-match "\\.$" ms)
-                (setq ms (substring ms 0 (1- (length ms))))))
+          ;; A . is a \s_ char, so we must remove periods from
+          ;; sentences more carefully.
+          (when (string-match-p "\\.$" ms)
+            (setq ms (substring ms 0 (1- (length ms)))))
           (if (and (not (checkdoc-in-sample-code-p start e))
                    (not (checkdoc-in-example-string-p start e))
                    (not (member ms checkdoc-symbol-words))
@@ -2013,7 +2019,12 @@ If the offending word is in a piece of quoted text, then it is skipped."
                         ;; surrounded by /, as in a URL or filename: /emacs/
                         (not (and (= ?/ (char-after e))
                                   (= ?/ (char-before b))))
-                        (not (checkdoc-in-example-string-p begin end)))
+                        (not (checkdoc-in-example-string-p begin end))
+                        ;; info or url links left alone
+                        (not (thing-at-point-looking-at
+                              help-xref-info-regexp))
+                        (not (thing-at-point-looking-at
+                              help-xref-url-regexp)))
                    (if (checkdoc-autofix-ask-replace
                         b e (format "Text %s should be capitalized.  Fix? "
                                     text)
@@ -2058,6 +2069,7 @@ If the offending word is in a piece of quoted text, then it is skipped."
                                      (progn
                                        (forward-sexp -1)
                                        ;; piece of an abbreviation
+                                       ;; FIXME etc
                                        (looking-at
                                         "\\([a-z]\\|[iI]\\.?e\\|[eE]\\.?g\\)\\."))
                                    (error t))))
@@ -2208,6 +2220,8 @@ News agents may remove it"
   ;; b) determine if we have lm-history symbol which doesn't always exist
   (require 'lisp-mnt))
 
+(defvar generate-autoload-cookie)
+
 (defun checkdoc-file-comments-engine ()
   "Return a message list if this file does not match the Emacs standard.
 This checks for style only, such as the first line, Commentary:,
@@ -2304,15 +2318,24 @@ Code:, and others referenced in the style guide."
        (or
        ;; * Code section
        (if (not (lm-code-mark))
-           (let ((cont t))
+           (let ((cont t)
+                 pos)
              (goto-char (point-min))
-             (while (and cont (re-search-forward "^(" nil t))
-               (setq cont (looking-at "require\\s-+")))
+             ;; match ";;;###autoload" cookie to keep it with the form
+             (require 'autoload)
+             (while (and cont (re-search-forward
+                               (concat "^\\("
+                                       (regexp-quote generate-autoload-cookie)
+                                       "\n\\)?"
+                                       "(")
+                               nil t))
+               (setq pos (match-beginning 0)
+                     cont (looking-at "require\\s-+")))
              (if (and (not cont)
                       (checkdoc-y-or-n-p
                        "There is no ;;; Code: marker.  Insert one? "))
-                 (progn (beginning-of-line)
-                        (insert ";;; Code:\n")
+                 (progn (goto-char pos)
+                        (insert ";;; Code:\n\n")
                         nil)
                (checkdoc-create-error
                 "You should have a section marked \";;; Code:\""
@@ -2615,7 +2638,9 @@ function called to create the messages."
       (checkdoc-output-mode)
       (setq default-directory dir)
       (goto-char (point-max))
-      (insert "\n\n\C-l\n*** " label ": " check-type " V " checkdoc-version))))
+      (let ((inhibit-read-only t))
+        (insert "\n\n\C-l\n*** " label ": "
+                check-type " V " checkdoc-version)))))
 
 (defun checkdoc-error (point msg)
   "Store POINT and MSG as errors in the checkdoc diagnostic buffer."
@@ -2626,7 +2651,8 @@ function called to create the messages."
                    ": " msg)))
     (with-current-buffer (get-buffer checkdoc-diagnostic-buffer)
       (goto-char (point-max))
-      (apply 'insert text))))
+      (let ((inhibit-read-only t))
+        (apply 'insert text)))))
 
 (defun checkdoc-show-diagnostics ()
   "Display the checkdoc diagnostic buffer in a temporary window."