13

I need to be able to remove all comments from a buffer from elisp code. For now, I am using:

(goto-char (point-min))
(comment-kill (count-lines (point-min) (point-max)))

However, comment-kill is an interactive function, and its primary usage is to delete one comment at a time. Additionally, it has annoying visible side-effects, since it adds all the comments it killed to the kill-ring.

Is there a function allowing to delete (not kill) some or all comments from a buffer?

T. Verron
  • 4,233
  • 1
  • 22
  • 55
  • 1
    You could do `M-x flush-lines ^\s-*\/\/` or something to that effect. Not perfect, but could work some times. – wvxvw Dec 16 '14 at 13:55
  • @wvxvw Thank you for the suggestion! However, I had briefly considered going this way, and concluded that it would be too complicated: flush-lines won't do, because comments may not take the entire line (replace-regexp would be OK I guess); more annoyingly, there are several syntax for comments, and they can be nested, making it (probably) out of the reach of regexps. – T. Verron Dec 16 '14 at 14:19
  • Out of curiosity, do you want the comments removed permanently or do you just want to get them out of the way temporarily? Do you perhaps just want to hide them? – Drew Dec 16 '14 at 16:46

2 Answers2

12

In general, there's nothing wrong with using commands as part of elisp code. Those functions which are only meant for interactive use will (or should) warn you about that. See next-line for instance.

In order to delete, instead of killing, just make sure the kill-ring isn't changed:

(goto-char (point-min))
(let (kill-ring)
  (comment-kill (count-lines (point-min) (point-max))))
Malabarba
  • 22,878
  • 6
  • 78
  • 163
  • Yes, I get that. My main issue with this command is the kill-ring (which you answer), and potential optimization issues (which will remain potential if there is nothing to compare against). – T. Verron Dec 16 '14 at 14:14
7

@Malabarba's answer looks like the simplest and most elegant solution. However, if you do this enough that it warrants its own function, you can also adapt comment-kill to delete without modifying the kill ring. Here's the source code of comment-kill with the single-line change to define comment-delete:

(defun comment-delete (arg)
  "Delete the first comment on this line, if any.  Don't touch
the kill ring.  With prefix ARG, delete comments on that many
lines starting with this one."
  (interactive "P")
  (comment-normalize-vars)
  (dotimes (_i (prefix-numeric-value arg))
    (save-excursion
      (beginning-of-line)
      (let ((cs (comment-search-forward (line-end-position) t)))
    (when cs
      (goto-char cs)
      (skip-syntax-backward " ")
      (setq cs (point))
      (comment-forward)
      ;; (kill-region cs (if (bolp) (1- (point)) (point))) ; original
      (delete-region cs (if (bolp) (1- (point)) (point)))  ; replace kill-region with delete-region
      (indent-according-to-mode))))
    (if arg (forward-line 1))))

And here's a function (NB: minimally tested) that provides some additional functionality, allowing you to delete comments on the current line, in the active region, or in the entire buffer:

(defun comment-delete-dwim (beg end arg)
  "Delete comments without touching the kill ring.  With active
region, delete comments in region.  With prefix, delete comments
in whole buffer.  With neither, delete comments on current line."
  (interactive "r\nP")
  (let ((lines (cond (arg
                      (count-lines (point-min) (point-max)))
                     ((region-active-p)
                      (count-lines beg end)))))
    (save-excursion
      (when lines
        (goto-char (if arg (point-min) beg)))
      (comment-delete (or lines 1)))))

I haven't checked performance issues, but perhaps there's a tiny bump from not touching the kill ring. Regardless, I doubt you'll notice performance problems unless you're working with a truly massive buffer. But since you're unlikely to use this function very frequently, it seems like it would not be worth the effort to work on optimization.

Dan
  • 32,584
  • 6
  • 98
  • 168
  • Oh, the function *is* run pretty often, and sometimes on large buffers. But the machinery that it is part of has some worse bottlenecks, at least for now. – T. Verron Dec 16 '14 at 16:23