(vc-diff-internal, vc-coding-system-for-diff, vc-default-diff-tree):
[bpt/emacs.git] / lisp / newcomment.el
index 2fe635b..ecef1c7 100644 (file)
@@ -1,12 +1,11 @@
 ;;; newcomment.el --- (un)comment regions of buffers
 
-;; Copyright (C) 1999-2000  Free Software Foundation Inc.
+;; Copyright (C) 19992000  Free Software Foundation Inc.
 
 ;; Author: code extracted from Emacs-20's simple.el
 ;; Maintainer: Stefan Monnier <monnier@cs.yale.edu>
 ;; Keywords: comment uncomment
-;; Version: $Name:  $
-;; Revision: $Id: newcomment.el,v 1.23 2000/11/14 10:03:56 monnier Exp $
+;; Revision: $Id: newcomment.el,v 1.36 2001/10/11 01:44:48 monnier Exp $
 
 ;; This file is part of GNU Emacs.
 
@@ -44,6 +43,7 @@
 
 ;;; Todo:
 
+;; - quantized steps in comment-alignment
 ;; - try to align tail comments
 ;; - check what c-comment-line-break-function has to say
 ;; - spill auto-fill of comments onto the end of the next line
@@ -203,6 +203,7 @@ This is obsolete because you might as well use \\[newline-and-indent]."
   "Return the mirror image of string S, without any trailing space."
   (comment-string-strip (concat (nreverse (string-to-list s))) nil t))
 
+;;;###autoload
 (defun comment-normalize-vars (&optional noerror)
   (if (not comment-start) (or noerror (error "No comment syntax is defined"))
     ;; comment-use-syntax
@@ -228,18 +229,26 @@ This is obsolete because you might as well use \\[newline-and-indent]."
     (unless (or comment-continue (string= comment-end ""))
       (set (make-local-variable 'comment-continue)
           (concat (if (string-match "\\S-\\S-" comment-start) " " "|")
-                  (substring comment-start 1))))
+                  (substring comment-start 1)))
+      ;; Hasn't been necessary yet.
+      ;; (unless (string-match comment-start-skip comment-continue)
+      ;;       (kill-local-variable 'comment-continue))
+      )
     ;; comment-skip regexps
     (unless comment-start-skip
       (set (make-local-variable 'comment-start-skip)
           (concat "\\(\\(^\\|[^\\\\\n]\\)\\(\\\\\\\\\\)*\\)\\(\\s<+\\|"
                   (regexp-quote (comment-string-strip comment-start t t))
-                  "+\\)\\s-*")))
+                  ;; Let's not allow any \s- but only [ \t] since \n
+                  ;; might be both a comment-end marker and \s-.
+                  "+\\)[ \t]*")))
     (unless comment-end-skip
       (let ((ce (if (string= "" comment-end) "\n"
                  (comment-string-strip comment-end t t))))
        (set (make-local-variable 'comment-end-skip)
-            (concat "\\s-*\\(\\s>" (if comment-quote-nested "" "+")
+            ;; We use [ \t] rather than \s- because we don't want to
+            ;; remove ^L in C mode when uncommenting.
+            (concat "[ \t]*\\(\\s>" (if comment-quote-nested "" "+")
                     "\\|" (regexp-quote (substring ce 0 1))
                     (if (and comment-quote-nested (<= (length ce) 1)) "" "+")
                     (regexp-quote (substring ce 1))
@@ -347,15 +356,30 @@ and raises an error or returns nil of NOERROR is non-nil."
   "Find the beginning of the enclosing comment.
 Returns nil if not inside a comment, else moves point and returns
 the same as `comment-search-forward'."
-  (let ((pt (point))
-       (cs (comment-search-backward nil t)))
-    (when cs
-      (if (save-excursion
-           (goto-char cs)
-           (if (comment-forward 1) (> (point) pt) (eobp)))
-         cs
-       (goto-char pt)
-       nil))))
+  ;; HACK ATTACK!
+  ;; We should really test `in-string-p' but that can be expensive.
+  (unless (eq (get-text-property (point) 'face) 'font-lock-string-face)
+    (let ((pt (point))
+         (cs (comment-search-backward nil t)))
+      (when cs
+       (if (save-excursion
+             (goto-char cs)
+             (and
+              ;; For modes where comment-start and comment-end are the same,
+              ;; the search above may have found a `ce' rather than a `cs'.
+              (or (not (looking-at comment-end-skip))
+                  ;; Maybe font-lock knows that it's a `cs'?
+                  (eq (get-text-property (match-end 0) 'face)
+                      'font-lock-comment-face)
+                  (unless (eq (get-text-property (point) 'face)
+                              'font-lock-comment-face)
+                    ;; Let's assume it's a `cs' if we're on the same line.
+                    (>= (line-end-position) pt)))
+              ;; Make sure that PT is not past the end of the comment.
+              (if (comment-forward 1) (> (point) pt) (eobp))))
+           cs
+         (goto-char pt)
+         nil)))))
 
 (defun comment-forward (&optional n)
   "Skip forward over N comments.
@@ -368,6 +392,7 @@ and can use regexps instead of syntax."
        (skip-syntax-forward " ")
        (setq n
              (if (and (looking-at comment-start-skip)
+                      (goto-char (match-end 0))
                       (re-search-forward comment-end-skip nil 'move))
                  (1- n) -1)))
       (= n 0))))
@@ -409,7 +434,7 @@ Point is assumed to be just at the end of a comment."
 ;;;###autoload
 (defun comment-indent (&optional continue)
   "Indent this line's comment to comment column, or insert an empty comment.
-If CONTINUE is non-nil, use the `comment-continuation' markers if any."
+If CONTINUE is non-nil, use the `comment-continue' markers if any."
   (interactive "*")
   (comment-normalize-vars)
   (let* ((empty (save-excursion (beginning-of-line)
@@ -418,41 +443,41 @@ If CONTINUE is non-nil, use the `comment-continuation' markers if any."
                      (and empty block-comment-start) comment-start))
         (ender (or (and continue comment-continue "")
                    (and empty block-comment-end) comment-end)))
-    (cond
-     ((null starter)
-      (error "No comment syntax defined"))
-     (t (let* ((eolpos (line-end-position))
-               cpos indent begpos)
-          (beginning-of-line)
-          (if (not (setq begpos (comment-search-forward eolpos t)))
-             (setq begpos (point))
-           (setq cpos (point-marker))
-           (goto-char begpos))
-         ;; Compute desired indent.
-         (setq indent (funcall comment-indent-function))
-         (if (not indent)
-             ;; comment-indent-function refuses delegates to indent.
-             (indent-according-to-mode)
-           ;; Avoid moving comments past the fill-column.
-           (setq indent
-                 (min indent
-                      (+ (current-column)
-                         (- fill-column
-                            (save-excursion (end-of-line) (current-column))))))
-           (if (= (current-column) indent)
-               (goto-char begpos)
-             ;; If that's different from current, change it.
-             (skip-chars-backward " \t")
-             (delete-region (point) begpos)
-             (indent-to (if (bolp) indent
-                          (max indent (1+ (current-column)))))))
-         ;; An existing comment?
-         (if cpos
-             (progn (goto-char cpos) (set-marker cpos nil))
-           ;; No, insert one.
+    (unless starter (error "No comment syntax defined"))
+    (beginning-of-line)
+    (let* ((eolpos (line-end-position))
+          (begpos (comment-search-forward eolpos t))
+          cpos indent)
+      ;; An existing comment?
+      (if begpos (setq cpos (point-marker))
+         ;; If none, insert one.
+         (save-excursion
+           ;; Some comment-indent-function insist on not moving comments that
+           ;; are in column 0, so we first go to the likely target column.
+           (indent-to comment-column)
+           (setq begpos (point))
            (insert starter)
-           (save-excursion
-             (insert ender))))))))
+           (setq cpos (point-marker))
+           (insert ender)))
+      (goto-char begpos)
+      ;; Compute desired indent.
+      (setq indent (save-excursion (funcall comment-indent-function)))
+      (if (not indent)
+         ;; comment-indent-function refuses delegates to indent.
+         (indent-according-to-mode)
+       ;; Avoid moving comments past the fill-column.
+       (setq indent
+             (min indent
+                  (+ (current-column)
+                     (- fill-column
+                        (save-excursion (end-of-line) (current-column))))))
+       (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)))))))
+      (goto-char cpos)
+      (set-marker cpos nil))))
 
 ;;;###autoload
 (defun comment-set-column (arg)
@@ -786,7 +811,7 @@ rather than at left margin."
 ;;;###autoload
 (defun comment-region (beg end &optional arg)
   "Comment or uncomment each line in the region.
-With just \\[universal-prefix] prefix arg, uncomment each line in region BEG..END.
+With just \\[universal-argument] prefix arg, uncomment each line in region BEG..END.
 Numeric prefix arg 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,
@@ -862,7 +887,7 @@ end- comment markers additionally to what `comment-add' already specifies."
 (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 in comments, in which
+  `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.
 Else if a prefix ARG is specified, call `comment-kill'.
@@ -884,6 +909,9 @@ Else, call `comment-indent'."
        (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
+       ;; 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)
@@ -896,6 +924,14 @@ This has no effect in modes that do not define a comment syntax."
   :type 'boolean
   :group 'comment)
 
+(defun comment-valid-prefix (prefix compos)
+  (or
+   ;; Accept any prefix if the current comment is not EOL-terminated.
+   (save-excursion (goto-char compos) (comment-forward) (not (bolp)))
+   ;; Accept any prefix that starts with a comment-start marker.
+   (string-match (concat "\\`[ \t]*\\(?:" comment-start-skip "\\)")
+                fill-prefix)))
+
 ;;;###autoload
 (defun comment-indent-new-line (&optional soft)
   "Break line at point and indent, continuing comment if within one.
@@ -923,10 +959,10 @@ unless optional argument SOFT is non-nil."
                          (setq comin (point))))))
 
       ;; Now we know we should auto-fill.
-      (delete-region (progn (skip-chars-backward " \t") (point))
-                    (progn (skip-chars-forward  " \t") (point)))
+      (delete-horizontal-space)
       (if soft (insert-and-inherit ?\n) (newline 1))
-      (if fill-prefix
+      (if (and fill-prefix (not adaptive-fill-mode))
+         ;; Blindly trust a non-adaptive fill-prefix.
          (progn
            (indent-to-left-margin)
            (insert-and-inherit fill-prefix))
@@ -938,8 +974,17 @@ unless optional argument SOFT is non-nil."
            (setq compos (comment-beginning))
            (setq comin (point))))
 
-       ;; If we're not inside a comment, just try to indent.
-       (if (not compos) (indent-according-to-mode)
+       (cond
+        ;; If there's an adaptive prefix, use it unless we're inside
+        ;; a comment and the prefix is not a comment starter.
+        ((and fill-prefix
+              (or (not compos)
+                  (comment-valid-prefix fill-prefix compos)))
+         (indent-to-left-margin)
+         (insert-and-inherit fill-prefix))
+        ;; If we're not inside a comment, just try to indent.
+        ((not compos) (indent-according-to-mode))
+        (t
          (let* ((comment-column
                  ;; The continuation indentation should be somewhere between
                  ;; the current line's indentation (plus 2 for good measure)
@@ -968,6 +1013,7 @@ unless optional argument SOFT is non-nil."
                         nil t)))))
                 (comment-start comstart)
                 ;; Force comment-continue to be recreated from comment-start.
+                ;; FIXME: wrong if comment-continue was set explicitly!
                 (comment-continue nil))
            (insert-and-inherit ?\n)
            (forward-char -1)
@@ -981,7 +1027,7 @@ unless optional argument SOFT is non-nil."
                  (beginning-of-line)
                  (backward-char)
                  (insert comend)
-                 (forward-char))))))))))
+                 (forward-char)))))))))))
 
 (provide 'newcomment)