| 1 | ;;; newcomment.el --- (un)comment regions of buffers -*- lexical-binding: t -*- |
| 2 | |
| 3 | ;; Copyright (C) 1999-2014 Free Software Foundation, Inc. |
| 4 | |
| 5 | ;; Author: code extracted from Emacs-20's simple.el |
| 6 | ;; Maintainer: Stefan Monnier <monnier@iro.umontreal.ca> |
| 7 | ;; Keywords: comment uncomment |
| 8 | ;; Package: emacs |
| 9 | |
| 10 | ;; This file is part of GNU Emacs. |
| 11 | |
| 12 | ;; GNU Emacs is free software: you can redistribute it and/or modify |
| 13 | ;; it under the terms of the GNU General Public License as published by |
| 14 | ;; the Free Software Foundation, either version 3 of the License, or |
| 15 | ;; (at your option) any later version. |
| 16 | |
| 17 | ;; GNU Emacs is distributed in the hope that it will be useful, |
| 18 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 19 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 20 | ;; GNU General Public License for more details. |
| 21 | |
| 22 | ;; You should have received a copy of the GNU General Public License |
| 23 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
| 24 | |
| 25 | ;;; Commentary: |
| 26 | |
| 27 | ;; This library contains functions and variables for commenting and |
| 28 | ;; uncommenting source code. |
| 29 | |
| 30 | ;; Prior to calling any `comment-*' function, you should ensure that |
| 31 | ;; `comment-normalize-vars' is first called to set up the appropriate |
| 32 | ;; variables; except for the `comment-*' commands, which call |
| 33 | ;; `comment-normalize-vars' automatically as a subroutine. |
| 34 | |
| 35 | ;;; Bugs: |
| 36 | |
| 37 | ;; - boxed comments in Perl are not properly uncommented because they are |
| 38 | ;; uncommented one-line at a time. |
| 39 | ;; - nested comments in sgml-mode are not properly quoted. |
| 40 | ;; - single-char nestable comment-start can only do the "\\s<+" stuff |
| 41 | ;; if the corresponding closing marker happens to be right. |
| 42 | ;; - uncomment-region with a numeric argument can render multichar |
| 43 | ;; comment markers invalid. |
| 44 | ;; - comment-indent or comment-region when called inside a comment |
| 45 | ;; will happily break the surrounding comment. |
| 46 | ;; - comment-quote-nested will not (un)quote properly all nested comment |
| 47 | ;; markers if there are more than just comment-start and comment-end. |
| 48 | ;; For example, in Pascal where {...*) and (*...} are possible. |
| 49 | |
| 50 | ;;; Todo: |
| 51 | |
| 52 | ;; - rebox.el-style refill. |
| 53 | ;; - quantized steps in comment-alignment. |
| 54 | ;; - try to align tail comments. |
| 55 | ;; - check what c-comment-line-break-function has to say. |
| 56 | ;; - spill auto-fill of comments onto the end of the next line. |
| 57 | ;; - uncomment-region with a consp (for blocks) or somehow make the |
| 58 | ;; deletion of continuation markers less dangerous. |
| 59 | ;; - drop block-comment-<foo> unless it's really used. |
| 60 | ;; - uncomment-region on a subpart of a comment. |
| 61 | ;; - support gnu-style "multi-line with space in continue". |
| 62 | ;; - somehow allow comment-dwim to use the region even if transient-mark-mode |
| 63 | ;; is not turned on. |
| 64 | |
| 65 | ;; - when auto-filling a comment, try to move the comment to the left |
| 66 | ;; rather than break it (if possible). |
| 67 | ;; - sometimes default the comment-column to the same |
| 68 | ;; one used on the preceding line(s). |
| 69 | |
| 70 | ;;; Code: |
| 71 | |
| 72 | ;;;###autoload |
| 73 | (defalias 'indent-for-comment 'comment-indent) |
| 74 | ;;;###autoload |
| 75 | (defalias 'set-comment-column 'comment-set-column) |
| 76 | ;;;###autoload |
| 77 | (defalias 'kill-comment 'comment-kill) |
| 78 | ;;;###autoload |
| 79 | (defalias 'indent-new-comment-line 'comment-indent-new-line) |
| 80 | |
| 81 | (defgroup comment nil |
| 82 | "Indenting and filling of comments." |
| 83 | :prefix "comment-" |
| 84 | :version "21.1" |
| 85 | :group 'fill) |
| 86 | |
| 87 | ;; Autoload this to avoid warnings, since some major modes define it. |
| 88 | ;;;###autoload |
| 89 | (defvar comment-use-syntax 'undecided |
| 90 | "Non-nil if syntax-tables can be used instead of regexps. |
| 91 | Can also be `undecided' which means that a somewhat expensive test will |
| 92 | be used to try to determine whether syntax-tables should be trusted |
| 93 | to understand comments or not in the given buffer. |
| 94 | Major modes should set this variable.") |
| 95 | |
| 96 | (defcustom comment-fill-column nil |
| 97 | "Column to use for `comment-indent'. If nil, use `fill-column' instead." |
| 98 | :type '(choice (const nil) integer) |
| 99 | :group 'comment) |
| 100 | |
| 101 | ;;;###autoload |
| 102 | (defcustom comment-column 32 |
| 103 | "Column to indent right-margin comments to. |
| 104 | Each mode may establish a different default value for this variable; you |
| 105 | can set the value for a particular mode using that mode's hook. |
| 106 | Comments might be indented to a different value in order not to go beyond |
| 107 | `comment-fill-column' or in order to align them with surrounding comments." |
| 108 | :type 'integer |
| 109 | :group 'comment) |
| 110 | (make-variable-buffer-local 'comment-column) |
| 111 | ;;;###autoload |
| 112 | (put 'comment-column 'safe-local-variable 'integerp) |
| 113 | |
| 114 | ;;;###autoload |
| 115 | (defvar comment-start nil |
| 116 | "String to insert to start a new comment, or nil if no comment syntax.") |
| 117 | ;;;###autoload |
| 118 | (put 'comment-start 'safe-local-variable 'string-or-null-p) |
| 119 | |
| 120 | ;;;###autoload |
| 121 | (defvar comment-start-skip nil |
| 122 | "Regexp to match the start of a comment plus everything up to its body. |
| 123 | If there are any \\(...\\) pairs and `comment-use-syntax' is nil, |
| 124 | the comment delimiter text is held to begin at the place matched |
| 125 | by the close of the first pair.") |
| 126 | ;;;###autoload |
| 127 | (put 'comment-start-skip 'safe-local-variable 'stringp) |
| 128 | |
| 129 | ;;;###autoload |
| 130 | (defvar comment-end-skip nil |
| 131 | "Regexp to match the end of a comment plus everything back to its body.") |
| 132 | ;;;###autoload |
| 133 | (put 'comment-end-skip 'safe-local-variable 'stringp) |
| 134 | |
| 135 | ;;;###autoload |
| 136 | (defvar comment-end (purecopy "") |
| 137 | "String to insert to end a new comment. |
| 138 | Should be an empty string if comments are terminated by end-of-line.") |
| 139 | ;;;###autoload |
| 140 | (put 'comment-end 'safe-local-variable 'stringp) |
| 141 | |
| 142 | ;;;###autoload |
| 143 | (defvar comment-indent-function 'comment-indent-default |
| 144 | "Function to compute desired indentation for a comment. |
| 145 | This function is called with no args with point at the beginning of |
| 146 | the comment's starting delimiter and should return either the desired |
| 147 | column indentation or nil. |
| 148 | If nil is returned, indentation is delegated to `indent-according-to-mode'.") |
| 149 | |
| 150 | ;;;###autoload |
| 151 | (defvar comment-insert-comment-function nil |
| 152 | "Function to insert a comment when a line doesn't contain one. |
| 153 | The function has no args. |
| 154 | |
| 155 | Applicable at least in modes for languages like fixed-format Fortran where |
| 156 | comments always start in column zero.") |
| 157 | |
| 158 | (defvar comment-region-function 'comment-region-default |
| 159 | "Function to comment a region. |
| 160 | Its args are the same as those of `comment-region', but BEG and END are |
| 161 | guaranteed to be correctly ordered. It is called within `save-excursion'. |
| 162 | |
| 163 | Applicable at least in modes for languages like fixed-format Fortran where |
| 164 | comments always start in column zero.") |
| 165 | |
| 166 | (defvar uncomment-region-function 'uncomment-region-default |
| 167 | "Function to uncomment a region. |
| 168 | Its args are the same as those of `uncomment-region', but BEG and END are |
| 169 | guaranteed to be correctly ordered. It is called within `save-excursion'. |
| 170 | |
| 171 | Applicable at least in modes for languages like fixed-format Fortran where |
| 172 | comments always start in column zero.") |
| 173 | |
| 174 | ;; ?? never set |
| 175 | (defvar block-comment-start nil) |
| 176 | (defvar block-comment-end nil) |
| 177 | |
| 178 | (defvar comment-quote-nested t |
| 179 | "Non-nil if nested comments should be quoted. |
| 180 | This should be locally set by each major mode if needed.") |
| 181 | |
| 182 | (defvar comment-continue nil |
| 183 | "Continuation string to insert for multiline comments. |
| 184 | This string will be added at the beginning of each line except the very |
| 185 | first one when commenting a region with a commenting style that allows |
| 186 | comments to span several lines. |
| 187 | It should generally have the same length as `comment-start' in order to |
| 188 | preserve indentation. |
| 189 | If it is nil a value will be automatically derived from `comment-start' |
| 190 | by replacing its first character with a space.") |
| 191 | |
| 192 | (defvar comment-add 0 |
| 193 | "How many more comment chars should be inserted by `comment-region'. |
| 194 | This determines the default value of the numeric argument of `comment-region'. |
| 195 | The `plain' comment style doubles this value. |
| 196 | |
| 197 | This should generally stay 0, except for a few modes like Lisp where |
| 198 | it is 1 so that regions are commented with two or three semi-colons.") |
| 199 | |
| 200 | ;;;###autoload |
| 201 | (defconst comment-styles |
| 202 | '((plain nil nil nil nil |
| 203 | "Start in column 0 (do not indent), as in Emacs-20") |
| 204 | (indent-or-triple nil nil nil multi-char |
| 205 | "Start in column 0, but only for single-char starters") |
| 206 | (indent nil nil nil t |
| 207 | "Full comment per line, ends not aligned") |
| 208 | (aligned nil t nil t |
| 209 | "Full comment per line, ends aligned") |
| 210 | (box nil t t t |
| 211 | "Full comment per line, ends aligned, + top and bottom") |
| 212 | (extra-line t nil t t |
| 213 | "One comment for all lines, end on a line by itself") |
| 214 | (multi-line t nil nil t |
| 215 | "One comment for all lines, end on last commented line") |
| 216 | (box-multi t t t t |
| 217 | "One comment for all lines, + top and bottom")) |
| 218 | "Comment region style definitions. |
| 219 | Each style is defined with a form (STYLE . (MULTI ALIGN EXTRA INDENT DOC)). |
| 220 | DOC should succinctly describe the style. |
| 221 | STYLE should be a mnemonic symbol. |
| 222 | MULTI specifies that comments are allowed to span multiple lines. |
| 223 | e.g. in C it comments regions as |
| 224 | /* blabla |
| 225 | * bli */ |
| 226 | rather than |
| 227 | /* blabla */ |
| 228 | /* bli */ |
| 229 | if `comment-end' is empty, this has no effect. |
| 230 | |
| 231 | ALIGN specifies that the `comment-end' markers should be aligned. |
| 232 | e.g. in C it comments regions as |
| 233 | /* blabla */ |
| 234 | /* bli */ |
| 235 | rather than |
| 236 | /* blabla */ |
| 237 | /* bli */ |
| 238 | if `comment-end' is empty, this has no effect, unless EXTRA is also set, |
| 239 | in which case the comment gets wrapped in a box. |
| 240 | |
| 241 | EXTRA specifies that an extra line should be used before and after the |
| 242 | region to comment (to put the `comment-end' and `comment-start'). |
| 243 | e.g. in C it comments regions as |
| 244 | /* |
| 245 | * blabla |
| 246 | * bli |
| 247 | */ |
| 248 | rather than |
| 249 | /* blabla |
| 250 | * bli */ |
| 251 | if the comment style is not multi line, this has no effect, unless ALIGN |
| 252 | is also set, in which case the comment gets wrapped in a box. |
| 253 | |
| 254 | INDENT specifies that the `comment-start' markers should not be put at the |
| 255 | left margin but at the current indentation of the region to comment. |
| 256 | If INDENT is `multi-char', that means indent multi-character |
| 257 | comment starters, but not one-character comment starters.") |
| 258 | |
| 259 | ;;;###autoload |
| 260 | (defcustom comment-style 'indent |
| 261 | "Style to be used for `comment-region'. |
| 262 | See `comment-styles' for a list of available styles." |
| 263 | :type (if (boundp 'comment-styles) |
| 264 | `(choice |
| 265 | ,@(mapcar (lambda (s) |
| 266 | `(const :tag ,(format "%s: %s" (car s) (nth 5 s)) |
| 267 | ,(car s))) |
| 268 | comment-styles)) |
| 269 | 'symbol) |
| 270 | :version "23.1" |
| 271 | :group 'comment) |
| 272 | |
| 273 | ;;;###autoload |
| 274 | (defcustom comment-padding (purecopy " ") |
| 275 | "Padding string that `comment-region' puts between comment chars and text. |
| 276 | Can also be an integer which will be automatically turned into a string |
| 277 | of the corresponding number of spaces. |
| 278 | |
| 279 | Extra spacing between the comment characters and the comment text |
| 280 | makes the comment easier to read. Default is 1. nil means 0." |
| 281 | :type '(choice string integer (const nil)) |
| 282 | :group 'comment) |
| 283 | |
| 284 | (defcustom comment-inline-offset 1 |
| 285 | "Inline comments have to be preceded by at least this many spaces. |
| 286 | This is useful when style-conventions require a certain minimal offset. |
| 287 | Python's PEP8 for example recommends two spaces, so you could do: |
| 288 | |
| 289 | \(add-hook 'python-mode-hook |
| 290 | (lambda () (set (make-local-variable 'comment-inline-offset) 2))) |
| 291 | |
| 292 | See `comment-padding' for whole-line comments." |
| 293 | :version "24.3" |
| 294 | :type 'integer |
| 295 | :group 'comment) |
| 296 | |
| 297 | ;;;###autoload |
| 298 | (defcustom comment-multi-line nil |
| 299 | "Non-nil means `comment-indent-new-line' continues comments. |
| 300 | That is, it inserts no new terminator or starter. |
| 301 | This affects `auto-fill-mode', which is the main reason to |
| 302 | customize this variable. |
| 303 | |
| 304 | It also affects \\[indent-new-comment-line]. However, if you want this |
| 305 | behavior for explicit filling, you might as well use \\[newline-and-indent]." |
| 306 | :type 'boolean |
| 307 | :group 'comment) |
| 308 | |
| 309 | (defcustom comment-empty-lines nil |
| 310 | "If nil, `comment-region' does not comment out empty lines. |
| 311 | If t, it always comments out empty lines. |
| 312 | If `eol' it only comments out empty lines if comments are |
| 313 | terminated by the end of line (i.e. `comment-end' is empty)." |
| 314 | :type '(choice (const :tag "Never" nil) |
| 315 | (const :tag "Always" t) |
| 316 | (const :tag "EOl-terminated" eol)) |
| 317 | :group 'comment) |
| 318 | |
| 319 | ;;;; |
| 320 | ;;;; Helpers |
| 321 | ;;;; |
| 322 | |
| 323 | (defun comment-string-strip (str beforep afterp) |
| 324 | "Strip STR of any leading (if BEFOREP) and/or trailing (if AFTERP) space." |
| 325 | (string-match (concat "\\`" (if beforep "\\s-*") |
| 326 | "\\(.*?\\)" (if afterp "\\s-*\n?") |
| 327 | "\\'") str) |
| 328 | (match-string 1 str)) |
| 329 | |
| 330 | (defun comment-string-reverse (s) |
| 331 | "Return the mirror image of string S, without any trailing space." |
| 332 | (comment-string-strip (concat (nreverse (string-to-list s))) nil t)) |
| 333 | |
| 334 | ;;;###autoload |
| 335 | (defun comment-normalize-vars (&optional noerror) |
| 336 | "Check and set up variables needed by other commenting functions. |
| 337 | All the `comment-*' commands call this function to set up various |
| 338 | variables, like `comment-start', to ensure that the commenting |
| 339 | functions work correctly. Lisp callers of any other `comment-*' |
| 340 | function should first call this function explicitly." |
| 341 | (unless (and (not comment-start) noerror) |
| 342 | (unless comment-start |
| 343 | (let ((cs (read-string "No comment syntax is defined. Use: "))) |
| 344 | (if (zerop (length cs)) |
| 345 | (error "No comment syntax defined") |
| 346 | (set (make-local-variable 'comment-start) cs) |
| 347 | (set (make-local-variable 'comment-start-skip) cs)))) |
| 348 | ;; comment-use-syntax |
| 349 | (when (eq comment-use-syntax 'undecided) |
| 350 | (set (make-local-variable 'comment-use-syntax) |
| 351 | (let ((st (syntax-table)) |
| 352 | (cs comment-start) |
| 353 | (ce (if (string= "" comment-end) "\n" comment-end))) |
| 354 | ;; Try to skip over a comment using forward-comment |
| 355 | ;; to see if the syntax tables properly recognize it. |
| 356 | (with-temp-buffer |
| 357 | (set-syntax-table st) |
| 358 | (insert cs " hello " ce) |
| 359 | (goto-char (point-min)) |
| 360 | (and (forward-comment 1) (eobp)))))) |
| 361 | ;; comment-padding |
| 362 | (unless comment-padding (setq comment-padding 0)) |
| 363 | (when (integerp comment-padding) |
| 364 | (setq comment-padding (make-string comment-padding ? ))) |
| 365 | ;; comment markers |
| 366 | ;;(setq comment-start (comment-string-strip comment-start t nil)) |
| 367 | ;;(setq comment-end (comment-string-strip comment-end nil t)) |
| 368 | ;; comment-continue |
| 369 | (unless (or comment-continue (string= comment-end "")) |
| 370 | (set (make-local-variable 'comment-continue) |
| 371 | (concat (if (string-match "\\S-\\S-" comment-start) " " "|") |
| 372 | (substring comment-start 1))) |
| 373 | ;; Hasn't been necessary yet. |
| 374 | ;; (unless (string-match comment-start-skip comment-continue) |
| 375 | ;; (kill-local-variable 'comment-continue)) |
| 376 | ) |
| 377 | ;; comment-skip regexps |
| 378 | (unless (and comment-start-skip |
| 379 | ;; In case comment-start has changed since last time. |
| 380 | (string-match comment-start-skip comment-start)) |
| 381 | (set (make-local-variable 'comment-start-skip) |
| 382 | (concat (unless (eq comment-use-syntax t) |
| 383 | ;; `syntax-ppss' will detect escaping. |
| 384 | "\\(\\(^\\|[^\\\n]\\)\\(\\\\\\\\\\)*\\)") |
| 385 | "\\(\\s<+\\|" |
| 386 | (regexp-quote (comment-string-strip comment-start t t)) |
| 387 | ;; Let's not allow any \s- but only [ \t] since \n |
| 388 | ;; might be both a comment-end marker and \s-. |
| 389 | "+\\)[ \t]*"))) |
| 390 | (unless (and comment-end-skip |
| 391 | ;; In case comment-end has changed since last time. |
| 392 | (string-match comment-end-skip |
| 393 | (if (string= "" comment-end) "\n" comment-end))) |
| 394 | (let ((ce (if (string= "" comment-end) "\n" |
| 395 | (comment-string-strip comment-end t t)))) |
| 396 | (set (make-local-variable 'comment-end-skip) |
| 397 | ;; We use [ \t] rather than \s- because we don't want to |
| 398 | ;; remove ^L in C mode when uncommenting. |
| 399 | (concat "[ \t]*\\(\\s>" (if comment-quote-nested "" "+") |
| 400 | "\\|" (regexp-quote (substring ce 0 1)) |
| 401 | (if (and comment-quote-nested (<= (length ce) 1)) "" "+") |
| 402 | (regexp-quote (substring ce 1)) |
| 403 | "\\)")))))) |
| 404 | |
| 405 | (defun comment-quote-re (str unp) |
| 406 | (concat (regexp-quote (substring str 0 1)) |
| 407 | "\\\\" (if unp "+" "*") |
| 408 | (regexp-quote (substring str 1)))) |
| 409 | |
| 410 | (defun comment-quote-nested (cs ce unp) |
| 411 | "Quote or unquote nested comments. |
| 412 | If UNP is non-nil, unquote nested comment markers." |
| 413 | (setq cs (comment-string-strip cs t t)) |
| 414 | (setq ce (comment-string-strip ce t t)) |
| 415 | (when (and comment-quote-nested (> (length ce) 0)) |
| 416 | (let ((re (concat (comment-quote-re ce unp) |
| 417 | "\\|" (comment-quote-re cs unp)))) |
| 418 | (goto-char (point-min)) |
| 419 | (while (re-search-forward re nil t) |
| 420 | (goto-char (match-beginning 0)) |
| 421 | (forward-char 1) |
| 422 | (if unp (delete-char 1) (insert "\\")) |
| 423 | (when (= (length ce) 1) |
| 424 | ;; If the comment-end is a single char, adding a \ after that |
| 425 | ;; "first" char won't deactivate it, so we turn such a CE |
| 426 | ;; into !CS. I.e. for pascal, we turn } into !{ |
| 427 | (if (not unp) |
| 428 | (when (string= (match-string 0) ce) |
| 429 | (replace-match (concat "!" cs) t t)) |
| 430 | (when (and (< (point-min) (match-beginning 0)) |
| 431 | (string= (buffer-substring (1- (match-beginning 0)) |
| 432 | (1- (match-end 0))) |
| 433 | (concat "!" cs))) |
| 434 | (backward-char 2) |
| 435 | (delete-char (- (match-end 0) (match-beginning 0))) |
| 436 | (insert ce)))))))) |
| 437 | |
| 438 | ;;;; |
| 439 | ;;;; Navigation |
| 440 | ;;;; |
| 441 | |
| 442 | (defvar comment-use-global-state t |
| 443 | "Non-nil means that the global syntactic context is used. |
| 444 | More specifically, it means that `syntax-ppss' is used to find out whether |
| 445 | point is within a string or not. Major modes whose syntax is not faithfully |
| 446 | described by the syntax-tables (or where `font-lock-syntax-table' is radically |
| 447 | different from the main syntax table) can set this to nil, |
| 448 | then `syntax-ppss' cache won't be used in comment-related routines.") |
| 449 | |
| 450 | (make-obsolete-variable 'comment-use-global-state 'comment-use-syntax "24.4") |
| 451 | |
| 452 | (defun comment-search-forward (limit &optional noerror) |
| 453 | "Find a comment start between point and LIMIT. |
| 454 | Moves point to inside the comment and returns the position of the |
| 455 | comment-starter. If no comment is found, moves point to LIMIT |
| 456 | and raises an error or returns nil if NOERROR is non-nil. |
| 457 | |
| 458 | Ensure that `comment-normalize-vars' has been called before you use this." |
| 459 | (if (not comment-use-syntax) |
| 460 | (if (re-search-forward comment-start-skip limit noerror) |
| 461 | (or (match-end 1) (match-beginning 0)) |
| 462 | (goto-char limit) |
| 463 | (unless noerror (error "No comment"))) |
| 464 | (let* ((pt (point)) |
| 465 | ;; Assume (at first) that pt is outside of any string. |
| 466 | (s (parse-partial-sexp pt (or limit (point-max)) nil nil |
| 467 | (if comment-use-global-state (syntax-ppss pt)) |
| 468 | t))) |
| 469 | (when (and (nth 8 s) (nth 3 s) (not comment-use-global-state)) |
| 470 | ;; The search ended at eol inside a string. Try to see if it |
| 471 | ;; works better when we assume that pt is inside a string. |
| 472 | (setq s (parse-partial-sexp |
| 473 | pt (or limit (point-max)) nil nil |
| 474 | (list nil nil nil (nth 3 s) nil nil nil nil) |
| 475 | t))) |
| 476 | (if (or (not (and (nth 8 s) (not (nth 3 s)))) |
| 477 | ;; Make sure the comment starts after PT. |
| 478 | (< (nth 8 s) pt)) |
| 479 | (unless noerror (error "No comment")) |
| 480 | ;; We found the comment. |
| 481 | (let ((pos (point)) |
| 482 | (start (nth 8 s)) |
| 483 | (bol (line-beginning-position)) |
| 484 | (end nil)) |
| 485 | (while (and (null end) (>= (point) bol)) |
| 486 | (if (looking-at comment-start-skip) |
| 487 | (setq end (min (or limit (point-max)) (match-end 0))) |
| 488 | (backward-char))) |
| 489 | (goto-char (or end pos)) |
| 490 | start))))) |
| 491 | |
| 492 | (defun comment-search-backward (&optional limit noerror) |
| 493 | "Find a comment start between LIMIT and point. |
| 494 | Moves point to inside the comment and returns the position of the |
| 495 | comment-starter. If no comment is found, moves point to LIMIT |
| 496 | and raises an error or returns nil if NOERROR is non-nil. |
| 497 | |
| 498 | Ensure that `comment-normalize-vars' has been called before you use this." |
| 499 | ;; FIXME: If a comment-start appears inside a comment, we may erroneously |
| 500 | ;; stop there. This can be rather bad in general, but since |
| 501 | ;; comment-search-backward is only used to find the comment-column (in |
| 502 | ;; comment-set-column) and to find the comment-start string (via |
| 503 | ;; comment-beginning) in indent-new-comment-line, it should be harmless. |
| 504 | (if (not (re-search-backward comment-start-skip limit t)) |
| 505 | (unless noerror (error "No comment")) |
| 506 | (beginning-of-line) |
| 507 | (let* ((end (match-end 0)) |
| 508 | (cs (comment-search-forward end t)) |
| 509 | (pt (point))) |
| 510 | (if (not cs) |
| 511 | (progn (beginning-of-line) |
| 512 | (comment-search-backward limit noerror)) |
| 513 | (while (progn (goto-char cs) |
| 514 | (comment-forward) |
| 515 | (and (< (point) end) |
| 516 | (setq cs (comment-search-forward end t)))) |
| 517 | (setq pt (point))) |
| 518 | (goto-char pt) |
| 519 | cs)))) |
| 520 | |
| 521 | (defun comment-beginning () |
| 522 | "Find the beginning of the enclosing comment. |
| 523 | Returns nil if not inside a comment, else moves point and returns |
| 524 | the same as `comment-search-backward'." |
| 525 | (if (and comment-use-syntax comment-use-global-state) |
| 526 | (let ((state (syntax-ppss))) |
| 527 | (when (nth 4 state) |
| 528 | (goto-char (nth 8 state)) |
| 529 | (prog1 (point) |
| 530 | (when (save-restriction |
| 531 | ;; `comment-start-skip' sometimes checks that the |
| 532 | ;; comment char is not escaped. (Bug#16971) |
| 533 | (narrow-to-region (point) (point-max)) |
| 534 | (looking-at comment-start-skip)) |
| 535 | (goto-char (match-end 0)))))) |
| 536 | ;; Can't rely on the syntax table, let's guess based on font-lock. |
| 537 | (unless (eq (get-text-property (point) 'face) 'font-lock-string-face) |
| 538 | (let ((pt (point)) |
| 539 | (cs (comment-search-backward nil t))) |
| 540 | (when cs |
| 541 | (if (save-excursion |
| 542 | (goto-char cs) |
| 543 | (and |
| 544 | ;; For modes where comment-start and comment-end are the same, |
| 545 | ;; the search above may have found a `ce' rather than a `cs'. |
| 546 | (or (if comment-end-skip (not (looking-at comment-end-skip))) |
| 547 | ;; Maybe font-lock knows that it's a `cs'? |
| 548 | (eq (get-text-property (match-end 0) 'face) |
| 549 | 'font-lock-comment-face) |
| 550 | (unless (eq (get-text-property (point) 'face) |
| 551 | 'font-lock-comment-face) |
| 552 | ;; Let's assume it's a `cs' if we're on the same line. |
| 553 | (>= (line-end-position) pt))) |
| 554 | ;; Make sure that PT is not past the end of the comment. |
| 555 | (if (comment-forward 1) (> (point) pt) (eobp)))) |
| 556 | cs |
| 557 | (goto-char pt) |
| 558 | nil)))))) |
| 559 | |
| 560 | (defun comment-forward (&optional n) |
| 561 | "Skip forward over N comments. |
| 562 | Just like `forward-comment' but only for positive N |
| 563 | and can use regexps instead of syntax." |
| 564 | (setq n (or n 1)) |
| 565 | (if (< n 0) (error "No comment-backward") |
| 566 | (if comment-use-syntax (forward-comment n) |
| 567 | (while (> n 0) |
| 568 | (setq n |
| 569 | (if (or (forward-comment 1) |
| 570 | (and (looking-at comment-start-skip) |
| 571 | (goto-char (match-end 0)) |
| 572 | (re-search-forward comment-end-skip nil 'move))) |
| 573 | (1- n) -1))) |
| 574 | (= n 0)))) |
| 575 | |
| 576 | (defun comment-enter-backward () |
| 577 | "Move from the end of a comment to the end of its content. |
| 578 | Point is assumed to be just at the end of a comment." |
| 579 | (if (bolp) |
| 580 | ;; comment-end = "" |
| 581 | (progn (backward-char) (skip-syntax-backward " ")) |
| 582 | (cond |
| 583 | ((save-excursion |
| 584 | (save-restriction |
| 585 | (narrow-to-region (line-beginning-position) (point)) |
| 586 | (goto-char (point-min)) |
| 587 | (re-search-forward (concat comment-end-skip "\\'") nil t))) |
| 588 | (goto-char (match-beginning 0))) |
| 589 | ;; comment-end-skip not found probably because it was not set |
| 590 | ;; right. Since \\s> should catch the single-char case, let's |
| 591 | ;; check that we're looking at a two-char comment ender. |
| 592 | ((not (or (<= (- (point-max) (line-beginning-position)) 1) |
| 593 | (zerop (logand (car (syntax-after (- (point) 1))) |
| 594 | ;; Here we take advantage of the fact that |
| 595 | ;; the syntax class " " is encoded to 0, |
| 596 | ;; so " 4" gives us just the 4 bit. |
| 597 | (car (string-to-syntax " 4")))) |
| 598 | (zerop (logand (car (syntax-after (- (point) 2))) |
| 599 | (car (string-to-syntax " 3")))))) |
| 600 | (backward-char 2) |
| 601 | (skip-chars-backward (string (char-after))) |
| 602 | (skip-syntax-backward " ")) |
| 603 | ;; No clue what's going on: maybe we're really not right after the |
| 604 | ;; end of a comment. Maybe we're at the "end" because of EOB rather |
| 605 | ;; than because of a marker. |
| 606 | (t (skip-syntax-backward " "))))) |
| 607 | |
| 608 | ;;;; |
| 609 | ;;;; Commands |
| 610 | ;;;; |
| 611 | |
| 612 | ;;;###autoload |
| 613 | (defun comment-indent-default () |
| 614 | "Default for `comment-indent-function'." |
| 615 | (if (and (looking-at "\\s<\\s<\\(\\s<\\)?") |
| 616 | (or (match-end 1) (/= (current-column) (current-indentation)))) |
| 617 | 0 |
| 618 | (when (or (/= (current-column) (current-indentation)) |
| 619 | (and (> comment-add 0) (looking-at "\\s<\\(\\S<\\|\\'\\)"))) |
| 620 | comment-column))) |
| 621 | |
| 622 | (defun comment-choose-indent (&optional indent) |
| 623 | "Choose the indentation to use for a right-hand-side comment. |
| 624 | The criteria are (in this order): |
| 625 | - try to keep the comment's text within `comment-fill-column'. |
| 626 | - try to align with surrounding comments. |
| 627 | - prefer INDENT (or `comment-column' if nil). |
| 628 | Point is expected to be at the start of the comment." |
| 629 | (unless indent (setq indent comment-column)) |
| 630 | ;; Avoid moving comments past the fill-column. |
| 631 | (let ((max (+ (current-column) |
| 632 | (- (or comment-fill-column fill-column) |
| 633 | (save-excursion (end-of-line) (current-column))))) |
| 634 | (other nil) |
| 635 | (min (save-excursion (skip-chars-backward " \t") |
| 636 | (if (bolp) 0 (+ comment-inline-offset (current-column)))))) |
| 637 | ;; Fix up the range. |
| 638 | (if (< max min) (setq max min)) |
| 639 | ;; Don't move past the fill column. |
| 640 | (if (<= max indent) (setq indent max)) |
| 641 | ;; We can choose anywhere between min..max. |
| 642 | ;; Let's try to align to a comment on the previous line. |
| 643 | (save-excursion |
| 644 | (when (and (zerop (forward-line -1)) |
| 645 | (setq other (comment-search-forward |
| 646 | (line-end-position) t))) |
| 647 | (goto-char other) (setq other (current-column)))) |
| 648 | (if (and other (<= other max) (>= other min)) |
| 649 | ;; There is a comment and it's in the range: bingo! |
| 650 | other |
| 651 | ;; Can't align to a previous comment: let's try to align to comments |
| 652 | ;; on the following lines, then. These have not been re-indented yet, |
| 653 | ;; so we can't directly align ourselves with them. All we do is to try |
| 654 | ;; and choose an indentation point with which they will be able to |
| 655 | ;; align themselves. |
| 656 | (save-excursion |
| 657 | (while (and (zerop (forward-line 1)) |
| 658 | (setq other (comment-search-forward |
| 659 | (line-end-position) t))) |
| 660 | (goto-char other) |
| 661 | (let ((omax (+ (current-column) |
| 662 | (- (or comment-fill-column fill-column) |
| 663 | (save-excursion (end-of-line) (current-column))))) |
| 664 | (omin (save-excursion (skip-chars-backward " \t") |
| 665 | (1+ (current-column))))) |
| 666 | (if (and (>= omax min) (<= omin max)) |
| 667 | (progn (setq min (max omin min)) |
| 668 | (setq max (min omax max))) |
| 669 | ;; Can't align with this anyway, so exit the loop. |
| 670 | (goto-char (point-max)))))) |
| 671 | ;; Return the closest point to indent within min..max. |
| 672 | (max min (min max indent))))) |
| 673 | |
| 674 | ;;;###autoload |
| 675 | (defun comment-indent (&optional continue) |
| 676 | "Indent this line's comment to `comment-column', or insert an empty comment. |
| 677 | If CONTINUE is non-nil, use the `comment-continue' markers if any." |
| 678 | (interactive "*") |
| 679 | (comment-normalize-vars) |
| 680 | (let* ((empty (save-excursion (beginning-of-line) |
| 681 | (looking-at "[ \t]*$"))) |
| 682 | (starter (or (and continue comment-continue) |
| 683 | (and empty block-comment-start) comment-start)) |
| 684 | (ender (or (and continue comment-continue "") |
| 685 | (and empty block-comment-end) comment-end))) |
| 686 | (unless starter (error "No comment syntax defined")) |
| 687 | (beginning-of-line) |
| 688 | (let* ((eolpos (line-end-position)) |
| 689 | (begpos (comment-search-forward eolpos t)) |
| 690 | cpos indent) |
| 691 | (if (and comment-insert-comment-function (not begpos)) |
| 692 | ;; If no comment and c-i-c-f is set, let it do everything. |
| 693 | (funcall comment-insert-comment-function) |
| 694 | ;; An existing comment? |
| 695 | (if begpos |
| 696 | (progn |
| 697 | (if (and (not (looking-at "[\t\n ]")) |
| 698 | (looking-at comment-end-skip)) |
| 699 | ;; The comment is empty and we have skipped all its space |
| 700 | ;; and landed right before the comment-ender: |
| 701 | ;; Go back to the middle of the space. |
| 702 | (forward-char (/ (skip-chars-backward " \t") -2))) |
| 703 | (setq cpos (point-marker))) |
| 704 | ;; If none, insert one. |
| 705 | (save-excursion |
| 706 | ;; Some `comment-indent-function's insist on not moving |
| 707 | ;; comments that are in column 0, so we first go to the |
| 708 | ;; likely target column. |
| 709 | (indent-to comment-column) |
| 710 | ;; Ensure there's a space before the comment for things |
| 711 | ;; like sh where it matters (as well as being neater). |
| 712 | (unless (memq (char-before) '(nil ?\n ?\t ?\s)) |
| 713 | (insert ?\s)) |
| 714 | (setq begpos (point)) |
| 715 | (insert starter) |
| 716 | (setq cpos (point-marker)) |
| 717 | (insert ender))) |
| 718 | (goto-char begpos) |
| 719 | ;; Compute desired indent. |
| 720 | (setq indent (save-excursion (funcall comment-indent-function))) |
| 721 | ;; If `indent' is nil and there's code before the comment, we can't |
| 722 | ;; use `indent-according-to-mode', so we default to comment-column. |
| 723 | (unless (or indent (save-excursion (skip-chars-backward " \t") (bolp))) |
| 724 | (setq indent comment-column)) |
| 725 | (if (not indent) |
| 726 | ;; comment-indent-function refuses: delegate to line-indent. |
| 727 | (indent-according-to-mode) |
| 728 | ;; If the comment is at the right of code, adjust the indentation. |
| 729 | (unless (save-excursion (skip-chars-backward " \t") (bolp)) |
| 730 | (setq indent (comment-choose-indent indent))) |
| 731 | ;; Update INDENT to leave at least one space |
| 732 | ;; after other nonwhite text on the line. |
| 733 | (save-excursion |
| 734 | (skip-chars-backward " \t") |
| 735 | (unless (bolp) |
| 736 | (setq indent (max indent |
| 737 | (+ (current-column) comment-inline-offset))))) |
| 738 | ;; If that's different from comment's current position, change it. |
| 739 | (unless (= (current-column) indent) |
| 740 | (delete-region (point) (progn (skip-chars-backward " \t") (point))) |
| 741 | (indent-to indent))) |
| 742 | (goto-char cpos) |
| 743 | (set-marker cpos nil))))) |
| 744 | |
| 745 | ;;;###autoload |
| 746 | (defun comment-set-column (arg) |
| 747 | "Set the comment column based on point. |
| 748 | With no ARG, set the comment column to the current column. |
| 749 | With just minus as arg, kill any comment on this line. |
| 750 | With any other arg, set comment column to indentation of the previous comment |
| 751 | and then align or create a comment on this line at that column." |
| 752 | (interactive "P") |
| 753 | (cond |
| 754 | ((eq arg '-) (comment-kill nil)) |
| 755 | (arg |
| 756 | (comment-normalize-vars) |
| 757 | (save-excursion |
| 758 | (beginning-of-line) |
| 759 | (comment-search-backward) |
| 760 | (beginning-of-line) |
| 761 | (goto-char (comment-search-forward (line-end-position))) |
| 762 | (setq comment-column (current-column)) |
| 763 | (message "Comment column set to %d" comment-column)) |
| 764 | (comment-indent)) |
| 765 | (t (setq comment-column (current-column)) |
| 766 | (message "Comment column set to %d" comment-column)))) |
| 767 | |
| 768 | ;;;###autoload |
| 769 | (defun comment-kill (arg) |
| 770 | "Kill the first comment on this line, if any. |
| 771 | With prefix ARG, kill comments on that many lines starting with this one." |
| 772 | (interactive "P") |
| 773 | (comment-normalize-vars) |
| 774 | (dotimes (_i (prefix-numeric-value arg)) |
| 775 | (save-excursion |
| 776 | (beginning-of-line) |
| 777 | (let ((cs (comment-search-forward (line-end-position) t))) |
| 778 | (when cs |
| 779 | (goto-char cs) |
| 780 | (skip-syntax-backward " ") |
| 781 | (setq cs (point)) |
| 782 | (comment-forward) |
| 783 | (kill-region cs (if (bolp) (1- (point)) (point))) |
| 784 | (indent-according-to-mode)))) |
| 785 | (if arg (forward-line 1)))) |
| 786 | |
| 787 | (defun comment-padright (str &optional n) |
| 788 | "Construct a string composed of STR plus `comment-padding'. |
| 789 | It also adds N copies of the last non-whitespace chars of STR. |
| 790 | If STR already contains padding, the corresponding amount is |
| 791 | ignored from `comment-padding'. |
| 792 | N defaults to 0. |
| 793 | If N is `re', a regexp is returned instead, that would match |
| 794 | the string for any N." |
| 795 | (setq n (or n 0)) |
| 796 | (when (and (stringp str) (not (string= "" str))) |
| 797 | ;; Separate the actual string from any leading/trailing padding |
| 798 | (string-match "\\`\\s-*\\(.*?\\)\\s-*\\'" str) |
| 799 | (let ((s (match-string 1 str)) ;actual string |
| 800 | (lpad (substring str 0 (match-beginning 1))) ;left padding |
| 801 | (rpad (concat (substring str (match-end 1)) ;original right padding |
| 802 | (substring comment-padding ;additional right padding |
| 803 | (min (- (match-end 0) (match-end 1)) |
| 804 | (length comment-padding))))) |
| 805 | ;; We can only duplicate C if the comment-end has multiple chars |
| 806 | ;; or if comments can be nested, else the comment-end `}' would |
| 807 | ;; be turned into `}}}' where only the first ends the comment |
| 808 | ;; and the rest becomes bogus junk. |
| 809 | (multi (not (and comment-quote-nested |
| 810 | ;; comment-end is a single char |
| 811 | (string-match "\\`\\s-*\\S-\\s-*\\'" comment-end))))) |
| 812 | (if (not (symbolp n)) |
| 813 | (concat lpad s (when multi (make-string n (aref str (1- (match-end 1))))) rpad) |
| 814 | ;; construct a regexp that would match anything from just S |
| 815 | ;; to any possible output of this function for any N. |
| 816 | (concat (mapconcat (lambda (c) (concat (regexp-quote (string c)) "?")) |
| 817 | lpad "") ;padding is not required |
| 818 | (regexp-quote s) |
| 819 | (when multi "+") ;the last char of S might be repeated |
| 820 | (mapconcat (lambda (c) (concat (regexp-quote (string c)) "?")) |
| 821 | rpad "")))))) ;padding is not required |
| 822 | |
| 823 | (defun comment-padleft (str &optional n) |
| 824 | "Construct a string composed of `comment-padding' plus STR. |
| 825 | It also adds N copies of the first non-whitespace chars of STR. |
| 826 | If STR already contains padding, the corresponding amount is |
| 827 | ignored from `comment-padding'. |
| 828 | N defaults to 0. |
| 829 | If N is `re', a regexp is returned instead, that would match |
| 830 | the string for any N." |
| 831 | (setq n (or n 0)) |
| 832 | (when (and (stringp str) (not (string= "" str))) |
| 833 | ;; Only separate the left pad because we assume there is no right pad. |
| 834 | (string-match "\\`\\s-*" str) |
| 835 | (let ((s (substring str (match-end 0))) |
| 836 | (pad (concat (substring comment-padding |
| 837 | (min (- (match-end 0) (match-beginning 0)) |
| 838 | (length comment-padding))) |
| 839 | (match-string 0 str))) |
| 840 | (c (aref str (match-end 0))) ;the first non-space char of STR |
| 841 | ;; We can only duplicate C if the comment-end has multiple chars |
| 842 | ;; or if comments can be nested, else the comment-end `}' would |
| 843 | ;; be turned into `}}}' where only the first ends the comment |
| 844 | ;; and the rest becomes bogus junk. |
| 845 | (multi (not (and comment-quote-nested |
| 846 | ;; comment-end is a single char |
| 847 | (string-match "\\`\\s-*\\S-\\s-*\\'" comment-end))))) |
| 848 | (if (not (symbolp n)) |
| 849 | (concat pad (when multi (make-string n c)) s) |
| 850 | ;; Construct a regexp that would match anything from just S |
| 851 | ;; to any possible output of this function for any N. |
| 852 | ;; We match any number of leading spaces because this regexp will |
| 853 | ;; be used for uncommenting where we might want to remove |
| 854 | ;; uncomment markers with arbitrary leading space (because |
| 855 | ;; they were aligned). |
| 856 | (concat "\\s-*" |
| 857 | (if multi (concat (regexp-quote (string c)) "*")) |
| 858 | (regexp-quote s)))))) |
| 859 | |
| 860 | ;;;###autoload |
| 861 | (defun uncomment-region (beg end &optional arg) |
| 862 | "Uncomment each line in the BEG .. END region. |
| 863 | The numeric prefix ARG can specify a number of chars to remove from the |
| 864 | comment markers." |
| 865 | (interactive "*r\nP") |
| 866 | (comment-normalize-vars) |
| 867 | (when (> beg end) (setq beg (prog1 end (setq end beg)))) |
| 868 | ;; Bind `comment-use-global-state' to nil. While uncommenting a region |
| 869 | ;; (which works a line at a time), a comment can appear to be |
| 870 | ;; included in a mult-line string, but it is actually not. |
| 871 | (let ((comment-use-global-state nil)) |
| 872 | (save-excursion |
| 873 | (funcall uncomment-region-function beg end arg)))) |
| 874 | |
| 875 | (defun uncomment-region-default (beg end &optional arg) |
| 876 | "Uncomment each line in the BEG .. END region. |
| 877 | The numeric prefix ARG can specify a number of chars to remove from the |
| 878 | comment markers." |
| 879 | (goto-char beg) |
| 880 | (setq end (copy-marker end)) |
| 881 | (let* ((numarg (prefix-numeric-value arg)) |
| 882 | (ccs comment-continue) |
| 883 | (srei (comment-padright ccs 're)) |
| 884 | (csre (comment-padright comment-start 're)) |
| 885 | (sre (and srei (concat "^\\s-*?\\(" srei "\\)"))) |
| 886 | spt) |
| 887 | (while (and (< (point) end) |
| 888 | (setq spt (comment-search-forward end t))) |
| 889 | (let ((ipt (point)) |
| 890 | ;; Find the end of the comment. |
| 891 | (ept (progn |
| 892 | (goto-char spt) |
| 893 | (unless (or (comment-forward) |
| 894 | ;; Allow non-terminated comments. |
| 895 | (eobp)) |
| 896 | (error "Can't find the comment end")) |
| 897 | (point))) |
| 898 | (box nil) |
| 899 | (box-equal nil)) ;Whether we might be using `=' for boxes. |
| 900 | (save-restriction |
| 901 | (narrow-to-region spt ept) |
| 902 | |
| 903 | ;; Remove the comment-start. |
| 904 | (goto-char ipt) |
| 905 | (skip-syntax-backward " ") |
| 906 | ;; A box-comment starts with a looong comment-start marker. |
| 907 | (when (and (or (and (= (- (point) (point-min)) 1) |
| 908 | (setq box-equal t) |
| 909 | (looking-at "=\\{7\\}") |
| 910 | (not (eq (char-before (point-max)) ?\n)) |
| 911 | (skip-chars-forward "=")) |
| 912 | (> (- (point) (point-min) (length comment-start)) 7)) |
| 913 | (> (count-lines (point-min) (point-max)) 2)) |
| 914 | (setq box t)) |
| 915 | ;; Skip the padding. Padding can come from comment-padding and/or |
| 916 | ;; from comment-start, so we first check comment-start. |
| 917 | (if (or (save-excursion (goto-char (point-min)) (looking-at csre)) |
| 918 | (looking-at (regexp-quote comment-padding))) |
| 919 | (goto-char (match-end 0))) |
| 920 | (when (and sre (looking-at (concat "\\s-*\n\\s-*" srei))) |
| 921 | (goto-char (match-end 0))) |
| 922 | (if (null arg) (delete-region (point-min) (point)) |
| 923 | (let ((opoint (point-marker))) |
| 924 | (skip-syntax-backward " ") |
| 925 | (delete-char (- numarg)) |
| 926 | (unless (and (not (bobp)) |
| 927 | (save-excursion (goto-char (point-min)) |
| 928 | (looking-at comment-start-skip))) |
| 929 | ;; If there's something left but it doesn't look like |
| 930 | ;; a comment-start any more, just remove it. |
| 931 | (delete-region (point-min) opoint)))) |
| 932 | |
| 933 | ;; Remove the end-comment (and leading padding and such). |
| 934 | (goto-char (point-max)) (comment-enter-backward) |
| 935 | ;; Check for special `=' used sometimes in comment-box. |
| 936 | (when (and box-equal (not (eq (char-before (point-max)) ?\n))) |
| 937 | (let ((pos (point))) |
| 938 | ;; skip `=' but only if there are at least 7. |
| 939 | (when (> (skip-chars-backward "=") -7) (goto-char pos)))) |
| 940 | (unless (looking-at "\\(\n\\|\\s-\\)*\\'") |
| 941 | (when (and (bolp) (not (bobp))) (backward-char)) |
| 942 | (if (null arg) (delete-region (point) (point-max)) |
| 943 | (skip-syntax-forward " ") |
| 944 | (delete-char numarg) |
| 945 | (unless (or (eobp) (looking-at comment-end-skip)) |
| 946 | ;; If there's something left but it doesn't look like |
| 947 | ;; a comment-end any more, just remove it. |
| 948 | (delete-region (point) (point-max))))) |
| 949 | |
| 950 | ;; Unquote any nested end-comment. |
| 951 | (comment-quote-nested comment-start comment-end t) |
| 952 | |
| 953 | ;; Eliminate continuation markers as well. |
| 954 | (when sre |
| 955 | (let* ((cce (comment-string-reverse (or comment-continue |
| 956 | comment-start))) |
| 957 | (erei (and box (comment-padleft cce 're))) |
| 958 | (ere (and erei (concat "\\(" erei "\\)\\s-*$")))) |
| 959 | (goto-char (point-min)) |
| 960 | (while (progn |
| 961 | (if (and ere (re-search-forward |
| 962 | ere (line-end-position) t)) |
| 963 | (replace-match "" t t nil (if (match-end 2) 2 1)) |
| 964 | (setq ere nil)) |
| 965 | (forward-line 1) |
| 966 | (re-search-forward sre (line-end-position) t)) |
| 967 | (replace-match "" t t nil (if (match-end 2) 2 1))))) |
| 968 | ;; Go to the end for the next comment. |
| 969 | (goto-char (point-max)))))) |
| 970 | (set-marker end nil)) |
| 971 | |
| 972 | (defun comment-make-extra-lines (cs ce ccs cce min-indent max-indent &optional block) |
| 973 | "Make the leading and trailing extra lines. |
| 974 | This is used for `extra-line' style (or `box' style if BLOCK is specified)." |
| 975 | (let ((eindent 0)) |
| 976 | (if (not block) |
| 977 | ;; Try to match CS and CE's content so they align aesthetically. |
| 978 | (progn |
| 979 | (setq ce (comment-string-strip ce t t)) |
| 980 | (when (string-match "\\(.+\\).*\n\\(.*?\\)\\1" (concat ce "\n" cs)) |
| 981 | (setq eindent |
| 982 | (max (- (match-end 2) (match-beginning 2) (match-beginning 0)) |
| 983 | 0)))) |
| 984 | ;; box comment |
| 985 | (let* ((width (- max-indent min-indent)) |
| 986 | (s (concat cs "a=m" cce)) |
| 987 | (e (concat ccs "a=m" ce)) |
| 988 | (c (if (string-match ".*\\S-\\S-" cs) |
| 989 | (aref cs (1- (match-end 0))) |
| 990 | (if (and (equal comment-end "") (string-match ".*\\S-" cs)) |
| 991 | (aref cs (1- (match-end 0))) ?=))) |
| 992 | (re "\\s-*a=m\\s-*") |
| 993 | (_ (string-match re s)) |
| 994 | (lcs (length cs)) |
| 995 | (fill |
| 996 | (make-string (+ width (- (match-end 0) |
| 997 | (match-beginning 0) lcs 3)) c))) |
| 998 | (setq cs (replace-match fill t t s)) |
| 999 | (when (and (not (string-match comment-start-skip cs)) |
| 1000 | (string-match "a=m" s)) |
| 1001 | ;; The whitespace around CS cannot be ignored: put it back. |
| 1002 | (setq re "a=m") |
| 1003 | (setq fill (make-string (- width lcs) c)) |
| 1004 | (setq cs (replace-match fill t t s))) |
| 1005 | (string-match re e) |
| 1006 | (setq ce (replace-match fill t t e)))) |
| 1007 | (cons (concat cs "\n" (make-string min-indent ? ) ccs) |
| 1008 | (concat cce "\n" (make-string (+ min-indent eindent) ? ) ce)))) |
| 1009 | |
| 1010 | (defmacro comment-with-narrowing (beg end &rest body) |
| 1011 | "Execute BODY with BEG..END narrowing. |
| 1012 | Space is added (and then removed) at the beginning for the text's |
| 1013 | indentation to be kept as it was before narrowing." |
| 1014 | (declare (debug t) (indent 2)) |
| 1015 | (let ((bindent (make-symbol "bindent"))) |
| 1016 | `(let ((,bindent (save-excursion (goto-char ,beg) (current-column)))) |
| 1017 | (save-restriction |
| 1018 | (narrow-to-region ,beg ,end) |
| 1019 | (goto-char (point-min)) |
| 1020 | (insert (make-string ,bindent ? )) |
| 1021 | (prog1 |
| 1022 | (progn ,@body) |
| 1023 | ;; remove the bindent |
| 1024 | (save-excursion |
| 1025 | (goto-char (point-min)) |
| 1026 | (when (looking-at " *") |
| 1027 | (let ((n (min (- (match-end 0) (match-beginning 0)) ,bindent))) |
| 1028 | (delete-char n) |
| 1029 | (setq ,bindent (- ,bindent n)))) |
| 1030 | (end-of-line) |
| 1031 | (let ((e (point))) |
| 1032 | (beginning-of-line) |
| 1033 | (while (and (> ,bindent 0) (re-search-forward " *" e t)) |
| 1034 | (let ((n (min ,bindent (- (match-end 0) (match-beginning 0) 1)))) |
| 1035 | (goto-char (match-beginning 0)) |
| 1036 | (delete-char n) |
| 1037 | (setq ,bindent (- ,bindent n))))))))))) |
| 1038 | |
| 1039 | (defun comment-add (arg) |
| 1040 | "Compute the number of extra comment starter characters. |
| 1041 | \(Extra semicolons in Lisp mode, extra stars in C mode, etc.) |
| 1042 | If ARG is non-nil, just follow ARG. |
| 1043 | If the comment starter is multi-char, just follow ARG. |
| 1044 | Otherwise obey `comment-add'." |
| 1045 | (if (and (null arg) (= (string-match "[ \t]*\\'" comment-start) 1)) |
| 1046 | (* comment-add 1) |
| 1047 | (1- (prefix-numeric-value arg)))) |
| 1048 | |
| 1049 | (defun comment-region-internal (beg end cs ce |
| 1050 | &optional ccs cce block lines indent) |
| 1051 | "Comment region BEG .. END. |
| 1052 | CS and CE are the comment start string and comment end string, |
| 1053 | respectively. CCS and CCE are the comment continuation strings |
| 1054 | for the start and end of lines, respectively (default to CS and CE). |
| 1055 | BLOCK indicates that end of lines should be marked with either CCE, |
| 1056 | CE or CS \(if CE is empty) and that those markers should be aligned. |
| 1057 | LINES indicates that an extra lines will be used at the beginning |
| 1058 | and end of the region for CE and CS. |
| 1059 | INDENT indicates to put CS and CCS at the current indentation of |
| 1060 | the region rather than at left margin." |
| 1061 | ;;(assert (< beg end)) |
| 1062 | (let ((no-empty (not (or (eq comment-empty-lines t) |
| 1063 | (and comment-empty-lines (zerop (length ce)))))) |
| 1064 | ce-sanitized) |
| 1065 | ;; Sanitize CE and CCE. |
| 1066 | (if (and (stringp ce) (string= "" ce)) (setq ce nil)) |
| 1067 | (setq ce-sanitized ce) |
| 1068 | (if (and (stringp cce) (string= "" cce)) (setq cce nil)) |
| 1069 | ;; If CE is empty, multiline cannot be used. |
| 1070 | (unless ce (setq ccs nil cce nil)) |
| 1071 | ;; Should we mark empty lines as well ? |
| 1072 | (if (or ccs block lines) (setq no-empty nil)) |
| 1073 | ;; Make sure we have end-markers for BLOCK mode. |
| 1074 | (when block (unless ce (setq ce (comment-string-reverse cs)))) |
| 1075 | ;; If BLOCK is not requested, we don't need CCE. |
| 1076 | (unless block (setq cce nil)) |
| 1077 | ;; Continuation defaults to the same as CS and CE. |
| 1078 | (unless ccs (setq ccs cs cce ce)) |
| 1079 | |
| 1080 | (save-excursion |
| 1081 | (goto-char end) |
| 1082 | ;; If the end is not at the end of a line and the comment-end |
| 1083 | ;; is implicit (i.e. a newline), explicitly insert a newline. |
| 1084 | (unless (or ce-sanitized (eolp)) (insert "\n") (indent-according-to-mode)) |
| 1085 | (comment-with-narrowing beg end |
| 1086 | (let ((min-indent (point-max)) |
| 1087 | (max-indent 0)) |
| 1088 | (goto-char (point-min)) |
| 1089 | ;; Quote any nested comment marker |
| 1090 | (comment-quote-nested comment-start comment-end nil) |
| 1091 | |
| 1092 | ;; Loop over all lines to find the needed indentations. |
| 1093 | (goto-char (point-min)) |
| 1094 | (while |
| 1095 | (progn |
| 1096 | (unless (looking-at "[ \t]*$") |
| 1097 | (setq min-indent (min min-indent (current-indentation)))) |
| 1098 | (end-of-line) |
| 1099 | (setq max-indent (max max-indent (current-column))) |
| 1100 | (not (or (eobp) (progn (forward-line) nil))))) |
| 1101 | |
| 1102 | (setq max-indent |
| 1103 | (+ max-indent (max (length cs) (length ccs)) |
| 1104 | ;; Inserting ccs can change max-indent by (1- tab-width) |
| 1105 | ;; but only if there are TABs in the boxed text, of course. |
| 1106 | (if (save-excursion (goto-char beg) |
| 1107 | (search-forward "\t" end t)) |
| 1108 | (1- tab-width) 0))) |
| 1109 | (unless indent (setq min-indent 0)) |
| 1110 | |
| 1111 | ;; make the leading and trailing lines if requested |
| 1112 | (when lines |
| 1113 | (let ((csce |
| 1114 | (comment-make-extra-lines |
| 1115 | cs ce ccs cce min-indent max-indent block))) |
| 1116 | (setq cs (car csce)) |
| 1117 | (setq ce (cdr csce)))) |
| 1118 | |
| 1119 | (goto-char (point-min)) |
| 1120 | ;; Loop over all lines from BEG to END. |
| 1121 | (while |
| 1122 | (progn |
| 1123 | (unless (and no-empty (looking-at "[ \t]*$")) |
| 1124 | (move-to-column min-indent t) |
| 1125 | (insert cs) (setq cs ccs) ;switch to CCS after the first line |
| 1126 | (end-of-line) |
| 1127 | (if (eobp) (setq cce ce)) |
| 1128 | (when cce |
| 1129 | (when block (move-to-column max-indent t)) |
| 1130 | (insert cce))) |
| 1131 | (end-of-line) |
| 1132 | (not (or (eobp) (progn (forward-line) nil)))))))))) |
| 1133 | |
| 1134 | ;;;###autoload |
| 1135 | (defun comment-region (beg end &optional arg) |
| 1136 | "Comment or uncomment each line in the region. |
| 1137 | With just \\[universal-argument] prefix arg, uncomment each line in region BEG .. END. |
| 1138 | Numeric prefix ARG means use ARG comment characters. |
| 1139 | If ARG is negative, delete that many comment characters instead. |
| 1140 | |
| 1141 | The strings used as comment starts are built from `comment-start' |
| 1142 | and `comment-padding'; the strings used as comment ends are built |
| 1143 | from `comment-end' and `comment-padding'. |
| 1144 | |
| 1145 | By default, the `comment-start' markers are inserted at the |
| 1146 | current indentation of the region, and comments are terminated on |
| 1147 | each line (even for syntaxes in which newline does not end the |
| 1148 | comment and blank lines do not get comments). This can be |
| 1149 | changed with `comment-style'." |
| 1150 | (interactive "*r\nP") |
| 1151 | (comment-normalize-vars) |
| 1152 | (if (> beg end) (let (mid) (setq mid beg beg end end mid))) |
| 1153 | (save-excursion |
| 1154 | ;; FIXME: maybe we should call uncomment depending on ARG. |
| 1155 | (funcall comment-region-function beg end arg))) |
| 1156 | |
| 1157 | (defun comment-region-default (beg end &optional arg) |
| 1158 | (let* ((numarg (prefix-numeric-value arg)) |
| 1159 | (style (cdr (assoc comment-style comment-styles))) |
| 1160 | (lines (nth 2 style)) |
| 1161 | (block (nth 1 style)) |
| 1162 | (multi (nth 0 style))) |
| 1163 | |
| 1164 | ;; We use `chars' instead of `syntax' because `\n' might be |
| 1165 | ;; of end-comment syntax rather than of whitespace syntax. |
| 1166 | ;; sanitize BEG and END |
| 1167 | (goto-char beg) (skip-chars-forward " \t\n\r") (beginning-of-line) |
| 1168 | (setq beg (max beg (point))) |
| 1169 | (goto-char end) (skip-chars-backward " \t\n\r") (end-of-line) |
| 1170 | (setq end (min end (point))) |
| 1171 | (if (>= beg end) (error "Nothing to comment")) |
| 1172 | |
| 1173 | ;; sanitize LINES |
| 1174 | (setq lines |
| 1175 | (and |
| 1176 | lines ;; multi |
| 1177 | (progn (goto-char beg) (beginning-of-line) |
| 1178 | (skip-syntax-forward " ") |
| 1179 | (>= (point) beg)) |
| 1180 | (progn (goto-char end) (end-of-line) (skip-syntax-backward " ") |
| 1181 | (<= (point) end)) |
| 1182 | (or block (not (string= "" comment-end))) |
| 1183 | (or block (progn (goto-char beg) (search-forward "\n" end t))))) |
| 1184 | |
| 1185 | ;; don't add end-markers just because the user asked for `block' |
| 1186 | (unless (or lines (string= "" comment-end)) (setq block nil)) |
| 1187 | |
| 1188 | (cond |
| 1189 | ((consp arg) (uncomment-region beg end)) |
| 1190 | ((< numarg 0) (uncomment-region beg end (- numarg))) |
| 1191 | (t |
| 1192 | (let ((multi-char (/= (string-match "[ \t]*\\'" comment-start) 1)) |
| 1193 | indent triple) |
| 1194 | (if (eq (nth 3 style) 'multi-char) |
| 1195 | (save-excursion |
| 1196 | (goto-char beg) |
| 1197 | (setq indent multi-char |
| 1198 | ;; Triple if we will put the comment starter at the margin |
| 1199 | ;; and the first line of the region isn't indented |
| 1200 | ;; at least two spaces. |
| 1201 | triple (and (not multi-char) (looking-at "\t\\| ")))) |
| 1202 | (setq indent (nth 3 style))) |
| 1203 | |
| 1204 | ;; In Lisp and similar modes with one-character comment starters, |
| 1205 | ;; double it by default if `comment-add' says so. |
| 1206 | ;; If it isn't indented, triple it. |
| 1207 | (if (and (null arg) (not multi-char)) |
| 1208 | (setq numarg (* comment-add (if triple 2 1))) |
| 1209 | (setq numarg (1- (prefix-numeric-value arg)))) |
| 1210 | |
| 1211 | (comment-region-internal |
| 1212 | beg end |
| 1213 | (let ((s (comment-padright comment-start numarg))) |
| 1214 | (if (string-match comment-start-skip s) s |
| 1215 | (comment-padright comment-start))) |
| 1216 | (let ((s (comment-padleft comment-end numarg))) |
| 1217 | (and s (if (string-match comment-end-skip s) s |
| 1218 | (comment-padright comment-end)))) |
| 1219 | (if multi (comment-padright comment-continue numarg)) |
| 1220 | (if multi |
| 1221 | (comment-padleft (comment-string-reverse comment-continue) numarg)) |
| 1222 | block |
| 1223 | lines |
| 1224 | indent)))))) |
| 1225 | |
| 1226 | ;;;###autoload |
| 1227 | (defun comment-box (beg end &optional arg) |
| 1228 | "Comment out the BEG .. END region, putting it inside a box. |
| 1229 | The numeric prefix ARG specifies how many characters to add to begin- and |
| 1230 | end- comment markers additionally to what variable `comment-add' already |
| 1231 | specifies." |
| 1232 | (interactive "*r\np") |
| 1233 | (comment-normalize-vars) |
| 1234 | (let ((comment-style (if (cadr (assoc comment-style comment-styles)) |
| 1235 | 'box-multi 'box))) |
| 1236 | (comment-region beg end (+ comment-add arg)))) |
| 1237 | |
| 1238 | (defun comment-only-p (beg end) |
| 1239 | "Return non-nil if the text between BEG and END is all comments." |
| 1240 | (save-excursion |
| 1241 | (goto-char beg) |
| 1242 | (comment-forward (point-max)) |
| 1243 | (<= end (point)))) |
| 1244 | |
| 1245 | ;;;###autoload |
| 1246 | (defun comment-or-uncomment-region (beg end &optional arg) |
| 1247 | "Call `comment-region', unless the region only consists of comments, |
| 1248 | in which case call `uncomment-region'. If a prefix arg is given, it |
| 1249 | is passed on to the respective function." |
| 1250 | (interactive "*r\nP") |
| 1251 | (comment-normalize-vars) |
| 1252 | (funcall (if (comment-only-p beg end) |
| 1253 | 'uncomment-region 'comment-region) |
| 1254 | beg end arg)) |
| 1255 | |
| 1256 | ;;;###autoload |
| 1257 | (defun comment-dwim (arg) |
| 1258 | "Call the comment command you want (Do What I Mean). |
| 1259 | If the region is active and `transient-mark-mode' is on, call |
| 1260 | `comment-region' (unless it only consists of comments, in which |
| 1261 | case it calls `uncomment-region'). |
| 1262 | Else, if the current line is empty, call `comment-insert-comment-function' |
| 1263 | if it is defined, otherwise insert a comment and indent it. |
| 1264 | Else if a prefix ARG is specified, call `comment-kill'. |
| 1265 | Else, call `comment-indent'. |
| 1266 | You can configure `comment-style' to change the way regions are commented." |
| 1267 | (interactive "*P") |
| 1268 | (comment-normalize-vars) |
| 1269 | (if (and mark-active transient-mark-mode) |
| 1270 | (comment-or-uncomment-region (region-beginning) (region-end) arg) |
| 1271 | (if (save-excursion (beginning-of-line) (not (looking-at "\\s-*$"))) |
| 1272 | ;; FIXME: If there's no comment to kill on this line and ARG is |
| 1273 | ;; specified, calling comment-kill is not very clever. |
| 1274 | (if arg (comment-kill (and (integerp arg) arg)) (comment-indent)) |
| 1275 | ;; Inserting a comment on a blank line. comment-indent calls |
| 1276 | ;; c-i-c-f if needed in the non-blank case. |
| 1277 | (if comment-insert-comment-function |
| 1278 | (funcall comment-insert-comment-function) |
| 1279 | (let ((add (comment-add arg))) |
| 1280 | ;; Some modes insist on keeping column 0 comment in column 0 |
| 1281 | ;; so we need to move away from it before inserting the comment. |
| 1282 | (indent-according-to-mode) |
| 1283 | (insert (comment-padright comment-start add)) |
| 1284 | (save-excursion |
| 1285 | (unless (string= "" comment-end) |
| 1286 | (insert (comment-padleft comment-end add))) |
| 1287 | (indent-according-to-mode))))))) |
| 1288 | |
| 1289 | ;;;###autoload |
| 1290 | (defcustom comment-auto-fill-only-comments nil |
| 1291 | "Non-nil means to only auto-fill inside comments. |
| 1292 | This has no effect in modes that do not define a comment syntax." |
| 1293 | :type 'boolean |
| 1294 | :group 'comment) |
| 1295 | |
| 1296 | (defun comment-valid-prefix-p (prefix compos) |
| 1297 | "Check that the adaptive fill prefix is consistent with the context. |
| 1298 | PREFIX is the prefix (presumably guessed by `adaptive-fill-mode'). |
| 1299 | COMPOS is the position of the beginning of the comment we're in, or nil |
| 1300 | if we're not inside a comment." |
| 1301 | ;; This consistency checking is mostly needed to workaround the limitation |
| 1302 | ;; of auto-fill-mode whose paragraph-determination doesn't pay attention |
| 1303 | ;; to comment boundaries. |
| 1304 | (if (null compos) |
| 1305 | ;; We're not inside a comment: the prefix shouldn't match |
| 1306 | ;; a comment-starter. |
| 1307 | (not (and comment-start comment-start-skip |
| 1308 | (string-match comment-start-skip prefix))) |
| 1309 | (or |
| 1310 | ;; Accept any prefix if the current comment is not EOL-terminated. |
| 1311 | (save-excursion (goto-char compos) (comment-forward) (not (bolp))) |
| 1312 | ;; Accept any prefix that starts with the same comment-start marker |
| 1313 | ;; as the current one. |
| 1314 | (when (string-match (concat "\\`[ \t]*\\(?:" comment-start-skip "\\)") |
| 1315 | prefix) |
| 1316 | (let ((prefix-com (comment-string-strip (match-string 0 prefix) nil t))) |
| 1317 | (string-match "\\`[ \t]*" prefix-com) |
| 1318 | (let* ((prefix-space (match-string 0 prefix-com)) |
| 1319 | (prefix-indent (string-width prefix-space)) |
| 1320 | (prefix-comstart (substring prefix-com (match-end 0)))) |
| 1321 | (save-excursion |
| 1322 | (goto-char compos) |
| 1323 | ;; The comstart marker is the same. |
| 1324 | (and (looking-at (regexp-quote prefix-comstart)) |
| 1325 | ;; The indentation as well. |
| 1326 | (or (= prefix-indent |
| 1327 | (- (current-column) (current-left-margin))) |
| 1328 | ;; Check the indentation in two different ways, just |
| 1329 | ;; to try and avoid most of the potential funny cases. |
| 1330 | (equal prefix-space |
| 1331 | (buffer-substring (point) |
| 1332 | (progn (move-to-left-margin) |
| 1333 | (point))))))))))))) |
| 1334 | |
| 1335 | |
| 1336 | ;;;###autoload |
| 1337 | (defun comment-indent-new-line (&optional soft) |
| 1338 | "Break line at point and indent, continuing comment if within one. |
| 1339 | This indents the body of the continued comment |
| 1340 | under the previous comment line. |
| 1341 | |
| 1342 | This command is intended for styles where you write a comment per line, |
| 1343 | starting a new comment (and terminating it if necessary) on each line. |
| 1344 | If you want to continue one comment across several lines, use \\[newline-and-indent]. |
| 1345 | |
| 1346 | If a fill column is specified, it overrides the use of the comment column |
| 1347 | or comment indentation. |
| 1348 | |
| 1349 | The inserted newline is marked hard if variable `use-hard-newlines' is true, |
| 1350 | unless optional argument SOFT is non-nil." |
| 1351 | (interactive) |
| 1352 | (comment-normalize-vars t) |
| 1353 | (let (compos comin) |
| 1354 | ;; If we are not inside a comment and we only auto-fill comments, |
| 1355 | ;; don't do anything (unless no comment syntax is defined). |
| 1356 | (unless (and comment-start |
| 1357 | comment-auto-fill-only-comments |
| 1358 | (not (called-interactively-p 'interactive)) |
| 1359 | (not (save-excursion |
| 1360 | (prog1 (setq compos (comment-beginning)) |
| 1361 | (setq comin (point)))))) |
| 1362 | |
| 1363 | ;; Now we know we should auto-fill. |
| 1364 | ;; Insert the newline before removing empty space so that markers |
| 1365 | ;; get preserved better. |
| 1366 | (if soft (insert-and-inherit ?\n) (newline 1)) |
| 1367 | (save-excursion (forward-char -1) (delete-horizontal-space)) |
| 1368 | (delete-horizontal-space) |
| 1369 | |
| 1370 | (if (and fill-prefix (not adaptive-fill-mode)) |
| 1371 | ;; Blindly trust a non-adaptive fill-prefix. |
| 1372 | (progn |
| 1373 | (indent-to-left-margin) |
| 1374 | (insert-before-markers-and-inherit fill-prefix)) |
| 1375 | |
| 1376 | ;; If necessary check whether we're inside a comment. |
| 1377 | (unless (or compos (null comment-start)) |
| 1378 | (save-excursion |
| 1379 | (backward-char) |
| 1380 | (setq compos (comment-beginning)) |
| 1381 | (setq comin (point)))) |
| 1382 | |
| 1383 | (cond |
| 1384 | ;; If there's an adaptive prefix, use it unless we're inside |
| 1385 | ;; a comment and the prefix is not a comment starter. |
| 1386 | ((and fill-prefix |
| 1387 | (comment-valid-prefix-p fill-prefix compos)) |
| 1388 | (indent-to-left-margin) |
| 1389 | (insert-and-inherit fill-prefix)) |
| 1390 | ;; If we're not inside a comment, just try to indent. |
| 1391 | ((not compos) (indent-according-to-mode)) |
| 1392 | (t |
| 1393 | (let* ((comment-column |
| 1394 | ;; The continuation indentation should be somewhere between |
| 1395 | ;; the current line's indentation (plus 2 for good measure) |
| 1396 | ;; and the current comment's indentation, with a preference |
| 1397 | ;; for comment-column. |
| 1398 | (save-excursion |
| 1399 | ;; FIXME: use prev line's info rather than first line's. |
| 1400 | (goto-char compos) |
| 1401 | (min (current-column) (max comment-column |
| 1402 | (+ 2 (current-indentation)))))) |
| 1403 | (comstart (buffer-substring compos comin)) |
| 1404 | (normalp |
| 1405 | (string-match (regexp-quote (comment-string-strip |
| 1406 | comment-start t t)) |
| 1407 | comstart)) |
| 1408 | (comment-end |
| 1409 | (if normalp comment-end |
| 1410 | ;; The comment starter is not the normal comment-start |
| 1411 | ;; so we can't just use comment-end. |
| 1412 | (save-excursion |
| 1413 | (goto-char compos) |
| 1414 | (if (not (comment-forward)) comment-end |
| 1415 | (comment-string-strip |
| 1416 | (buffer-substring |
| 1417 | (save-excursion (comment-enter-backward) (point)) |
| 1418 | (point)) |
| 1419 | nil t))))) |
| 1420 | (comment-start comstart) |
| 1421 | (continuep (or comment-multi-line |
| 1422 | (cadr (assoc comment-style comment-styles)))) |
| 1423 | ;; Force comment-continue to be recreated from comment-start. |
| 1424 | ;; FIXME: wrong if comment-continue was set explicitly! |
| 1425 | ;; FIXME: use prev line's continuation if available. |
| 1426 | (comment-continue nil)) |
| 1427 | (if (and comment-multi-line (> (length comment-end) 0)) |
| 1428 | (indent-according-to-mode) |
| 1429 | (insert-and-inherit ?\n) |
| 1430 | (forward-char -1) |
| 1431 | (comment-indent continuep) |
| 1432 | (save-excursion |
| 1433 | (let ((pt (point))) |
| 1434 | (end-of-line) |
| 1435 | (let ((comend (buffer-substring pt (point)))) |
| 1436 | ;; The 1+ is to make sure we delete the \n inserted above. |
| 1437 | (delete-region pt (1+ (point))) |
| 1438 | (end-of-line 0) |
| 1439 | (insert comend)))))))))))) |
| 1440 | |
| 1441 | (provide 'newcomment) |
| 1442 | |
| 1443 | ;;; newcomment.el ends here |