I noticed something that might be a feature, but I find it rather annoying. Say I have a piece of code:

some_function = (x, y) ->

and I wish to add a new function call one indentation level deeper than the z(). To illustrate it I will use indenting.

some_function = (x, y) ->

This is with no indentation

some_function = (x, y) ->

Pressing tab once, places two spaces in front of foo()

some_function = (x, y) ->

Pressing tab again does not do the expected behavior of adding two additional spaces. Instead, it de-indents back to the beginning.

Is there a way to override this?


Here's my relevant configuration stuff

   '(coffee-tab-width 2)
   '(coffee-indent-like-python t)

(setq-default indent-tabs-mode nil)
(setq-default tab-width 2)
(setq tab-always-indent t)
(electric-indent-mode 1)
  • 2
    What major mode are you using? – nanny Dec 22 '15 at 14:18
  • @nanny I have seen this behavior in coffee mode (coffeescript) but I'm sure it occurs elsewhere – Steve Dec 22 '15 at 16:27
  • I cannot reproduce this behavior. Pressing TAB repeatedly cycles between 0, 1, and 2 indent levels, as I expect in a indentation-significant language like coffeescript. Can you share any relevant configuration? Indentation settings, what function TAB is bound to, etc. – nanny Dec 22 '15 at 17:08
  • @nanny added anything I have that touches indentation. It seems tabbing only goes up to the level of the thing above it. You can't go passed it by pressing tab. – Steve Dec 22 '15 at 17:41
  • I don't have any experience with coffeescript, but the same thing happens in Python mode, and with good reason. It seems like the behaviour you are describing is simply cycling between valid indentation levels. At least in python, nesting your call to foo() under z() would cause an IndentationError because you are using an unexpected indent? Could you confirm whether or not you are trying to indent foo() further than z()? – elethan Dec 22 '15 at 17:59

From what I have seen with the languages that I work in, emacs major modes for programming languages will often define their own functions to indent code properly for that language. To see some of these functions you can do C-h f type coffee-indent- and then tab to see the list of different indentation functions that coffee-mode provides, and pick one to read it's documentation. I looked through the source code of coffee-mode.el and I don't really understand enough elisp to comment on exactly how what setting coffee-indent-like-python-mode to t will do exactly, but my assumtion from the variable name and from the behaviour it achieves as described in my tests below, is that it causes the coffee-mode indentation commands to behave like python-mode indentation commands (i.e., causes them to behave exactly as you are describing above).

From tests that I ran in a few scratch buffers, I think that the problem is indeed caused by the variable coffee-indent-like-python-mode. Here are the steps that I took to reproduce and then fix your problem (at least in my version of emacs). (Also note that my tabs are bigger than yours, but that shouldn't make a difference. I have enabled whitespace-mode for these screenshots so that it is clear that each indent is a single tab)

  1. Opened a scratch buffer and set it to coffee-mode with M-x coffee-mode.

  2. Pasted in this code with z() and foo() at the same indentation level:

enter image description here

  1. Hit tab on the line with z() indenting it on level

enter image description here

  1. Hit tab on the line with foo() indenting it to the same level as z()

enter image description here

  1. Hit tab again on the line with foo() nesting it one level below z()

enter image description here

If I understand your question correctly, this is the behaviour you are looking for, right? Pressing tab again on the line with foo() will bring it back to to the first level, subsiquent tabs will cycle through levels one, two, and three in this case.

  1. I opened a new scratch buffer in lisp-interaction-mode, entered the code (setq coffee-indent-like-python-mode t) (notice the mode at the end of the variable name which is missing from your sample configuration), and evaluated that code with the point after the last paren with C-x C-e. Then I returned to my coffee-mode buffer and tried indenting again with tab. As expected it indents "like python-mode", i.e., it will not indent foo() past z(), because this kind of indentation is invalid in Python.

  2. I went back to my lisp buffer, changed the t to nil, i.e., (setq coffee-indent-like-python-mode nil), evaluated that, and back in my coffee-mode buffer I can indent foo() past z() again.

Please try these experiments, or simply try removing the reference to coffee-indent-like-python-mode in your config (or set it to nil) to see if it works. Let me know if you have other questions or need to do more troubleshooting.

  • +1, this is a very generous answer that could've easily just been a comment similar to the one I left on the question. Though it's overly-generous if you ask me: the problem was immediately clear after op edited-in his settings. It took me less than a minute to install coffee-mode and figure it out, I assume you figured it out very quickly as well. – nanny Dec 23 '15 at 18:05
  • 1
    @nanny From the conversation in comments above, it seemed like I was not understanding the OP or the OP was not understanding me, so I did as you said, installing coffee-mode to see for myself, and decided to post a detailed answer to try to make the cause of the problem and the solution very clear for the OP and for future users who may have a similar question. I am also somewhat sympathetic to the OP because I had similar indentation-related confusion when I first started using emacs - it often works in a way that makes sense to me now, but that is different from other editors and IDEs – elethan Dec 23 '15 at 18:16
  • This is a great answer. Wow. Thank you. – Steve Dec 25 '15 at 21:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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