3

I've been trying to configure Emacs so that it insert a 'tab' instead of a series of 'spaces' when indenting Ruby code.

So far, I've tried setting the var ruby-indent-tabs-mode to t so that, as per the documentation, it would "insert tabs in ruby mode if this is non-nil.". But so far, no dice.

I've also tried customising it via Easy customisation, which inserted the following into my init.el:

(custom-set-variables
 ;; custom-set-variables was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(ruby-indent-tabs-mode t))
(custom-set-faces
 ;; custom-set-faces was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 )

And after inspecting the variable via C-h v, it reports the variable is set to t, but pressing TAB keeps on inserting spaces.

I even tried editing the .el file for ruby-mode and re-compiling it to no effect.

Help would be appreciated.

----- EDIT -----

Here's the minor modes reported active via C-h m:

Enabled minor modes: Abbrev Auto-Complete Auto-Composition
Auto-Compression Auto-Encryption File-Name-Shadow Font-Lock
Global-Auto-Complete Global-Font-Lock Inf-Ruby Line-Number Menu-Bar
Show-Smartparens Show-Smartparens-Global Smartparens
Smartparens-Global Transient-Mark

The init.el file currently has:

(require 'cask "/Users/snowingheart/.cask/cask.el")
(cask-initialize)
(require 'pallet)

(add-to-list 'load-path "~/elisp")
(load "php-mode")
(add-to-list 'auto-mode-alist
             '("\\.php[34]?\\'\\|\\.phtml\\'" . php-mode))

(global-set-key (kbd "C-x <up>") 'windmove-up)
(global-set-key (kbd "C-x <down>") 'windmove-down)
(global-set-key (kbd "C-x <right>") 'windmove-right)
(global-set-key (kbd "C-x <left>") 'windmove-left)

(require 'package)
(add-to-list 'package-archives
    '("marmalade" .
      "http://marmalade-repo.org/packages/"))
(package-initialize)

(global-set-key (kbd "C-x >") 'mc/mark-next-like-this)
(global-set-key (kbd "C-x <") 'mc/mark-previous-like-this)
(global-set-key (kbd "C-c C-<") 'mc/mark-all-like-this)
(global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)

(require 'smartparens-config)
(require 'smartparens-ruby)
(require 'smartparens-erb)
(smartparens-global-mode)
(show-smartparens-global-mode t)

(sp-with-modes '(rhtml-mode)
               (sp-local-pair "<%=" "%>")
               (sp-local-pair "<%-" "%>"))
(require 'auto-complete-config)
(add-to-list 'ac-dictionary-directories
             "~/.emacs.d/.cask/24.3.50.1/elpa/auto-complete-20130724.1750/dict")
(ac-config-default)
(setq ac-ignore-case nil)
(add-to-list 'ac-modes 'enh-ruby-mode)
(add-to-list 'ac-modes 'web-mode)

(custom-set-variables
 ;; custom-set-variables was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(indent-tabs-mode t)
 '(ruby-indent-tabs-mode t))
(custom-set-faces
 ;; custom-set-faces was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 )

(setq-default indent-tabs-mode t)
(setq enh-ruby-indent-tabs-mode t)

(smart-tabs-insinuate 'ruby)
(smart-tabs-advice ruby-indent-line ruby-indent-level)
(setq ruby-indent-tabs-mode t)
itsjeyd
  • 5,070
  • 2
  • 30
  • 49
snowingheart
  • 120
  • 9
  • 4
    Please reconsider using a tab vs. spaces. Tabs are displayed differently in various editors, especially when they're configured by other people, and can make code alignments break badly. Some people want a tab to display as two spaces, others want them displaying as four, and some want them as eight. As a result, in Ruby we use two *spaces* for indenting, not tabs, to keep the code written very consistent. Indenting isn't just for your comfort, it's for those people who maintain or inherit your code also. – the Tin Man Apr 07 '14 at 23:52
  • And I quite agree with you. The issue is that this is not for my benefit as for a coworker of mine's. His editor (sublime) displays code indented with tabs, and when working on the same files, things tend to break when I give over my 2-spaced files. – snowingheart Apr 08 '14 at 00:23
  • How about something like this, but for Ruby mode instead?: http://stackoverflow.com/a/21167633/2112489 I'm not sure what else in Ruby mode may need to be changed for the code in my link to work. I use that code with a `text-mode-hook`, and it gets inherited by the other major modes that I normally use. – lawlist Apr 08 '14 at 00:49
  • You mean changing `org-mode-hook` to `ruby-mode-hook`, right? Well, it does change the behaviour of the TAB key, but does not indent anymore (as in just inserts tab after tab after tab...) – snowingheart Apr 08 '14 at 00:54
  • Ah . . . I was thinking only of `tab` . . . I haven't experimented with `indent` -- sorry. – lawlist Apr 08 '14 at 01:15
  • 2
    @snowingheart: Sublime Text is fully-configurable in this regard. It will even examine the file to make a good attempt at guessing what the indent interval is. I don't see why this is your problem rather than your colleague's? – Borodin Apr 08 '14 at 03:18
  • @Borodin lol well, I guess he hasn't fully explored it yet or something? And I thought I'd be able to configure emacs easily... That being the said, I'll tell him to look into it so that the problem might be solved that way instead. – snowingheart Apr 08 '14 at 04:46
  • I use both Sublime and vim, with absolutely no problem. It's easy to set the Sublime default to two-spaces, and not use tabs at all. The same is true with vim. Emacs is surely as flexible as either of those other two. – the Tin Man Apr 08 '14 at 06:33

2 Answers2

2

Try adding the following to your init.el (below the customizations you already have):

(setq-default indent-tabs-mode t)

From the documentation for indent-tabs-mode:

Indentation can insert tabs if this is non-nil.

I don't use ruby-mode so I don't know about possible interactions between indent-tabs-mode and ruby-indent-tabs-mode. It might just be enough to set indent-tabs-mode to t (and erase the customizations you made to ruby-indent-tabs-mode). But when you add the snippet above to your configuration, the default behavior for Emacs will be to insert tabs for indentation.


EDIT

As can be seen here, enh-ruby-mode defines a customizable variable called enh-ruby-indent-tabs-mode with a default value of nil. Later on the value of this variable is used to override the value of indent-tabs-mode, which is why setting indent-tabs-mode to t has no effect on buffers with enh-ruby-mode enabled.

So unless you enable any other modes besides ruby-mode and enh-ruby-mode that might be modifying the indent-tabs-mode variable, adding

(setq enh-ruby-indent-tabs-mode t)

to your init.el should fix your problem.


Another EDIT (working solution)

(Credits: This answer put me on the right track.)

Using

  • Emacs 24.3.1

  • ruby-mode version 1.2 (built-in)

  • enh-ruby-mode version 20140406.252 (installed via M-x package-install ...)

I was able to make it work by adding the following to an otherwise completely empty init.el file:

(package-initialize)

(setq-default tab-width 2)
(setq enh-ruby-indent-tabs-mode t)
(defvaralias 'enh-ruby-indent-level 'tab-width)
(defvaralias 'enh-ruby-hanging-indent-level 'tab-width)

This solution works for both the GUI and the console version of Emacs. It will probably integrate fine with your other customizations but you will need to remove the custom-set-variables section and everything below it from the version of your init.el you posted above.

Note also that if you do come across a situation in which Emacs inserts a space instead of a tab you can always delete it and force insertion of a tab by quoting it via C-q TAB.


Wrapping up

Turns out there is a bug in enh-ruby-mode which causes indentation to fail for blocks starting from the second level when enh-ruby-indent-tabs-mode is set to t. The author/maintainer of enh-ruby-mode has no plans of fixing it, but the bug report includes a patch that supposedly fixes the issue.

Community
  • 1
  • 1
itsjeyd
  • 5,070
  • 2
  • 30
  • 49
  • Somehow that gets overwritten somewhere. I used cask and pallet for package management and installed the `enh-ruby-mode` on top of `ruby-mode`; since it's all done via those tools, my `init.el` does not explicitly require any of those modes. Still, putting the line you said and afterwards starting up a new emacs instance yields the same space-indenting behaviour. I inspected the variable via `C-h v` and it outputs that the current value is `nil`, where the original value was `t`. – snowingheart Apr 08 '14 at 15:55
  • I tried setting the variable via `M-x set-variable` and it is now set to `t`, but still indenting with spaces... – snowingheart Apr 08 '14 at 16:07
  • @snowingheart Thanks for providing more information about the modes you are using when editing Ruby code. I looked at the [source](https://github.com/zenspider/enhanced-ruby-mode/blob/master/enh-ruby-mode.el) of `enh-ruby-mode` and I think I know what's going on. See my updated answer. – itsjeyd Apr 08 '14 at 19:51
  • *sigh* Well, I tried that and now all of the `indent-tab-mode` variables (the `enh`, `ruby` and default one) are set to `t`... And still pressing tab indents the line with spaces and not tabs. – snowingheart Apr 08 '14 at 20:59
  • @snowingheart Interesting. Well, without knowing your exact configuration (and all add-on packages you use) there's not much else I can say. You could try running Emacs without any customizations (via `emacs --no-init-file`) and edit a Ruby file. If Emacs inserts tabs, try enabling the add-on packages you normally use one by one until Emacs starts to insert spaces instead of tabs. That might get you closer to the source of the problem. – itsjeyd Apr 08 '14 at 21:08
  • I'll give that a try and see what gives. Additionally, what info would you require to have my 'exact configuration'? The packages listed via `C-h m` for instance? And the init.el file? Do tell me so as to edit the question and append that info there :D – snowingheart Apr 08 '14 at 21:10
  • Just tried it, so that the file is opened in `Fundamental` mode. The variable `indent-tabs-mode` is set to `t`, but hitting the TAB key just inserts 6 spaces for lines after the first one. The first line is the only one where a tab is actually inserted. After 'tabbing' the first one, the following ones do get tabs 'most' of the time, since some spaces are still inserted now and again. – snowingheart Apr 08 '14 at 21:14
  • @snowingheart That would depend on the size of your `init.el`. If it is large, you might want to consider creating a [Pastebin](http://pastebin.com/) for it and linking to it in the question. As for your suggestion about including the packages enabled for Ruby files, I think that's a good idea. :) – itsjeyd Apr 08 '14 at 21:14
  • @snowingheart I can't reproduce that behavior. When I open Emacs via `emacs --no-init-file` and open an empty `.rb` file in `fundamental-mode` I am able to insert tabs everywhere I want. – itsjeyd Apr 08 '14 at 21:19
  • O.O Well I dunno what's going on then. Would it be related to me using a Mac? I'm looking in the Terminal preferences to see if there's anything at all there that meddles with the way TAB behaves, but I don't see how that would affect emacs at all... And I've pasted the modes and `init.el` file btw. – snowingheart Apr 08 '14 at 21:24
  • @snowingheart Yes, thanks for doing that. I'm actually looking at your `init.el` right now. What happens when you remove the two lines concerning `smart-tabs` and restart Emacs (with the other customizations enabled)? **Also**: You shouldn't set `indent-tabs-mode` and `ruby-indent-tabs-mode` twice. Reset the values of these variables via the customization interface to make the `custom-set-variables` section disappear. – itsjeyd Apr 08 '14 at 21:29
  • Did so. The `smart-tabs` were just there since I thought I'd try that way of enforcing tabs as well (to no avail). And I toggled and erased the customised variables as requested, but the behaviour is exactly the same as before; indenting is done via space insertion, even though every indenting variable is set to `t` (checked again with `C-h v`) – snowingheart Apr 08 '14 at 22:43
  • @snowingheart RE: your question about Terminal preferences meddling with the way `TAB` behaves: Have you tried running Emacs in GUI mode? Both with and without customizations enabled? I am not sure about `TAB` per se but I have seen [questions](http://stackoverflow.com/q/5556678/1199226) on here from users having problems with the behavior of certain keys when running Emacs from the console. These problems are usually caused by the way terminals pass keys to Emacs, so you should definitely try and see if running Emacs in GUI mode makes any difference w/r/t to your problem. – itsjeyd Apr 09 '14 at 07:14
  • @snowingheart I finally got a chance to install and play around with `enh-ruby-mode` and I found a way to make it work, see the new edit to my original answer. – itsjeyd Apr 09 '14 at 08:58
  • wow you've been incredibly helpful, I'm really thankful. And I tried your new solution and have managed to sort-of have tabs for indenting. It appears to be able to indent the 'first level' things (like classes within modules), but the inner class block still is 'indented' with only one space! That is, unless I specifically quote insert the TAB as you stated. Is this the same behaviour you have on your installation? – snowingheart Apr 09 '14 at 14:56
  • 1
    @snowingheart You're welcome and yes, it is. I have no idea why... But since we pretty much solved your original issue (and this comments section is getting *really* long ;)) you might want to consider posting a separate question addressing this particular issue. Alternatively, if you have a GitHub account it might also make sense to ask the developers of `enh-ruby-mode` directly by filing an issue on their [issue tracker](https://github.com/zenspider/enhanced-ruby-mode/issues). **EDIT**: Actually, there already is [such an issue](https://github.com/zenspider/enhanced-ruby-mode/issues/42). – itsjeyd Apr 09 '14 at 15:18
  • I'll go over to github then and see if they can't help with that. Again, thanks a lot :D :D – snowingheart Apr 09 '14 at 15:22
  • @snowingheart ... which also includes a patch that fixes it! (You will have to apply this patch yourself though because the author of `enh-ruby-mode` did not want to include it in the code base. – itsjeyd Apr 09 '14 at 15:23
  • 1
    I'll be trying out the code in there, then :D And it's kinda sad to read the author's take on the issue, since as lyro says, if tabs were not planned to have support, then it should be clearly stated as so. – snowingheart Apr 09 '14 at 15:29
  • 1
    Oh and could you link to that issue on your answer? Just for completeness :P – snowingheart Apr 09 '14 at 15:30
  • 1
    @snowingheart Sure, will do :) Even though it was a rocky road I think we created a good resource here for people who run into the same issue. It probably won't be that many, but anyway ... :) – itsjeyd Apr 09 '14 at 15:35
0

Updated answer au goût du jour (Emacs 28.2):

Set the indent-tabs-mode and ruby-indent-tabs-mode to t.

Globally, in your ~/.emacs.el:

(setq indent-tabs-mode t)
(setq ruby-indent-tabs-mode t)
(setq tab-width 2)
(setq ruby-indent-level 2)

Or better, limited to a particular project, in a ~/src/your-project/.dir-locals.el (for example) file:

((ruby-mode . ((indent-tabs-mode . t)
               (ruby-indent-tabs-mode . t)
               (tab-width . 2)
               (ruby-indent-level . 2))))
Apteryx
  • 5,822
  • 3
  • 16
  • 18