smarttabs
smarttabs copied to clipboard
Ruby: indentation is inserting tabs inappropriately.
It appears that the Ruby indentation configuration is broken. C indentation is conforming to the Smart Tabs concept, but the following (example) Ruby code gets indented incorrectly. I have tried removing all tab characters and reindenting the buffer, but the same problem persists. I have replaced tab characters with -> |.
require "banana"
class Test
-> |class Banana
-> |-> |def initialize
-> |-> |-> |if (ENV["banana"] ||
-> |-> |-> |-> |ENV["chicken"] ||
-> |-> |-> |-> |ENV["cow"])
-> |-> |-> |-> |puts "happy"
-> |-> |-> |end
-> |-> |end
-> |end
end
I would expect it to instead do the following:
require "banana"
class Test
-> |class Banana
-> |-> |def initialize
-> |-> |-> |if (ENV["banana"] ||
-> |-> |-> |....ENV["chicken"] ||
-> |-> |-> |....ENV["cow"])
-> |-> |-> |-> |puts "happy"
-> |-> |-> |end
-> |-> |end
-> |end
end
In examining behavior in much larger and more complex reindentation situations, this problem is the same in many situations: it appears that ruby-indent-line or ruby-indent-region is interpreting what should be four spaces as a tab character and is converting to tab characters when it should not.
Is there something that I am missing? I am currently using a very recent version of the Git mirror of the Emacs BZR repository (the development version).
Either the smart-tabs-mode set-up for Ruby is using the wrong variables, or the Ruby mode’s indentation logic is different to other languages’. In the first case, a patch should be relatively straightforward for someone familiar with Emacs’s Ruby mode; in the second, this mode cannot easily be made compatible with Ruby.
Patches are very welcome; analyses showing incompatibility less so, but still welcome.
I recently tested some possible fixes for this. One of them was to simply call the ruby-indent-line function to reindent lines. This works perfectly fine, indenting the aforementioned lines correctly. However, ruby-indent-line is not the default indent-line-function; smie-indent-line is. To fix this, I just always (setq indent-line-function 'ruby-indent-line) during ruby-mode-hook.
Will switching ruby-indent-line for smie-indent-line present surprises to the user, and can this switch be included in the smart-tabs-create-language-advice ruby lines? Or should smart-tabs-mode be cleverer and use the correct indentation function? (I ask out of ignorance of Ruby-mode behavior; whichever you decide on and submit as a patch will be added.)
Well, I know that ruby-indent-line works correctly, and smie-indent-line does not.
It appears that the variable ruby-use-smie in ruby-mode.el determines if Ruby will use SMIE or not. If indent-line-function is buffer-locally set to ruby-indent-line, ruby-indent-line is therefore (duh) used, and it works perfectly. I tried defining a hook to do this (pegged to ruby-mode-hook), but it didn't work.
Unfortunately, I do not have much experience with EmacsLISP packaging, and so I'm somewhat at a loss as to what to do.
EDIT: Fixed words.
It appears that smart-tabs-advice's modifications to the value of indent-line-function are simply getting obliterated by SMIE, and so any modifications don't carry through to the end of all of the hooks that are called.
I fixed it in my personal configuration this morning, by adding (setq ruby-use-smie nil) to my configuration. Perhaps this should be documented for others?
I would prefer a patch that included this within the Ruby set-up; either on its own or within the Ruby mode hook.
Thanks @rye for the fix. This should be indeed documented.