2

I am trying to delete all HTML style comments from my current buffer.

I found a solution in "Function to delete all comments from a buffer, without moving them to kill ring", but since it is more than two lines, M-x eval-expression does not work.

How do I evaluate a multiline elisp expression?

Zolomon
  • 131
  • 6

4 Answers4

4

I guess you mean M-x eval-expression, because eval is not interactive function (command).

You can either:

  • define temporary function in *scratch* and then call it or

  • write everything you need in *scratch*, kill it and yank into minibuffer of eval-expression or

  • use C-q C-j to insert new lines in minibuffer.

Mark Karpov
  • 4,893
  • 1
  • 24
  • 53
  • I didn't know that you could yank a multiline string into minibuffer while `eval-expression` is being executed, or that `C-q C-j` would insert newlines. Thanks a lot! – Zolomon Sep 15 '15 at 11:29
3

I assume that the code you want to run is

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

Actually, the problem is not that the Lisp code contains multiple lines — that would work just fine — but that the Lisp code consists of multiple expressions that need to be executed in sequence.

M-x eval-expression requires a single expression. If you want to evaluate two expressions successively, the simplest solution, cognitively speaking, is to call M-x eval-expression twice.

M-x eval-expression RET (goto-char (point-min)) RET
M-x (let (kill-ring) (comment-kill (count-lines (point-min) (point-max)))) RET

Since whitespace isn't significant in Lisp, you can put a space instead of the newline if you're typing the code. If you're copy-pasting, keeping the pasted newline is fine too.

From a Lisp perspective, the “right” solution would be to put the two expressions into a progn form. A progn expression runs each expression in sequence (and returns the value of the last one).

M-x eval-expression RET (progn (goto-char (point-min)) (let (kill-ring) (comment-kill (count-lines (point-min) (point-max))))) RET

In this particular case, there are other solutions that are simpler but don't generalize:

  • Instead of running (goto-char (point-min)), use key bindings to move to the beginning of the buffer (C-home or M-<).
  • Since let itself allows multiple expressions (let is like progn, but first binds some variables), you could write that code

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

Another approach would be to copy the code into the buffer you want to modify, select it, run M-x eval-region, and finally remove the code. That only works if the code you want to run wouldn't affect itself, and if the buffer is a normal, non-read-only text edition buffer.

If you're going to use that code more than once, make it a function and define it in your init file.

  • I really like your answer, but I also like @Mark's notes on `C-q C-j` and using the `*scratch*` buffer. Not sure which solution I want to mark as an answer. – Zolomon Sep 16 '15 at 06:08
2

M-x eval-expression, aka M-: evaluates a multiline expression just fine.

And besides pasting a multiline sexp into the minibuffer, you can insert a newline char there using C-q C-j.

Drew
  • 75,699
  • 9
  • 109
  • 225
  • I didn't know about `C-q C-j` before, pressing `RET` inside eval expression caused it to perform the evaluation. Thanks! – Zolomon Sep 15 '15 at 14:57
  • 1
    `C-j` normally inserts a newline character (`CONTROL J` **is** the newline character). But in the minibuffer `C-j` does something different, in vanilla Emacs. It should not, IMHO. (And in [Icicles](http://www.emacswiki.org/emacs/Icicles) it does not - it just inserts a newline char, just as `?` inserts a `?` char and `SPC` inserts a space char.) – Drew Sep 15 '15 at 15:01
  • @Zolomon, I thought I said you about `C-q C-j` already. I wonder if my answer is getting invisible somehow if Drew thinks he should replicate its contents in his answer. – Mark Karpov Sep 15 '15 at 15:40
  • -1 This answer is **not useful**. It doesn't add anything to answer that I posted 4 hours before this answer. Reduced to its original content, it says "`eval-expression` evaluates multiline expressions". It doesn't answer the question "how". The fact that it does evaluate them is apparent from my answer and I provide several ways to do it. If you think `C-q C-j` is useful thing to mention, you could upvote my answer that did it, instead of posting your own. Yet this is even upvoted, don't know why. – Mark Karpov Sep 15 '15 at 16:02
  • @Mark: Uh, if I thought you had said the same thing then I would not have posted this answer. You did not say that `eval-expression` evaluates multiline sexps (and your answer still does not say that, AFAICT). Your answer sends the OP to buffer `*scratch*`, which has nothing to do with what I said. And your answer does not say that you can paste a multiline sexp in the *minibuffer* -- which, I think, was the OP's misunderstanding. But if you make these things clear in your answer I will be glad to delete my answer. :-) – Drew Sep 16 '15 at 00:02
  • @Drew, I did say that you can kill expression past it into minibuffer, re-read my answer. I just mentioned `*scratch*` as an example. – Mark Karpov Sep 16 '15 at 04:40
  • @Mark: I repeat that if you make the things my answer says clear in your answer I will gladly delete mine. I do not agree that your answer covers what mine says, so far. – Drew Sep 16 '15 at 15:19
  • @Drew, I disagree with your disagreement. Let it be, after all. Maybe it's different indeed. – Mark Karpov Sep 16 '15 at 15:30
1

I'm not sure if I understand your question correctly but if you just want to have a command to delete the comments you can take the code from your referenced answer and wrap it in a function like this:

(defun delete-comments ()
  (interactive)
  (save-excursion 
    (goto-char (point-min))
    (let (kill-ring)
      (comment-kill (count-lines (point-min) (point-max))))))

The (interactive) expression makes this function a command which means you can call it from M-x or use a keybinding for it. The save-excursion will restore the position of the point after the function is evaluated. If you want to use that command more then once you can add it to your init file and if you want a keybdinding for it you would add something like the following to the init file:

(global-set-key (kbd "C-x #") 'delete-comments)

If you just have a temproary use for this you can put the function in your *scratch* buffer and M-x eval-buffer after that go to your html buffer and call M-x delete-comments. Hope that helps.

clemera
  • 3,401
  • 13
  • 40
  • 2
    This responds to what the OP wanted to do, apparently. But it is *not* an answer to the question posed. The OP should consider completely rewriting the question to correspond to this answer (or perhaps post a new question). Someone looking for this answer, and the real question it responds to, will likely not find it by searching, because the question as posed is entirely different. – Drew Sep 15 '15 at 14:54
  • 1
    @Drew I agree, the way OP posted the question, I assumed a general answer with basic informations would help best. I thought more in terms of "How could I help him to approach what he want" instead of "how do I match the question".But for discoverablity reasons OP may consider to rephrase it a bit, any ideas for a better title? – clemera Sep 15 '15 at 15:00
  • 1
    The real question is a good one, as is the answer. It merits being posed clearly, rather than hiding behind the question that was posed in its place. – Drew Sep 15 '15 at 15:02
  • @Drew How would you prefer I rewrite the question title or body? – Zolomon Sep 15 '15 at 15:11
  • It's your question, not mine. This answer starts by saying that "*if you just want to have a command to delete the comments*...". So if that's what you are looking for then ask for that. If you want to leave this question also (two questions), then @hatschipuh could move this answer to the new question, and you could accept it there as the answer. If you want to just replace this question with the one you meant to ask then that's OK to, AFAIK. – Drew Sep 15 '15 at 15:28
  • @Zolomon would you please unaccept my answer so I can delete it? Because there are other answers here that better match your question. If you want you can start a new question and I will post the same answer there. But it's not necessary I don't care about the points really ;) – clemera Sep 15 '15 at 23:21