nex3 / haml-mode

Emacs mode for Haml.
http://haml-lang.com
MIT License
149 stars 42 forks source link

automagic indentation behaves strangely #30

Open recursive-madman opened 10 years ago

recursive-madman commented 10 years ago

I'm noticing various situations in which the automatic indentation in haml-mode does not what I expect it to do.

First issue:

Situation: (using <> to denote my cursor position)

.element-a
  some text
.element-b<>

When I press RET now, I would expect the following result:

.element-a
  some text
.element-b
  <>

What happens instead is this:

.element-a
  some text
  .element-b
    <>

In words: the line I just wrote has become nested under the deepest context above it.

(my workaround for this is currently to press C-j TAB. It is strange that this even works, since C-j is bound to electric-newline-and-maybe-indent, which is the function I would expect to have the bahavior that haml-mode apparently attaches to newline)

Second issue:

Situation:

:javascript
  function someFunction() {<>

When I now press RET, the situation becomes:

:javascript
  function someFunction() {
  <>

Pressing TAB now only allows me to step out of the :javascript block (to the left), not indent within it.

I would expect:

:javascript
  function someFunction() {
    <>

So far so good. But it becomes weirder.

Third issue:

:javascript
  function someFunction() {
    someCode();<>

(i.e. I manually indented the line with spaces and wrote a line)

Now when I press RET, the situation again becomes:

:javascript
  function someFunction() {
  someCode();
  <>

In general what all those have in common is that haml-mode is altering the indentation of the line I am leaving, when it should at most change the indentation of the new line I am creating by pressing RET.

purcell commented 10 years ago

Yes, if you enable electric indenting, then this isn't going to work, as you've discovered. This is because there's no single unambiguously correct indentation, and so TAB "bounces" the indentation level. The same happens in other languages such as Haskell and Python. You should disable electric-indent-mode in haml-mode buffers.

recursive-madman commented 10 years ago

Indeed. That does solve my problem! Even C-j works as expected again :)

Since I didn't enable electric-indent-mode myself, I assume it's my emacs' default (using GNU emacs 24.4.1 at the moment).

Would you consider disabling it by default for haml buffers? I'm sure it confuses a lot of people.

purcell commented 10 years ago

Done in 6ce934b. If that fixes the problem for you, please go ahead and close the issue. :-)

recursive-madman commented 10 years ago

Kind of.

After your last comment I added this to my .emacs:

(add-hook 'haml-mode-hook (lambda () (set 'electric-indent-mode '())))

It had the effect that newline (bound to RET) inserts a newline character, as one would expect. electric-newline-maybe-indent (bound to C-j) inserts a newline and indents -- also as expected.

Your change solves the original problem (RET/C-j no longer cause indentation change on the previous line), but the role of RET and C-j is reversed.

purcell commented 10 years ago

Yes, it's electric-indent-mode which reverses those keys from what they used to be prior to Emacs 24.4. I may be an outlier, because I'm one of those people who rebinds RET to newline-and-indent, and I don't habitually use C-j, so I didn't notice the difference.

The right solution is probably to leave electric-indent-mode active and set electric-indent-functions to something sensible. That would require some digging.

P.S. I read back through your (excellent) bug description above, and the :javascript block behaviour is unrelated: haml-mode doesn't know anything about filter blocks other than that they must be indented relative to the containing :filtername. Fixing that particular behaviour would be complicated, and it's something I'm unlikely to have the bandwidth to tackle in the foreseeable future.

purcell commented 10 years ago

P.S. I think that the bindings don't actually get reversed by electric-indent-mode. Rather, when electric-indent-mode is on, RET ends up working like C-j always does. But it turns out that RET is already overridden in haskell-mode by (at least) haskell-indentation-mode in order to auto-indent, so I think there's a good chance few will ever notice this change.

recursive-madman commented 10 years ago

Yes, it's electric-indent-mode which reverses those keys from what they used to be prior to Emacs 24.4.

I realize that now. Also I realize that my fix caused electric-indent-mode to be disabled globally, which as I also realize now is what I wanted in the first place -- but haml-mode shouldn't impose on people.

In light of this, your fix seems to be the correct solution for haml-mode.

Regarding the :javascript block: With electric-indent-inhibit set at least regular TAB indenting works -- the HAML way, not the JS way, but that is kind of ok. It means I only have to type spaces when descending in context, not on every line in the context.

I don't have haskell-mode installed, so I don't know what it does. My gut feeling when reading your comment though was: if haskell-mode globally changes the binding of RET, then it should stop doing that ;)

purcell commented 10 years ago

Oh, the haskell-mode comment got typed into the wrong tab, because I'm working out similar electric-indent-mode issues there too! :-)