5

i desperately try to make my emacs xml (sgml?) mode indent with tabs instead of spaces. What i tried so far:

(defun my-xml-hook ()
  (setq c-tab-always-indent t
        tab-width 4
        indent-tabs-mode t) ; use tabs for indentation
  (setq indent-line-function 'insert-tab)
)
(add-hook 'xml-mode-hook 'my-xml-hook)
(defun local-sgml-mode-hook
  (setq fill-column 70
        indent-tabs-mode t
        next-line-add-newlines nil
        sgml-indent-data t)
  (auto-fill-mode t)
  (setq indent-line-function 'insert-tab)
  )
(add-hook 'psgml-mode-hook '(lambda () (local-psgml-mode-hook)))

Nothing works though, indentation will still happen with 2 spaces (emacs23 and emacs24) when editing *.xml files.

Note that i also have

(setq indent-tabs-mode nil)

in my .emacs file, but the hook should be called afterwards so this should be overridden.

How can i force emacs to indent with tabs in *.xml files? Why are my hooks not working?

eci
  • 2,294
  • 20
  • 18
  • `c-tab-always-indent` is for C/C++/Java. Since xml doesn't inherit them, I don't think it will work – abo-abo Aug 08 '13 at 09:27
  • there's equivalent `tab-always-indent` var that you should use – abo-abo Aug 08 '13 at 09:28
  • @abo-abo: tab-always-indent will always insert a tab when hitting tab. However i want _auto-indentation_ using tabs, such that if the indentation is already correct and i hit TAB, nothing happens. For inserting tabs manually i can always use C-q TAB. – eci Aug 08 '13 at 09:38

2 Answers2

7

(c-)tab-always-indent controls what hitting the TAB key does, not what is inserted.

Setting indent-line-function to insert-tab will make you lose the smart indentation of the mode.

If you are using a modern emacs, chances are you are using nxml-mode instead of xml-mode. In that case nxml-mode-hook should be the one where you should do (setq indent-tabs-mode t).

If you are using default sgml mode, sgml-mode-hook should be the one where you should do (setq indent-tabs-mode t) should be done (in your snippet you are using psgml-mode-hook)

(and tab-always-indent and indent-line-function could be leave in their default states)

EDIT

To summarize conversation below: variable nxml-child-indent should not be less than tab-width.

(and since default emacs values for those variables are 2 and 8, imho configuring emacs to indent XML using tabs in emacs is harder than it should be)

juanleon
  • 9,220
  • 30
  • 41
  • You are right, I use nxml-mode. Your solution does not seem to work, though. Even if I run eval-expression: `(setq indent-tabs-mode t)` right in the xml buffer indentation is still performed with 2 spaces. – eci Aug 08 '13 at 09:47
  • The issue with sgml and nxml indentations is that they use indent-to. This function will use spaces when tabs don't fit. So you should check that `sgml-basic-offset` and `tab-width` are configured in a way they match (both to 4, for instance), and that previous lines are indented in multiples of that amount. – juanleon Aug 08 '13 at 10:26
  • I set both variables to 4 and started indentation one line below a line starting at the very left, still 2 spaces indent :( – eci Aug 08 '13 at 10:34
  • 2
    Try also increasing `nxml-child-indent` – juanleon Aug 08 '13 at 10:46
  • Thanks - this variable worked! All i need to make it align with tabs in *.xml (emacs 24) is the following code in .emacs: `(defun my-indent-func () (setq nxml-child-indent 4) ) (add-hook 'nxml-mode-hook 'my-indent-func) ` . Problem solved - thanks jualeon – eci Aug 08 '13 at 11:59
4

It took me quite a while to get nxml-mode to use tabs. I ended up using smart-tabs-mode, which offers a concise solution. For what it's worth, here is the configuration that I finally settled on:

;; indentation using smart-tabs-mode
(setq-default tab-width 4)
(smart-tabs-insinuate 'c 'c++ 'java 'javascript 'cperl 'python 'ruby 'nxml)

;; nxml-mode
(setq 
    nxml-child-indent 4
    nxml-attribute-indent 4
    nxml-slash-auto-complete-flag t)

You don't actually need to set nxml-slash-auto-complete-flag, but it gets you auto end-tag completion, which is really nice.

Chris Clark
  • 1,439
  • 2
  • 17
  • 25