(defgroup reftex): Update home page url-link.
[bpt/emacs.git] / lisp / newcomment.el
index 59044da..0cf0160 100644 (file)
@@ -1,9 +1,10 @@
 ;;; newcomment.el --- (un)comment regions of buffers
 
-;; Copyright (C) 1999, 2000, 2003, 2004  Free Software Foundation Inc.
+;; Copyright (C) 1999, 2000, 2002, 2003, 2004,
+;;   2005, 2006 Free Software Foundation, Inc.
 
 ;; Author: code extracted from Emacs-20's simple.el
-;; Maintainer: Stefan Monnier <monnier@cs.yale.edu>
+;; Maintainer: Stefan Monnier <monnier@iro.umontreal.ca>
 ;; Keywords: comment uncomment
 
 ;; This file is part of GNU Emacs.
@@ -20,8 +21,8 @@
 
 ;; 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., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
@@ -95,7 +96,7 @@ Major modes should set this variable.")
 
 ;;;###autoload
 (defcustom comment-column 32
-  "*Column to indent right-margin comments to.
+  "Column to indent right-margin comments to.
 Each mode establishes a different default value for this variable; you
 can set the value for a particular mode using that mode's hook.
 Comments might be indented to a value smaller than this in order
@@ -103,25 +104,30 @@ not to go beyond `comment-fill-column'."
   :type 'integer
   :group 'comment)
 (make-variable-buffer-local 'comment-column)
+;;;###autoload(put 'comment-column 'safe-local-variable 'integerp)
 
 ;;;###autoload
 (defvar comment-start nil
   "*String to insert to start a new comment, or nil if no comment syntax.")
+;;;###autoload(put 'comment-start 'safe-local-variable 'string-or-null-p)
 
 ;;;###autoload
 (defvar comment-start-skip nil
   "*Regexp to match the start of a comment plus everything up to its body.
 If there are any \\(...\\) pairs, the comment delimiter text is held to begin
 at the place matched by the close of the first pair.")
+;;;###autoload(put 'comment-start-skip 'safe-local-variable 'string-or-null-p)
 
 ;;;###autoload
 (defvar comment-end-skip nil
   "Regexp to match the end of a comment plus everything up to its body.")
+;;;###autoload(put 'comment-end-skip 'safe-local-variable 'string-or-null-p)
 
 ;;;###autoload
 (defvar comment-end ""
   "*String to insert to end a new comment.
 Should be an empty string if comments are terminated by end-of-line.")
+;;;###autoload(put 'comment-end 'safe-local-variable 'string-or-null-p)
 
 ;;;###autoload
 (defvar comment-indent-function 'comment-indent-default
@@ -199,7 +205,7 @@ INDENT specifies that the `comment-start' markers should not be put at the
 
 ;;;###autoload
 (defcustom comment-style 'plain
-  "*Style to be used for `comment-region'.
+  "Style to be used for `comment-region'.
 See `comment-styles' for a list of available styles."
   :type (if (boundp 'comment-styles)
            `(choice ,@(mapcar (lambda (s) `(const ,(car s))) comment-styles))
@@ -219,7 +225,7 @@ makes the comment easier to read.  Default is 1.  nil means 0."
 
 ;;;###autoload
 (defcustom comment-multi-line nil
-  "*Non-nil means `comment-indent-new-line' continues comments.
+  "Non-nil means `comment-indent-new-line' continues comments.
 That is, it inserts no new terminator or starter.
 This affects `auto-fill-mode', which is the main reason to
 customize this variable.
@@ -293,7 +299,7 @@ the variables are properly set."
                   (substring comment-start 1)))
       ;; Hasn't been necessary yet.
       ;; (unless (string-match comment-start-skip comment-continue)
-      ;;       (kill-local-variable 'comment-continue))
+      ;;       (kill-local-variable 'comment-continue))
       )
     ;; comment-skip regexps
     (unless (and comment-start-skip
@@ -477,19 +483,22 @@ Point is assumed to be just at the end of a comment."
   (if (bolp)
       ;; comment-end = ""
       (progn (backward-char) (skip-syntax-backward " "))
-    (let ((end (point)))
-      (beginning-of-line)
-      (save-restriction
-       (narrow-to-region (point) end)
-       (if (re-search-forward (concat comment-end-skip "\\'") nil t)
-           (goto-char (match-beginning 0))
-         ;; comment-end-skip not found probably because it was not set right.
-         ;; Since \\s> should catch the single-char case, we'll blindly
-         ;; assume we're at the end of a two-char comment-end.
-         (goto-char (point-max))
-         (backward-char 2)
-         (skip-chars-backward (string (char-after)))
-         (skip-syntax-backward " "))))))
+    (cond
+     ((save-restriction
+        (narrow-to-region (line-beginning-position) (point))
+        (goto-char (point-min))
+        (re-search-forward (concat comment-end-skip "\\'") nil t))
+      (goto-char (match-beginning 0)))
+     ;; comment-end-skip not found.  Maybe we're at EOB which implicitly
+     ;; closes the comment.
+     ((eobp) (skip-syntax-backward " "))
+     (t
+      ;; else comment-end-skip was not found probably because it was not
+      ;; set right.  Since \\s> should catch the single-char case, we'll
+      ;; blindly assume we're at the end of a two-char comment-end.
+      (backward-char 2)
+      (skip-chars-backward (string (char-after)))
+      (skip-syntax-backward " ")))))
 
 ;;;;
 ;;;; Commands
@@ -502,7 +511,7 @@ Point is assumed to be just at the end of a comment."
           (or (match-end 1) (/= (current-column) (current-indentation))))
       0
     (when (or (/= (current-column) (current-indentation))
-             (and (> comment-add 0) (looking-at "\\s<\\S<")))
+             (and (> comment-add 0) (looking-at "\\s<\\(\\S<\\|\\'\\)")))
       comment-column)))
 
 ;;;###autoload
@@ -590,11 +599,16 @@ If CONTINUE is non-nil, use the `comment-continue' markers if any."
                    (if (and other (<= other max) (> other min))
                        ;; There is a comment and it's in the range: bingo.
                        (setq indent other))))))))
+       ;; Update INDENT to leave at least one space
+       ;; after other nonwhite text on the line.
+       (save-excursion
+         (skip-chars-backward " \t")
+         (unless (bolp)
+           (setq indent (max indent (1+ (current-column))))))
+       ;; If that's different from comment's current position, change it.
        (unless (= (current-column) indent)
-         ;; If that's different from current, change it.
          (delete-region (point) (progn (skip-chars-backward " \t") (point)))
-         (indent-to (if (bolp) indent
-                      (max indent (1+ (current-column)))))))
+         (indent-to indent)))
       (goto-char cpos)
       (set-marker cpos nil))))
 
@@ -755,7 +769,7 @@ comment markers."
            (box-equal nil))       ;Whether we might be using `=' for boxes.
        (save-restriction
          (narrow-to-region spt ept)
-               
+
          ;; Remove the comment-start.
          (goto-char ipt)
          (skip-syntax-backward " ")
@@ -784,7 +798,7 @@ comment markers."
              ;; If there's something left but it doesn't look like
              ;; a comment-start any more, just remove it.
              (delete-region (point-min) (point))))
-               
+
          ;; Remove the end-comment (and leading padding and such).
          (goto-char (point-max)) (comment-enter-backward)
          ;; Check for special `=' used sometimes in comment-box.
@@ -891,6 +905,11 @@ indentation to be kept as it was before narrowing."
                   (delete-char n)
                   (setq ,bindent (- ,bindent n)))))))))))
 
+(defun comment-add (arg)
+  (if (and (null arg) (= (string-match "[ \t]*\\'" comment-start) 1))
+      comment-add
+    (1- (prefix-numeric-value arg))))
+
 (defun comment-region-internal (beg end cs ce
                                 &optional ccs cce block lines indent)
   "Comment region BEG .. END.
@@ -942,9 +961,13 @@ the region rather than at left margin."
                (setq max-indent (max max-indent (current-column)))
                (not (or (eobp) (progn (forward-line) nil)))))
 
-         ;; Inserting ccs can change max-indent by (1- tab-width).
          (setq max-indent
-               (+ max-indent (max (length cs) (length ccs)) tab-width -1))
+               (+ max-indent (max (length cs) (length ccs))
+                   ;; Inserting ccs can change max-indent by (1- tab-width)
+                   ;; but only if there are TABs in the boxed text, of course.
+                   (if (save-excursion (goto-char beg)
+                                       (search-forward "\t" end t))
+                       (1- tab-width) 0)))
          (unless indent (setq min-indent 0))
 
          ;; make the leading and trailing lines if requested
@@ -991,7 +1014,6 @@ The strings used as comment starts are built from
 
 (defun comment-region-default (beg end &optional arg)
   (let* ((numarg (prefix-numeric-value arg))
-        (add comment-add)
         (style (cdr (assoc comment-style comment-styles)))
         (lines (nth 2 style))
         (block (nth 1 style))
@@ -1024,8 +1046,7 @@ The strings used as comment starts are built from
      ((consp arg) (uncomment-region beg end))
      ((< numarg 0) (uncomment-region beg end (- numarg)))
      (t
-      (setq numarg (if (and (null arg) (= (length comment-start) 1))
-                      add (1- numarg)))
+      (setq numarg (comment-add arg))
       (comment-region-internal
        beg end
        (let ((s (comment-padright comment-start numarg)))
@@ -1041,11 +1062,13 @@ The strings used as comment starts are built from
        lines
        (nth 3 style))))))
 
+;;;###autoload
 (defun comment-box (beg end &optional arg)
   "Comment out the BEG .. END region, putting it inside a box.
 The numeric prefix ARG specifies how many characters to add to begin- and
 end- comment markers additionally to what `comment-add' already specifies."
   (interactive "*r\np")
+  (comment-normalize-vars)
   (let ((comment-style (if (cadr (assoc comment-style comment-styles))
                           'box-multi 'box)))
     (comment-region beg end (+ comment-add arg))))
@@ -1073,7 +1096,8 @@ If the region is active and `transient-mark-mode' is on, call
   case it calls `uncomment-region').
 Else, if the current line is empty, insert a comment and indent it.
 Else if a prefix ARG is specified, call `comment-kill'.
-Else, call `comment-indent'."
+Else, call `comment-indent'.
+You can configure `comment-style' to change the way regions are commented."
   (interactive "*P")
   (comment-normalize-vars)
   (if (and mark-active transient-mark-mode)
@@ -1082,9 +1106,8 @@ Else, call `comment-indent'."
        ;; FIXME: If there's no comment to kill on this line and ARG is
        ;; specified, calling comment-kill is not very clever.
        (if arg (comment-kill (and (integerp arg) arg)) (comment-indent))
-      (let ((add (if arg (prefix-numeric-value arg)
-                  (if (= (length comment-start) 1) comment-add 0))))
-       ;; Some modes insist on keeping column 0 comment in column 0
+      (let ((add (comment-add arg)))
+        ;; Some modes insist on keeping column 0 comment in column 0
        ;; so we need to move away from it before inserting the comment.
        (indent-according-to-mode)
        (insert (comment-padright comment-start add))