;;; newcomment.el --- (un)comment regions of buffers
-;; Copyright (C) 1999, 2000 Free Software Foundation Inc.
+;; Copyright (C) 1999,2000,2003 Free Software Foundation Inc.
;; Author: code extracted from Emacs-20's simple.el
;; Maintainer: Stefan Monnier <monnier@cs.yale.edu>
;; - nested comments in sgml-mode are not properly quoted.
;; - single-char nestable comment-start can only do the "\\s<+" stuff
;; if the corresponding closing marker happens to be right.
-;; - comment-box in TeXinfo generate bogus comments @ccccc@
;; - uncomment-region with a numeric argument can render multichar
;; comment markers invalid.
;; - comment-indent or comment-region when called inside a comment
;;;###autoload
(defalias 'indent-new-comment-line 'comment-indent-new-line)
-;;;###autoload
(defgroup comment nil
"Indenting and filling of comments."
:prefix "comment-"
:version "21.1"
:group 'fill)
+;; Autoload this to avoid warnings, since some major modes define it.
+;;;###autoload
(defvar comment-use-syntax 'undecided
"Non-nil if syntax-tables can be used instead of regexps.
Can also be `undecided' which means that a somewhat expensive test will
This is obsolete because you might as well use \\[newline-and-indent]."
:type 'boolean)
+(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)))
+
;;;;
;;;; Helpers
;;;;
;;;###autoload
(defun comment-normalize-vars (&optional noerror)
- (if (not comment-start) (or noerror (error "No comment syntax is defined"))
+ "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."
+ (if (not comment-start)
+ (unless noerror
+ (set (make-local-variable 'comment-start)
+ (read-string "No comment syntax is defined. Use: ")))
;; comment-use-syntax
(when (eq comment-use-syntax 'undecided)
(set (make-local-variable 'comment-use-syntax)
;; 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<+\\|"
+ (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-.
(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 "+" "*")
;; 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)
+ ;; Ensure there's a space before the comment for things
+ ;; like sh where it matters (as well as being neater).
+ (unless (memq (char-before) '(nil ?\n ?\t ?\ ))
+ (insert ?\ ))
(setq begpos (point))
(insert starter)
(setq cpos (point-marker))
;; Compute desired indent.
(setq indent (save-excursion (funcall comment-indent-function)))
(if (not indent)
- ;; comment-indent-function refuses: delegate to indent.
+ ;; comment-indent-function refuses: delegate to line-indent.
(indent-according-to-mode)
;; Avoid moving comments past the fill-column.
(unless (save-excursion (skip-chars-backward " \t") (bolp))
- (setq indent
- (min indent
- (+ (current-column)
+ (let ((max (+ (current-column)
(- (or comment-fill-column fill-column)
- (save-excursion (end-of-line) (current-column)))))))
+ (save-excursion (end-of-line) (current-column))))))
+ (if (<= max indent)
+ (setq indent max) ;Don't move past the fill column.
+ ;; We can choose anywhere between indent..max.
+ ;; Let's try to align to a comment on the previous line.
+ (let ((other nil))
+ (save-excursion
+ (when (and (zerop (forward-line -1))
+ (setq other (comment-search-forward
+ (line-end-position) t)))
+ (goto-char other) (setq other (current-column))))
+ (if (and other (<= other max) (> other indent))
+ ;; There is a comment and it's in the range: bingo.
+ (setq indent other)
+ ;; Let's try to align to a comment on the next line, then.
+ (let ((other nil))
+ (save-excursion
+ (when (and (zerop (forward-line 1))
+ (setq other (comment-search-forward
+ (line-end-position) t)))
+ (goto-char other) (setq other (current-column))))
+ (if (and other (<= other max) (> other indent))
+ ;; There is a comment and it's in the range: bingo.
+ (setq indent other))))))))
(unless (= (current-column) indent)
;; If that's different from current, change it.
(delete-region (point) (progn (skip-chars-backward " \t") (point)))
(cond
((eq arg '-) (comment-kill nil))
(arg
+ (comment-normalize-vars)
(save-excursion
(beginning-of-line)
(comment-search-backward)
"Kill the comment on this line, if any.
With prefix ARG, kill comments on that many lines starting with this one."
(interactive "P")
+ (comment-normalize-vars)
(dotimes (_ (prefix-numeric-value arg))
(save-excursion
(beginning-of-line)
;;;###autoload
(defun uncomment-region (beg end &optional arg)
- "Uncomment each line in the BEG..END region.
+ "Uncomment each line in the BEG .. END region.
The numeric prefix ARG can specify a number of chars to remove from the
comment markers."
(interactive "*r\nP")
(save-excursion
(goto-char beg)
(setq end (copy-marker end))
- (let ((numarg (prefix-numeric-value arg))
- spt)
+ (let* ((numarg (prefix-numeric-value arg))
+ (ccs comment-continue)
+ (srei (comment-padright ccs 're))
+ (csre (comment-padright comment-start 're))
+ (sre (and srei (concat "^\\s-*?\\(" srei "\\)")))
+ spt)
(while (and (< (point) end)
(setq spt (comment-search-forward end t)))
- (let* ((ipt (point))
- ;; Find the end of the comment.
- (ept (progn
- (goto-char spt)
- (unless (comment-forward)
- (error "Can't find the comment end"))
- (point)))
- (box nil)
- (ccs comment-continue)
- (srei (comment-padright ccs 're))
- (sre (and srei (concat "^\\s-*?\\(" srei "\\)"))))
+ (let ((ipt (point))
+ ;; Find the end of the comment.
+ (ept (progn
+ (goto-char spt)
+ (unless (comment-forward)
+ (error "Can't find the comment end"))
+ (point)))
+ (box nil)
+ (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 " ")
- ;; Check for special `=' used sometimes in comment-box.
- (when (and (= (- (point) (point-min)) 1) (looking-at "=\\{7\\}"))
- (skip-chars-forward "="))
;; A box-comment starts with a looong comment-start marker.
- (when (> (- (point) (point-min) (length comment-start)) 7)
+ (when (and (or (and (= (- (point) (point-min)) 1)
+ (setq box-equal t)
+ (looking-at "=\\{7\\}")
+ (not (eq (char-before (point-max)) ?\n))
+ (skip-chars-forward "="))
+ (> (- (point) (point-min) (length comment-start)) 7))
+ (> (count-lines (point-min) (point-max)) 2))
(setq box t))
- (when (looking-at (regexp-quote comment-padding))
- (goto-char (match-end 0)))
+ ;; Skip the padding. Padding can come from comment-padding and/or
+ ;; from comment-start, so we first check comment-start.
+ (if (or (save-excursion (goto-char (point-min)) (looking-at csre))
+ (looking-at (regexp-quote comment-padding)))
+ (goto-char (match-end 0)))
(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)))
+ (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))))
;; Remove the end-comment (and leading padding and such).
(goto-char (point-max)) (comment-enter-backward)
;; Check for special `=' used sometimes in comment-box.
- (when (= (- (point-max) (point)) 1)
+ (when (and box-equal (not (eq (char-before (point-max)) ?\n)))
(let ((pos (point)))
;; skip `=' but only if there are at least 7.
(when (> (skip-chars-backward "=") -7) (goto-char pos))))
(when (and (bolp) (not (bobp))) (backward-char))
(if (null arg) (delete-region (point) (point-max))
(skip-syntax-forward " ")
- (delete-char numarg)))
+ (delete-char numarg)
+ (unless (or (eobp) (looking-at comment-end-skip))
+ ;; If there's something left but it doesn't look like
+ ;; a comment-end any more, just remove it.
+ (delete-region (point) (point-max)))))
;; Unquote any nested end-comment.
(comment-quote-nested comment-start comment-end t)
(cons (concat cs "\n" (make-string min-indent ? ) ccs)
(concat cce "\n" (make-string (+ min-indent eindent) ? ) ce))))
-(def-edebug-spec comment-with-narrowing t)
-(put 'comment-with-narrowing 'lisp-indent-function 2)
(defmacro comment-with-narrowing (beg end &rest body)
"Execute BODY with BEG..END narrowing.
Space is added (and then removed) at the beginning for the text's
indentation to be kept as it was before narrowing."
+ (declare (debug t) (indent 2))
(let ((bindent (make-symbol "bindent")))
- `(let ((,bindent (save-excursion (goto-char beg) (current-column))))
+ `(let ((,bindent (save-excursion (goto-char ,beg) (current-column))))
(save-restriction
- (narrow-to-region beg end)
+ (narrow-to-region ,beg ,end)
(goto-char (point-min))
(insert (make-string ,bindent ? ))
(prog1
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 t))
+ (let ((no-empty (not (or (eq comment-empty-lines t)
+ (and comment-empty-lines (zerop (length ce)))))))
;; Sanitize CE and CCE.
(if (and (stringp ce) (string= "" ce)) (setq ce nil))
(if (and (stringp cce) (string= "" cce)) (setq cce nil))
(unless block (setq cce nil))
;; Continuation defaults to the same as CS and CE.
(unless ccs (setq ccs cs cce ce))
-
+
(save-excursion
(goto-char end)
;; If the end is not at the end of a line and the comment-end
(end-of-line)
(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))
cs ce ccs cce min-indent max-indent block)))
(setq cs (car csce))
(setq ce (cdr csce))))
-
+
(goto-char (point-min))
;; Loop over all lines from BEG to END.
(while
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))
This has no effect in modes that do not define a comment syntax."
:type 'boolean)
-(defun comment-valid-prefix (prefix compos)
+(defun comment-valid-prefix-p (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)))
+ prefix)))
;;;###autoload
(defun comment-indent-new-line (&optional soft)
;; a comment and the prefix is not a comment starter.
((and fill-prefix
(or (not compos)
- (comment-valid-prefix fill-prefix compos)))
+ (comment-valid-prefix-p fill-prefix compos)))
(indent-to-left-margin)
(insert-and-inherit fill-prefix))
;; If we're not inside a comment, just try to indent.
(provide 'newcomment)
+;;; arch-tag: 01e3320a-00c8-44ea-a696-8f8e7354c858
;;; newcomment.el ends here