]> code.delx.au - gnu-emacs/blobdiff - lisp/newcomment.el
* lisp/emacs-lisp/smie.el (smie--matching-block-data): Invalidate the
[gnu-emacs] / lisp / newcomment.el
index 3227d2ac5398c11d7bc8df92354d752ee37b254d..251c1605345d806ded666a5f934ed3038f498981 100644 (file)
@@ -1,7 +1,6 @@
-;;; newcomment.el --- (un)comment regions of buffers
+;;; newcomment.el --- (un)comment regions of buffers -*- lexical-binding: t -*-
 
-;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004,
-;;   2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+;; Copyright (C) 1999-2013 Free Software Foundation, Inc.
 
 ;; Author: code extracted from Emacs-20's simple.el
 ;; Maintainer: Stefan Monnier <monnier@iro.umontreal.ca>
 
 ;;; Commentary:
 
-;; A replacement for simple.el's comment-related functions.
+;; This library contains functions and variables for commenting and
+;; uncommenting source code.
+
+;; Prior to calling any `comment-*' function, you should ensure that
+;; `comment-normalize-vars' is first called to set up the appropriate
+;; variables; except for the `comment-*' commands, which call
+;; `comment-normalize-vars' automatically as a subroutine.
 
 ;;; Bugs:
 
@@ -103,30 +108,35 @@ Comments might be indented to a different value in order not to go beyond
   :type 'integer
   :group 'comment)
 (make-variable-buffer-local 'comment-column)
-;;;###autoload(put 'comment-column 'safe-local-variable 'integerp)
+;;;###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)
+  "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.
+  "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
+(put 'comment-start-skip 'safe-local-variable 'stringp)
 
 ;;;###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)
+  "Regexp to match the end of a comment plus everything back to its body.")
+;;;###autoload
+(put 'comment-end-skip 'safe-local-variable 'stringp)
 
 ;;;###autoload
 (defvar comment-end (purecopy "")
-  "*String to insert to end a new comment.
+  "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
+(put 'comment-end 'safe-local-variable 'stringp)
 
 ;;;###autoload
 (defvar comment-indent-function 'comment-indent-default
@@ -186,6 +196,7 @@ The `plain' comment style doubles this value.
 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.")
 
+;;;###autoload
 (defconst comment-styles
   '((plain      nil nil nil nil
                 "Start in column 0 (do not indent), as in Emacs-20")
@@ -225,7 +236,7 @@ ALIGN specifies that the `comment-end' markers should be aligned.
      /* 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').
   e.g. in C it comments regions as
@@ -269,6 +280,19 @@ makes the comment easier to read.  Default is 1.  nil means 0."
   :type '(choice string integer (const nil))
   :group 'comment)
 
+(defcustom comment-inline-offset 1
+  "Inline comments have to be preceded by at least this many spaces.
+This is useful when style-conventions require a certain minimal offset.
+Python's PEP8 for example recommends two spaces, so you could do:
+
+\(add-hook 'python-mode-hook
+   (lambda () (set (make-local-variable 'comment-inline-offset) 2)))
+
+See `comment-padding' for whole-line comments."
+  :version "24.3"
+  :type 'integer
+  :group 'comment)
+
 ;;;###autoload
 (defcustom comment-multi-line nil
   "Non-nil means `comment-indent-new-line' continues comments.
@@ -308,16 +332,18 @@ terminated by the end of line (i.e. `comment-end' is empty)."
 
 ;;;###autoload
 (defun comment-normalize-vars (&optional noerror)
-  "Check and setup the variables needed by other commenting functions.
-Functions autoloaded from newcomment.el, being entry points, should call
-this function before any other, so the rest of the code can assume that
-the variables are properly set."
+  "Check and set up variables needed by other commenting functions.
+All the `comment-*' commands call this function to set up various
+variables, like `comment-start', to ensure that the commenting
+functions work correctly.  Lisp callers of any other `comment-*'
+function should first call this function explicitly."
   (unless (and (not comment-start) noerror)
     (unless comment-start
       (let ((cs (read-string "No comment syntax is defined.  Use: ")))
        (if (zerop (length cs))
            (error "No comment syntax defined")
-         (set (make-local-variable 'comment-start) cs))))
+         (set (make-local-variable 'comment-start) cs)
+         (set (make-local-variable 'comment-start-skip) cs))))
     ;; comment-use-syntax
     (when (eq comment-use-syntax 'undecided)
       (set (make-local-variable 'comment-use-syntax)
@@ -409,18 +435,23 @@ If UNP is non-nil, unquote nested comment markers."
 ;;;; Navigation
 ;;;;
 
-(defvar comment-use-global-state nil
+(defvar comment-use-global-state t
   "Non-nil means that the global syntactic context is used.
 More specifically, it means that `syntax-ppss' is used to find out whether
-point is within a string or not.  Major modes whose syntax is faithfully
-described by the syntax-tables can set this to non-nil so comment markers
-in strings will not confuse Emacs.")
+point is within a string or not.  Major modes whose syntax is not faithfully
+described by the syntax-tables (or where `font-lock-syntax-table' is radically
+different from the main syntax table) can set this to nil,
+then `syntax-ppss' cache won't be used in comment-related routines.")
+
+(make-obsolete-variable 'comment-use-global-state 'comment-use-syntax "24.4")
 
 (defun comment-search-forward (limit &optional noerror)
   "Find a comment start between point and LIMIT.
 Moves point to inside the comment and returns the position of the
 comment-starter.  If no comment is found, moves point to LIMIT
-and raises an error or returns nil if NOERROR is non-nil."
+and raises an error or returns nil if NOERROR is non-nil.
+
+Ensure that `comment-normalize-vars' has been called before you use this."
   (if (not comment-use-syntax)
       (if (re-search-forward comment-start-skip limit noerror)
          (or (match-end 1) (match-beginning 0))
@@ -458,7 +489,9 @@ and raises an error or returns nil if NOERROR is non-nil."
   "Find a comment start between LIMIT and point.
 Moves point to inside the comment and returns the position of the
 comment-starter.  If no comment is found, moves point to LIMIT
-and raises an error or returns nil if NOERROR is non-nil."
+and raises an error or returns nil if NOERROR is non-nil.
+
+Ensure that `comment-normalize-vars' has been called before you use this."
   ;; FIXME: If a comment-start appears inside a comment, we may erroneously
   ;; stop there.  This can be rather bad in general, but since
   ;; comment-search-backward is only used to find the comment-column (in
@@ -485,30 +518,36 @@ and raises an error or returns nil if 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-backward'."
-  ;; 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 (if comment-end-skip (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)))))
+  (if (and comment-use-syntax comment-use-global-state)
+      (let ((state (syntax-ppss)))
+        (when (nth 4 state)
+          (goto-char (nth 8 state))
+          (prog1 (point)
+            (when (looking-at comment-start-skip)
+              (goto-char (match-end 0))))))
+    ;; Can't rely on the syntax table, let's guess based on font-lock.
+    (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 (if comment-end-skip (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.
@@ -586,7 +625,7 @@ Point is expected to be at the start of the comment."
                    (save-excursion (end-of-line) (current-column)))))
         (other nil)
         (min (save-excursion (skip-chars-backward " \t")
-                             (1+ (current-column)))))
+                             (if (bolp) 0 (+ comment-inline-offset (current-column))))))
     ;; Fix up the range.
     (if (< max min) (setq max min))
     ;; Don't move past the fill column.
@@ -686,7 +725,8 @@ If CONTINUE is non-nil, use the `comment-continue' markers if any."
          (save-excursion
            (skip-chars-backward " \t")
            (unless (bolp)
-             (setq indent (max indent (1+ (current-column))))))
+             (setq indent (max indent
+                                (+ (current-column) comment-inline-offset)))))
          ;; If that's different from comment's current position, change it.
          (unless (= (current-column) indent)
            (delete-region (point) (progn (skip-chars-backward " \t") (point)))
@@ -723,7 +763,7 @@ With any other arg, set comment column to indentation of the previous comment
 With prefix ARG, kill comments on that many lines starting with this one."
   (interactive "P")
   (comment-normalize-vars)
-  (dotimes (_ (prefix-numeric-value arg))
+  (dotimes (_i (prefix-numeric-value arg))
     (save-excursion
       (beginning-of-line)
       (let ((cs (comment-search-forward (line-end-position) t)))
@@ -872,14 +912,15 @@ comment markers."
          (when (and sre (looking-at (concat "\\s-*\n\\s-*" srei)))
            (goto-char (match-end 0)))
          (if (null arg) (delete-region (point-min) (point))
-           (skip-syntax-backward " ")
-           (delete-char (- numarg))
-           (unless (or (bobp)
-                       (save-excursion (goto-char (point-min))
-                                       (looking-at comment-start-skip)))
-             ;; If there's something left but it doesn't look like
-             ;; a comment-start any more, just remove it.
-             (delete-region (point-min) (point))))
+            (let ((opoint (point-marker)))
+              (skip-syntax-backward " ")
+              (delete-char (- numarg))
+              (unless (and (not (bobp))
+                           (save-excursion (goto-char (point-min))
+                                           (looking-at comment-start-skip)))
+                ;; If there's something left but it doesn't look like
+                ;; a comment-start any more, just remove it.
+                (delete-region (point-min) opoint))))
 
          ;; Remove the end-comment (and leading padding and such).
          (goto-char (point-max)) (comment-enter-backward)
@@ -988,8 +1029,8 @@ indentation to be kept as it was before narrowing."
                   (setq ,bindent (- ,bindent n)))))))))))
 
 (defun comment-add (arg)
-  "Compute the number of extra comment starter characters
-\(extra semicolons in Lisp mode, extra stars in C mode, etc.)
+  "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'."
@@ -1178,13 +1219,20 @@ changed with `comment-style'."
 (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."
+end- comment markers additionally to what variable `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))))
 
+(defun comment-only-p (beg end)
+  "Return non-nil if the text between BEG and END is all comments."
+  (save-excursion
+    (goto-char beg)
+    (comment-forward (point-max))
+    (<= end (point))))
 
 ;;;###autoload
 (defun comment-or-uncomment-region (beg end &optional arg)
@@ -1193,10 +1241,7 @@ in which case call `uncomment-region'.  If a prefix arg is given, it
 is passed on to the respective function."
   (interactive "*r\nP")
   (comment-normalize-vars)
-  (funcall (if (save-excursion ;; check for already commented region
-                (goto-char beg)
-                (comment-forward (point-max))
-                (<= end (point)))
+  (funcall (if (comment-only-p beg end)
               'uncomment-region 'comment-region)
           beg end arg))
 
@@ -1241,7 +1286,7 @@ This has no effect in modes that do not define a comment syntax."
   :group 'comment)
 
 (defun comment-valid-prefix-p (prefix compos)
-    "Check that the adaptive-fill-prefix is consistent with the context.
+    "Check that the adaptive fill prefix is consistent with the context.
 PREFIX is the prefix (presumably guessed by `adaptive-fill-mode').
 COMPOS is the position of the beginning of the comment we're in, or nil
 if we're not inside a comment."
@@ -1387,5 +1432,4 @@ unless optional argument SOFT is non-nil."
 
 (provide 'newcomment)
 
-;; arch-tag: 01e3320a-00c8-44ea-a696-8f8e7354c858
 ;;; newcomment.el ends here