+the comment's starting delimiter and should return either the desired
+column indentation or nil.
+If nil is returned, indentation is delegated to `indent-according-to-mode'.")
+
+;;;###autoload
+(defvar comment-insert-comment-function nil
+ "Function to insert a comment when a line doesn't contain one.
+The function has no args.
+
+Applicable at least in modes for languages like fixed-format Fortran where
+comments always start in column zero.")
+
+(defvar comment-region-function 'comment-region-default
+ "Function to comment a region.
+Its args are the same as those of `comment-region', but BEG and END are
+guaranteed to be correctly ordered. It is called within `save-excursion'.
+
+Applicable at least in modes for languages like fixed-format Fortran where
+comments always start in column zero.")
+
+(defvar uncomment-region-function 'uncomment-region-default
+ "Function to uncomment a region.
+Its args are the same as those of `uncomment-region', but BEG and END are
+guaranteed to be correctly ordered. It is called within `save-excursion'.
+
+Applicable at least in modes for languages like fixed-format Fortran where
+comments always start in column zero.")
+
+;; ?? never set
+(defvar block-comment-start nil)
+(defvar block-comment-end nil)
+
+(defvar comment-quote-nested t
+ "Non-nil if nested comments should be quoted.
+This should be locally set by each major mode if needed.")
+
+(defvar comment-continue nil
+ "Continuation string to insert for multiline comments.
+This string will be added at the beginning of each line except the very
+first one when commenting a region with a commenting style that allows
+comments to span several lines.
+It should generally have the same length as `comment-start' in order to
+preserve indentation.
+If it is nil a value will be automatically derived from `comment-start'
+by replacing its first character with a space.")
+
+(defvar comment-add 0
+ "How many more comment chars should be inserted by `comment-region'.
+This determines the default value of the numeric argument of `comment-region'.
+This should generally stay 0, except for a few modes like Lisp where
+it can be convenient to set it to 1 so that regions are commented with
+two semi-colons.")
+
+(defconst comment-styles
+ '((plain . (nil nil nil nil))
+ (indent . (nil nil nil t))
+ (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)))
+ "Possible comment styles of the form (STYLE . (MULTI ALIGN EXTRA INDENT)).
+STYLE should be a mnemonic symbol.
+MULTI specifies that comments are allowed to span multiple lines.
+ALIGN specifies that the `comment-end' markers should be aligned.
+EXTRA specifies that an extra line should be used before and after the
+ region to comment (to put the `comment-end' and `comment-start').
+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.")
+
+;;;###autoload
+(defcustom comment-style 'plain
+ "*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))
+ 'symbol)
+ :group 'comment)
+
+;;;###autoload
+(defcustom comment-padding " "
+ "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.
+
+Extra spacing between the comment characters and the comment text
+makes the comment easier to read. Default is 1. nil means 0."
+ :type '(choice string integer (const nil))
+ :group 'comment)
+
+;;;###autoload
+(defcustom comment-multi-line nil
+ "*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.
+
+It also affects \\[indent-new-comment-line]. However, if you want this
+behavior for explicit filling, you might as well use \\[newline-and-indent]."
+ :type 'boolean
+ :group 'comment)
+
+(defcustom comment-empty-lines nil
+ "If nil, `comment-region' does not comment out empty lines.
+If t, it always comments out empty lines.
+if `eol' it only comments out empty lines if comments are
+terminated by the end of line (i.e. `comment-end' is empty)."
+ :type '(choice (const :tag "Never" nil)
+ (const :tag "Always" t)
+ (const :tag "EOl-terminated" 'eol))
+ :group 'comment)
+
+;;;;
+;;;; Helpers
+;;;;
+
+(defun comment-string-strip (str beforep afterp)
+ "Strip STR of any leading (if BEFOREP) and/or trailing (if AFTERP) space."
+ (string-match (concat "\\`" (if beforep "\\s-*")
+ "\\(.*?\\)" (if afterp "\\s-*\n?")
+ "\\'") str)
+ (match-string 1 str))
+
+(defun comment-string-reverse (s)
+ "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)
+ "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."
+ (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))))
+ ;; comment-use-syntax
+ (when (eq comment-use-syntax 'undecided)
+ (set (make-local-variable 'comment-use-syntax)
+ (let ((st (syntax-table))
+ (cs comment-start)
+ (ce (if (string= "" comment-end) "\n" comment-end)))
+ ;; Try to skip over a comment using forward-comment
+ ;; to see if the syntax tables properly recognize it.
+ (with-temp-buffer
+ (set-syntax-table st)
+ (insert cs " hello " ce)
+ (goto-char (point-min))
+ (and (forward-comment 1) (eobp))))))
+ ;; comment-padding
+ (unless comment-padding (setq comment-padding 0))
+ (when (integerp comment-padding)
+ (setq comment-padding (make-string comment-padding ? )))
+ ;; comment markers
+ ;;(setq comment-start (comment-string-strip comment-start t nil))
+ ;;(setq comment-end (comment-string-strip comment-end nil t))
+ ;; comment-continue
+ (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)))
+ ;; Hasn't been necessary yet.
+ ;; (unless (string-match comment-start-skip comment-continue)
+ ;; (kill-local-variable 'comment-continue))
+ )
+ ;; comment-skip regexps
+ (unless (and comment-start-skip
+ ;; In case comment-start has changed since last time.
+ (string-match comment-start-skip comment-start))
+ (set (make-local-variable 'comment-start-skip)
+ (concat "\\(\\(^\\|[^\\\n]\\)\\(\\\\\\\\\\)*\\)\\(\\s<+\\|"
+ (regexp-quote (comment-string-strip comment-start t t))
+ ;; Let's not allow any \s- but only [ \t] since \n
+ ;; might be both a comment-end marker and \s-.
+ "+\\)[ \t]*")))
+ (unless (and comment-end-skip
+ ;; In case comment-end has changed since last time.
+ (string-match comment-end-skip comment-end))
+ (let ((ce (if (string= "" comment-end) "\n"
+ (comment-string-strip comment-end t t))))
+ (set (make-local-variable 'comment-end-skip)
+ ;; 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))
+ "\\)"))))))
+
+(defun comment-quote-re (str unp)
+ (concat (regexp-quote (substring str 0 1))
+ "\\\\" (if unp "+" "*")
+ (regexp-quote (substring str 1))))
+
+(defun comment-quote-nested (cs ce unp)
+ "Quote or unquote nested comments.
+If UNP is non-nil, unquote nested comment markers."
+ (setq cs (comment-string-strip cs t t))
+ (setq ce (comment-string-strip ce t t))
+ (when (and comment-quote-nested (> (length ce) 0))
+ (let ((re (concat (comment-quote-re ce unp)
+ "\\|" (comment-quote-re cs unp))))
+ (goto-char (point-min))
+ (while (re-search-forward re nil t)
+ (goto-char (match-beginning 0))
+ (forward-char 1)
+ (if unp (delete-char 1) (insert "\\"))
+ (when (= (length ce) 1)
+ ;; If the comment-end is a single char, adding a \ after that
+ ;; "first" char won't deactivate it, so we turn such a CE
+ ;; into !CS. I.e. for pascal, we turn } into !{
+ (if (not unp)
+ (when (string= (match-string 0) ce)
+ (replace-match (concat "!" cs) t t))
+ (when (and (< (point-min) (match-beginning 0))
+ (string= (buffer-substring (1- (match-beginning 0))
+ (1- (match-end 0)))
+ (concat "!" cs)))
+ (backward-char 2)
+ (delete-char (- (match-end 0) (match-beginning 0)))
+ (insert ce))))))))
+
+;;;;
+;;;; Navigation
+;;;;
+
+(defvar comment-use-global-state nil
+ "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.")
+
+(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."
+ (if (not comment-use-syntax)
+ (if (re-search-forward comment-start-skip limit noerror)
+ (or (match-end 1) (match-beginning 0))
+ (goto-char limit)
+ (unless noerror (error "No comment")))
+ (let* ((pt (point))
+ ;; Assume (at first) that pt is outside of any string.
+ (s (parse-partial-sexp pt (or limit (point-max)) nil nil
+ (if comment-use-global-state (syntax-ppss pt))
+ t)))
+ (when (and (nth 8 s) (nth 3 s) (not comment-use-global-state))
+ ;; The search ended at eol inside a string. Try to see if it
+ ;; works better when we assume that pt is inside a string.
+ (setq s (parse-partial-sexp
+ pt (or limit (point-max)) nil nil
+ (list nil nil nil (nth 3 s) nil nil nil nil)
+ t)))
+ (if (not (and (nth 8 s) (not (nth 3 s))))
+ (unless noerror (error "No comment"))
+ ;; We found the comment.
+ (let ((pos (point))
+ (start (nth 8 s))
+ (bol (line-beginning-position))
+ (end nil))
+ (while (and (null end) (>= (point) bol))
+ (if (looking-at comment-start-skip)
+ (setq end (min (or limit (point-max)) (match-end 0)))
+ (backward-char)))
+ (goto-char (or end pos))
+ start)))))
+
+(defun comment-search-backward (&optional limit noerror)
+ "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."
+ ;; 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
+ ;; comment-set-column) and to find the comment-start string (via
+ ;; comment-beginning) in indent-new-comment-line, it should be harmless.
+ (if (not (re-search-backward comment-start-skip limit t))
+ (unless noerror (error "No comment"))
+ (beginning-of-line)
+ (let* ((end (match-end 0))
+ (cs (comment-search-forward end t))
+ (pt (point)))
+ (if (not cs)
+ (progn (beginning-of-line)
+ (comment-search-backward limit noerror))
+ (while (progn (goto-char cs)
+ (comment-forward)
+ (and (< (point) end)
+ (setq cs (comment-search-forward end t))))
+ (setq pt (point)))
+ (goto-char pt)
+ cs))))
+
+(defun comment-beginning ()
+ "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)))))
+
+(defun comment-forward (&optional n)
+ "Skip forward over N comments.
+Just like `forward-comment' but only for positive N
+and can use regexps instead of syntax."
+ (setq n (or n 1))
+ (if (< n 0) (error "No comment-backward")
+ (if comment-use-syntax (forward-comment n)
+ (while (> n 0)
+ (setq n
+ (if (or (forward-comment 1)
+ (and (looking-at comment-start-skip)
+ (goto-char (match-end 0))
+ (re-search-forward comment-end-skip nil 'move)))
+ (1- n) -1)))
+ (= n 0))))
+
+(defun comment-enter-backward ()
+ "Move from the end of a comment to the end of its content.
+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 " "))))))
+
+;;;;
+;;;; Commands
+;;;;
+
+;;;###autoload
+(defun comment-indent-default ()
+ "Default for `comment-indent-function'."
+ (if (and (looking-at "\\s<\\s<\\(\\s<\\)?")
+ (or (match-end 1) (/= (current-column) (current-indentation))))
+ 0
+ (when (or (/= (current-column) (current-indentation))
+ (and (> comment-add 0) (looking-at "\\s<\\(\\S<\\|\\'\\)")))
+ comment-column)))
+
+;;;###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-continue' markers if any."