0

When I need to disable code without removing it, I comment it out. I find this clumsy, especially when the code is a function definition or some other kind of cohesive whole, such as:

(global-set-key "\C-x" 'do-stuff)
(defun do-stuff () ...)

Is there a better way? I think something like the following would be nice:

(off
   (global-set-key "\C-x" 'do-stuff)
   (defun do-stuff () ...))

I understand I can define off myself, but isn’t there a standard way to do this?

4
  • 3
    What's the problem with commenting things out? Selecting the code and typing M-; is easy, no? Wrapping your off form around something still requires acting on the beginning and the end of the forms you're disabling, so I don't see an advantage of that over the commenting workflow which acts on those exact same positions.
    – phils
    Commented Mar 18, 2023 at 9:42
  • 2
    @phils: The way Elisp handles ; is based on lines of text instead of S-structures. If we want to comment some code, we first need to make them separate from the code snippet. Sometimes it is annoying. It would be nice to use an S-expression-based approach to comment some code. I also asked a question which is related to this topic.
    – shynur
    Commented Mar 18, 2023 at 11:24
  • @phils off conveys my intention to turn code off. Comments can be used for a lot of other purposes. Also, sometimes, albeit infrequently, I like disabled code to keep being editable without loosing indentation and highlighting. For instance, it’s harder to read commented-out, not highlighted, code. Commented Mar 18, 2023 at 11:36
  • 1
    @Shynur Emacs breaks the lines for you, if necessary, when you comment out a region, and there's a standard key binding for joining lines if uncommenting again. I can only speak for myself of course, but I don't personally find it annoying.
    – phils
    Commented Mar 18, 2023 at 13:16

2 Answers 2

2

The answer to this question generally is to use block-commenting. That's essentially what you're asking for by asking for a (off...) envelope. Think of your (off as starting a comment block and the corresponding ) as ending it.

Unlike Common Lisp, Emacs Lisp doesn't provide a block-commenting feature. That is, it provides only a comment-start string, which is ";", and no comment-end string -- that's the empty string, "".

But you can use the ordinary end-of-line commenting (;) to achieve the effect of block-commenting, provided you have a command that not only lets you (1) comment out code that might, itself, contain comments -- in other words, nest commented code, but also (2) unnest a given level of such a (pseudo) block comment.

The standard command comment-region comes close to this description. And the standard command comment-dwim also comes (less) close to it.

comment-region lets you nest and unnest a given number of ; commenting. comment-dwim doesn't do (un)nesting well. It tries to both comment out a region and add an end-of-line comment (or reposition such an existing comment).

I use my command comment-region-lines, from library misc-cmds.el. It does what comment-region does, except that it comments or uncomments whole lines. I bind it to C-x C-; (which by default is bound comment-line). And I use M-; (bound to comment-dwim) only for end-of-line commenting.

Here's the doc of standard command comment-region.

Comment or uncomment each line in the region.

With just C-u prefix arg, uncomment each line in region BEG .. END.

Numeric prefix ARG means use ARG comment characters. If ARG is negative, delete that many comment characters instead.

The strings used as comment starts are built from comment-start and comment-padding; the strings used as comment ends are built from comment-end and comment-padding.

By default, the comment-start markers are inserted at the current indentation of the region, and comments are terminated on each line (even for syntaxes in which newline does not end the comment and blank lines do not get comments). This can be changed with comment-style.


In your question you also speak about the distraction that commenting code can introduce. For that, I suggest command https://www.emacswiki.org/emacs/HideOrIgnoreComments from my library hide-comnt.el.

It hides the comments in the active region (or the whole buffer, if no active region). With a prefix arg it shows the hidden comments. Or use command hide/show-comments-toggle, which toggles hiding/showing commented text.

There's also Lisp macro with-comments-hidden, for hiding/ignoring comments while executing some code, i.e., when you want some code to ignore the commented text.

And there are some user options that control comment hiding:

  • hide-whitespace-before-comment-flag – If non-nil then whitespace preceding a comment is hidden. Empty lines (newline chars) are not hidden, however.
  • ignore-comments-flag – If nil then with-comments-hidden does not ignore comments.
  • show-invisible-comments-shows-all – If non-nil then showing comments after hiding them shows all text that was invisible, however it was made so. The default is nil: make visible only text that was made invisible by hide/show-comments.
1
  • Thanks for the detailed information. I do use comment-region. About hiding comments, I wouldn’t want to do that indiscriminately. Information provided by comments is rarely less valuable than information provided by code to me – with the obvious exception of commented-out code. Commented Mar 19, 2023 at 17:48
1

This is already a functionality in emacs:

(ignore
 ...)

See: C-h f ignore.

As noted by @shynur, that is a function though, so the arguments will be evaluated, which is not desirable. A macro is the path to avoid that, but it will at a minimum expand to nil. There are scenarios where that is not the right thing to do though (e.g. https://stackoverflow.com/questions/75775454/how-to-define-a-macro-that-returns-nothing), and there are likewise scenarios where it is not correct to return nothing (i.e. as if the code was not there).

For the first case consider:

(+ 8 (off 4))

if off returns nil, this will be an error since you can't add 8 and nil.

For the second case example, consider:

(message "%s" (off (some-code)))

That will give rise to an error if somehow the off macro somehow results in nothing in that position because there would not be enough arguments for the format string.

There isn't a solution for both issues I think.

A comment approach is to wrap the body in (progn ...), and use something like lispy-comment that comments out the sexp if you type ; in front of it, and C-u ; to uncomment the body. There is nothing more simple than this. Even if you had a macro for off, undoing it is more work than this solution, unless you do something like replace off with progn I think.

2
  • 1
    No, it is a function, whose arguments will be evaluated.
    – shynur
    Commented Mar 18, 2023 at 14:31
  • True, thanks for noting it. I expanded my answer a little. Commented Mar 18, 2023 at 16:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.