aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier1999-11-29 00:49:18 +0000
committerStefan Monnier1999-11-29 00:49:18 +0000
commit7a0a180a0a512424ed47360bfc9237e70b3ebab4 (patch)
tree7d629559d11cc5bcb4077a05f77d837d95a0b4fd
parentaac88001d4ded0af679bf29b4b36d1141122dc5c (diff)
downloademacs-7a0a180a0a512424ed47360bfc9237e70b3ebab4.tar.gz
emacs-7a0a180a0a512424ed47360bfc9237e70b3ebab4.zip
(kill-comment): Fixed by rewriting it with syntax-tables rather than regexps
(comment-normalize-vars): Set default (cdr comment-continue) (comment-end-quote-re): new function taken out of `comment-region-internal' (uncomment-region): Rewritten using syntax-tables. Also unquotes nested comment-ends and eliminates continuation markers. (comment-region-internal): Don't create a default for cce. Use `comment-end-quote-re'.
-rw-r--r--lisp/newcomment.el261
1 files changed, 136 insertions, 125 deletions
diff --git a/lisp/newcomment.el b/lisp/newcomment.el
index 2cce9386fd7..748330a599c 100644
--- a/lisp/newcomment.el
+++ b/lisp/newcomment.el
@@ -5,7 +5,7 @@
5;; Author: Stefan Monnier <monnier@cs.yale.edu> 5;; Author: Stefan Monnier <monnier@cs.yale.edu>
6;; Keywords: comment uncomment 6;; Keywords: comment uncomment
7;; Version: $Name: $ 7;; Version: $Name: $
8;; Revision: $Id: newcomment.el,v 1.1 1999/11/28 18:51:06 monnier Exp $ 8;; Revision: $Id: newcomment.el,v 1.2 1999/11/28 21:33:55 monnier Exp $
9 9
10;; This program is free software; you can redistribute it and/or modify 10;; This program is free software; you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by 11;; it under the terms of the GNU General Public License as published by
@@ -39,6 +39,9 @@
39;; - extract comment data from the syntax-table 39;; - extract comment data from the syntax-table
40;; - maybe do the opposite as well (set the syntax-table from other data) 40;; - maybe do the opposite as well (set the syntax-table from other data)
41;; - customizable auto-fill of comments 41;; - customizable auto-fill of comments
42;; - uncomment-region with a numeric argument
43;; - uncomment-region with a consp (for blocks) or somehow make the
44;; deletion of continuation markers less dangerous
42 45
43;;; Code: 46;;; Code:
44 47
@@ -173,45 +176,6 @@ With any other arg, set comment column to indentation of the previous comment
173 (setq comment-column (current-column)) 176 (setq comment-column (current-column))
174 (message "Comment column set to %d" comment-column)))) 177 (message "Comment column set to %d" comment-column))))
175 178
176(defun kill-comment (arg)
177 "Kill the comment on this line, if any.
178With argument, kill comments on that many lines starting with this one."
179 ;; this function loses in a lot of situations. it incorrectly recognises
180 ;; comment delimiters sometimes (ergo, inside a string), doesn't work
181 ;; with multi-line comments, can kill extra whitespace if comment wasn't
182 ;; through end-of-line, et cetera.
183 (interactive "P")
184 (or comment-start-skip (error "No comment syntax defined"))
185 (let ((count (prefix-numeric-value arg)) endc)
186 (while (> count 0)
187 (save-excursion
188 (end-of-line)
189 (setq endc (point))
190 (beginning-of-line)
191 (and (string< "" comment-end)
192 (setq endc
193 (progn
194 (re-search-forward (regexp-quote comment-end) endc 'move)
195 (skip-chars-forward " \t")
196 (point))))
197 (beginning-of-line)
198 (if (re-search-forward comment-start-skip endc t)
199 (progn
200 (goto-char (match-beginning 0))
201 (skip-chars-backward " \t")
202 (kill-region (point) endc)
203 ;; to catch comments a line beginnings
204 (indent-according-to-mode))))
205 (if arg (forward-line 1))
206 (setq count (1- count)))))
207
208(defvar comment-padding 1
209 "Number of spaces `comment-region' puts between comment chars and text.
210Can also be a string instead.
211
212Extra spacing between the comment characters and the comment text
213makes the comment easier to read. Default is 1. Nil means 0.")
214
215;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 179;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
216 180
217(defcustom comment-nested nil 181(defcustom comment-nested nil
@@ -228,6 +192,34 @@ If 'multiline, only add them for truly multiline comments.")
228;; (defcustom comment-multiline t 192;; (defcustom comment-multiline t
229;; "non-nil if `comment-region' should use multi-line comments.") 193;; "non-nil if `comment-region' should use multi-line comments.")
230 194
195(defvar comment-padding 1
196 "Number of spaces `comment-region' puts between comment chars and text.
197Can also be a string instead.
198
199Extra spacing between the comment characters and the comment text
200makes the comment easier to read. Default is 1. Nil means 0.")
201
202(defun kill-comment (arg)
203 "Kill the comment on this line, if any.
204With prefix ARG, kill comments on that many lines starting with this one."
205 (interactive "P")
206 (let (endc)
207 (dotimes (_ (prefix-numeric-value arg))
208 (save-excursion
209 (end-of-line)
210 (setq endc (point))
211 (beginning-of-line)
212 (let ((cs (nth 8 (parse-partial-sexp (point) endc nil nil nil t))))
213 (when cs
214 (goto-char cs)
215 (skip-syntax-backward " ")
216 (setq cs (point))
217 (forward-comment 1)
218 (skip-syntax-backward " ")
219 (kill-region cs (if (bolp) (1- (point)) (point)))
220 (indent-according-to-mode))))
221 (if arg (forward-line 1)))))
222
231(defun comment-normalize-vars () 223(defun comment-normalize-vars ()
232 (or comment-start (error "No comment syntax is defined")) 224 (or comment-start (error "No comment syntax is defined"))
233 (when (integerp comment-padding) 225 (when (integerp comment-padding)
@@ -238,11 +230,12 @@ If 'multiline, only add them for truly multiline comments.")
238 (when (string-match "\\`\\s-*\\(.*\\S-\\)\\s-*\\'" comment-end) 230 (when (string-match "\\`\\s-*\\(.*\\S-\\)\\s-*\\'" comment-end)
239 (setq comment-end (match-string 1 comment-end))) 231 (setq comment-end (match-string 1 comment-end)))
240 ;; 232 ;;
241 (let ((csl (length comment-start))) 233 (unless (or (car comment-continue) (string= comment-end ""))
242 (if (not (or comment-continue (string= comment-end ""))) 234 (set (make-local-variable 'comment-continue)
243 (set (make-local-variable 'comment-continue) 235 (cons (concat " " (substring comment-start 1))
244 (cons (concat " " (substring comment-start 1)) 236 nil)))
245 ""))))) 237 (when (and (car comment-continue) (null (cdr comment-continue)))
238 (setf (cdr comment-continue) (string-reverse (car comment-continue)))))
246 239
247(defmacro until (&rest body) 240(defmacro until (&rest body)
248 (let ((retsym (make-symbol "ret"))) 241 (let ((retsym (make-symbol "ret")))
@@ -253,81 +246,98 @@ If 'multiline, only add them for truly multiline comments.")
253 246
254(defun string-reverse (s) (concat (reverse (string-to-list s)))) 247(defun string-reverse (s) (concat (reverse (string-to-list s))))
255 248
256(defun uncomment-region (beg end &optional arg) 249(defun comment-end-quote-re (str &optional re)
257 "Comment or uncomment each line in the region. 250 "Make a regexp that matches the (potentially quoted) STR comment-end.
258With just C-u prefix arg, uncomment each line in region. 251The regexp has one group in it which matches RE right after the
259Numeric prefix arg ARG means use ARG comment characters. 252potential quoting."
260If ARG is negative, delete that many comment characters instead. 253 (when (and (not comment-nested) (> (length str) 1))
261Comments are terminated on each line, even for syntax in which newline does 254 (concat (regexp-quote (substring str 0 1))
262not end the comment. Blank lines do not get comments. 255 "\\\\*\\(" re "\\)"
256 (regexp-quote (substring str 1)))))
263 257
264The strings used as comment starts are build from 258(defun uncomment-region (beg end &optional arg)
265`comment-start' without trailing spaces and `comment-padding'." 259 "Uncomment each line in the BEG..END region.
260ARG is currently ignored."
266 (interactive "*r\nP") 261 (interactive "*r\nP")
267 (comment-normalize-vars) 262 (comment-normalize-vars)
268 (if (> beg end) (let (mid) (setq mid beg beg end end mid))) 263 (if (> beg end) (let (mid) (setq mid beg beg end end mid)))
269 (save-excursion 264 (save-excursion
270 (save-restriction 265 (goto-char beg)
271 (let* ((cs comment-start) (ce comment-end) 266 (unless (markerp end) (setq end (copy-marker end)))
272 numarg) 267 (let ((numarg (prefix-numeric-value arg))
273 (if (consp arg) (setq numarg t) 268 state spt)
274 (setq numarg (prefix-numeric-value arg)) 269 (while (and (< (point) end)
275 ;; For positive arg > 1, replicate the comment delims now, 270 (setq state (parse-partial-sexp
276 ;; then insert the replicated strings just once. 271 (point) end
277 (while (> numarg 1) 272 nil nil nil t))
278 (setq cs (concat cs comment-start) 273 (setq spt (nth 8 state)))
279 ce (concat ce comment-end)) 274 (unless (nth 3 state)
280 (setq numarg (1- numarg)))) 275 (let* ((stxt (buffer-substring spt (point)))
281 ;; Loop over all lines from BEG to END. 276 ;; find the end of the comment
282 (narrow-to-region beg end) 277 (ept (progn
283 (goto-char beg) 278 (when (nth 8 (parse-partial-sexp
284 (cond 279 (point) (point-max)
285 ((consp arg) (comment-region beg end)) 280 nil nil state 'syntax-table))
286 ((< numarg 0) (comment-region beg end (- numarg))) 281 (error "Can't find the comment end"))
287 (t 282 (point-marker)))
288 (while (not (eobp)) 283 ;; find the start of the end-comment
289 (let (found-comment) 284 (_ (while (save-excursion
290 ;; Delete comment start from beginning of line. 285 (nth 8
291 (if (eq numarg t) 286 (save-restriction
292 (while (looking-at (regexp-quote cs)) 287 (narrow-to-region (point) ept)
293 (setq found-comment t) 288 (parse-partial-sexp (point) ept
294 (delete-char (length cs))) 289 nil nil state))))
295 (let ((count numarg)) 290 (backward-char)))
296 (while (and (> 1 (setq count (1+ count))) 291 (etxt (buffer-substring (point) ept))
297 (looking-at (regexp-quote cs))) 292 (end-quote-re (comment-end-quote-re etxt "\\\\")))
298 (setq found-comment t) 293 (save-restriction
299 (delete-char (length cs))))) 294 (narrow-to-region spt ept)
300 ;; Delete comment padding from beginning of line 295 ;; remove the end-comment (and leading padding and such)
301 (when (and found-comment comment-padding 296 (unless (string= "\n" etxt)
302 (looking-at (regexp-quote comment-padding))) 297 (beginning-of-line)
303 (delete-char (length comment-padding))) 298 (re-search-forward (concat "\\(^\\s-*\\|\\("
304 ;; Delete comment end from end of line. 299 (regexp-quote comment-padding)
305 (if (string= "" ce) 300 "\\)?\\)"
306 nil 301 (regexp-quote (substring etxt 0 1))
307 (if (eq numarg t) 302 "+"
308 (progn 303 (regexp-quote (substring etxt 1))
309 (end-of-line) 304 "\\'"))
310 ;; This is questionable if comment-end ends in 305 (delete-region (match-beginning 0) (match-end 0)))
311 ;; whitespace. That is pretty brain-damaged, 306
312 ;; though. 307 ;; remove the comment-start
313 (while (progn (skip-chars-backward " \t") 308 (goto-char (point-min))
314 (and (>= (- (point) (point-min)) (length ce)) 309 (looking-at (concat (regexp-quote stxt)
315 (save-excursion 310 "+\\(\\s-*$\\|"
316 (backward-char (length ce)) 311 (regexp-quote comment-padding)
317 (looking-at (regexp-quote ce))))) 312 "\\)"))
318 (delete-char (- (length ce))))) 313 (delete-region (match-beginning 0) (match-end 0))
319 (let ((count numarg)) 314
320 (while (> 1 (setq count (1+ count))) 315 ;; unquote any nested end-comment
321 (end-of-line) 316 (when end-quote-re
322 ;; this is questionable if comment-end ends in whitespace 317 (goto-char (point-min))
323 ;; that is pretty brain-damaged though 318 (while (re-search-forward end-quote-re nil t)
324 (skip-chars-backward " \t") 319 (delete-region (match-beginning 1) (match-end 1))))
325 (if (>= (- (point) (point-min)) (length ce)) 320
326 (save-excursion 321 ;; eliminate continuation markers as well
327 (backward-char (length ce)) 322 (let* ((ccs (car comment-continue))
328 (if (looking-at (regexp-quote ce)) 323 (cce (cdr comment-continue))
329 (delete-char (length ce))))))))) 324 (sre (when (and (stringp ccs) (not (string= "" ccs)))
330 (forward-line 1))))))))) 325 (concat
326 "^\\s-*\\(" (regexp-quote ccs)
327 "+\\(" (regexp-quote comment-padding)
328 "\\)?\\)")))
329 (ere (when (and (stringp cce) (not (string= "" cce)))
330 (concat
331 "\\(\\(" (regexp-quote comment-padding)
332 "\\)?" (regexp-quote cce) "\\)\\s-*$")))
333 (re (if (and sre ere) (concat sre "\\|" ere)
334 (or sre ere))))
335 (when re
336 (goto-char (point-min))
337 (while (re-search-forward re nil t)
338 (replace-match "" t t nil (if (match-end 1) 1 3)))))
339 ;; go the the end for the next comment
340 (goto-char (point-max)))))))))
331 341
332(defun comment-make-extra-lines (cs ce ccs cce min-indent max-indent &optional block) 342(defun comment-make-extra-lines (cs ce ccs cce min-indent max-indent &optional block)
333 (if block 343 (if block
@@ -395,23 +405,17 @@ indentation to be kept as it was before narrowing."
395 (if (and (stringp cce) (string= "" cce)) (setq cce nil)) 405 (if (and (stringp cce) (string= "" cce)) (setq cce nil))
396 ;; should we mark empty lines as well ? 406 ;; should we mark empty lines as well ?
397 (if (or ccs block lines) (setq no-empty nil)) 407 (if (or ccs block lines) (setq no-empty nil))
408 ;; make sure we have end-markers for BLOCK mode
409 (when block (unless ce (setq ce (string-reverse cs))))
398 ;; continuation defaults to the same 410 ;; continuation defaults to the same
399 (if ccs (unless block (setq cce nil)) 411 (if ccs (unless block (setq cce nil))
400 (setq ccs cs cce ce)) 412 (setq ccs cs cce ce))
401 ;; make sure we have end-markers for BLOCK mode 413
402 (when block
403 (if (null ce) (setq ce (string-reverse cs)))
404 (if (null cce) (setq cce (string-reverse ccs))))
405
406 (save-excursion 414 (save-excursion
407 (goto-char end) 415 (goto-char end)
408 (unless (or ce (eolp)) (insert "\n") (indent-according-to-mode)) 416 (unless (or ce (eolp)) (insert "\n") (indent-according-to-mode))
409 (comment-with-narrowing beg end 417 (comment-with-narrowing beg end
410 (let ((ce-quote-re 418 (let ((ce-quote-re (comment-end-quote-re comment-end))
411 (when (and (not comment-nested) (> (length comment-end) 1))
412 (concat (regexp-quote (substring comment-end 0 1))
413 "\\\\*\\(\\)"
414 (regexp-quote (substring comment-end 1)))))
415 (min-indent (point-max)) 419 (min-indent (point-max))
416 (max-indent 0)) 420 (max-indent 0))
417 (goto-char (point-min)) 421 (goto-char (point-min))
@@ -532,6 +536,13 @@ The strings used as comment starts are built from
532 536
533;;; Change Log: 537;;; Change Log:
534;; $Log: newcomment.el,v $ 538;; $Log: newcomment.el,v $
539;; Revision 1.2 1999/11/28 21:33:55 monnier
540;; (comment-make-extra-lines): Moved out of comment-region-internal.
541;; (comment-with-narrowing): New macro. Provides a way to preserve
542;; indentation inside narrowing.
543;; (comment-region-internal): Add "\n" to close the comment if necessary.
544;; Correctly handle commenting-out when BEG is not bolp.
545;;
535;; Revision 1.1 1999/11/28 18:51:06 monnier 546;; Revision 1.1 1999/11/28 18:51:06 monnier
536;; First "working" version: 547;; First "working" version:
537;; - uncomment-region doesn't work for some unknown reason 548;; - uncomment-region doesn't work for some unknown reason