]> code.delx.au - gnu-emacs/blobdiff - lisp/newcomment.el
Merge changes made in Gnus trunk.
[gnu-emacs] / lisp / newcomment.el
index 06dc7efbc99ee63d437687b7fb969e4246407fbc..3227d2ac5398c11d7bc8df92354d752ee37b254d 100644 (file)
@@ -1,18 +1,19 @@
 ;;; newcomment.el --- (un)comment regions of buffers
 
 ;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004,
 ;;; newcomment.el --- (un)comment regions of buffers
 
 ;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004,
-;;   2005, 2006, 2007 Free Software Foundation, Inc.
+;;   2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 
 ;; Author: code extracted from Emacs-20's simple.el
 ;; Maintainer: Stefan Monnier <monnier@iro.umontreal.ca>
 ;; Keywords: comment uncomment
 
 ;; Author: code extracted from Emacs-20's simple.el
 ;; Maintainer: Stefan Monnier <monnier@iro.umontreal.ca>
 ;; Keywords: comment uncomment
+;; Package: emacs
 
 ;; This file is part of GNU Emacs.
 
 
 ;; 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
 ;; 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
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,9 +21,7 @@
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
 ;; 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:
 
 
 ;;; Commentary:
 
@@ -124,7 +123,7 @@ at the place matched by the close of the first pair.")
 ;;;###autoload(put 'comment-end-skip 'safe-local-variable 'string-or-null-p)
 
 ;;;###autoload
 ;;;###autoload(put 'comment-end-skip 'safe-local-variable 'string-or-null-p)
 
 ;;;###autoload
-(defvar comment-end ""
+(defvar comment-end (purecopy "")
   "*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)
   "*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)
@@ -188,38 +187,79 @@ This should generally stay 0, except for a few modes like Lisp where
 it is 1 so that regions are commented with two or three semi-colons.")
 
 (defconst comment-styles
 it is 1 so that regions are commented with two or three semi-colons.")
 
 (defconst comment-styles
-  '((plain     . (nil nil nil nil))
-    (indent    . (nil nil nil t))
-    (indent-or-triple
-                . (nil nil nil multi-char))
-    (aligned   . (nil t nil t))
-    (multi-line        . (t nil nil t))
-    (extra-line        . (t nil t t))
-    (box       . (nil t t t))
-    (box-multi . (t t t t)))
-  "Comment region styles of the form (STYLE . (MULTI ALIGN EXTRA INDENT)).
+  '((plain      nil nil nil nil
+                "Start in column 0 (do not indent), as in Emacs-20")
+    (indent-or-triple nil nil nil multi-char
+              "Start in column 0, but only for single-char starters")
+    (indent     nil nil nil t
+                "Full comment per line, ends not aligned")
+    (aligned   nil t   nil t
+                "Full comment per line, ends aligned")
+    (box       nil t   t   t
+                "Full comment per line, ends aligned, + top and bottom")
+    (extra-line        t   nil t   t
+                "One comment for all lines, end on a line by itself")
+    (multi-line        t   nil nil t
+                "One comment for all lines, end on last commented line")
+    (box-multi t   t   t   t
+                "One comment for all lines, + top and bottom"))
+  "Comment region style definitions.
+Each style is defined with a form (STYLE . (MULTI ALIGN EXTRA INDENT DOC)).
+DOC should succinctly describe the style.
 STYLE should be a mnemonic symbol.
 MULTI specifies that comments are allowed to span multiple lines.
 STYLE should be a mnemonic symbol.
 MULTI specifies that comments are allowed to span multiple lines.
+  e.g. in C it comments regions as
+     /* blabla
+      * bli */
+  rather than
+     /* blabla */
+     /* bli */
+  if `comment-end' is empty, this has no effect.
+
 ALIGN specifies that the `comment-end' markers should be aligned.
 ALIGN specifies that the `comment-end' markers should be aligned.
+  e.g. in C it comments regions as
+     /* blabla */
+     /* bli    */
+  rather than
+     /* blabla */
+     /* bli */
+  if `comment-end' is empty, this has no effect, unless EXTRA is also set,
+  in which case the comment gets wrapped in a box.
+  
 EXTRA specifies that an extra line should be used before and after the
   region to comment (to put the `comment-end' and `comment-start').
 EXTRA specifies that an extra line should be used before and after the
   region to comment (to put the `comment-end' and `comment-start').
+  e.g. in C it comments regions as
+     /*
+      * blabla
+      * bli
+      */
+  rather than
+     /* blabla
+      * bli */
+  if the comment style is not multi line, this has no effect, unless ALIGN
+  is also set, in which case the comment gets wrapped in a box.
+
 INDENT specifies that the `comment-start' markers should not be put at the
   left margin but at the current indentation of the region to comment.
 If INDENT is `multi-char', that means indent multi-character
   comment starters, but not one-character comment starters.")
 
 ;;;###autoload
 INDENT specifies that the `comment-start' markers should not be put at the
   left margin but at the current indentation of the region to comment.
 If INDENT is `multi-char', that means indent multi-character
   comment starters, but not one-character comment starters.")
 
 ;;;###autoload
-(defcustom comment-style 'indent-or-triple
+(defcustom comment-style 'indent
   "Style to be used for `comment-region'.
 See `comment-styles' for a list of available styles."
   :type (if (boundp 'comment-styles)
   "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))
+           `(choice
+              ,@(mapcar (lambda (s)
+                          `(const :tag ,(format "%s: %s" (car s) (nth 5 s))
+                                  ,(car s)))
+                        comment-styles))
          'symbol)
          'symbol)
+  :version "23.1"
   :group 'comment)
 
 ;;;###autoload
   :group 'comment)
 
 ;;;###autoload
-(defcustom comment-padding " "
+(defcustom comment-padding (purecopy " ")
   "Padding string that `comment-region' puts between comment chars and text.
 Can also be an integer which will be automatically turned into a string
 of the corresponding number of spaces.
   "Padding string that `comment-region' puts between comment chars and text.
 Can also be an integer which will be automatically turned into a string
 of the corresponding number of spaces.
@@ -319,7 +359,8 @@ the variables are properly set."
                   "+\\)[ \t]*")))
     (unless (and comment-end-skip
                 ;; In case comment-end has changed since last time.
                   "+\\)[ \t]*")))
     (unless (and comment-end-skip
                 ;; In case comment-end has changed since last time.
-                (string-match comment-end-skip comment-end))
+                (string-match comment-end-skip
+                               (if (string= "" comment-end) "\n" comment-end)))
       (let ((ce (if (string= "" comment-end) "\n"
                  (comment-string-strip comment-end t t))))
        (set (make-local-variable 'comment-end-skip)
       (let ((ce (if (string= "" comment-end) "\n"
                  (comment-string-strip comment-end t t))))
        (set (make-local-variable 'comment-end-skip)
@@ -492,10 +533,11 @@ Point is assumed to be just at the end of a comment."
       ;; comment-end = ""
       (progn (backward-char) (skip-syntax-backward " "))
     (cond
       ;; comment-end = ""
       (progn (backward-char) (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))
+     ((save-excursion
+        (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 probably because it was not set
      ;; right.  Since \\s> should catch the single-char case, let's
       (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, let's
@@ -599,19 +641,20 @@ If CONTINUE is non-nil, use the `comment-continue' markers if any."
     (let* ((eolpos (line-end-position))
           (begpos (comment-search-forward eolpos t))
           cpos indent)
     (let* ((eolpos (line-end-position))
           (begpos (comment-search-forward eolpos t))
           cpos indent)
-      ;; An existing comment?
-      (if begpos
-         (progn
-           (if (and (not (looking-at "[\t\n ]"))
-                    (looking-at comment-end-skip))
-               ;; The comment is empty and we have skipped all its space
-               ;; and landed right before the comment-ender:
-               ;; Go back to the middle of the space.
-               (forward-char (/ (skip-chars-backward " \t") -2)))
-           (setq cpos (point-marker)))
+      (if (and comment-insert-comment-function (not begpos))
+         ;; If no comment and c-i-c-f is set, let it do everything.
+         (funcall comment-insert-comment-function)
+       ;; An existing comment?
+       (if begpos
+           (progn
+             (if (and (not (looking-at "[\t\n ]"))
+                      (looking-at comment-end-skip))
+                 ;; The comment is empty and we have skipped all its space
+                 ;; and landed right before the comment-ender:
+                 ;; Go back to the middle of the space.
+                 (forward-char (/ (skip-chars-backward " \t") -2)))
+             (setq cpos (point-marker)))
          ;; If none, insert one.
          ;; If none, insert one.
-       (if comment-insert-comment-function
-           (funcall comment-insert-comment-function)
          (save-excursion
            ;; Some `comment-indent-function's insist on not moving
            ;; comments that are in column 0, so we first go to the
          (save-excursion
            ;; Some `comment-indent-function's insist on not moving
            ;; comments that are in column 0, so we first go to the
@@ -624,32 +667,32 @@ If CONTINUE is non-nil, use the `comment-continue' markers if any."
            (setq begpos (point))
            (insert starter)
            (setq cpos (point-marker))
            (setq begpos (point))
            (insert starter)
            (setq cpos (point-marker))
-           (insert ender))))
-      (goto-char begpos)
-      ;; Compute desired indent.
-      (setq indent (save-excursion (funcall comment-indent-function)))
-      ;; If `indent' is nil and there's code before the comment, we can't
-      ;; use `indent-according-to-mode', so we default to comment-column.
-      (unless (or indent (save-excursion (skip-chars-backward " \t") (bolp)))
-       (setq indent comment-column))
-      (if (not indent)
-         ;; comment-indent-function refuses: delegate to line-indent.
-         (indent-according-to-mode)
-       ;; If the comment is at the right of code, adjust the indentation.
-       (unless (save-excursion (skip-chars-backward " \t") (bolp))
-          (setq indent (comment-choose-indent indent)))
-       ;; 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)
-         (delete-region (point) (progn (skip-chars-backward " \t") (point)))
-         (indent-to indent)))
-      (goto-char cpos)
-      (set-marker cpos nil))))
+           (insert ender)))
+       (goto-char begpos)
+       ;; Compute desired indent.
+       (setq indent (save-excursion (funcall comment-indent-function)))
+       ;; If `indent' is nil and there's code before the comment, we can't
+       ;; use `indent-according-to-mode', so we default to comment-column.
+       (unless (or indent (save-excursion (skip-chars-backward " \t") (bolp)))
+         (setq indent comment-column))
+       (if (not indent)
+           ;; comment-indent-function refuses: delegate to line-indent.
+           (indent-according-to-mode)
+         ;; If the comment is at the right of code, adjust the indentation.
+         (unless (save-excursion (skip-chars-backward " \t") (bolp))
+           (setq indent (comment-choose-indent indent)))
+         ;; 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)
+           (delete-region (point) (progn (skip-chars-backward " \t") (point)))
+           (indent-to indent)))
+       (goto-char cpos)
+       (set-marker cpos nil)))))
 
 ;;;###autoload
 (defun comment-set-column (arg)
 
 ;;;###autoload
 (defun comment-set-column (arg)
@@ -676,7 +719,7 @@ With any other arg, set comment column to indentation of the previous comment
 
 ;;;###autoload
 (defun comment-kill (arg)
 
 ;;;###autoload
 (defun comment-kill (arg)
-  "Kill the comment on this line, if any.
+  "Kill the first comment on this line, if any.
 With prefix ARG, kill comments on that many lines starting with this one."
   (interactive "P")
   (comment-normalize-vars)
 With prefix ARG, kill comments on that many lines starting with this one."
   (interactive "P")
   (comment-normalize-vars)
@@ -944,12 +987,12 @@ indentation to be kept as it was before narrowing."
                   (delete-char n)
                   (setq ,bindent (- ,bindent n)))))))))))
 
                   (delete-char n)
                   (setq ,bindent (- ,bindent n)))))))))))
 
-;; Compute the number of extra comment starter characters
-;; (extra semicolons in Lisp mode, extra stars in C mode, etc.)
-;; If ARG is non-nil, just follow ARG.
-;; If the comment-starter is multi-char, just follow ARG.
-;; Otherwise obey comment-add, and double it if EXTRA is non-nil.
 (defun comment-add (arg)
 (defun comment-add (arg)
+  "Compute the number of extra comment starter characters
+\(extra semicolons in Lisp mode, extra stars in C mode, etc.)
+If ARG is non-nil, just follow ARG.
+If the comment starter is multi-char, just follow ARG.
+Otherwise obey `comment-add'."
   (if (and (null arg) (= (string-match "[ \t]*\\'" comment-start) 1))
       (* comment-add 1)
     (1- (prefix-numeric-value arg))))
   (if (and (null arg) (= (string-match "[ \t]*\\'" comment-start) 1))
       (* comment-add 1)
     (1- (prefix-numeric-value arg))))
@@ -968,9 +1011,11 @@ INDENT indicates to put CS and CCS at the current indentation of
 the region rather than at left margin."
   ;;(assert (< beg end))
   (let ((no-empty (not (or (eq comment-empty-lines t)
 the region rather than at left margin."
   ;;(assert (< beg end))
   (let ((no-empty (not (or (eq comment-empty-lines t)
-                          (and comment-empty-lines (zerop (length ce)))))))
+                          (and comment-empty-lines (zerop (length ce))))))
+       ce-sanitized)
     ;; Sanitize CE and CCE.
     (if (and (stringp ce) (string= "" ce)) (setq ce nil))
     ;; Sanitize CE and CCE.
     (if (and (stringp ce) (string= "" ce)) (setq ce nil))
+    (setq ce-sanitized ce)
     (if (and (stringp cce) (string= "" cce)) (setq cce nil))
     ;; If CE is empty, multiline cannot be used.
     (unless ce (setq ccs nil cce nil))
     (if (and (stringp cce) (string= "" cce)) (setq cce nil))
     ;; If CE is empty, multiline cannot be used.
     (unless ce (setq ccs nil cce nil))
@@ -987,7 +1032,7 @@ the region rather than at left margin."
       (goto-char end)
       ;; If the end is not at the end of a line and the comment-end
       ;; is implicit (i.e. a newline), explicitly insert a newline.
       (goto-char end)
       ;; If the end is not at the end of a line and the comment-end
       ;; is implicit (i.e. a newline), explicitly insert a newline.
-      (unless (or ce (eolp)) (insert "\n") (indent-according-to-mode))
+      (unless (or ce-sanitized (eolp)) (insert "\n") (indent-according-to-mode))
       (comment-with-narrowing beg end
        (let ((min-indent (point-max))
              (max-indent 0))
       (comment-with-narrowing beg end
        (let ((min-indent (point-max))
              (max-indent 0))
@@ -1043,12 +1088,16 @@ the region rather than at left margin."
 With just \\[universal-argument] prefix arg, uncomment each line in region BEG .. END.
 Numeric prefix ARG means use ARG comment characters.
 If ARG is negative, delete that many comment characters instead.
 With just \\[universal-argument] prefix arg, uncomment each line in region BEG .. END.
 Numeric prefix ARG means use ARG comment characters.
 If ARG is negative, delete that many comment characters instead.
-By default, comments start at the left margin, are terminated on each line,
-even for syntax in which newline does not end the comment and blank lines
-do not get comments.  This can be changed with `comment-style'.
 
 
-The strings used as comment starts are built from
-`comment-start' without trailing spaces and `comment-padding'."
+The strings used as comment starts are built from `comment-start'
+and `comment-padding'; the strings used as comment ends are built
+from `comment-end' and `comment-padding'.
+
+By default, the `comment-start' markers are inserted at the
+current indentation of the region, and comments are terminated on
+each line (even for syntaxes in which newline does not end the
+comment and blank lines do not get comments).  This can be
+changed with `comment-style'."
   (interactive "*r\nP")
   (comment-normalize-vars)
   (if (> beg end) (let (mid) (setq mid beg beg end end mid)))
   (interactive "*r\nP")
   (comment-normalize-vars)
   (if (> beg end) (let (mid) (setq mid beg beg end end mid)))
@@ -1092,16 +1141,22 @@ The strings used as comment starts are built from
      ((< numarg 0) (uncomment-region beg end (- numarg)))
      (t
       (let ((multi-char (/= (string-match "[ \t]*\\'" comment-start) 1))
      ((< numarg 0) (uncomment-region beg end (- numarg)))
      (t
       (let ((multi-char (/= (string-match "[ \t]*\\'" comment-start) 1))
-           indent)
+           indent triple)
        (if (eq (nth 3 style) 'multi-char)
        (if (eq (nth 3 style) 'multi-char)
-           (setq indent multi-char)
+           (save-excursion
+             (goto-char beg)
+             (setq indent multi-char
+                   ;; Triple if we will put the comment starter at the margin
+                   ;; and the first line of the region isn't indented
+                   ;; at least two spaces.
+                   triple (and (not multi-char) (looking-at "\t\\|  "))))
          (setq indent (nth 3 style)))
 
        ;; In Lisp and similar modes with one-character comment starters,
        ;; double it by default if `comment-add' says so.
        ;; If it isn't indented, triple it.
        (if (and (null arg) (not multi-char))
          (setq indent (nth 3 style)))
 
        ;; In Lisp and similar modes with one-character comment starters,
        ;; double it by default if `comment-add' says so.
        ;; If it isn't indented, triple it.
        (if (and (null arg) (not multi-char))
-           (setq numarg (* comment-add (if indent 1 2)))
+           (setq numarg (* comment-add (if triple 2 1)))
          (setq numarg (1- (prefix-numeric-value arg))))
 
        (comment-region-internal
          (setq numarg (1- (prefix-numeric-value arg))))
 
        (comment-region-internal
@@ -1149,9 +1204,10 @@ is passed on to the respective function."
 (defun comment-dwim (arg)
   "Call the comment command you want (Do What I Mean).
 If the region is active and `transient-mark-mode' is on, call
 (defun comment-dwim (arg)
   "Call the comment command you want (Do What I Mean).
 If the region is active and `transient-mark-mode' is on, call
-  `comment-region' (unless it only consists of comments, in which
-  case it calls `uncomment-region').
-Else, if the current line is empty, insert a comment and indent it.
+`comment-region' (unless it only consists of comments, in which
+case it calls `uncomment-region').
+Else, if the current line is empty, call `comment-insert-comment-function'
+if it is defined, otherwise insert a comment and indent it.
 Else if a prefix ARG is specified, call `comment-kill'.
 Else, call `comment-indent'.
 You can configure `comment-style' to change the way regions are commented."
 Else if a prefix ARG is specified, call `comment-kill'.
 Else, call `comment-indent'.
 You can configure `comment-style' to change the way regions are commented."
@@ -1163,15 +1219,19 @@ You can configure `comment-style' to change the way regions are commented."
        ;; 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))
        ;; 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 (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))
-       (save-excursion
-         (unless (string= "" comment-end)
-           (insert (comment-padleft comment-end add)))
-         (indent-according-to-mode))))))
+      ;; Inserting a comment on a blank line. comment-indent calls
+      ;; c-i-c-f if needed in the non-blank case.
+      (if comment-insert-comment-function
+          (funcall comment-insert-comment-function)
+        (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))
+          (save-excursion
+            (unless (string= "" comment-end)
+              (insert (comment-padleft comment-end add)))
+            (indent-according-to-mode)))))))
 
 ;;;###autoload
 (defcustom comment-auto-fill-only-comments nil
 
 ;;;###autoload
 (defcustom comment-auto-fill-only-comments nil
@@ -1218,7 +1278,7 @@ if we're not inside a comment."
                              (buffer-substring (point)
                                                (progn (move-to-left-margin)
                                                       (point)))))))))))))
                              (buffer-substring (point)
                                                (progn (move-to-left-margin)
                                                       (point)))))))))))))
-                    
+
 
 ;;;###autoload
 (defun comment-indent-new-line (&optional soft)
 
 ;;;###autoload
 (defun comment-indent-new-line (&optional soft)
@@ -1242,7 +1302,7 @@ unless optional argument SOFT is non-nil."
     ;; don't do anything (unless no comment syntax is defined).
     (unless (and comment-start
                 comment-auto-fill-only-comments
     ;; don't do anything (unless no comment syntax is defined).
     (unless (and comment-start
                 comment-auto-fill-only-comments
-                (not (interactive-p))
+                (not (called-interactively-p 'interactive))
                 (not (save-excursion
                        (prog1 (setq compos (comment-beginning))
                          (setq comin (point))))))
                 (not (save-excursion
                        (prog1 (setq compos (comment-beginning))
                          (setq comin (point))))))